feat(discussions): questions on published studysets, answered by learners
A learner asks about a published studyset, a topic in it, or one card, note or step of a release, and others answer, as on Stack Exchange (ADR 0013): questions and answers in the app's editor without images, sounds or videos, comments of up to 600 characters under the question and each answer. There are no votes: the asker accepts an answer, which comes first, then the oldest; the author's posts are marked. The instance reads from git's file list which topics a question's target sits in, so a topic lists what is asked within it and below it. Posts live in two server-only tables, written through endpoints, so the synced tables stay as they are and v0.17.0 keeps syncing. Everyone signed in reads; writing needs an identity and a public profile; the studyset's author hides posts and blocks people with feedback's blocks; a withdrawn studyset takes no new questions; anyone writes at most 30 posts an hour. A post with others' replies under it is emptied when deleted, else deleted; deletePerson deletes what a person wrote the same way, and a published studyset's deletion takes its discussions with it. The migration adds Serverpod's gen_random_uuid_v7(), discussion_post and discussion_seen with their indexes and cascading foreign keys, and changes nothing else. In the app, discussions open from a copy's studyset or topic menu, a studied card's "Ask about this", Explore's summary and the Publish sheet; the Profile tab's inbox lists those the person follows, and its count includes what is new in them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
25237b8011
commit
5efa552489
1 changed files with 28214 additions and 27 deletions
|
|
@ -10362,7 +10362,7 @@ abstract class AppLocalizations {
|
|||
/// No description provided for @inboxIntro.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Reports and suggestions on your published studysets, and those you wrote.'**
|
||||
/// **'Questions and answers, reports and suggestions on your published studysets, and those you wrote in.'**
|
||||
String get inboxIntro;
|
||||
|
||||
/// No description provided for @inboxEmpty.
|
||||
|
|
@ -10389,6 +10389,384 @@ abstract class AppLocalizations {
|
|||
/// **'Report to the author'**
|
||||
String get reportToAuthor;
|
||||
|
||||
/// No description provided for @discussionsTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Discussions'**
|
||||
String get discussionsTitle;
|
||||
|
||||
/// No description provided for @discussionsSearch.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Search questions'**
|
||||
String get discussionsSearch;
|
||||
|
||||
/// No description provided for @discussionsAsk.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Ask a question'**
|
||||
String get discussionsAsk;
|
||||
|
||||
/// No description provided for @discussionsEmpty.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No questions yet'**
|
||||
String get discussionsEmpty;
|
||||
|
||||
/// No description provided for @discussionsEmptyHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Ask the first: about the studyset, a topic or one of its flashcards.'**
|
||||
String get discussionsEmptyHint;
|
||||
|
||||
/// No description provided for @discussionsNoMatch.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No question\'s title says that.'**
|
||||
String get discussionsNoMatch;
|
||||
|
||||
/// No description provided for @discussionsMore.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Show more'**
|
||||
String get discussionsMore;
|
||||
|
||||
/// No description provided for @discussionsUnreachable.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The discussions can\'t be reached right now.'**
|
||||
String get discussionsUnreachable;
|
||||
|
||||
/// No description provided for @discussionsAnswers.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =0{No answers} =1{1 answer} other{{count} answers}}'**
|
||||
String discussionsAnswers(int count);
|
||||
|
||||
/// No description provided for @discussionsBy.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{name} · {date}'**
|
||||
String discussionsBy(String name, String date);
|
||||
|
||||
/// No description provided for @discussionsSomeone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Someone'**
|
||||
String get discussionsSomeone;
|
||||
|
||||
/// No description provided for @discussionsDeletedQuestion.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Deleted question'**
|
||||
String get discussionsDeletedQuestion;
|
||||
|
||||
/// No description provided for @discussionsHidden.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Hidden'**
|
||||
String get discussionsHidden;
|
||||
|
||||
/// No description provided for @discussionsAboutCard.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'About a flashcard'**
|
||||
String get discussionsAboutCard;
|
||||
|
||||
/// No description provided for @discussionsAboutNote.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'About a note'**
|
||||
String get discussionsAboutNote;
|
||||
|
||||
/// No description provided for @discussionsAboutStep.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'About a step'**
|
||||
String get discussionsAboutStep;
|
||||
|
||||
/// No description provided for @discussionsAccepted.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Accepted'**
|
||||
String get discussionsAccepted;
|
||||
|
||||
/// No description provided for @discussionsOn.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'On {title}'**
|
||||
String discussionsOn(String title);
|
||||
|
||||
/// No description provided for @discussionRefusalNoIdentity.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'To ask and answer, sign in with an identity in Profile: posts show who wrote them.'**
|
||||
String get discussionRefusalNoIdentity;
|
||||
|
||||
/// No description provided for @discussionRefusalNoProfile.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'To ask and answer, make a public profile in Profile: posts show who wrote them.'**
|
||||
String get discussionRefusalNoProfile;
|
||||
|
||||
/// No description provided for @discussionRefusalBlocked.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The author of this studyset keeps you from writing on their studysets.'**
|
||||
String get discussionRefusalBlocked;
|
||||
|
||||
/// No description provided for @discussionRefusalWithdrawn.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The author took this studyset off Explore: what is here stays, but nothing new is asked.'**
|
||||
String get discussionRefusalWithdrawn;
|
||||
|
||||
/// No description provided for @discussionRefusalNotInRelease.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'That isn\'t in the studyset\'s release any more.'**
|
||||
String get discussionRefusalNotInRelease;
|
||||
|
||||
/// No description provided for @discussionRefusalEmpty.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Write something first.'**
|
||||
String get discussionRefusalEmpty;
|
||||
|
||||
/// No description provided for @discussionRefusalTooLong.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'That\'s longer than allowed.'**
|
||||
String get discussionRefusalTooLong;
|
||||
|
||||
/// No description provided for @discussionRefusalTooMany.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'You\'ve written a lot in the last hour. Try again a little later.'**
|
||||
String get discussionRefusalTooMany;
|
||||
|
||||
/// No description provided for @discussionRefusalWithFiles.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Images and sounds can\'t be posted: your files are yours alone, so nobody else would see them.'**
|
||||
String get discussionRefusalWithFiles;
|
||||
|
||||
/// No description provided for @discussionFailed.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Couldn\'t reach the instance. Try again once you are online.'**
|
||||
String get discussionFailed;
|
||||
|
||||
/// No description provided for @discussionTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Question'**
|
||||
String get discussionTitle;
|
||||
|
||||
/// No description provided for @discussionMissing.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'This question isn\'t there any more.'**
|
||||
String get discussionMissing;
|
||||
|
||||
/// No description provided for @discussionDeleted.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'This was deleted.'**
|
||||
String get discussionDeleted;
|
||||
|
||||
/// No description provided for @discussionEdited.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'edited'**
|
||||
String get discussionEdited;
|
||||
|
||||
/// No description provided for @discussionWriteAnswer.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Write an answer'**
|
||||
String get discussionWriteAnswer;
|
||||
|
||||
/// No description provided for @discussionYourAnswer.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Your answer'**
|
||||
String get discussionYourAnswer;
|
||||
|
||||
/// No description provided for @discussionEditHeading.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Edit'**
|
||||
String get discussionEditHeading;
|
||||
|
||||
/// No description provided for @discussionTitleField.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Title'**
|
||||
String get discussionTitleField;
|
||||
|
||||
/// No description provided for @discussionTitleHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'What do you want to know?'**
|
||||
String get discussionTitleHint;
|
||||
|
||||
/// No description provided for @discussionPost.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Post'**
|
||||
String get discussionPost;
|
||||
|
||||
/// No description provided for @discussionComment.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add a comment'**
|
||||
String get discussionComment;
|
||||
|
||||
/// No description provided for @discussionCommentHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'A short remark'**
|
||||
String get discussionCommentHint;
|
||||
|
||||
/// No description provided for @discussionAccept.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Accept'**
|
||||
String get discussionAccept;
|
||||
|
||||
/// No description provided for @discussionUnaccept.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Take back'**
|
||||
String get discussionUnaccept;
|
||||
|
||||
/// No description provided for @discussionMenu.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'More'**
|
||||
String get discussionMenu;
|
||||
|
||||
/// No description provided for @discussionMenuEdit.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Edit'**
|
||||
String get discussionMenuEdit;
|
||||
|
||||
/// No description provided for @discussionMenuDelete.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Delete'**
|
||||
String get discussionMenuDelete;
|
||||
|
||||
/// No description provided for @discussionMenuHide.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Hide'**
|
||||
String get discussionMenuHide;
|
||||
|
||||
/// No description provided for @discussionMenuShow.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Show again'**
|
||||
String get discussionMenuShow;
|
||||
|
||||
/// No description provided for @discussionMenuBlock.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Block {name}'**
|
||||
String discussionMenuBlock(String name);
|
||||
|
||||
/// No description provided for @discussionDeleteTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Delete this?'**
|
||||
String get discussionDeleteTitle;
|
||||
|
||||
/// No description provided for @discussionDeleteBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'What others replied under it stays, without your text and name.'**
|
||||
String get discussionDeleteBody;
|
||||
|
||||
/// No description provided for @discussionAnswered.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Answer posted.'**
|
||||
String get discussionAnswered;
|
||||
|
||||
/// No description provided for @discussionCommented.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Comment posted.'**
|
||||
String get discussionCommented;
|
||||
|
||||
/// No description provided for @discussionSaved.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Saved.'**
|
||||
String get discussionSaved;
|
||||
|
||||
/// No description provided for @discussionDeletedDone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Deleted.'**
|
||||
String get discussionDeletedDone;
|
||||
|
||||
/// No description provided for @discussionAcceptedDone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Answer accepted.'**
|
||||
String get discussionAcceptedDone;
|
||||
|
||||
/// No description provided for @discussionUnacceptedDone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No answer accepted now.'**
|
||||
String get discussionUnacceptedDone;
|
||||
|
||||
/// No description provided for @discussionHiddenDone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Hidden: only its writer and you see it.'**
|
||||
String get discussionHiddenDone;
|
||||
|
||||
/// No description provided for @discussionShownDone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Shown again.'**
|
||||
String get discussionShownDone;
|
||||
|
||||
/// No description provided for @discussionBlockedDone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Blocked: what they write on your studysets shows to them alone.'**
|
||||
String get discussionBlockedDone;
|
||||
|
||||
/// No description provided for @discussionAskAbout.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Ask about this'**
|
||||
String get discussionAskAbout;
|
||||
|
||||
/// No description provided for @inboxDiscussions.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Discussions'**
|
||||
String get inboxDiscussions;
|
||||
|
||||
/// No description provided for @inboxFeedback.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Reports and suggestions'**
|
||||
String get inboxFeedback;
|
||||
|
||||
/// No description provided for @inboxDiscussionsEmpty.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No discussions yet.'**
|
||||
String get inboxDiscussionsEmpty;
|
||||
|
||||
/// No description provided for @cardReportToAuthor.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
|
|||
Loading…
Reference in a new issue