feat(learn): a studyset is made private in Edit, no longer from its options
The developer's review of 3 Nov 2026: Make private and Make non-private leave a studyset's options (its card's menu, its screen's); a top-level studyset's Edit has a Visibility section instead, its switch making it private, or non-private, at once once the person agreed in the dialog as before (ADR 0019), not on Save, and what that means behind the question mark. A topic's Edit offers none, its privacy being its tree's. The lock on a studyset's card still explains its privacy and keeps its own button. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
96b1a0fc64
commit
a7904bac05
8 changed files with 156 additions and 61 deletions
|
|
@ -2129,5 +2129,7 @@
|
|||
"studysetPrivacyReadableTitle": "„{title}“ ist nicht privat",
|
||||
"studysetPrivacyReadableBody": "Die Instanz kann es lesen: Du kannst es veröffentlichen. Privat wird es auf deinen Geräten Ende-zu-Ende-verschlüsselt; Kopien in den Sicherungen der Instanz bleiben lesbar, bis diese ablaufen.",
|
||||
"studysetPrivacyTopic": "Seine Privatsphäre ist die des Lernsets, in dem es liegt.",
|
||||
"studysetPrivacyPublish": "Veröffentlichen …"
|
||||
"studysetPrivacyPublish": "Veröffentlichen …",
|
||||
"studysetSheetVisibility": "Sichtbarkeit",
|
||||
"studysetSheetPrivate": "Privat"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2545,5 +2545,9 @@
|
|||
"@studysetPrivacyReadableTitle": {"placeholders": {"title": {"type": "String"}}},
|
||||
"studysetPrivacyReadableBody": "The instance can read it: you can publish it. Making it private encrypts it end to end on your devices; copies in the instance's backups stay readable until those expire.",
|
||||
"studysetPrivacyTopic": "Its privacy is that of the studyset it's in.",
|
||||
"studysetPrivacyPublish": "Publish…"
|
||||
"studysetPrivacyPublish": "Publish…",
|
||||
"studysetSheetVisibility": "Visibility",
|
||||
"@studysetSheetVisibility": {"description": "Heading in a top-level studyset's Edit sheet above its privacy switch (ADR 0019)."},
|
||||
"studysetSheetPrivate": "Private",
|
||||
"@studysetSheetPrivate": {"description": "The switch making a top-level studyset private (end-to-end encrypted) in its Edit sheet."}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12565,6 +12565,18 @@ abstract class AppLocalizations {
|
|||
/// In en, this message translates to:
|
||||
/// **'Publish…'**
|
||||
String get studysetPrivacyPublish;
|
||||
|
||||
/// Heading in a top-level studyset's Edit sheet above its privacy switch (ADR 0019).
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Visibility'**
|
||||
String get studysetSheetVisibility;
|
||||
|
||||
/// The switch making a top-level studyset private (end-to-end encrypted) in its Edit sheet.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Private'**
|
||||
String get studysetSheetPrivate;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -8061,4 +8061,10 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get studysetPrivacyPublish => 'Veröffentlichen …';
|
||||
|
||||
@override
|
||||
String get studysetSheetVisibility => 'Sichtbarkeit';
|
||||
|
||||
@override
|
||||
String get studysetSheetPrivate => 'Privat';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7988,6 +7988,12 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get studysetPrivacyPublish => 'Publish…';
|
||||
|
||||
@override
|
||||
String get studysetSheetVisibility => 'Visibility';
|
||||
|
||||
@override
|
||||
String get studysetSheetPrivate => 'Private';
|
||||
}
|
||||
|
||||
/// The translations for English, as used in the United Kingdom (`en_GB`).
|
||||
|
|
|
|||
|
|
@ -39,8 +39,6 @@ enum StudysetOption() {
|
|||
unarchive,
|
||||
delete,
|
||||
info,
|
||||
makePrivate,
|
||||
makeReadable,
|
||||
reportToAuthor,
|
||||
feedback,
|
||||
discussions,
|
||||
|
|
@ -133,20 +131,9 @@ List<StudysetOptionEntry> studysetOptions(
|
|||
l10n.studysetMenuDelete,
|
||||
destroys: true,
|
||||
),
|
||||
// Making it private or not is in Edit, with what it means one tap
|
||||
// away, not a shortcut here (the developer's review of 3 Nov 2026).
|
||||
entry(StudysetOption.info, LucideIcons.info, l10n.moreInfo),
|
||||
if (studyset.parentId == null)
|
||||
if (studyset.isPrivate)
|
||||
entry(
|
||||
StudysetOption.makeReadable,
|
||||
LucideIcons.lockOpen,
|
||||
l10n.studysetMenuMakeReadable,
|
||||
)
|
||||
else
|
||||
entry(
|
||||
StudysetOption.makePrivate,
|
||||
LucideIcons.lock,
|
||||
l10n.studysetMenuMakePrivate,
|
||||
),
|
||||
if (fromRelease(studyset.content.published)) ...[
|
||||
entry(
|
||||
StudysetOption.reportToAuthor,
|
||||
|
|
@ -245,12 +232,6 @@ Future<void> doStudysetOption(
|
|||
deleteStudysetWithUndo(context, studyset, onDeleted: onDeleted);
|
||||
case StudysetOption.info:
|
||||
await showStudysetInfo(context, studyset);
|
||||
case StudysetOption.makePrivate || StudysetOption.makeReadable:
|
||||
await setStudysetPrivacy(
|
||||
context,
|
||||
studyset,
|
||||
private: option == StudysetOption.makePrivate,
|
||||
);
|
||||
case StudysetOption.reportToAuthor:
|
||||
if (studyset.content.published case final origin?) {
|
||||
await reportStudysetToAuthor(context, origin);
|
||||
|
|
@ -291,6 +272,12 @@ Future<void> editStudyset(
|
|||
final content = await showStudysetSheet(
|
||||
context,
|
||||
initial: studyset.content,
|
||||
// A top-level studyset's privacy, its topics' too (ADR 0019), changed
|
||||
// at once, once the person agreed.
|
||||
private: parentId == null ? studyset.isPrivate : null,
|
||||
onPrivate: parentId == null
|
||||
? (private) => setStudysetPrivacy(context, studyset, private: private)
|
||||
: null,
|
||||
insideAnother: parentId != null,
|
||||
inheritedColorName: parentId == null ? null : colorNameOf(parentId, all),
|
||||
inheritedLanguages: parentId == null
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import 'package:material_ui/material_ui.dart';
|
|||
/// readable by the instance again (ADR 0019), once the person agreed: the
|
||||
/// dialog says what changes, and that the instance's backups keep readable
|
||||
/// copies until they expire. Where this device can't encrypt (an account
|
||||
/// whose keys aren't here), says how to.
|
||||
Future<void> setStudysetPrivacy(
|
||||
/// whose keys aren't here), says how to. Whether it was changed.
|
||||
Future<bool> setStudysetPrivacy(
|
||||
BuildContext context,
|
||||
Studyset studyset, {
|
||||
required bool private,
|
||||
|
|
@ -21,7 +21,7 @@ Future<void> setStudysetPrivacy(
|
|||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(l10n.studysetPrivateNoKeys)),
|
||||
);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
final title = studyset.content.title;
|
||||
final confirmed = await showDialog<bool>(
|
||||
|
|
@ -52,9 +52,10 @@ Future<void> setStudysetPrivacy(
|
|||
),
|
||||
);
|
||||
if (confirmed != true || !context.mounted) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
await applyStudysetPrivacy(context, studyset, private: private);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Makes the top-level [studyset] private or not at once, the person
|
||||
|
|
|
|||
|
|
@ -35,6 +35,15 @@ Future<StudysetContent?> showStudysetSheet(
|
|||
/// The studyset edited, whose files its description's pictures go with;
|
||||
/// none for a new one, which takes them once made.
|
||||
String? studysetId,
|
||||
|
||||
/// Whether the top-level studyset edited is private (ADR 0019); null
|
||||
/// where the sheet offers no choice: a new studyset, or a topic, whose
|
||||
/// privacy is its tree's.
|
||||
bool? private,
|
||||
|
||||
/// Makes it private or not at once, once the person agreed, rather than
|
||||
/// on Save, which the content alone waits for; whether it was changed.
|
||||
Future<bool> Function(bool private)? onPrivate,
|
||||
}) => showAdaptiveSheet<StudysetContent>(
|
||||
context,
|
||||
// Swiping would discard changes without asking.
|
||||
|
|
@ -46,6 +55,8 @@ Future<StudysetContent?> showStudysetSheet(
|
|||
inheritedLanguages: inheritedLanguages,
|
||||
inheritedLicense: inheritedLicense,
|
||||
studysetId: studysetId,
|
||||
private: private,
|
||||
onPrivate: onPrivate,
|
||||
),
|
||||
);
|
||||
|
||||
|
|
@ -59,6 +70,8 @@ class const _StudysetSheet({
|
|||
required final StudysetLanguages inheritedLanguages,
|
||||
required final StudysetLicense inheritedLicense,
|
||||
final String? studysetId,
|
||||
final bool? private,
|
||||
final Future<bool> Function(bool private)? onPrivate,
|
||||
}) extends StatefulWidget {
|
||||
@override
|
||||
State<_StudysetSheet> createState() => _StudysetSheetState();
|
||||
|
|
@ -110,6 +123,17 @@ class _StudysetSheetState() extends State<_StudysetSheet> {
|
|||
late String? _frontLanguage = widget.initial?.frontLanguage;
|
||||
late String? _backLanguage = widget.initial?.backLanguage;
|
||||
|
||||
/// Whether the studyset is private now, as last changed here.
|
||||
late var _private = widget.private;
|
||||
|
||||
Future<void> _setPrivate(bool private) async {
|
||||
if (await widget.onPrivate?.call(private) ?? false) {
|
||||
if (mounted) {
|
||||
setState(() => _private = private);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
|
@ -487,6 +511,37 @@ class _StudysetSheetState() extends State<_StudysetSheet> {
|
|||
setState(() => _backLanguage = language),
|
||||
),
|
||||
],
|
||||
// Who can read it (ADR 0019), here rather than in its options
|
||||
// (the developer's review of 3 Nov 2026), what it means one tap
|
||||
// away.
|
||||
if (_private case final private?) ...[
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
l10n.studysetSheetVisibility,
|
||||
style: theme.textTheme.labelLarge,
|
||||
),
|
||||
),
|
||||
HelpButton(
|
||||
private
|
||||
? l10n.studysetReadableBody
|
||||
: l10n.studysetPrivateBody,
|
||||
title: l10n.studysetSheetPrivate,
|
||||
),
|
||||
],
|
||||
),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
secondary: Icon(
|
||||
private ? LucideIcons.lock : LucideIcons.lockOpen,
|
||||
),
|
||||
title: Text(l10n.studysetSheetPrivate),
|
||||
value: private,
|
||||
onChanged: _setPrivate,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in a new issue