feat: add quotations from marked text, with citations and sharing
This commit is contained in:
parent
0e2027c9e2
commit
e6e84fdc01
25 changed files with 1558 additions and 4 deletions
|
|
@ -36,6 +36,7 @@ class MewsPageView extends StatefulWidget {
|
|||
this.onFormChange,
|
||||
this.fetchImageBytes,
|
||||
this.scrollController,
|
||||
this.onSaveQuotation,
|
||||
this.ownPage = false,
|
||||
super.key,
|
||||
});
|
||||
|
|
@ -57,6 +58,10 @@ class MewsPageView extends StatefulWidget {
|
|||
final Future<Uint8List?> Function(String url)? fetchImageBytes;
|
||||
final ScrollController? scrollController;
|
||||
|
||||
/// Called with text the reader marked and chose to keep as a quotation.
|
||||
/// Null on a view that cannot keep one, such as a swipe peek.
|
||||
final void Function(String text)? onSaveQuotation;
|
||||
|
||||
/// Whether this is one of the client's own pages. Those are built from the
|
||||
/// same blocks, but they are interface rather than an article, so they are
|
||||
/// laid out denser and wider, rows are divided instead of bulleted, and
|
||||
|
|
@ -171,8 +176,14 @@ class _MewsPageViewState extends State<MewsPageView> {
|
|||
textDirection: widget.page.direction == TextDirection.rtl
|
||||
? ui.TextDirection.rtl
|
||||
: ui.TextDirection.ltr,
|
||||
// Page text is the reader's to copy; forms manage their own selection.
|
||||
// Page text is the reader's to copy and to keep; forms manage
|
||||
// their own selection. The toolbar offers to keep the marked
|
||||
// text as a quotation, so the selection's text is carried here.
|
||||
child: SelectionArea(
|
||||
onSelectionChanged: (content) =>
|
||||
_markedText = content?.plainText,
|
||||
contextMenuBuilder: (context, selectableRegion) =>
|
||||
_selectionToolbar(context, selectableRegion),
|
||||
child: ColoredBox(
|
||||
color: palette.background,
|
||||
child: ListView(
|
||||
|
|
@ -201,6 +212,36 @@ class _MewsPageViewState extends State<MewsPageView> {
|
|||
);
|
||||
}
|
||||
|
||||
/// The text of the selection now on the page, if any, so the toolbar can
|
||||
/// offer to keep it.
|
||||
String? _markedText;
|
||||
|
||||
/// The selection toolbar: the platform's own buttons, plus the choice to
|
||||
/// keep the marked text as a quotation when a place to keep it is given.
|
||||
Widget _selectionToolbar(
|
||||
BuildContext context, SelectableRegionState selectableRegion) {
|
||||
final items = selectableRegion.contextMenuButtonItems;
|
||||
final marked = _markedText?.trim();
|
||||
if (widget.onSaveQuotation != null && marked != null && marked.isNotEmpty) {
|
||||
items.insert(
|
||||
0,
|
||||
ContextMenuButtonItem(
|
||||
type: ContextMenuButtonType.custom,
|
||||
label: StringsScope.of(context).t('quotations-save'),
|
||||
onPressed: () {
|
||||
widget.onSaveQuotation!(marked);
|
||||
selectableRegion.hideToolbar();
|
||||
selectableRegion.clearSelection();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||
anchors: selectableRegion.contextMenuAnchors,
|
||||
buttonItems: items,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _notice(String text, double base, MewsPalette palette) => Padding(
|
||||
padding: EdgeInsets.only(bottom: base),
|
||||
child: Text(
|
||||
|
|
|
|||
|
|
@ -336,6 +336,14 @@ class _ReaderScreenState extends State<ReaderScreen> {
|
|||
},
|
||||
onFormChange: (form, values) =>
|
||||
deps.browser.narrowWhileTyping(form.action, values),
|
||||
// The reader's marked text is kept with the page it came from, so
|
||||
// its citation can name the author when the page did.
|
||||
onSaveQuotation: (text) => deps.db.addQuotation(
|
||||
quote: text,
|
||||
pageUrl: page.url,
|
||||
pageTitle: page.title,
|
||||
author: page.author,
|
||||
),
|
||||
fetchImageBytes: deps.browser.fetchImageBytes,
|
||||
scrollController: _scroll,
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue