Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: who can reply logic #467

Merged
merged 3 commits into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:convert';

import 'package:ion/app/exceptions/exceptions.dart';
import 'package:ion/app/features/feed/data/models/entities/article_data.c.dart';
import 'package:ion/app/features/feed/data/models/who_can_reply_settings_option.dart';
import 'package:ion/app/features/gallery/providers/providers.dart';
import 'package:ion/app/features/nostr/model/file_alt.dart';
import 'package:ion/app/features/nostr/model/file_metadata.c.dart';
Expand All @@ -24,6 +25,7 @@ class CreateArticle extends _$CreateArticle {

Future<void> create({
required String content,
required WhoCanReplySettingsOption whoCanReply,
String? title,
String? summary,
String? imageId,
Expand All @@ -43,14 +45,15 @@ class CreateArticle extends _$CreateArticle {

final relatedHashtags = ArticleData.extractHashtagsFromMarkdown(updatedContent);

final articleData = ArticleData(
final articleData = ArticleData.fromData(
title: title,
summary: summary,
image: imageUrl,
content: updatedContent,
media: {for (final attachment in mediaAttachments) attachment.url: attachment},
relatedHashtags: relatedHashtags,
publishedAt: publishedAt ?? DateTime.now(),
whoCanReplySettings: {whoCanReply},
);

await ref.read(nostrNotifierProvider.notifier).sendEntitiesData([...files, articleData]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/list_item/list_item.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/feed/providers/selected_visibility_options_provider.c.dart';
import 'package:ion/app/features/feed/views/pages/visibility_settings_modal/visibility_settings_modal.dart';
import 'package:ion/app/features/feed/providers/selected_who_can_reply_option_provider.c.dart';
import 'package:ion/app/features/feed/views/pages/who_can_reply_settings_modal/who_can_reply_settings_modal.dart';
import 'package:ion/app/router/utils/show_simple_bottom_sheet.dart';
import 'package:ion/generated/assets.gen.dart';

Expand All @@ -16,7 +16,7 @@ class CreateArticleTopics extends ConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
final selectedOption = ref.watch(selectedVisibilityOptionsProvider);
final selectedOption = ref.watch(selectedWhoCanReplyOptionProvider);

return ListItem(
title: Text(
Expand All @@ -33,7 +33,7 @@ class CreateArticleTopics extends ConsumerWidget {
onTap: () {
showSimpleBottomSheet<void>(
context: context,
child: const VisibilitySettingsModal(),
child: const WhoCanReplySettingsModal(),
);
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/list_item/list_item.dart';
import 'package:ion/app/components/screen_offset/screen_side_offset.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/feed/providers/selected_visibility_options_provider.c.dart';
import 'package:ion/app/features/feed/views/pages/visibility_settings_modal/visibility_settings_modal.dart';
import 'package:ion/app/features/feed/providers/selected_who_can_reply_option_provider.c.dart';
import 'package:ion/app/features/feed/views/pages/who_can_reply_settings_modal/who_can_reply_settings_modal.dart';
import 'package:ion/app/router/utils/show_simple_bottom_sheet.dart';
import 'package:ion/generated/assets.gen.dart';

class SelectArticleVisibilityItem extends ConsumerWidget {
const SelectArticleVisibilityItem({super.key});
class SelectArticleWhoCanReplyItem extends ConsumerWidget {
const SelectArticleWhoCanReplyItem({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final selectedOption = ref.watch(selectedVisibilityOptionsProvider);
final selectedOption = ref.watch(selectedWhoCanReplyOptionProvider);

return ScreenSideOffset.medium(
child: ListItem(
Expand Down Expand Up @@ -46,7 +46,7 @@ class SelectArticleVisibilityItem extends ConsumerWidget {
onTap: () {
showSimpleBottomSheet<void>(
context: context,
child: VisibilitySettingsModal(title: context.i18n.article_settings_title),
child: WhoCanReplySettingsModal(title: context.i18n.article_settings_title),
);
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import 'package:ion/app/features/feed/create_article/providers/create_article_pr
import 'package:ion/app/features/feed/create_article/providers/draft_article_provider.c.dart';
import 'package:ion/app/features/feed/create_article/views/pages/create_article_preview_modal/components/article_preview.dart';
import 'package:ion/app/features/feed/create_article/views/pages/create_article_preview_modal/components/select_article_topics_item.dart';
import 'package:ion/app/features/feed/create_article/views/pages/create_article_preview_modal/components/select_article_visibility_item.dart';
import 'package:ion/app/features/feed/create_article/views/pages/create_article_preview_modal/components/select_article_who_can_reply_item.dart';
import 'package:ion/app/features/feed/providers/selected_who_can_reply_option_provider.c.dart';
import 'package:ion/app/router/components/navigation_app_bar/navigation_app_bar.dart';
import 'package:ion/app/router/components/sheet_content/sheet_content.dart';
import 'package:ion/generated/assets.gen.dart';
Expand All @@ -24,6 +25,7 @@ class CreateArticlePreviewModal extends HookConsumerWidget {
final paddingValue = 20.0.s;

final DraftArticleState(:title, :image, :imageIds, :content) = ref.watch(draftArticleProvider);
final whoCanReply = ref.watch(selectedWhoCanReplyOptionProvider);

return SheetContent(
bottomPadding: 0,
Expand All @@ -42,7 +44,7 @@ class CreateArticlePreviewModal extends HookConsumerWidget {
SizedBox(height: 20.0.s),
const HorizontalSeparator(),
SizedBox(height: 20.0.s),
const SelectArticleVisibilityItem(),
const SelectArticleWhoCanReplyItem(),
const Spacer(),
Align(
alignment: Alignment.bottomCenter,
Expand All @@ -60,6 +62,7 @@ class CreateArticlePreviewModal extends HookConsumerWidget {
content: content,
imageId: image?.path,
mediaIds: imageIds,
whoCanReply: whoCanReply,
);

if (!ref.read(createArticleProvider).hasError && ref.context.mounted) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:ion/app/features/core/providers/env_provider.c.dart';
import 'package:ion/app/features/feed/create_post/model/create_post_option.dart';
import 'package:ion/app/features/feed/data/models/entities/article_data.c.dart';
import 'package:ion/app/features/feed/data/models/entities/post_data.c.dart';
import 'package:ion/app/features/feed/data/models/who_can_reply_settings_option.dart';
import 'package:ion/app/features/feed/providers/counters/replies_count_provider.c.dart';
import 'package:ion/app/features/feed/providers/counters/reposts_count_provider.c.dart';
import 'package:ion/app/features/nostr/model/entity_expiration.c.dart';
Expand Down Expand Up @@ -36,14 +37,15 @@ class CreatePostNotifier extends _$CreatePostNotifier {

Future<void> create({
required String content,
required WhoCanReplySettingsOption whoCanReply,
EventReference? parentEvent,
EventReference? quotedEvent,
List<MediaFile>? mediaFiles,
}) async {
state = const AsyncValue.loading();

state = await AsyncValue.guard(() async {
var data = PostData.fromRawContent(content.trim());
var data = PostData.fromRawContent(content.trim(), whoCanReplySettings: {whoCanReply});
final files = <FileMetadata>[];

if (mediaFiles != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:ion/app/features/core/providers/poll/poll_title_notifier.c.dart'
import 'package:ion/app/features/feed/create_post/model/create_post_option.dart';
import 'package:ion/app/features/feed/create_post/providers/create_post_notifier.c.dart';
import 'package:ion/app/features/feed/create_post/views/pages/create_post_modal/hooks/use_has_poll.dart';
import 'package:ion/app/features/feed/providers/selected_who_can_reply_option_provider.c.dart';
import 'package:ion/app/features/feed/views/components/text_editor/hooks/use_text_editor_has_content.dart';
import 'package:ion/app/features/feed/views/components/toolbar_buttons/toolbar_send_button.dart';
import 'package:ion/app/features/nostr/model/event_reference.c.dart';
Expand Down Expand Up @@ -45,6 +46,7 @@ class PostSubmitButton extends HookConsumerWidget {
final pollTitle = ref.watch(pollTitleNotifierProvider);
final pollAnswers = ref.watch(pollAnswersNotifierProvider);
final hasPoll = useHasPoll(textEditorController);
final whoCanReply = ref.watch(selectedWhoCanReplyOptionProvider);

final isSubmitButtonEnabled = useMemoized(
() {
Expand Down Expand Up @@ -81,6 +83,7 @@ class PostSubmitButton extends HookConsumerWidget {
parentEvent: parentEvent,
quotedEvent: quotedEvent,
mediaFiles: convertedMediaFiles,
whoCanReply: whoCanReply,
),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import 'package:ion/app/features/feed/views/components/actions_toolbar/actions_t
import 'package:ion/app/features/feed/views/components/text_editor/hooks/use_quill_controller.dart';
import 'package:ion/app/features/feed/views/components/text_editor/text_editor.dart';
import 'package:ion/app/features/feed/views/components/toolbar_buttons/toolbar_buttons.dart';
import 'package:ion/app/features/feed/views/components/visibility_settings_toolbar/visibility_settings_toolbar.dart';
import 'package:ion/app/features/feed/views/components/who_can_reply_toolbar/who_can_reply_toolbar.dart';
import 'package:ion/app/features/feed/views/pages/cancel_creation_modal/cancel_creation_modal.dart';
import 'package:ion/app/features/nostr/model/event_reference.c.dart';
import 'package:ion/app/router/components/navigation_app_bar/navigation_app_bar.dart';
Expand Down Expand Up @@ -51,13 +51,13 @@ class CreatePostModal extends HookConsumerWidget {
final textEditorController = useQuillController(defaultText: content);
final scrollController = useScrollController();

final visibilityToolbarKey = useMemoized(GlobalKey.new);
final whoCanReplyToolbarKey = useMemoized(GlobalKey.new);
final actionsToolbarKey = useMemoized(GlobalKey.new);
final textInputKey = useMemoized(GlobalKey.new);

useKeyboardScrollHandler(
scrollController: scrollController,
keysToMeasure: [visibilityToolbarKey, actionsToolbarKey, textInputKey],
keysToMeasure: [whoCanReplyToolbarKey, actionsToolbarKey, textInputKey],
);

final createOption = videoPath != null
Expand Down Expand Up @@ -153,8 +153,8 @@ class CreatePostModal extends HookConsumerWidget {
),
const HorizontalSeparator(),
ScreenSideOffset.small(
key: visibilityToolbarKey,
child: const VisibilitySettingsToolbar(),
key: whoCanReplyToolbarKey,
child: const WhoCanReplyToolbar(),
),
ScreenSideOffset.small(
key: actionsToolbarKey,
Expand Down
31 changes: 31 additions & 0 deletions lib/app/features/feed/data/models/entities/article_data.c.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import 'package:collection/collection.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/feed/data/models/who_can_reply_settings_option.dart';
import 'package:ion/app/features/nostr/model/event_serializable.dart';
import 'package:ion/app/features/nostr/model/event_setting.c.dart';
import 'package:ion/app/features/nostr/model/media_attachment.dart';
import 'package:ion/app/features/nostr/model/nostr_entity.dart';
import 'package:ion/app/features/nostr/model/related_hashtag.c.dart';
Expand Down Expand Up @@ -74,6 +76,7 @@ class ArticleData with _$ArticleData implements EventSerializable {
String? summary,
DateTime? publishedAt,
List<RelatedHashtag>? relatedHashtags,
List<EventSetting>? settings,
}) = _ArticleData;

const ArticleData._();
Expand Down Expand Up @@ -103,6 +106,33 @@ class ArticleData with _$ArticleData implements EventSerializable {
summary: summary,
publishedAt: publishedAt,
relatedHashtags: tags[RelatedHashtag.tagName]?.map(RelatedHashtag.fromTag).toList(),
settings: tags[EventSetting.settingTagName]?.map(EventSetting.fromTag).toList(),
);
}

factory ArticleData.fromData({
required String content,
required Map<String, MediaAttachment> media,
String? title,
String? image,
String? summary,
DateTime? publishedAt,
List<RelatedHashtag>? relatedHashtags,
Set<WhoCanReplySettingsOption> whoCanReplySettings = const {},
}) {
final setting = whoCanReplySettings.isNotEmpty
? WhoCanReplyEventSetting(values: whoCanReplySettings)
: null;

return ArticleData(
content: content,
media: media,
title: title,
image: image,
summary: summary,
publishedAt: publishedAt,
relatedHashtags: relatedHashtags,
settings: setting != null ? [setting] : null,
);
}

Expand All @@ -127,6 +157,7 @@ class ArticleData with _$ArticleData implements EventSerializable {
['published_at', (publishedAt!.millisecondsSinceEpoch ~/ 1000).toString()],
if (media.isNotEmpty) ...media.values.map((mediaAttachment) => mediaAttachment.toTag()),
['d', uniqueIdForEditing],
if (settings != null) ...settings!.map((setting) => setting.toTag()),
],
content: content,
);
Expand Down
15 changes: 14 additions & 1 deletion lib/app/features/feed/data/models/entities/post_data.c.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import 'package:collection/collection.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:ion/app/exceptions/exceptions.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/feed/data/models/who_can_reply_settings_option.dart';
import 'package:ion/app/features/nostr/model/entity_expiration.c.dart';
import 'package:ion/app/features/nostr/model/entity_media_data.dart';
import 'package:ion/app/features/nostr/model/event_serializable.dart';
import 'package:ion/app/features/nostr/model/event_setting.c.dart';
import 'package:ion/app/features/nostr/model/media_attachment.dart';
import 'package:ion/app/features/nostr/model/nostr_entity.dart';
import 'package:ion/app/features/nostr/model/related_event.c.dart';
Expand Down Expand Up @@ -69,6 +71,7 @@ class PostData with _$PostData, EntityMediaDataMixin implements EventSerializabl
List<RelatedEvent>? relatedEvents,
List<RelatedPubkey>? relatedPubkeys,
List<RelatedHashtag>? relatedHashtags,
List<EventSetting>? settings,
}) = _PostData;

factory PostData.fromEventMessage(EventMessage eventMessage) {
Expand All @@ -88,21 +91,30 @@ class PostData with _$PostData, EntityMediaDataMixin implements EventSerializabl
relatedEvents: tags[RelatedEvent.tagName]?.map(RelatedEvent.fromTag).toList(),
relatedPubkeys: tags[RelatedPubkey.tagName]?.map(RelatedPubkey.fromTag).toList(),
relatedHashtags: tags[RelatedHashtag.tagName]?.map(RelatedHashtag.fromTag).toList(),
settings: tags[EventSetting.settingTagName]?.map(EventSetting.fromTag).toList(),
);
}

factory PostData.fromRawContent(String content) {
factory PostData.fromRawContent(
String content, {
Set<WhoCanReplySettingsOption> whoCanReplySettings = const {},
}) {
final parsedContent = TextParser.allMatchers().parse(content);

final hashtags = parsedContent
.where((match) => match.matcher is HashtagMatcher)
.map((match) => RelatedHashtag(value: match.text))
.toList();

final setting = whoCanReplySettings.isNotEmpty
? WhoCanReplyEventSetting(values: whoCanReplySettings)
: null;

return PostData(
content: parsedContent,
relatedHashtags: hashtags,
media: {},
settings: [setting].whereNotNull().toList(),
);
}

Expand All @@ -127,6 +139,7 @@ class PostData with _$PostData, EntityMediaDataMixin implements EventSerializabl
if (relatedHashtags != null) ...relatedHashtags!.map((hashtag) => hashtag.toTag()),
if (relatedEvents != null) ...relatedEvents!.map((event) => event.toTag()),
if (media.isNotEmpty) ...media.values.map((mediaAttachment) => mediaAttachment.toTag()),
if (settings != null) ...settings!.map((setting) => setting.toTag()),
],
);
}
Expand Down

This file was deleted.

Loading