Flutter upgrade
This commit is contained in:
parent
3131e0ed62
commit
5669b36fb7
|
|
@ -413,6 +413,7 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
|
||||||
*/
|
*/
|
||||||
theme: state.prefState.enableDarkMode
|
theme: state.prefState.enableDarkMode
|
||||||
? ThemeData(
|
? ThemeData(
|
||||||
|
useMaterial3: false,
|
||||||
tooltipTheme: TooltipThemeData(
|
tooltipTheme: TooltipThemeData(
|
||||||
waitDuration: Duration(milliseconds: 500),
|
waitDuration: Duration(milliseconds: 500),
|
||||||
),
|
),
|
||||||
|
|
@ -438,6 +439,7 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
|
||||||
BottomAppBarTheme(color: const Color(0xFF1B1C1E)),
|
BottomAppBarTheme(color: const Color(0xFF1B1C1E)),
|
||||||
)
|
)
|
||||||
: ThemeData(
|
: ThemeData(
|
||||||
|
useMaterial3: false,
|
||||||
tooltipTheme: TooltipThemeData(
|
tooltipTheme: TooltipThemeData(
|
||||||
waitDuration: Duration(milliseconds: 500),
|
waitDuration: Duration(milliseconds: 500),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
|
||||||
}
|
}
|
||||||
|
|
||||||
final companies =
|
final companies =
|
||||||
list.where((CompanyEntity company) => (company.id).isNotEmpty).toList();
|
list.where((CompanyEntity company) => company.id.isNotEmpty).toList();
|
||||||
|
|
||||||
return companies;
|
return companies;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ List<TaskEntity?> _runningTasks({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tasks.sort((taskA, taskB) => (taskB.updatedAt).compareTo(taskA.updatedAt));
|
tasks.sort((taskA, taskB) => taskB.updatedAt.compareTo(taskA.updatedAt));
|
||||||
|
|
||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
|
|
@ -219,7 +219,7 @@ List<TaskEntity> _recentTasks({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tasks.sort((taskA, taskB) => (taskB.updatedAt).compareTo(taskA.updatedAt));
|
tasks.sort((taskA, taskB) => taskB.updatedAt.compareTo(taskA.updatedAt));
|
||||||
|
|
||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -388,10 +388,9 @@ void handleRecurringExpenseAction(BuildContext? context,
|
||||||
break;
|
break;
|
||||||
case EntityAction.start:
|
case EntityAction.start:
|
||||||
store.dispatch(StartRecurringExpensesRequest(
|
store.dispatch(StartRecurringExpensesRequest(
|
||||||
completer: snackBarCompleter<Null>(
|
completer: snackBarCompleter<Null>(recurringExpense.lastSentDate.isEmpty
|
||||||
(recurringExpense.lastSentDate).isEmpty
|
? localization!.startedRecurringInvoice
|
||||||
? localization!.startedRecurringInvoice
|
: localization!.resumedRecurringInvoice),
|
||||||
: localization!.resumedRecurringInvoice),
|
|
||||||
expenseIds: recurringExpenseIds,
|
expenseIds: recurringExpenseIds,
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -629,10 +629,9 @@ void handleRecurringInvoiceAction(BuildContext? context,
|
||||||
break;
|
break;
|
||||||
case EntityAction.start:
|
case EntityAction.start:
|
||||||
store.dispatch(StartRecurringInvoicesRequest(
|
store.dispatch(StartRecurringInvoicesRequest(
|
||||||
completer: snackBarCompleter<Null>(
|
completer: snackBarCompleter<Null>(recurringInvoice.lastSentDate.isEmpty
|
||||||
(recurringInvoice.lastSentDate).isEmpty
|
? localization!.startedRecurringInvoice
|
||||||
? localization!.startedRecurringInvoice
|
: localization!.resumedRecurringInvoice),
|
||||||
: localization!.resumedRecurringInvoice),
|
|
||||||
invoiceIds: recurringInvoiceIds,
|
invoiceIds: recurringInvoiceIds,
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,7 @@ void handleVendorAction(
|
||||||
break;
|
break;
|
||||||
case EntityAction.vendorPortal:
|
case EntityAction.vendorPortal:
|
||||||
final contact = vendor.contacts.firstWhere((contact) {
|
final contact = vendor.contacts.firstWhere((contact) {
|
||||||
return (contact.link).isNotEmpty;
|
return contact.link.isNotEmpty;
|
||||||
}, orElse: null);
|
}, orElse: null);
|
||||||
launchUrl(Uri.parse(contact.silentLink));
|
launchUrl(Uri.parse(contact.silentLink));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ class MultiSelectListState extends State<MultiSelectList> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
selected =
|
selected =
|
||||||
(widget.selected).isNotEmpty ? widget.selected : widget.defaultSelected;
|
widget.selected.isNotEmpty ? widget.selected : widget.defaultSelected;
|
||||||
_controller = ScrollController();
|
_controller = ScrollController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -459,7 +459,7 @@ class DocumentPreview extends StatelessWidget {
|
||||||
key: ValueKey(document.preview),
|
key: ValueKey(document.preview),
|
||||||
imageUrl:
|
imageUrl:
|
||||||
'${cleanApiUrl(state.credentials.url)}/documents/${document.hash}',
|
'${cleanApiUrl(state.credentials.url)}/documents/${document.hash}',
|
||||||
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
|
//imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
|
||||||
httpHeaders: {'X-API-TOKEN': state.credentials.token},
|
httpHeaders: {'X-API-TOKEN': state.credentials.token},
|
||||||
placeholder: (context, url) => Container(
|
placeholder: (context, url) => Container(
|
||||||
height: height,
|
height: height,
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ class _InvoiceEmailViewState extends State<InvoiceEmailView>
|
||||||
selectedTemplate = EmailTemplate.reminder3;
|
selectedTemplate = EmailTemplate.reminder3;
|
||||||
else if ((invoice.reminder1Sent ?? '').isNotEmpty)
|
else if ((invoice.reminder1Sent ?? '').isNotEmpty)
|
||||||
selectedTemplate = EmailTemplate.reminder2;
|
selectedTemplate = EmailTemplate.reminder2;
|
||||||
else if ((invoice.lastSentDate).isNotEmpty)
|
else if (invoice.lastSentDate.isNotEmpty)
|
||||||
selectedTemplate = EmailTemplate.reminder1;
|
selectedTemplate = EmailTemplate.reminder1;
|
||||||
else
|
else
|
||||||
selectedTemplate = EmailTemplate.invoice;
|
selectedTemplate = EmailTemplate.invoice;
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ class ActivityListTile extends StatelessWidget {
|
||||||
subtitle: Row(
|
subtitle: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(((activity.notes).isNotEmpty
|
child: Text((activity.notes.isNotEmpty
|
||||||
? localization.lookup(activity.notes).trim() + '\n'
|
? localization.lookup(activity.notes).trim() + '\n'
|
||||||
: '') +
|
: '') +
|
||||||
formatDate(
|
formatDate(
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ class ClientOverview extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListDivider(),
|
ListDivider(),
|
||||||
if ((client.privateNotes).isNotEmpty) ...[
|
if (client.privateNotes.isNotEmpty) ...[
|
||||||
IconMessage(client.privateNotes, iconData: Icons.lock),
|
IconMessage(client.privateNotes, iconData: Icons.lock),
|
||||||
ListDivider()
|
ListDivider()
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ class _InvoiceItemSelectorState extends State<InvoiceItemSelector>
|
||||||
|
|
||||||
if (selected != null) {
|
if (selected != null) {
|
||||||
_filterClientId = (selected as BelongsToClient).clientId;
|
_filterClientId = (selected as BelongsToClient).clientId;
|
||||||
} else if ((widget.clientId).isEmpty) {
|
} else if (widget.clientId.isEmpty) {
|
||||||
_filterClientId = null;
|
_filterClientId = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ class PurchaseOrderListItem extends StatelessWidget {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: filterMatch == null
|
child: filterMatch == null
|
||||||
? Text((((purchaseOrder.number).isEmpty
|
? Text(((purchaseOrder.number.isEmpty
|
||||||
? localization!.pending
|
? localization!.pending
|
||||||
: purchaseOrder.number) +
|
: purchaseOrder.number) +
|
||||||
' • ' +
|
' • ' +
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class PurchaseOrderPresenter extends EntityPresenter {
|
||||||
case PurchaseOrderFields.status:
|
case PurchaseOrderFields.status:
|
||||||
return EntityStatusChip(entity: purchaseOrder, showState: true);
|
return EntityStatusChip(entity: purchaseOrder, showState: true);
|
||||||
case PurchaseOrderFields.number:
|
case PurchaseOrderFields.number:
|
||||||
return Text((purchaseOrder.number).isEmpty
|
return Text(purchaseOrder.number.isEmpty
|
||||||
? localization!.pending
|
? localization!.pending
|
||||||
: purchaseOrder.number);
|
: purchaseOrder.number);
|
||||||
case PurchaseOrderFields.client:
|
case PurchaseOrderFields.client:
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ class QuoteListItem extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
(quote.number).isEmpty
|
quote.number.isEmpty
|
||||||
? localization!.pending
|
? localization!.pending
|
||||||
: quote.number,
|
: quote.number,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ class RecurringInvoiceListItem extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
(invoice.number).isEmpty
|
invoice.number.isEmpty
|
||||||
? localization.pending
|
? localization.pending
|
||||||
: invoice.number,
|
: invoice.number,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/*
|
||||||
// DELETE THIS FILE ONCE SUPER EDITOR IS UPDATED
|
// DELETE THIS FILE ONCE SUPER EDITOR IS UPDATED
|
||||||
// Note: using the standard function crashes with h1 tags
|
// Note: using the standard function crashes with h1 tags
|
||||||
|
|
||||||
|
|
@ -588,3 +589,4 @@ class _EmptyParagraphSyntax extends md.BlockSyntax {
|
||||||
return md.Element('p', []);
|
return md.Element('p', []);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
|
//import 'package:example/logging.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/markdown.dart';
|
|
||||||
import 'package:invoiceninja_flutter/utils/super_editor/toolbar.dart';
|
|
||||||
import 'package:super_editor/super_editor.dart';
|
import 'package:super_editor/super_editor.dart';
|
||||||
|
import 'package:super_editor_markdown/super_editor_markdown.dart';
|
||||||
|
|
||||||
|
import 'package:invoiceninja_flutter/utils/super_editor/toolbar.dart';
|
||||||
|
//import '_toolbar.dart';
|
||||||
|
|
||||||
/// Example of a rich text editor.
|
/// Example of a rich text editor.
|
||||||
///
|
///
|
||||||
|
|
@ -19,39 +22,46 @@ class ExampleEditor extends StatefulWidget {
|
||||||
final Function(String)? onChanged;
|
final Function(String)? onChanged;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ExampleEditorState createState() => _ExampleEditorState();
|
State<ExampleEditor> createState() => _ExampleEditorState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ExampleEditorState extends State<ExampleEditor> {
|
class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
|
final GlobalKey _viewportKey = GlobalKey();
|
||||||
final GlobalKey _docLayoutKey = GlobalKey();
|
final GlobalKey _docLayoutKey = GlobalKey();
|
||||||
|
|
||||||
late Document _doc;
|
late MutableDocument _doc;
|
||||||
DocumentEditor? _docEditor;
|
final _docChangeSignal = SignalNotifier();
|
||||||
DocumentComposer? _composer;
|
late MutableDocumentComposer _composer;
|
||||||
|
late Editor _docEditor;
|
||||||
late CommonEditorOperations _docOps;
|
late CommonEditorOperations _docOps;
|
||||||
|
|
||||||
FocusNode? _editorFocusNode;
|
late FocusNode _editorFocusNode;
|
||||||
|
|
||||||
ScrollController? _scrollController;
|
late ScrollController _scrollController;
|
||||||
|
|
||||||
|
final SelectionLayerLinks _selectionLayerLinks = SelectionLayerLinks();
|
||||||
|
|
||||||
final _darkBackground = const Color(0xFF222222);
|
final _darkBackground = const Color(0xFF222222);
|
||||||
final _lightBackground = Colors.white;
|
final _lightBackground = Colors.white;
|
||||||
//Brightness _brightness = Brightness.light;
|
final _brightness = ValueNotifier<Brightness>(Brightness.light);
|
||||||
|
|
||||||
SuperEditorDebugVisualsConfig? _debugConfig;
|
SuperEditorDebugVisualsConfig? _debugConfig;
|
||||||
|
|
||||||
OverlayEntry? _textFormatBarOverlayEntry;
|
final _textFormatBarOverlayController = OverlayPortalController();
|
||||||
final _textSelectionAnchor = ValueNotifier<Offset?>(null);
|
final _textSelectionAnchor = ValueNotifier<Offset?>(null);
|
||||||
|
|
||||||
OverlayEntry? _imageFormatBarOverlayEntry;
|
final _imageFormatBarOverlayController = OverlayPortalController();
|
||||||
final _imageSelectionAnchor = ValueNotifier<Offset?>(null);
|
final _imageSelectionAnchor = ValueNotifier<Offset?>(null);
|
||||||
|
|
||||||
final _overlayController = MagnifierAndToolbarController();
|
// TODO: get rid of overlay controller once Android is refactored to use a control scope (as follow up to: https://github.com/superlistapp/super_editor/pull/1470)
|
||||||
|
final _overlayController = MagnifierAndToolbarController() //
|
||||||
|
..screenPadding = const EdgeInsets.all(20.0);
|
||||||
|
|
||||||
|
late final SuperEditorIosControlsController _iosControlsController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
// Fix for <p> tags cutting off text
|
// Fix for <p> tags cutting off text
|
||||||
var markdown = widget.value;
|
var markdown = widget.value;
|
||||||
markdown = markdown.replaceAll('<p/>', '\n');
|
markdown = markdown.replaceAll('<p/>', '\n');
|
||||||
|
|
@ -60,64 +70,38 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
markdown = markdown.replaceAll('</p>', '');
|
markdown = markdown.replaceAll('</p>', '');
|
||||||
markdown = markdown.replaceAll('</div>', '');
|
markdown = markdown.replaceAll('</div>', '');
|
||||||
|
|
||||||
|
// _doc = createInitialDocument()..addListener(_onDocumentChange);
|
||||||
_doc = deserializeMarkdownToDocument(markdown)
|
_doc = deserializeMarkdownToDocument(markdown)
|
||||||
..addListener(_hideOrShowToolbar)
|
..addListener(_onDocumentChange);
|
||||||
..addListener(_onChanged);
|
_composer = MutableDocumentComposer();
|
||||||
|
_composer.selectionNotifier.addListener(_hideOrShowToolbar);
|
||||||
_docEditor = DocumentEditor(document: _doc as MutableDocument);
|
_docEditor =
|
||||||
_composer = DocumentComposer();
|
createDefaultDocumentEditor(document: _doc, composer: _composer);
|
||||||
_composer!.selectionNotifier.addListener(_hideOrShowToolbar);
|
|
||||||
_docOps = CommonEditorOperations(
|
_docOps = CommonEditorOperations(
|
||||||
editor: _docEditor!,
|
editor: _docEditor,
|
||||||
composer: _composer!,
|
document: _doc,
|
||||||
|
composer: _composer,
|
||||||
documentLayoutResolver: () =>
|
documentLayoutResolver: () =>
|
||||||
_docLayoutKey.currentState as DocumentLayout,
|
_docLayoutKey.currentState as DocumentLayout,
|
||||||
);
|
);
|
||||||
_editorFocusNode = FocusNode();
|
_editorFocusNode = FocusNode();
|
||||||
_scrollController = ScrollController()..addListener(_hideOrShowToolbar);
|
_scrollController = ScrollController()..addListener(_hideOrShowToolbar);
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
_iosControlsController = SuperEditorIosControlsController();
|
||||||
void didUpdateWidget(ExampleEditor oldWidget) {
|
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
|
|
||||||
if (widget.value != oldWidget.value) {
|
|
||||||
_setValue(widget.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _setValue(String value) {
|
|
||||||
_doc.removeListener(_hideOrShowToolbar);
|
|
||||||
_doc.removeListener(_onChanged);
|
|
||||||
_doc = deserializeMarkdownToDocument(value)
|
|
||||||
..addListener(_hideOrShowToolbar)
|
|
||||||
..addListener(_onChanged);
|
|
||||||
_docEditor = DocumentEditor(document: _doc as MutableDocument);
|
|
||||||
_editorFocusNode = FocusNode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (_textFormatBarOverlayEntry != null) {
|
_iosControlsController.dispose();
|
||||||
_textFormatBarOverlayEntry!.remove();
|
_scrollController.dispose();
|
||||||
}
|
_editorFocusNode.dispose();
|
||||||
|
_composer.dispose();
|
||||||
_doc.removeListener(_hideOrShowToolbar);
|
|
||||||
_doc.removeListener(_onChanged);
|
|
||||||
_scrollController!.removeListener(_hideOrShowToolbar);
|
|
||||||
_composer!.removeListener(_hideOrShowToolbar);
|
|
||||||
|
|
||||||
_scrollController!.dispose();
|
|
||||||
_editorFocusNode!.dispose();
|
|
||||||
_composer!.dispose();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onChanged() {
|
void _onDocumentChange(_) {
|
||||||
if (widget.onChanged != null) {
|
_hideOrShowToolbar();
|
||||||
final value = serializeDocumentToMarkdown(_docEditor!.document);
|
_docChangeSignal.notifyListeners();
|
||||||
widget.onChanged!(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _hideOrShowToolbar() {
|
void _hideOrShowToolbar() {
|
||||||
|
|
@ -127,7 +111,7 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final selection = _composer!.selection;
|
final selection = _composer.selection;
|
||||||
if (selection == null) {
|
if (selection == null) {
|
||||||
// Nothing is selected. We don't want to show a toolbar
|
// Nothing is selected. We don't want to show a toolbar
|
||||||
// in this case.
|
// in this case.
|
||||||
|
|
@ -155,6 +139,7 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
final selectedNode = _doc.getNodeById(selection.extent.nodeId);
|
final selectedNode = _doc.getNodeById(selection.extent.nodeId);
|
||||||
|
|
||||||
if (selectedNode is ImageNode) {
|
if (selectedNode is ImageNode) {
|
||||||
|
//appLog.fine("Showing image toolbar");
|
||||||
// Show the editor's toolbar for image sizing.
|
// Show the editor's toolbar for image sizing.
|
||||||
_showImageToolbar();
|
_showImageToolbar();
|
||||||
_hideEditorToolbar();
|
_hideEditorToolbar();
|
||||||
|
|
@ -178,36 +163,16 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showEditorToolbar() {
|
void _showEditorToolbar() {
|
||||||
if (_textFormatBarOverlayEntry == null) {
|
_textFormatBarOverlayController.show();
|
||||||
// Create an overlay entry to build the editor toolbar.
|
|
||||||
// TODO: add an overlay to the Editor widget to avoid using the
|
|
||||||
// application overlay
|
|
||||||
_textFormatBarOverlayEntry ??= OverlayEntry(builder: (context) {
|
|
||||||
return EditorToolbar(
|
|
||||||
anchor: _textSelectionAnchor,
|
|
||||||
editorFocusNode: _editorFocusNode,
|
|
||||||
editor: _docEditor,
|
|
||||||
composer: _composer,
|
|
||||||
closeToolbar: _hideEditorToolbar,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Display the toolbar in the application overlay.
|
|
||||||
final overlay = Overlay.of(context);
|
|
||||||
overlay.insert(_textFormatBarOverlayEntry!);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Schedule a callback after this frame to locate the selection
|
// Schedule a callback after this frame to locate the selection
|
||||||
// bounds on the screen and display the toolbar near the selected
|
// bounds on the screen and display the toolbar near the selected
|
||||||
// text.
|
// text.
|
||||||
|
// TODO: switch this to use a Leader and Follower
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
if (_textFormatBarOverlayEntry == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final docBoundingBox = (_docLayoutKey.currentState as DocumentLayout)
|
final docBoundingBox = (_docLayoutKey.currentState as DocumentLayout)
|
||||||
.getRectForSelection(
|
.getRectForSelection(
|
||||||
_composer!.selection!.base, _composer!.selection!.extent)!;
|
_composer.selection!.base, _composer.selection!.extent)!;
|
||||||
final docBox =
|
final docBox =
|
||||||
_docLayoutKey.currentContext!.findRenderObject() as RenderBox;
|
_docLayoutKey.currentContext!.findRenderObject() as RenderBox;
|
||||||
final overlayBoundingBox = Rect.fromPoints(
|
final overlayBoundingBox = Rect.fromPoints(
|
||||||
|
|
@ -224,22 +189,14 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
// the bar doesn't momentarily "flash" at its old anchor position.
|
// the bar doesn't momentarily "flash" at its old anchor position.
|
||||||
_textSelectionAnchor.value = null;
|
_textSelectionAnchor.value = null;
|
||||||
|
|
||||||
if (_textFormatBarOverlayEntry != null) {
|
_textFormatBarOverlayController.hide();
|
||||||
// Remove the toolbar overlay and null-out the entry.
|
|
||||||
// We null out the entry because we can't query whether
|
|
||||||
// or not the entry exists in the overlay, so in our
|
|
||||||
// case, null implies the entry is not in the overlay,
|
|
||||||
// and non-null implies the entry is in the overlay.
|
|
||||||
_textFormatBarOverlayEntry!.remove();
|
|
||||||
_textFormatBarOverlayEntry = null;
|
|
||||||
|
|
||||||
// Ensure that focus returns to the editor.
|
// Ensure that focus returns to the editor.
|
||||||
//
|
//
|
||||||
// I tried explicitly unfocus()'ing the URL textfield
|
// I tried explicitly unfocus()'ing the URL textfield
|
||||||
// in the toolbar but it didn't return focus to the
|
// in the toolbar but it didn't return focus to the
|
||||||
// editor. I'm not sure why.
|
// editor. I'm not sure why.
|
||||||
_editorFocusNode!.requestFocus();
|
_editorFocusNode.requestFocus();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentGestureMode get _gestureMode {
|
DocumentGestureMode get _gestureMode {
|
||||||
|
|
@ -267,63 +224,41 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
case TargetPlatform.macOS:
|
case TargetPlatform.macOS:
|
||||||
case TargetPlatform.windows:
|
case TargetPlatform.windows:
|
||||||
return TextInputSource.ime;
|
return TextInputSource.ime;
|
||||||
// return DocumentInputSource.keyboard;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _cut() {
|
void _cut() {
|
||||||
_docOps.cut();
|
_docOps.cut();
|
||||||
|
// TODO: get rid of overlay controller once Android is refactored to use a control scope (as follow up to: https://github.com/superlistapp/super_editor/pull/1470)
|
||||||
_overlayController.hideToolbar();
|
_overlayController.hideToolbar();
|
||||||
|
_iosControlsController.hideToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _copy() {
|
void _copy() {
|
||||||
_docOps.copy();
|
_docOps.copy();
|
||||||
|
// TODO: get rid of overlay controller once Android is refactored to use a control scope (as follow up to: https://github.com/superlistapp/super_editor/pull/1470)
|
||||||
_overlayController.hideToolbar();
|
_overlayController.hideToolbar();
|
||||||
|
_iosControlsController.hideToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _paste() {
|
void _paste() {
|
||||||
_docOps.paste();
|
_docOps.paste();
|
||||||
|
// TODO: get rid of overlay controller once Android is refactored to use a control scope (as follow up to: https://github.com/superlistapp/super_editor/pull/1470)
|
||||||
_overlayController.hideToolbar();
|
_overlayController.hideToolbar();
|
||||||
|
_iosControlsController.hideToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectAll() => _docOps.selectAll();
|
void _selectAll() => _docOps.selectAll();
|
||||||
|
|
||||||
void _showImageToolbar() {
|
void _showImageToolbar() {
|
||||||
if (_imageFormatBarOverlayEntry == null) {
|
|
||||||
// Create an overlay entry to build the image toolbar.
|
|
||||||
_imageFormatBarOverlayEntry ??= OverlayEntry(builder: (context) {
|
|
||||||
return ImageFormatToolbar(
|
|
||||||
anchor: _imageSelectionAnchor,
|
|
||||||
composer: _composer,
|
|
||||||
setWidth: (nodeId, width) {
|
|
||||||
final node = _doc.getNodeById(nodeId)!;
|
|
||||||
final currentStyles =
|
|
||||||
SingleColumnLayoutComponentStyles.fromMetadata(node);
|
|
||||||
SingleColumnLayoutComponentStyles(
|
|
||||||
width: width,
|
|
||||||
padding: currentStyles.padding,
|
|
||||||
).applyTo(node);
|
|
||||||
},
|
|
||||||
closeToolbar: _hideImageToolbar,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Display the toolbar in the application overlay.
|
|
||||||
final overlay = Overlay.of(context);
|
|
||||||
overlay.insert(_imageFormatBarOverlayEntry!);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Schedule a callback after this frame to locate the selection
|
// Schedule a callback after this frame to locate the selection
|
||||||
// bounds on the screen and display the toolbar near the selected
|
// bounds on the screen and display the toolbar near the selected
|
||||||
// text.
|
// text.
|
||||||
|
// TODO: switch to a Leader and Follower for this
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
if (_imageFormatBarOverlayEntry == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final docBoundingBox = (_docLayoutKey.currentState as DocumentLayout)
|
final docBoundingBox = (_docLayoutKey.currentState as DocumentLayout)
|
||||||
.getRectForSelection(
|
.getRectForSelection(
|
||||||
_composer!.selection!.base, _composer!.selection!.extent)!;
|
_composer.selection!.base, _composer.selection!.extent)!;
|
||||||
final docBox =
|
final docBox =
|
||||||
_docLayoutKey.currentContext!.findRenderObject() as RenderBox;
|
_docLayoutKey.currentContext!.findRenderObject() as RenderBox;
|
||||||
final overlayBoundingBox = Rect.fromPoints(
|
final overlayBoundingBox = Rect.fromPoints(
|
||||||
|
|
@ -333,6 +268,8 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
|
|
||||||
_imageSelectionAnchor.value = overlayBoundingBox.center;
|
_imageSelectionAnchor.value = overlayBoundingBox.center;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_imageFormatBarOverlayController.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _hideImageToolbar() {
|
void _hideImageToolbar() {
|
||||||
|
|
@ -340,49 +277,67 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
// it doesn't momentarily "flash" at its old anchor position.
|
// it doesn't momentarily "flash" at its old anchor position.
|
||||||
_imageSelectionAnchor.value = null;
|
_imageSelectionAnchor.value = null;
|
||||||
|
|
||||||
if (_imageFormatBarOverlayEntry != null) {
|
_imageFormatBarOverlayController.hide();
|
||||||
// Remove the image toolbar overlay and null-out the entry.
|
|
||||||
// We null out the entry because we can't query whether
|
|
||||||
// or not the entry exists in the overlay, so in our
|
|
||||||
// case, null implies the entry is not in the overlay,
|
|
||||||
// and non-null implies the entry is in the overlay.
|
|
||||||
_imageFormatBarOverlayEntry!.remove();
|
|
||||||
_imageFormatBarOverlayEntry = null;
|
|
||||||
|
|
||||||
// Ensure that focus returns to the editor.
|
// Ensure that focus returns to the editor.
|
||||||
_editorFocusNode!.requestFocus();
|
_editorFocusNode.requestFocus();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Theme(
|
return ValueListenableBuilder(
|
||||||
data: ThemeData(brightness: Brightness.light),
|
valueListenable: _brightness,
|
||||||
child: Builder(builder: (themedContext) {
|
builder: (context, brightness, child) {
|
||||||
// This builder captures the new theme
|
return Theme(
|
||||||
return Stack(
|
data: ThemeData(brightness: brightness),
|
||||||
children: [
|
child: child!,
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: _buildEditor(themedContext),
|
|
||||||
),
|
|
||||||
if (_isMobile) _buildMountedToolbar(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
/*
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.bottomRight,
|
|
||||||
child: _buildCornerFabs(),
|
|
||||||
),
|
|
||||||
*/
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
|
child: Builder(
|
||||||
|
// This builder captures the new theme
|
||||||
|
builder: (themedContext) {
|
||||||
|
return OverlayPortal(
|
||||||
|
controller: _textFormatBarOverlayController,
|
||||||
|
overlayChildBuilder: _buildFloatingToolbar,
|
||||||
|
child: OverlayPortal(
|
||||||
|
controller: _imageFormatBarOverlayController,
|
||||||
|
overlayChildBuilder: _buildImageToolbar,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _buildEditor(themedContext),
|
||||||
|
),
|
||||||
|
if (_isMobile) //
|
||||||
|
_buildMountedToolbar(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.bottomRight,
|
||||||
|
child: ListenableBuilder(
|
||||||
|
listenable: _composer.selectionNotifier,
|
||||||
|
builder: (context, child) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
bottom: _isMobile && _composer.selection != null
|
||||||
|
? 48
|
||||||
|
: 0),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: _buildCornerFabs(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Widget _buildCornerFabs() {
|
Widget _buildCornerFabs() {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(right: 16, bottom: 16),
|
padding: const EdgeInsets.only(right: 16, bottom: 16),
|
||||||
|
|
@ -397,21 +352,21 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Widget _buildDebugVisualsToggle() {
|
Widget _buildDebugVisualsToggle() {
|
||||||
return FloatingActionButton(
|
return FloatingActionButton(
|
||||||
backgroundColor:
|
backgroundColor: _brightness.value == Brightness.light
|
||||||
_brightness == Brightness.light ? _darkBackground : _lightBackground,
|
? _darkBackground
|
||||||
foregroundColor:
|
: _lightBackground,
|
||||||
_brightness == Brightness.light ? _lightBackground : _darkBackground,
|
foregroundColor: _brightness.value == Brightness.light
|
||||||
|
? _lightBackground
|
||||||
|
: _darkBackground,
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_debugConfig = _debugConfig != null
|
_debugConfig = _debugConfig != null
|
||||||
? null
|
? null
|
||||||
: SuperEditorDebugVisualsConfig(
|
: const SuperEditorDebugVisualsConfig(
|
||||||
showFocus: true,
|
showFocus: true,
|
||||||
showImeConnection: true,
|
showImeConnection: true,
|
||||||
);
|
);
|
||||||
|
|
@ -425,19 +380,19 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
|
|
||||||
Widget _buildLightAndDarkModeToggle() {
|
Widget _buildLightAndDarkModeToggle() {
|
||||||
return FloatingActionButton(
|
return FloatingActionButton(
|
||||||
backgroundColor:
|
backgroundColor: _brightness.value == Brightness.light
|
||||||
_brightness == Brightness.light ? _darkBackground : _lightBackground,
|
? _darkBackground
|
||||||
foregroundColor:
|
: _lightBackground,
|
||||||
_brightness == Brightness.light ? _lightBackground : _darkBackground,
|
foregroundColor: _brightness.value == Brightness.light
|
||||||
|
? _lightBackground
|
||||||
|
: _darkBackground,
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
_brightness.value = _brightness.value == Brightness.light
|
||||||
_brightness = _brightness == Brightness.light
|
? Brightness.dark
|
||||||
? Brightness.dark
|
: Brightness.light;
|
||||||
: Brightness.light;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
child: _brightness == Brightness.light
|
child: _brightness.value == Brightness.light
|
||||||
? const Icon(
|
? const Icon(
|
||||||
Icons.dark_mode,
|
Icons.dark_mode,
|
||||||
)
|
)
|
||||||
|
|
@ -446,7 +401,6 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
Widget _buildEditor(BuildContext context) {
|
Widget _buildEditor(BuildContext context) {
|
||||||
final isLight = Theme.of(context).brightness == Brightness.light;
|
final isLight = Theme.of(context).brightness == Brightness.light;
|
||||||
|
|
@ -455,77 +409,134 @@ class _ExampleEditorState extends State<ExampleEditor> {
|
||||||
color: isLight ? _lightBackground : _darkBackground,
|
color: isLight ? _lightBackground : _darkBackground,
|
||||||
child: SuperEditorDebugVisuals(
|
child: SuperEditorDebugVisuals(
|
||||||
config: _debugConfig ?? const SuperEditorDebugVisualsConfig(),
|
config: _debugConfig ?? const SuperEditorDebugVisualsConfig(),
|
||||||
child: SuperEditor(
|
child: KeyedSubtree(
|
||||||
editor: _docEditor!,
|
key: _viewportKey,
|
||||||
composer: _composer,
|
child: SuperEditorIosControlsScope(
|
||||||
focusNode: _editorFocusNode,
|
controller: _iosControlsController,
|
||||||
scrollController: _scrollController,
|
child: SuperEditor(
|
||||||
documentLayoutKey: _docLayoutKey,
|
editor: _docEditor,
|
||||||
documentOverlayBuilders: [
|
document: _doc,
|
||||||
DefaultCaretOverlayBuilder(
|
composer: _composer,
|
||||||
CaretStyle()
|
focusNode: _editorFocusNode,
|
||||||
.copyWith(color: isLight ? Colors.black : Colors.redAccent),
|
scrollController: _scrollController,
|
||||||
),
|
documentLayoutKey: _docLayoutKey,
|
||||||
],
|
documentOverlayBuilders: [
|
||||||
selectionStyle: isLight
|
DefaultCaretOverlayBuilder(
|
||||||
? defaultSelectionStyle
|
caretStyle: const CaretStyle().copyWith(
|
||||||
: SelectionStyles(
|
color: isLight ? Colors.black : Colors.redAccent),
|
||||||
selectionColor: Colors.red.withOpacity(0.3),
|
|
||||||
),
|
),
|
||||||
stylesheet: defaultStylesheet.copyWith(
|
if (defaultTargetPlatform == TargetPlatform.iOS) ...[
|
||||||
addRulesAfter: [
|
SuperEditorAndroidToolbarFocalPointDocumentLayerBuilder(),
|
||||||
if (!isLight) ..._darkModeStyles,
|
SuperEditorAndroidHandlesDocumentLayerBuilder(),
|
||||||
taskStyles,
|
],
|
||||||
],
|
if (defaultTargetPlatform == TargetPlatform.android) ...[
|
||||||
|
SuperEditorAndroidToolbarFocalPointDocumentLayerBuilder(),
|
||||||
|
SuperEditorAndroidHandlesDocumentLayerBuilder(),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
selectionLayerLinks: _selectionLayerLinks,
|
||||||
|
selectionStyle: isLight
|
||||||
|
? defaultSelectionStyle
|
||||||
|
: SelectionStyles(
|
||||||
|
selectionColor: Colors.red.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
stylesheet: defaultStylesheet.copyWith(
|
||||||
|
addRulesAfter: [
|
||||||
|
if (!isLight) ..._darkModeStyles,
|
||||||
|
taskStyles,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
componentBuilders: [
|
||||||
|
TaskComponentBuilder(_docEditor),
|
||||||
|
...defaultComponentBuilders,
|
||||||
|
],
|
||||||
|
gestureMode: _gestureMode,
|
||||||
|
inputSource: _inputSource,
|
||||||
|
keyboardActions: _inputSource == TextInputSource.ime
|
||||||
|
? defaultImeKeyboardActions
|
||||||
|
: defaultKeyboardActions,
|
||||||
|
androidToolbarBuilder: (_) => _buildAndroidFloatingToolbar(),
|
||||||
|
overlayController: _overlayController,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
componentBuilders: [
|
),
|
||||||
TaskComponentBuilder(_docEditor!),
|
),
|
||||||
...defaultComponentBuilders,
|
);
|
||||||
],
|
}
|
||||||
gestureMode: _gestureMode,
|
|
||||||
inputSource: _inputSource,
|
Widget _buildAndroidFloatingToolbar() {
|
||||||
keyboardActions: _inputSource == TextInputSource.ime
|
return ListenableBuilder(
|
||||||
? defaultImeKeyboardActions
|
listenable: _brightness,
|
||||||
: defaultKeyboardActions,
|
builder: (context, _) {
|
||||||
androidToolbarBuilder: (_) => AndroidTextEditingFloatingToolbar(
|
return Theme(
|
||||||
|
data: ThemeData(brightness: _brightness.value),
|
||||||
|
child: AndroidTextEditingFloatingToolbar(
|
||||||
onCutPressed: _cut,
|
onCutPressed: _cut,
|
||||||
onCopyPressed: _copy,
|
onCopyPressed: _copy,
|
||||||
onPastePressed: _paste,
|
onPastePressed: _paste,
|
||||||
onSelectAllPressed: _selectAll,
|
onSelectAllPressed: _selectAll,
|
||||||
),
|
),
|
||||||
iOSToolbarBuilder: (_) => IOSTextEditingFloatingToolbar(
|
);
|
||||||
onCutPressed: _cut,
|
},
|
||||||
onCopyPressed: _copy,
|
|
||||||
onPastePressed: _paste,
|
|
||||||
focalPoint: _overlayController.toolbarTopAnchor!,
|
|
||||||
),
|
|
||||||
overlayController: _overlayController,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMountedToolbar() {
|
Widget _buildMountedToolbar() {
|
||||||
return MultiListenableBuilder(
|
return MultiListenableBuilder(
|
||||||
listenables: <Listenable>{
|
listenables: <Listenable>{
|
||||||
_doc,
|
_docChangeSignal,
|
||||||
_composer!.selectionNotifier,
|
_composer.selectionNotifier,
|
||||||
},
|
},
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
final selection = _composer!.selection;
|
final selection = _composer.selection;
|
||||||
|
|
||||||
if (selection == null) {
|
if (selection == null) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
return KeyboardEditingToolbar(
|
return KeyboardEditingToolbar(
|
||||||
|
editor: _docEditor,
|
||||||
document: _doc,
|
document: _doc,
|
||||||
composer: _composer!,
|
composer: _composer,
|
||||||
commonOps: _docOps,
|
commonOps: _docOps,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildFloatingToolbar(BuildContext context) {
|
||||||
|
return EditorToolbar(
|
||||||
|
editorViewportKey: _viewportKey,
|
||||||
|
anchor: _selectionLayerLinks.expandedSelectionBoundsLink,
|
||||||
|
editorFocusNode: _editorFocusNode,
|
||||||
|
editor: _docEditor,
|
||||||
|
document: _doc,
|
||||||
|
composer: _composer,
|
||||||
|
closeToolbar: _hideEditorToolbar,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildImageToolbar(BuildContext context) {
|
||||||
|
return ImageFormatToolbar(
|
||||||
|
anchor: _imageSelectionAnchor,
|
||||||
|
composer: _composer,
|
||||||
|
setWidth: (nodeId, width) {
|
||||||
|
print('Applying width $width to node $nodeId');
|
||||||
|
final node = _doc.getNodeById(nodeId)!;
|
||||||
|
final currentStyles =
|
||||||
|
SingleColumnLayoutComponentStyles.fromMetadata(node);
|
||||||
|
SingleColumnLayoutComponentStyles(
|
||||||
|
width: width,
|
||||||
|
padding: currentStyles.padding,
|
||||||
|
).applyTo(node);
|
||||||
|
|
||||||
|
// TODO: schedule a presentation reflow so that the image changes size immediately (https://github.com/superlistapp/super_editor/issues/1529)
|
||||||
|
// Right now, nothing happens when pressing the button, unless we force a
|
||||||
|
// rebuild/reflow.
|
||||||
|
},
|
||||||
|
closeToolbar: _hideImageToolbar,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Makes text light, for use during dark mode styling.
|
// Makes text light, for use during dark mode styling.
|
||||||
|
|
@ -533,7 +544,7 @@ final _darkModeStyles = [
|
||||||
StyleRule(
|
StyleRule(
|
||||||
BlockSelector.all,
|
BlockSelector.all,
|
||||||
(doc, docNode) {
|
(doc, docNode) {
|
||||||
return <String, dynamic>{
|
return {
|
||||||
'textStyle': const TextStyle(
|
'textStyle': const TextStyle(
|
||||||
color: Color(0xFFCCCCCC),
|
color: Color(0xFFCCCCCC),
|
||||||
),
|
),
|
||||||
|
|
@ -543,7 +554,7 @@ final _darkModeStyles = [
|
||||||
StyleRule(
|
StyleRule(
|
||||||
const BlockSelector('header1'),
|
const BlockSelector('header1'),
|
||||||
(doc, docNode) {
|
(doc, docNode) {
|
||||||
return <String, dynamic>{
|
return {
|
||||||
'textStyle': const TextStyle(
|
'textStyle': const TextStyle(
|
||||||
color: Color(0xFF888888),
|
color: Color(0xFF888888),
|
||||||
),
|
),
|
||||||
|
|
@ -553,7 +564,7 @@ final _darkModeStyles = [
|
||||||
StyleRule(
|
StyleRule(
|
||||||
const BlockSelector('header2'),
|
const BlockSelector('header2'),
|
||||||
(doc, docNode) {
|
(doc, docNode) {
|
||||||
return <String, dynamic>{
|
return {
|
||||||
'textStyle': const TextStyle(
|
'textStyle': const TextStyle(
|
||||||
color: Color(0xFF888888),
|
color: Color(0xFF888888),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
//import 'package:example/logging.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
//import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:follow_the_leader/follow_the_leader.dart';
|
||||||
|
import 'package:overlord/follow_the_leader.dart';
|
||||||
import 'package:super_editor/super_editor.dart';
|
import 'package:super_editor/super_editor.dart';
|
||||||
|
|
||||||
/// Small toolbar that is intended to display near some selected
|
/// Small toolbar that is intended to display near some selected
|
||||||
|
|
@ -13,33 +17,40 @@ import 'package:super_editor/super_editor.dart';
|
||||||
class EditorToolbar extends StatefulWidget {
|
class EditorToolbar extends StatefulWidget {
|
||||||
const EditorToolbar({
|
const EditorToolbar({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.anchor,
|
required this.editorViewportKey,
|
||||||
required this.editorFocusNode,
|
required this.editorFocusNode,
|
||||||
required this.editor,
|
required this.editor,
|
||||||
|
required this.document,
|
||||||
required this.composer,
|
required this.composer,
|
||||||
|
required this.anchor,
|
||||||
required this.closeToolbar,
|
required this.closeToolbar,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// [EditorToolbar] displays itself horizontally centered and
|
/// [GlobalKey] that should be attached to a widget that wraps the viewport
|
||||||
/// slightly above the given [anchor] value.
|
/// area, which keeps the toolbar from appearing outside of the editor area.
|
||||||
|
final GlobalKey editorViewportKey;
|
||||||
|
|
||||||
|
/// A [LeaderLink] that should be attached to the boundary of the toolbar
|
||||||
|
/// focal area, such as wrapped around the user's selection area.
|
||||||
///
|
///
|
||||||
/// [anchor] is a [ValueNotifier] so that [EditorToolbar] can
|
/// The toolbar is positioned relative to this anchor link.
|
||||||
/// reposition itself as the [Offset] value changes.
|
final LeaderLink anchor;
|
||||||
final ValueNotifier<Offset?> anchor;
|
|
||||||
|
|
||||||
/// The [FocusNode] attached to the editor to which this toolbar applies.
|
/// The [FocusNode] attached to the editor to which this toolbar applies.
|
||||||
final FocusNode? editorFocusNode;
|
final FocusNode editorFocusNode;
|
||||||
|
|
||||||
/// The [editor] is used to alter document content, such as
|
/// The [editor] is used to alter document content, such as
|
||||||
/// when the user selects a different block format for a
|
/// when the user selects a different block format for a
|
||||||
/// text blob, e.g., paragraph, header, blockquote, or
|
/// text blob, e.g., paragraph, header, blockquote, or
|
||||||
/// to apply styles to text.
|
/// to apply styles to text.
|
||||||
final DocumentEditor? editor;
|
final Editor? editor;
|
||||||
|
|
||||||
|
final Document document;
|
||||||
|
|
||||||
/// The [composer] provides access to the user's current
|
/// The [composer] provides access to the user's current
|
||||||
/// selection within the document, which dictates the
|
/// selection within the document, which dictates the
|
||||||
/// content that is altered by the toolbar's options.
|
/// content that is altered by the toolbar's options.
|
||||||
final DocumentComposer? composer;
|
final DocumentComposer composer;
|
||||||
|
|
||||||
/// Delegate that instructs the owner of this [EditorToolbar]
|
/// Delegate that instructs the owner of this [EditorToolbar]
|
||||||
/// to close the toolbar, such as after submitting a URL
|
/// to close the toolbar, such as after submitting a URL
|
||||||
|
|
@ -47,41 +58,62 @@ class EditorToolbar extends StatefulWidget {
|
||||||
final VoidCallback closeToolbar;
|
final VoidCallback closeToolbar;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_EditorToolbarState createState() => _EditorToolbarState();
|
State<EditorToolbar> createState() => _EditorToolbarState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EditorToolbarState extends State<EditorToolbar> {
|
class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
|
late final FollowerAligner _toolbarAligner;
|
||||||
|
late FollowerBoundary _screenBoundary;
|
||||||
|
|
||||||
bool _showUrlField = false;
|
bool _showUrlField = false;
|
||||||
FocusNode? _urlFocusNode;
|
late FocusNode _popoverFocusNode;
|
||||||
AttributedTextEditingController? _urlController;
|
late FocusNode _urlFocusNode;
|
||||||
|
ImeAttributedTextEditingController? _urlController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
_toolbarAligner = CupertinoPopoverToolbarAligner(widget.editorViewportKey);
|
||||||
|
|
||||||
|
_popoverFocusNode = FocusNode();
|
||||||
|
|
||||||
_urlFocusNode = FocusNode();
|
_urlFocusNode = FocusNode();
|
||||||
_urlController = SingleLineAttributedTextEditingController(_applyLink);
|
_urlController = ImeAttributedTextEditingController(
|
||||||
|
controller: SingleLineAttributedTextEditingController(_applyLink)) //
|
||||||
|
..onPerformActionPressed = _onPerformAction
|
||||||
|
..text = AttributedText('https://');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
|
||||||
|
_screenBoundary = WidgetFollowerBoundary(
|
||||||
|
boundaryKey: widget.editorViewportKey,
|
||||||
|
devicePixelRatio: MediaQuery.devicePixelRatioOf(context),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_urlFocusNode!.dispose();
|
_urlFocusNode.dispose();
|
||||||
_urlController!.dispose();
|
_urlController!.dispose();
|
||||||
|
_popoverFocusNode.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
/// Returns true if the currently selected text node is capable of being
|
/// Returns true if the currently selected text node is capable of being
|
||||||
/// transformed into a different type text node, returns false if
|
/// transformed into a different type text node, returns false if
|
||||||
/// multiple nodes are selected, no node is selected, or the selected
|
/// multiple nodes are selected, no node is selected, or the selected
|
||||||
/// node is not a standard text block.
|
/// node is not a standard text block.
|
||||||
bool _isConvertibleNode() {
|
bool _isConvertibleNode() {
|
||||||
final selection = widget.composer.selection;
|
final selection = widget.composer.selection!;
|
||||||
if (selection.base.nodeId != selection.extent.nodeId) {
|
if (selection.base.nodeId != selection.extent.nodeId) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedNode =
|
final selectedNode = widget.document.getNodeById(selection.extent.nodeId);
|
||||||
widget.editor.document.getNodeById(selection.extent.nodeId);
|
|
||||||
return selectedNode is ParagraphNode || selectedNode is ListItemNode;
|
return selectedNode is ParagraphNode || selectedNode is ListItemNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,10 +121,10 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
///
|
///
|
||||||
/// Throws an exception if the currently selected node is not a text node.
|
/// Throws an exception if the currently selected node is not a text node.
|
||||||
_TextType _getCurrentTextType() {
|
_TextType _getCurrentTextType() {
|
||||||
final selectedNode = widget.editor.document
|
final selectedNode =
|
||||||
.getNodeById(widget.composer.selection.extent.nodeId);
|
widget.document.getNodeById(widget.composer.selection!.extent.nodeId);
|
||||||
if (selectedNode is ParagraphNode) {
|
if (selectedNode is ParagraphNode) {
|
||||||
final dynamic type = selectedNode.getMetadataValue('blockType');
|
final type = selectedNode.getMetadataValue('blockType');
|
||||||
|
|
||||||
if (type == header1Attribution) {
|
if (type == header1Attribution) {
|
||||||
return _TextType.header1;
|
return _TextType.header1;
|
||||||
|
|
@ -118,10 +150,10 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
///
|
///
|
||||||
/// Throws an exception if the currently selected node is not a text node.
|
/// Throws an exception if the currently selected node is not a text node.
|
||||||
TextAlign _getCurrentTextAlignment() {
|
TextAlign _getCurrentTextAlignment() {
|
||||||
final selectedNode = widget.editor.document
|
final selectedNode =
|
||||||
.getNodeById(widget.composer.selection.extent.nodeId);
|
widget.document.getNodeById(widget.composer.selection!.extent.nodeId);
|
||||||
if (selectedNode is ParagraphNode) {
|
if (selectedNode is ParagraphNode) {
|
||||||
final dynamic align = selectedNode.getMetadataValue('textAlign');
|
final align = selectedNode.getMetadataValue('textAlign');
|
||||||
switch (align) {
|
switch (align) {
|
||||||
case 'left':
|
case 'left':
|
||||||
return TextAlign.left;
|
return TextAlign.left;
|
||||||
|
|
@ -143,13 +175,12 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
/// Returns true if a single text node is selected and that text node
|
/// Returns true if a single text node is selected and that text node
|
||||||
/// is capable of respecting alignment, returns false otherwise.
|
/// is capable of respecting alignment, returns false otherwise.
|
||||||
bool _isTextAlignable() {
|
bool _isTextAlignable() {
|
||||||
final selection = widget.composer.selection;
|
final selection = widget.composer.selection!;
|
||||||
if (selection.base.nodeId != selection.extent.nodeId) {
|
if (selection.base.nodeId != selection.extent.nodeId) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedNode =
|
final selectedNode = widget.document.getNodeById(selection.extent.nodeId);
|
||||||
widget.editor.document.getNodeById(selection.extent.nodeId);
|
|
||||||
return selectedNode is ParagraphNode;
|
return selectedNode is ParagraphNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,7 +189,7 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
///
|
///
|
||||||
/// For example: convert a paragraph to a blockquote, or a header
|
/// For example: convert a paragraph to a blockquote, or a header
|
||||||
/// to a list item.
|
/// to a list item.
|
||||||
void _convertTextToNewType(_TextType newType) {
|
void _convertTextToNewType(_TextType? newType) {
|
||||||
final existingTextType = _getCurrentTextType();
|
final existingTextType = _getCurrentTextType();
|
||||||
|
|
||||||
if (existingTextType == newType) {
|
if (existingTextType == newType) {
|
||||||
|
|
@ -167,53 +198,53 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isListItem(existingTextType) && _isListItem(newType)) {
|
if (_isListItem(existingTextType) && _isListItem(newType)) {
|
||||||
widget.editor.executeCommand(
|
widget.editor!.execute([
|
||||||
ChangeListItemTypeCommand(
|
ChangeListItemTypeRequest(
|
||||||
nodeId: widget.composer.selection.extent.nodeId,
|
nodeId: widget.composer.selection!.extent.nodeId,
|
||||||
newType: newType == _TextType.orderedListItem
|
newType: newType == _TextType.orderedListItem
|
||||||
? ListItemType.ordered
|
? ListItemType.ordered
|
||||||
: ListItemType.unordered,
|
: ListItemType.unordered,
|
||||||
),
|
),
|
||||||
);
|
]);
|
||||||
} else if (_isListItem(existingTextType) && !_isListItem(newType)) {
|
} else if (_isListItem(existingTextType) && !_isListItem(newType)) {
|
||||||
widget.editor.executeCommand(
|
widget.editor!.execute([
|
||||||
ConvertListItemToParagraphCommand(
|
ConvertListItemToParagraphRequest(
|
||||||
nodeId: widget.composer.selection.extent.nodeId,
|
nodeId: widget.composer.selection!.extent.nodeId,
|
||||||
paragraphMetadata: <String, dynamic>{
|
paragraphMetadata: {
|
||||||
'blockType': _getBlockTypeAttribution(newType),
|
'blockType': _getBlockTypeAttribution(newType),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
]);
|
||||||
} else if (!_isListItem(existingTextType) && _isListItem(newType)) {
|
} else if (!_isListItem(existingTextType) && _isListItem(newType)) {
|
||||||
widget.editor.executeCommand(
|
widget.editor!.execute([
|
||||||
ConvertParagraphToListItemCommand(
|
ConvertParagraphToListItemRequest(
|
||||||
nodeId: widget.composer.selection.extent.nodeId,
|
nodeId: widget.composer.selection!.extent.nodeId,
|
||||||
type: newType == _TextType.orderedListItem
|
type: newType == _TextType.orderedListItem
|
||||||
? ListItemType.ordered
|
? ListItemType.ordered
|
||||||
: ListItemType.unordered,
|
: ListItemType.unordered,
|
||||||
),
|
),
|
||||||
);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// Apply a new block type to an existing paragraph node.
|
// Apply a new block type to an existing paragraph node.
|
||||||
final existingNode = widget.editor.document
|
widget.editor!.execute([
|
||||||
.getNodeById(widget.composer.selection.extent.nodeId)
|
ChangeParagraphBlockTypeRequest(
|
||||||
as ParagraphNode;
|
nodeId: widget.composer.selection!.extent.nodeId,
|
||||||
existingNode.putMetadataValue(
|
blockType: _getBlockTypeAttribution(newType),
|
||||||
'blockType', _getBlockTypeAttribution(newType));
|
),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns true if the given [_TextType] represents an
|
/// Returns true if the given [_TextType] represents an
|
||||||
/// ordered or unordered list item, returns false otherwise.
|
/// ordered or unordered list item, returns false otherwise.
|
||||||
bool _isListItem(_TextType type) {
|
bool _isListItem(_TextType? type) {
|
||||||
return type == _TextType.orderedListItem ||
|
return type == _TextType.orderedListItem ||
|
||||||
type == _TextType.unorderedListItem;
|
type == _TextType.unorderedListItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the text [Attribution] associated with the given
|
/// Returns the text [Attribution] associated with the given
|
||||||
/// [_TextType], e.g., [_TextType.header1] -> [header1Attribution].
|
/// [_TextType], e.g., [_TextType.header1] -> [header1Attribution].
|
||||||
Attribution _getBlockTypeAttribution(_TextType newType) {
|
Attribution? _getBlockTypeAttribution(_TextType? newType) {
|
||||||
switch (newType) {
|
switch (newType) {
|
||||||
case _TextType.header1:
|
case _TextType.header1:
|
||||||
return header1Attribution;
|
return header1Attribution;
|
||||||
|
|
@ -228,36 +259,35 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/// Toggles bold styling for the current selected text.
|
/// Toggles bold styling for the current selected text.
|
||||||
void _toggleBold() {
|
void _toggleBold() {
|
||||||
widget.editor!.executeCommand(
|
widget.editor!.execute([
|
||||||
ToggleTextAttributionsCommand(
|
ToggleTextAttributionsRequest(
|
||||||
documentSelection: widget.composer!.selection!,
|
documentRange: widget.composer.selection!,
|
||||||
attributions: {boldAttribution},
|
attributions: {boldAttribution},
|
||||||
),
|
),
|
||||||
);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Toggles italic styling for the current selected text.
|
/// Toggles italic styling for the current selected text.
|
||||||
void _toggleItalics() {
|
void _toggleItalics() {
|
||||||
widget.editor!.executeCommand(
|
widget.editor!.execute([
|
||||||
ToggleTextAttributionsCommand(
|
ToggleTextAttributionsRequest(
|
||||||
documentSelection: widget.composer!.selection!,
|
documentRange: widget.composer.selection!,
|
||||||
attributions: {italicsAttribution},
|
attributions: {italicsAttribution},
|
||||||
),
|
),
|
||||||
);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Toggles strikethrough styling for the current selected text.
|
/// Toggles strikethrough styling for the current selected text.
|
||||||
void _toggleStrikethrough() {
|
void _toggleStrikethrough() {
|
||||||
widget.editor!.executeCommand(
|
widget.editor!.execute([
|
||||||
ToggleTextAttributionsCommand(
|
ToggleTextAttributionsRequest(
|
||||||
documentSelection: widget.composer!.selection!,
|
documentRange: widget.composer.selection!,
|
||||||
attributions: {strikethroughAttribution},
|
attributions: {strikethroughAttribution},
|
||||||
),
|
),
|
||||||
);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the current text selection includes part
|
/// Returns true if the current text selection includes part
|
||||||
|
|
@ -276,16 +306,15 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
/// Returns any link-based [AttributionSpan]s that appear partially
|
/// Returns any link-based [AttributionSpan]s that appear partially
|
||||||
/// or wholly within the current text selection.
|
/// or wholly within the current text selection.
|
||||||
Set<AttributionSpan> _getSelectedLinkSpans() {
|
Set<AttributionSpan> _getSelectedLinkSpans() {
|
||||||
final selection = widget.composer!.selection!;
|
final selection = widget.composer.selection!;
|
||||||
final baseOffset = (selection.base.nodePosition as TextPosition).offset;
|
final baseOffset = (selection.base.nodePosition as TextPosition).offset;
|
||||||
final extentOffset = (selection.extent.nodePosition as TextPosition).offset;
|
final extentOffset = (selection.extent.nodePosition as TextPosition).offset;
|
||||||
final selectionStart = min(baseOffset, extentOffset);
|
final selectionStart = min(baseOffset, extentOffset);
|
||||||
final selectionEnd = max(baseOffset, extentOffset);
|
final selectionEnd = max(baseOffset, extentOffset);
|
||||||
final selectionRange =
|
final selectionRange = SpanRange(selectionStart, selectionEnd - 1);
|
||||||
SpanRange(start: selectionStart, end: selectionEnd - 1);
|
|
||||||
|
|
||||||
final textNode = widget.editor!.document
|
final textNode =
|
||||||
.getNodeById(selection.extent.nodeId) as TextNode;
|
widget.document.getNodeById(selection.extent.nodeId) as TextNode;
|
||||||
final text = textNode.text;
|
final text = textNode.text;
|
||||||
|
|
||||||
final overlappingLinkAttributions = text.getAttributionSpansInRange(
|
final overlappingLinkAttributions = text.getAttributionSpansInRange(
|
||||||
|
|
@ -300,16 +329,15 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
/// Takes appropriate action when the toolbar's link button is
|
/// Takes appropriate action when the toolbar's link button is
|
||||||
/// pressed.
|
/// pressed.
|
||||||
void _onLinkPressed() {
|
void _onLinkPressed() {
|
||||||
final selection = widget.composer!.selection!;
|
final selection = widget.composer.selection!;
|
||||||
final baseOffset = (selection.base.nodePosition as TextPosition).offset;
|
final baseOffset = (selection.base.nodePosition as TextPosition).offset;
|
||||||
final extentOffset = (selection.extent.nodePosition as TextPosition).offset;
|
final extentOffset = (selection.extent.nodePosition as TextPosition).offset;
|
||||||
final selectionStart = min(baseOffset, extentOffset);
|
final selectionStart = min(baseOffset, extentOffset);
|
||||||
final selectionEnd = max(baseOffset, extentOffset);
|
final selectionEnd = max(baseOffset, extentOffset);
|
||||||
final selectionRange =
|
final selectionRange = SpanRange(selectionStart, selectionEnd - 1);
|
||||||
SpanRange(start: selectionStart, end: selectionEnd - 1);
|
|
||||||
|
|
||||||
final textNode = widget.editor!.document
|
final textNode =
|
||||||
.getNodeById(selection.extent.nodeId) as TextNode;
|
widget.document.getNodeById(selection.extent.nodeId) as TextNode;
|
||||||
final text = textNode.text;
|
final text = textNode.text;
|
||||||
|
|
||||||
final overlappingLinkAttributions = text.getAttributionSpansInRange(
|
final overlappingLinkAttributions = text.getAttributionSpansInRange(
|
||||||
|
|
@ -341,15 +369,14 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
// the entire link attribution.
|
// the entire link attribution.
|
||||||
text.removeAttribution(
|
text.removeAttribution(
|
||||||
overlappingLinkSpan.attribution,
|
overlappingLinkSpan.attribution,
|
||||||
SpanRange(
|
SpanRange(overlappingLinkSpan.start, overlappingLinkSpan.end),
|
||||||
start: overlappingLinkSpan.start, end: overlappingLinkSpan.end),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// There are no other links in the selection. Show the URL text field.
|
// There are no other links in the selection. Show the URL text field.
|
||||||
setState(() {
|
setState(() {
|
||||||
_showUrlField = true;
|
_showUrlField = true;
|
||||||
_urlFocusNode!.requestFocus();
|
_urlFocusNode.requestFocus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -359,7 +386,7 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
void _applyLink() {
|
void _applyLink() {
|
||||||
final url = _urlController!.text.text;
|
final url = _urlController!.text.text;
|
||||||
|
|
||||||
final selection = widget.composer!.selection!;
|
final selection = widget.composer.selection!;
|
||||||
final baseOffset = (selection.base.nodePosition as TextPosition).offset;
|
final baseOffset = (selection.base.nodePosition as TextPosition).offset;
|
||||||
final extentOffset = (selection.extent.nodePosition as TextPosition).offset;
|
final extentOffset = (selection.extent.nodePosition as TextPosition).offset;
|
||||||
final selectionStart = min(baseOffset, extentOffset);
|
final selectionStart = min(baseOffset, extentOffset);
|
||||||
|
|
@ -367,8 +394,8 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
final selectionRange =
|
final selectionRange =
|
||||||
TextRange(start: selectionStart, end: selectionEnd - 1);
|
TextRange(start: selectionStart, end: selectionEnd - 1);
|
||||||
|
|
||||||
final textNode = widget.editor!.document
|
final textNode =
|
||||||
.getNodeById(selection.extent.nodeId) as TextNode;
|
widget.document.getNodeById(selection.extent.nodeId) as TextNode;
|
||||||
final text = textNode.text;
|
final text = textNode.text;
|
||||||
|
|
||||||
final trimmedRange = _trimTextRangeWhitespace(text, selectionRange);
|
final trimmedRange = _trimTextRangeWhitespace(text, selectionRange);
|
||||||
|
|
@ -383,8 +410,8 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
_urlController!.clear();
|
_urlController!.clear();
|
||||||
setState(() {
|
setState(() {
|
||||||
_showUrlField = false;
|
_showUrlField = false;
|
||||||
_urlFocusNode!
|
_urlFocusNode.unfocus(
|
||||||
.unfocus(disposition: UnfocusDisposition.previouslyFocusedChild);
|
disposition: UnfocusDisposition.previouslyFocusedChild);
|
||||||
widget.closeToolbar();
|
widget.closeToolbar();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -403,17 +430,16 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
endOffset -= 1;
|
endOffset -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SpanRange(start: startOffset, end: endOffset);
|
return SpanRange(startOffset, endOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
/// Changes the alignment of the current selected text node
|
/// Changes the alignment of the current selected text node
|
||||||
/// to reflect [newAlignment].
|
/// to reflect [newAlignment].
|
||||||
void _changeAlignment(TextAlign newAlignment) {
|
void _changeAlignment(TextAlign? newAlignment) {
|
||||||
if (newAlignment == null) {
|
if (newAlignment == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String newAlignmentValue;
|
String? newAlignmentValue;
|
||||||
switch (newAlignment) {
|
switch (newAlignment) {
|
||||||
case TextAlign.left:
|
case TextAlign.left:
|
||||||
case TextAlign.start:
|
case TextAlign.start:
|
||||||
|
|
@ -431,8 +457,8 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedNode = widget.editor.document
|
final selectedNode = widget.document
|
||||||
.getNodeById(widget.composer.selection.extent.nodeId) as ParagraphNode;
|
.getNodeById(widget.composer.selection!.extent.nodeId) as ParagraphNode;
|
||||||
selectedNode.putMetadataValue('textAlign', newAlignmentValue);
|
selectedNode.putMetadataValue('textAlign', newAlignmentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -441,190 +467,199 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
String _getTextTypeName(_TextType textType) {
|
String _getTextTypeName(_TextType textType) {
|
||||||
switch (textType) {
|
switch (textType) {
|
||||||
case _TextType.header1:
|
case _TextType.header1:
|
||||||
|
// return AppLocalizations.of(context)!.labelHeader1;
|
||||||
return 'Header 1';
|
return 'Header 1';
|
||||||
case _TextType.header2:
|
case _TextType.header2:
|
||||||
|
// return AppLocalizations.of(context)!.labelHeader2;
|
||||||
return 'Header 2';
|
return 'Header 2';
|
||||||
case _TextType.header3:
|
case _TextType.header3:
|
||||||
|
// return AppLocalizations.of(context)!.labelHeader3;
|
||||||
return 'Header 3';
|
return 'Header 3';
|
||||||
case _TextType.paragraph:
|
case _TextType.paragraph:
|
||||||
|
// return AppLocalizations.of(context)!.labelParagraph;
|
||||||
return 'Paragraph';
|
return 'Paragraph';
|
||||||
case _TextType.blockquote:
|
case _TextType.blockquote:
|
||||||
|
// return AppLocalizations.of(context)!.labelBlockquote;
|
||||||
return 'Blockquote';
|
return 'Blockquote';
|
||||||
case _TextType.orderedListItem:
|
case _TextType.orderedListItem:
|
||||||
|
// return AppLocalizations.of(context)!.labelOrderedListItem;
|
||||||
return 'Ordered List Item';
|
return 'Ordered List Item';
|
||||||
case _TextType.unorderedListItem:
|
case _TextType.unorderedListItem:
|
||||||
|
// return AppLocalizations.of(context)!.labelUnorderedListItem;
|
||||||
return 'Unordered List Item';
|
return 'Unordered List Item';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
void _onPerformAction(TextInputAction action) {
|
||||||
|
if (action == TextInputAction.done) {
|
||||||
|
_applyLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
return BuildInOrder(
|
||||||
children: [
|
children: [
|
||||||
// Conditionally display the URL text field below
|
FollowerFadeOutBeyondBoundary(
|
||||||
// the standard toolbar.
|
link: widget.anchor,
|
||||||
if (_showUrlField)
|
boundary: _screenBoundary,
|
||||||
Positioned(
|
child: Follower.withAligner(
|
||||||
left: widget.anchor.value!.dx,
|
link: widget.anchor,
|
||||||
top: widget.anchor.value!.dy,
|
aligner: _toolbarAligner,
|
||||||
child: FractionalTranslation(
|
boundary: _screenBoundary,
|
||||||
translation: const Offset(-0.5, 0.0),
|
showWhenUnlinked: false,
|
||||||
child: _buildUrlField(),
|
child: _buildToolbars(),
|
||||||
),
|
|
||||||
),
|
|
||||||
_PositionedToolbar(
|
|
||||||
anchor: widget.anchor,
|
|
||||||
composer: widget.composer,
|
|
||||||
child: ValueListenableBuilder<DocumentSelection?>(
|
|
||||||
valueListenable: widget.composer!.selectionNotifier,
|
|
||||||
builder: (context, selection, child) {
|
|
||||||
if (selection == null) {
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
if (selection.extent.nodePosition is! TextPosition) {
|
|
||||||
// The user selected non-text content. This toolbar is probably
|
|
||||||
// about to disappear. Until then, build nothing, because the
|
|
||||||
// toolbar needs to inspect selected text to build correctly.
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buildToolbar();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildToolbar() {
|
Widget _buildToolbars() {
|
||||||
return Material(
|
return SuperEditorPopover(
|
||||||
shape: const StadiumBorder(),
|
popoverFocusNode: _popoverFocusNode,
|
||||||
elevation: 5,
|
editorFocusNode: widget.editorFocusNode,
|
||||||
clipBehavior: Clip.hardEdge,
|
child: Column(
|
||||||
child: SizedBox(
|
mainAxisSize: MainAxisSize.min,
|
||||||
height: 40,
|
children: [
|
||||||
child: Row(
|
_buildToolbar(),
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
if (_showUrlField) ...[
|
||||||
children: [
|
const SizedBox(height: 8),
|
||||||
/*
|
_buildUrlField(),
|
||||||
// https://github.com/superlistapp/super_editor/issues/689
|
|
||||||
// https://github.com/flutter/flutter/issues/106923
|
|
||||||
// Only allow the user to select a new type of text node if
|
|
||||||
// the currently selected node can be converted.
|
|
||||||
if (_isConvertibleNode()) ...[
|
|
||||||
Tooltip(
|
|
||||||
message: 'Text Block Type',
|
|
||||||
child: DropdownButton<_TextType>(
|
|
||||||
value: _getCurrentTextType(),
|
|
||||||
items: _TextType.values
|
|
||||||
.map((textType) => DropdownMenuItem<_TextType>(
|
|
||||||
value: textType,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 16.0),
|
|
||||||
child: Text(_getTextTypeName(textType)),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
icon: const Icon(Icons.arrow_drop_down),
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
|
||||||
? Colors.white
|
|
||||||
: Colors.black,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
underline: const SizedBox(),
|
|
||||||
elevation: 0,
|
|
||||||
itemHeight: 48,
|
|
||||||
onChanged: _convertTextToNewType,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_buildVerticalDivider(),
|
|
||||||
],
|
|
||||||
*/
|
|
||||||
Center(
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: _toggleBold,
|
|
||||||
icon: const Icon(Icons.format_bold),
|
|
||||||
splashRadius: 16,
|
|
||||||
tooltip: 'Bold',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: _toggleItalics,
|
|
||||||
icon: const Icon(Icons.format_italic),
|
|
||||||
splashRadius: 16,
|
|
||||||
tooltip: 'Italics',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: _toggleStrikethrough,
|
|
||||||
icon: const Icon(Icons.strikethrough_s),
|
|
||||||
splashRadius: 16,
|
|
||||||
tooltip: 'Strikethrough',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: _areMultipleLinksSelected() ? null : _onLinkPressed,
|
|
||||||
icon: const Icon(Icons.link),
|
|
||||||
color: _isSingleLinkSelected()
|
|
||||||
? const Color(0xFF007AFF)
|
|
||||||
: IconTheme.of(context).color,
|
|
||||||
splashRadius: 16,
|
|
||||||
tooltip: 'Link',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Only display alignment controls if the currently selected text
|
|
||||||
// node respects alignment. List items, for example, do not.
|
|
||||||
/*
|
|
||||||
if (_isTextAlignable()) ...[
|
|
||||||
_buildVerticalDivider(),
|
|
||||||
Tooltip(
|
|
||||||
message: 'Text Alignment',
|
|
||||||
child: DropdownButton<TextAlign>(
|
|
||||||
value: _getCurrentTextAlignment(),
|
|
||||||
items: [
|
|
||||||
TextAlign.left,
|
|
||||||
TextAlign.center,
|
|
||||||
TextAlign.right,
|
|
||||||
TextAlign.justify
|
|
||||||
]
|
|
||||||
.map((textAlign) => DropdownMenuItem<TextAlign>(
|
|
||||||
value: textAlign,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 8.0),
|
|
||||||
child: Icon(_buildTextAlignIcon(textAlign)),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
icon: const Icon(Icons.arrow_drop_down),
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
underline: const SizedBox(),
|
|
||||||
elevation: 0,
|
|
||||||
itemHeight: 48,
|
|
||||||
onChanged: _changeAlignment,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
_buildVerticalDivider(),
|
|
||||||
Center(
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () {},
|
|
||||||
icon: const Icon(Icons.more_vert),
|
|
||||||
splashRadius: 16,
|
|
||||||
tooltip: 'More Options',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
*/
|
|
||||||
],
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildToolbar() {
|
||||||
|
return IntrinsicWidth(
|
||||||
|
child: Material(
|
||||||
|
shape: const StadiumBorder(),
|
||||||
|
elevation: 5,
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
// Only allow the user to select a new type of text node if
|
||||||
|
// the currently selected node can be converted.
|
||||||
|
if (_isConvertibleNode()) ...[
|
||||||
|
Tooltip(
|
||||||
|
//message: AppLocalizations.of(context)!.labelTextBlockType,
|
||||||
|
message: 'Block Type',
|
||||||
|
child: DropdownButton<_TextType>(
|
||||||
|
value: _getCurrentTextType(),
|
||||||
|
items: _TextType.values
|
||||||
|
.map((textType) => DropdownMenuItem<_TextType>(
|
||||||
|
value: textType,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 16.0),
|
||||||
|
child: Text(_getTextTypeName(textType)),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
icon: const Icon(Icons.arrow_drop_down),
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
underline: const SizedBox(),
|
||||||
|
elevation: 0,
|
||||||
|
itemHeight: 48,
|
||||||
|
onChanged: _convertTextToNewType,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_buildVerticalDivider(),
|
||||||
|
],
|
||||||
|
Center(
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: _toggleBold,
|
||||||
|
icon: const Icon(Icons.format_bold),
|
||||||
|
splashRadius: 16,
|
||||||
|
//tooltip: AppLocalizations.of(context)!.Bold,
|
||||||
|
tooltip: 'Bold',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: _toggleItalics,
|
||||||
|
icon: const Icon(Icons.format_italic),
|
||||||
|
splashRadius: 16,
|
||||||
|
//tooltip: AppLocalizations.of(context)!.labelItalics,
|
||||||
|
tooltip: 'Italics',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: _toggleStrikethrough,
|
||||||
|
icon: const Icon(Icons.strikethrough_s),
|
||||||
|
splashRadius: 16,
|
||||||
|
//tooltip: AppLocalizations.of(context)!.labelStrikethrough,
|
||||||
|
tooltip: 'Strikethrough',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: IconButton(
|
||||||
|
onPressed:
|
||||||
|
_areMultipleLinksSelected() ? null : _onLinkPressed,
|
||||||
|
icon: const Icon(Icons.link),
|
||||||
|
color: _isSingleLinkSelected()
|
||||||
|
? const Color(0xFF007AFF)
|
||||||
|
: IconTheme.of(context).color,
|
||||||
|
splashRadius: 16,
|
||||||
|
//tooltip: AppLocalizations.of(context)!.labelLink,
|
||||||
|
tooltip: 'Link',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Only display alignment controls if the currently selected text
|
||||||
|
// node respects alignment. List items, for example, do not.
|
||||||
|
if (_isTextAlignable()) ...[
|
||||||
|
_buildVerticalDivider(),
|
||||||
|
Tooltip(
|
||||||
|
//message: AppLocalizations.of(context)!.labelTextAlignment,
|
||||||
|
message: 'Text Alignment',
|
||||||
|
child: DropdownButton<TextAlign>(
|
||||||
|
value: _getCurrentTextAlignment(),
|
||||||
|
items: [
|
||||||
|
TextAlign.left,
|
||||||
|
TextAlign.center,
|
||||||
|
TextAlign.right,
|
||||||
|
TextAlign.justify
|
||||||
|
]
|
||||||
|
.map((textAlign) => DropdownMenuItem<TextAlign>(
|
||||||
|
value: textAlign,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8.0),
|
||||||
|
child: Icon(_buildTextAlignIcon(textAlign)),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
icon: const Icon(Icons.arrow_drop_down),
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
underline: const SizedBox(),
|
||||||
|
elevation: 0,
|
||||||
|
itemHeight: 48,
|
||||||
|
onChanged: _changeAlignment,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
_buildVerticalDivider(),
|
||||||
|
Center(
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: const Icon(Icons.more_vert),
|
||||||
|
splashRadius: 16,
|
||||||
|
//tooltip: AppLocalizations.of(context)!.labelMoreOptions,
|
||||||
|
tooltip: 'More Options',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -642,9 +677,9 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FocusWithCustomParent(
|
child: Focus(
|
||||||
focusNode: _urlFocusNode,
|
focusNode: _urlFocusNode,
|
||||||
parentFocusNode: widget.editorFocusNode,
|
parentNode: _popoverFocusNode,
|
||||||
// We use a SuperTextField instead of a TextField because TextField
|
// We use a SuperTextField instead of a TextField because TextField
|
||||||
// automatically re-parents its FocusNode, which causes #609. Flutter
|
// automatically re-parents its FocusNode, which causes #609. Flutter
|
||||||
// #106923 tracks the TextField issue.
|
// #106923 tracks the TextField issue.
|
||||||
|
|
@ -656,19 +691,17 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
inputSource: TextInputSource.ime,
|
inputSource: TextInputSource.ime,
|
||||||
hintBehavior: HintBehavior.displayHintUntilTextEntered,
|
hintBehavior: HintBehavior.displayHintUntilTextEntered,
|
||||||
hintBuilder: (context) {
|
hintBuilder: (context) {
|
||||||
return Text(
|
return const Text(
|
||||||
'Enter a url...',
|
'enter a url...',
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
textStyleBuilder: (_) {
|
textStyleBuilder: (_) {
|
||||||
return TextStyle(
|
return const TextStyle(
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: Colors.black,
|
||||||
? Colors.white
|
|
||||||
: Colors.black,
|
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -682,7 +715,7 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_urlFocusNode!.unfocus();
|
_urlFocusNode.unfocus();
|
||||||
_showUrlField = false;
|
_showUrlField = false;
|
||||||
_urlController!.clear();
|
_urlController!.clear();
|
||||||
});
|
});
|
||||||
|
|
@ -694,7 +727,6 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Widget _buildVerticalDivider() {
|
Widget _buildVerticalDivider() {
|
||||||
return Container(
|
return Container(
|
||||||
width: 1,
|
width: 1,
|
||||||
|
|
@ -702,7 +734,6 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IconData _buildTextAlignIcon(TextAlign align) {
|
IconData _buildTextAlignIcon(TextAlign align) {
|
||||||
switch (align) {
|
switch (align) {
|
||||||
case TextAlign.left:
|
case TextAlign.left:
|
||||||
|
|
@ -716,13 +747,9 @@ class _EditorToolbarState extends State<EditorToolbar> {
|
||||||
case TextAlign.justify:
|
case TextAlign.justify:
|
||||||
return Icons.format_align_justify;
|
return Icons.format_align_justify;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
enum _TextType {
|
enum _TextType {
|
||||||
header1,
|
header1,
|
||||||
header2,
|
header2,
|
||||||
|
|
@ -732,7 +759,6 @@ enum _TextType {
|
||||||
orderedListItem,
|
orderedListItem,
|
||||||
unorderedListItem,
|
unorderedListItem,
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/// Small toolbar that is intended to display over an image and
|
/// Small toolbar that is intended to display over an image and
|
||||||
/// offer controls to expand or contract the size of the image.
|
/// offer controls to expand or contract the size of the image.
|
||||||
|
|
@ -760,7 +786,7 @@ class ImageFormatToolbar extends StatefulWidget {
|
||||||
/// The [composer] provides access to the user's current
|
/// The [composer] provides access to the user's current
|
||||||
/// selection within the document, which dictates the
|
/// selection within the document, which dictates the
|
||||||
/// content that is altered by the toolbar's options.
|
/// content that is altered by the toolbar's options.
|
||||||
final DocumentComposer? composer;
|
final DocumentComposer composer;
|
||||||
|
|
||||||
/// Callback that should update the width of the component with
|
/// Callback that should update the width of the component with
|
||||||
/// the given [nodeId] to match the given [width].
|
/// the given [nodeId] to match the given [width].
|
||||||
|
|
@ -771,16 +797,16 @@ class ImageFormatToolbar extends StatefulWidget {
|
||||||
final VoidCallback closeToolbar;
|
final VoidCallback closeToolbar;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ImageFormatToolbarState createState() => _ImageFormatToolbarState();
|
State<ImageFormatToolbar> createState() => _ImageFormatToolbarState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ImageFormatToolbarState extends State<ImageFormatToolbar> {
|
class _ImageFormatToolbarState extends State<ImageFormatToolbar> {
|
||||||
void _makeImageConfined() {
|
void _makeImageConfined() {
|
||||||
widget.setWidth(widget.composer!.selection!.extent.nodeId, null);
|
widget.setWidth(widget.composer.selection!.extent.nodeId, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _makeImageFullBleed() {
|
void _makeImageFullBleed() {
|
||||||
widget.setWidth(widget.composer!.selection!.extent.nodeId, double.infinity);
|
widget.setWidth(widget.composer.selection!.extent.nodeId, double.infinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -789,8 +815,9 @@ class _ImageFormatToolbarState extends State<ImageFormatToolbar> {
|
||||||
anchor: widget.anchor,
|
anchor: widget.anchor,
|
||||||
composer: widget.composer,
|
composer: widget.composer,
|
||||||
child: ValueListenableBuilder<DocumentSelection?>(
|
child: ValueListenableBuilder<DocumentSelection?>(
|
||||||
valueListenable: widget.composer!.selectionNotifier,
|
valueListenable: widget.composer.selectionNotifier,
|
||||||
builder: (context, selection, child) {
|
builder: (context, selection, child) {
|
||||||
|
//appLog.fine("Building image toolbar. Selection: $selection");
|
||||||
if (selection == null) {
|
if (selection == null) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
@ -825,6 +852,7 @@ class _ImageFormatToolbarState extends State<ImageFormatToolbar> {
|
||||||
onPressed: _makeImageConfined,
|
onPressed: _makeImageConfined,
|
||||||
icon: const Icon(Icons.photo_size_select_large),
|
icon: const Icon(Icons.photo_size_select_large),
|
||||||
splashRadius: 16,
|
splashRadius: 16,
|
||||||
|
//tooltip: AppLocalizations.of(context)!.labelBold,
|
||||||
tooltip: 'Bold',
|
tooltip: 'Bold',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -833,6 +861,7 @@ class _ImageFormatToolbarState extends State<ImageFormatToolbar> {
|
||||||
onPressed: _makeImageFullBleed,
|
onPressed: _makeImageFullBleed,
|
||||||
icon: const Icon(Icons.photo_size_select_actual),
|
icon: const Icon(Icons.photo_size_select_actual),
|
||||||
splashRadius: 16,
|
splashRadius: 16,
|
||||||
|
//tooltip: AppLocalizations.of(context)!.labelItalics,
|
||||||
tooltip: 'Italics',
|
tooltip: 'Italics',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -853,7 +882,7 @@ class _PositionedToolbar extends StatelessWidget {
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final ValueNotifier<Offset?> anchor;
|
final ValueNotifier<Offset?> anchor;
|
||||||
final DocumentComposer? composer;
|
final DocumentComposer composer;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -861,12 +890,16 @@ class _PositionedToolbar extends StatelessWidget {
|
||||||
return ValueListenableBuilder<Offset?>(
|
return ValueListenableBuilder<Offset?>(
|
||||||
valueListenable: anchor,
|
valueListenable: anchor,
|
||||||
builder: (context, offset, _) {
|
builder: (context, offset, _) {
|
||||||
if (offset == null || composer!.selection == null) {
|
//appLog.fine(
|
||||||
|
// "(Re)Building _PositionedToolbar widget due to anchor change");
|
||||||
|
if (offset == null || composer.selection == null) {
|
||||||
|
//appLog.fine("Anchor is null. Building an empty box.");
|
||||||
// When no anchor position is available, or the user hasn't
|
// When no anchor position is available, or the user hasn't
|
||||||
// selected any text, show nothing.
|
// selected any text, show nothing.
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//appLog.fine("Anchor is non-null: $offset, child: $child");
|
||||||
return SizedBox.expand(
|
return SizedBox.expand(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
|
|
|
||||||
356
pubspec.lock
356
pubspec.lock
|
|
@ -21,10 +21,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: "7e0d52067d05f2e0324268097ba723b71cb41ac8a6a2b24d1edf9c536b987b03"
|
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.6"
|
version: "3.4.9"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -42,12 +42,13 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.0"
|
version: "2.11.0"
|
||||||
attributed_text:
|
attributed_text:
|
||||||
dependency: transitive
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: attributed_text
|
path: attributed_text
|
||||||
sha256: e43495051b63e6cdbe96aa62123974074cca109d9c56f74ce2ffaec8060e044e
|
ref: stable
|
||||||
url: "https://pub.dev"
|
resolved-ref: c040c690f1dc0f7c482d8ece02622c200cb8e1b1
|
||||||
source: hosted
|
url: "https://github.com/superlistapp/super_editor"
|
||||||
|
source: git
|
||||||
version: "0.2.2"
|
version: "0.2.2"
|
||||||
barcode:
|
barcode:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
|
|
@ -102,10 +103,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_daemon
|
name: build_daemon
|
||||||
sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65"
|
sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.1"
|
||||||
build_resolvers:
|
build_resolvers:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -118,10 +119,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b"
|
sha256: "67d591d602906ef9201caf93452495ad1812bea2074f04e25dbd7c133785821b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.6"
|
version: "2.4.7"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -142,26 +143,42 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: a8de5955205b4d1dbbbc267daddf2178bd737e4bab8987c04a500478c9651e74
|
sha256: "69acb7007eb2a31dc901512bfe0f7b767168be34cb734835d54c070bfa74c1b2"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.6.3"
|
version: "8.8.0"
|
||||||
built_value_generator:
|
built_value_generator:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: built_value_generator
|
name: built_value_generator
|
||||||
sha256: a7a20bd4a943316c46c6e89b1a5631a2dace50ca6742b73d0b719fd243a7da00
|
sha256: "78680d78a6cab222fc5725ffa21065a05bba951452ae84d08b3c0e150fd3f9f6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.6.3"
|
version: "8.8.0"
|
||||||
cached_network_image:
|
cached_network_image:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: cached_network_image
|
name: cached_network_image
|
||||||
sha256: ebab9f6c55a7aa8d62cdfe0877f8b5ce806c1956b0a244ba39fcadeb0e1aad85
|
sha256: f98972704692ba679db144261172a8e20feb145636c617af0eb4022132a6797f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.3.0"
|
||||||
|
cached_network_image_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cached_network_image_platform_interface
|
||||||
|
sha256: "56aa42a7a01e3c9db8456d9f3f999931f1e05535b5a424271e9a38cabf066613"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
cached_network_image_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cached_network_image_web
|
||||||
|
sha256: "759b9a9f8f6ccbb66c185df805fac107f05730b1dab9c64626d1008cca532257"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -222,18 +239,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: code_builder
|
name: code_builder
|
||||||
sha256: "1be9be30396d7e4c0db42c35ea6ccd7cc6a1e19916b5dc64d6ac216b5544d677"
|
sha256: b2151ce26a06171005b379ecff6e08d34c470180ffe16b8e14b6d52be292b55f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.7.0"
|
version: "4.8.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.2"
|
version: "1.18.0"
|
||||||
console:
|
console:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -262,18 +279,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: coverage
|
name: coverage
|
||||||
sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097"
|
sha256: "595a29b55ce82d53398e1bcc2cba525d7bd7c59faeb2d2540e9d42c390cfeeeb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.3"
|
version: "1.6.4"
|
||||||
cross_file:
|
cross_file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: cross_file
|
name: cross_file
|
||||||
sha256: "445db18de832dba8d851e287aff8ccf169bed30d2e94243cb54c7d2f1ed2142c"
|
sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.3+6"
|
version: "0.3.3+8"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -310,10 +327,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: device_info_plus
|
name: device_info_plus
|
||||||
sha256: "7035152271ff67b072a211152846e9f1259cf1be41e34cd3e0b5463d2d6b8419"
|
sha256: "0042cb3b2a76413ea5f8a2b40cec2a33e01d0c937e91f0f7c211fde4f7739ba6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.1.0"
|
version: "9.1.1"
|
||||||
device_info_plus_platform_interface:
|
device_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -423,14 +440,6 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
flutter_blurhash:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_blurhash
|
|
||||||
sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.7.0"
|
|
||||||
flutter_cache_manager:
|
flutter_cache_manager:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -469,10 +478,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_plugin_android_lifecycle
|
name: flutter_plugin_android_lifecycle
|
||||||
sha256: f185ac890306b5779ecbd611f52502d8d4d63d27703ef73161ca0407e815f02c
|
sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.16"
|
version: "2.0.17"
|
||||||
flutter_redux:
|
flutter_redux:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -485,10 +494,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_slidable
|
name: flutter_slidable
|
||||||
sha256: cc4231579e3eae41ae166660df717f4bad1359c87f4a4322ad8ba1befeb3d2be
|
sha256: "19ed4813003a6ff4e9c6bcce37e792a2a358919d7603b2b31ff200229191e44c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.1"
|
||||||
flutter_staggered_grid_view:
|
flutter_staggered_grid_view:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -527,10 +536,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: follow_the_leader
|
name: follow_the_leader
|
||||||
sha256: "40112c4fa8fdc9e60c3350f09e5b9c86e1205f4f8427feee15ef8da4c60c635c"
|
sha256: "71f4bfca904974a98d21558bbf7489e1262da6ac46de912791fe84cf6516b9ae"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.4+5"
|
version: "0.0.4+7"
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -580,18 +589,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_sign_in_ios
|
name: google_sign_in_ios
|
||||||
sha256: "974944859f9cd40eb8a15b3fe8efb2d47fb7e99438f763f61a1ccd28d74ff4ce"
|
sha256: "81495441405c138e3c638f5097bebaa0db644567b3976e08944cfb8926ff2e6d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.6.4"
|
version: "5.6.5"
|
||||||
google_sign_in_platform_interface:
|
google_sign_in_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_sign_in_platform_interface
|
name: google_sign_in_platform_interface
|
||||||
sha256: "35ceee5f0eadc1c07b0b4af7553246e315c901facbb7d3dadf734ba2693ceec4"
|
sha256: e10eaaa30a0cb03af12dd324fb2e630ac7e9d854d0530f7a87a4d825031f9a4a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.2"
|
version: "2.4.3"
|
||||||
google_sign_in_web:
|
google_sign_in_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -692,10 +701,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_android
|
name: image_picker_android
|
||||||
sha256: "0c7b83bbe2980c8a8e36e974f055e11e51675784e13a4762889feed0f3937ff2"
|
sha256: d6a6e78821086b0b737009b09363018309bbc6de3fd88cc5c26bc2bb44a4957f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.8+1"
|
version: "0.8.8+2"
|
||||||
image_picker_for_web:
|
image_picker_for_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -708,10 +717,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_ios
|
name: image_picker_ios
|
||||||
sha256: c5538cacefacac733c724be7484377923b476216ad1ead35a0d2eadcdc0fc497
|
sha256: "76ec722aeea419d03aa915c2c96bf5b47214b053899088c9abb4086ceecf97a7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.8+2"
|
version: "0.8.8+4"
|
||||||
image_picker_linux:
|
image_picker_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -764,10 +773,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: in_app_purchase_android
|
name: in_app_purchase_android
|
||||||
sha256: "63997b855f10799a1022939bbf02e3f59b6f400f4deee858f46fd528df5f5fab"
|
sha256: c4b84caa4e2c7ffebda444c5033fd8423cc3a45a6e1066929bbbcd4daf665db5
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.0+13"
|
version: "0.3.0+15"
|
||||||
in_app_purchase_platform_interface:
|
in_app_purchase_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -780,26 +789,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: in_app_purchase_storekit
|
name: in_app_purchase_storekit
|
||||||
sha256: "88afd256c7605d431f0ce29d0161f9554851f90ecb92ceb9e18196c4e7858d52"
|
sha256: "29526f5ce85bd908b4cacdadb2e8ef299bccbb516b90d2881805343f868502ab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.6+7"
|
version: "0.3.7"
|
||||||
in_app_review:
|
in_app_review:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: in_app_review
|
name: in_app_review
|
||||||
sha256: "16328b8202d36522322b95804ae5d975577aa9f584d634985849ba1099645850"
|
sha256: "41ec6f30427ab09eb6ae1c85c4a2a624a145fc5d726f023de4d97170ec9e5466"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.6"
|
version: "2.0.8"
|
||||||
in_app_review_platform_interface:
|
in_app_review_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: in_app_review_platform_interface
|
name: in_app_review_platform_interface
|
||||||
sha256: b12ec9aaf6b34d3a72aa95895eb252b381896246bdad4ef378d444affe8410ef
|
sha256: fed2c755f2125caa9ae10495a3c163aa7fab5af3585a9c62ef4a6920c5b45f10
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.4"
|
version: "2.0.5"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -844,10 +853,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: linkify
|
name: linkify
|
||||||
sha256: bdfbdafec6cdc9cd0ebb333a868cafc046714ad508e48be8095208c54691d959
|
sha256: "4139ea77f4651ab9c315b577da2dd108d9aa0bd84b5d03d33323f1970c645832"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "5.0.0"
|
||||||
local_auth:
|
local_auth:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -860,18 +869,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: local_auth_android
|
name: local_auth_android
|
||||||
sha256: "9ad0b1ffa6f04f4d91e38c2d4c5046583e23f4cae8345776a994e8670df57fb1"
|
sha256: df4ccb3193525b8a60c78a5ca7bf188a47705bcf77bcc837a6b2cf6da64ae0e2
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.34"
|
version: "1.0.35"
|
||||||
local_auth_ios:
|
local_auth_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: local_auth_ios
|
name: local_auth_ios
|
||||||
sha256: "26a8d1ad0b4ef6f861d29921be8383000fda952e323a5b6752cf82ca9cf9a7a9"
|
sha256: "8293faf72ef0ac4710f209edd03916c2d4c1eeab0483bdcf9b2e659c2f7d737b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.4"
|
version: "1.1.5"
|
||||||
local_auth_platform_interface:
|
local_auth_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -940,10 +949,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -964,10 +973,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: msix
|
name: msix
|
||||||
sha256: "6e76e2491d5c809d784ce2b68e6c3426097fb5c68e61fe121c8c3341ab89bf46"
|
sha256: "519b183d15dc9f9c594f247e2d2339d855cf0eaacc30e19b128e14f3ecc62047"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.16.4"
|
version: "3.16.7"
|
||||||
navigation_builder:
|
navigation_builder:
|
||||||
dependency: "direct overridden"
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
|
|
@ -988,10 +997,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: octo_image
|
name: octo_image
|
||||||
sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143"
|
sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "2.0.0"
|
||||||
overflow_view:
|
overflow_view:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1028,10 +1037,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_info_plus
|
name: package_info_plus
|
||||||
sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017"
|
sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.0"
|
version: "5.0.1"
|
||||||
package_info_plus_platform_interface:
|
package_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1068,10 +1077,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1"
|
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.1"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1108,58 +1117,66 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pdf
|
name: pdf
|
||||||
sha256: "9f75fc7f5580ea5e635b5724de58fb27f684c9ad03ed46fdc1aac768e4557315"
|
sha256: "93cbb2c06de9bab91844550f19896b2373e7a5ce25173995e7e5ec5e1741429d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.10.4"
|
version: "3.10.7"
|
||||||
permission_handler:
|
permission_handler:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: permission_handler
|
name: permission_handler
|
||||||
sha256: "284a66179cabdf942f838543e10413246f06424d960c92ba95c84439154fcac8"
|
sha256: "860c6b871c94c78e202dc69546d4d8fd84bd59faeb36f8fb9888668a53ff4f78"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.0.1"
|
version: "11.1.0"
|
||||||
permission_handler_android:
|
permission_handler_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_android
|
name: permission_handler_android
|
||||||
sha256: f9fddd3b46109bd69ff3f9efa5006d2d309b7aec0f3c1c5637a60a2d5659e76e
|
sha256: "2f1bec180ee2f5665c22faada971a8f024761f632e93ddc23310487df52dcfa6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.1.0"
|
version: "12.0.1"
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_apple
|
name: permission_handler_apple
|
||||||
sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
|
sha256: "1a816084338ada8d574b1cb48390e6e8b19305d5120fe3a37c98825bacc78306"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.1.4"
|
version: "9.2.0"
|
||||||
|
permission_handler_html:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_html
|
||||||
|
sha256: "11b762a8c123dced6461933a88ea1edbbe036078c3f9f41b08886e678e7864df"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.0+2"
|
||||||
permission_handler_platform_interface:
|
permission_handler_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_platform_interface
|
name: permission_handler_platform_interface
|
||||||
sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4"
|
sha256: d87349312f7eaf6ce0adaf668daf700ac5b06af84338bd8b8574dfbd93ffe1a1
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.12.0"
|
version: "4.0.2"
|
||||||
permission_handler_windows:
|
permission_handler_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_windows
|
name: permission_handler_windows
|
||||||
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
|
sha256: "1e8640c1e39121128da6b816d236e714d2cf17fac5a105dd6acdd3403a628004"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.3"
|
version: "0.2.0"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: petitparser
|
name: petitparser
|
||||||
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.4.0"
|
version: "6.0.2"
|
||||||
pigeon:
|
pigeon:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1188,26 +1205,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: platform
|
name: platform
|
||||||
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
|
sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.2"
|
||||||
plugin_platform_interface:
|
plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
|
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.6"
|
version: "2.1.7"
|
||||||
pointer_interceptor:
|
pointer_interceptor:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: pointer_interceptor
|
name: pointer_interceptor
|
||||||
sha256: "7626e034489820fd599380d2bb4d3f4a0a5e3529370b62bfce53ab736b91adb2"
|
sha256: adf7a637f97c077041d36801b43be08559fd4322d2127b3f20bb7be1b9eebc22
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.9.3+6"
|
version: "0.9.3+7"
|
||||||
pointycastle:
|
pointycastle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1228,10 +1245,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: printing
|
name: printing
|
||||||
sha256: e7c383dca95ee7b88c02dc1c66638628d3dcdc2fb2cc47e7a595facd47e46b56
|
sha256: ad39a42a5f83125952457dfd94f395c8cf0eb1f7759583dadb769be5c7f99d24
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.11.0"
|
version: "5.11.1"
|
||||||
process:
|
process:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1325,34 +1342,34 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sentry
|
name: sentry
|
||||||
sha256: "9cfd325611ab54b57d5e26957466823f05bea9d6cfcc8d48f11817b8bcedf0d1"
|
sha256: e7ded42974bac5f69e4ca4ddc57d30499dd79381838f24b7e8fd9aa4139e7b79
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.12.0"
|
version: "7.13.2"
|
||||||
sentry_flutter:
|
sentry_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sentry_flutter
|
name: sentry_flutter
|
||||||
sha256: "0cd7d622cb63c94fd1b2f87ab508e158b950bd281e2a80f327ebf73bb217eaf3"
|
sha256: d6f55ec7a1f681784165021f749007712a72ff57eadf91e963331b6ae326f089
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.12.0"
|
version: "7.13.2"
|
||||||
share_plus:
|
share_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: share_plus
|
name: share_plus
|
||||||
sha256: "2dafa6c1f8d8ee67b0e0587881947b78baab4671b7c08792cf91279e7ac14192"
|
sha256: f74fc3f1cbd99f39760182e176802f693fa0ec9625c045561cfad54681ea93dd
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.0"
|
version: "7.2.1"
|
||||||
share_plus_platform_interface:
|
share_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: share_plus_platform_interface
|
name: share_plus_platform_interface
|
||||||
sha256: "357412af4178d8e11d14f41723f80f12caea54cf0d5cd29af9dcdab85d58aea7"
|
sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.0"
|
version: "3.3.1"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1397,10 +1414,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_web
|
name: shared_preferences_web
|
||||||
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
|
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.2.2"
|
||||||
shared_preferences_windows:
|
shared_preferences_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1522,18 +1539,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a"
|
sha256: bb4738f15b23352822f4c42a531677e5c6f522e079461fd240ead29d8d8a54a6
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0"
|
version: "2.5.0+2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
states_rebuilder:
|
states_rebuilder:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1546,10 +1563,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
stream_transform:
|
stream_transform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1567,29 +1584,32 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
super_editor:
|
super_editor:
|
||||||
dependency: "direct main"
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: super_editor
|
path: super_editor
|
||||||
sha256: "2d5acf95449f53eec1c7d0788530b3a667758224a1e4aa4164bd5d6c0d159bab"
|
ref: stable
|
||||||
url: "https://pub.dev"
|
resolved-ref: c040c690f1dc0f7c482d8ece02622c200cb8e1b1
|
||||||
source: hosted
|
url: "https://github.com/superlistapp/super_editor"
|
||||||
|
source: git
|
||||||
version: "0.2.6"
|
version: "0.2.6"
|
||||||
super_editor_markdown:
|
super_editor_markdown:
|
||||||
dependency: "direct main"
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: super_editor_markdown
|
path: super_editor_markdown
|
||||||
sha256: "2515d0183ee21aa22d577e95e80b1e4bc1b9ce0f651127d40844be7cb58b5330"
|
ref: stable
|
||||||
url: "https://pub.dev"
|
resolved-ref: c040c690f1dc0f7c482d8ece02622c200cb8e1b1
|
||||||
source: hosted
|
url: "https://github.com/superlistapp/super_editor"
|
||||||
|
source: git
|
||||||
version: "0.1.5"
|
version: "0.1.5"
|
||||||
super_text_layout:
|
super_text_layout:
|
||||||
dependency: transitive
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: super_text_layout
|
path: super_text_layout
|
||||||
sha256: "2f2a8b36553f775c390924f079b5a8ba6c717b0885f44d80a9602bfa182b6f9f"
|
ref: stable
|
||||||
url: "https://pub.dev"
|
resolved-ref: c040c690f1dc0f7c482d8ece02622c200cb8e1b1
|
||||||
source: hosted
|
url: "https://github.com/superlistapp/super_editor"
|
||||||
version: "0.1.7"
|
source: git
|
||||||
|
version: "0.1.8"
|
||||||
sync_http:
|
sync_http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1618,34 +1638,34 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: test
|
name: test
|
||||||
sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46"
|
sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.24.3"
|
version: "1.24.9"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.6.1"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e"
|
sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.3"
|
version: "0.5.9"
|
||||||
timeago:
|
timeago:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: timeago
|
name: timeago
|
||||||
sha256: "4addcda362e51f23cf7ae2357fccd053f29d59b4ddd17fb07fc3e7febb47a456"
|
sha256: c44b80cbc6b44627c00d76960f2af571f6f50e5dbedef4d9215d455e4335165b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.5.0"
|
version: "3.6.0"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1682,66 +1702,66 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27"
|
sha256: b1c9e98774adf8820c96fbc7ae3601231d324a7d5ebd8babe27b6dfac91357ba
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.14"
|
version: "6.2.1"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330
|
sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.0"
|
version: "6.2.0"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_ios
|
name: url_launcher_ios
|
||||||
sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f"
|
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.5"
|
version: "6.2.1"
|
||||||
url_launcher_linux:
|
url_launcher_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_linux
|
name: url_launcher_linux
|
||||||
sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e
|
sha256: "9f2d390e096fdbe1e6e6256f97851e51afc2d9c423d3432f1d6a02a8a9a8b9fd"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.6"
|
version: "3.1.0"
|
||||||
url_launcher_macos:
|
url_launcher_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_macos
|
name: url_launcher_macos
|
||||||
sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88
|
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.7"
|
version: "3.1.0"
|
||||||
url_launcher_platform_interface:
|
url_launcher_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_platform_interface
|
name: url_launcher_platform_interface
|
||||||
sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618"
|
sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.5"
|
version: "2.2.0"
|
||||||
url_launcher_web:
|
url_launcher_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5"
|
sha256: "138bd45b3a456dcfafc46d1a146787424f8d2edfbf2809c9324361e58f851cf7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.20"
|
version: "2.2.1"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_windows
|
name: url_launcher_windows
|
||||||
sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069"
|
sha256: "7754a1ad30ee896b265f8d14078b0513a4dba28d358eabb9d5f339886f4a1adc"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.8"
|
version: "3.1.0"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1778,10 +1798,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f
|
sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.7.1"
|
version: "11.10.0"
|
||||||
vs_scrollbar:
|
vs_scrollbar:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1802,10 +1822,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.4-beta"
|
version: "0.3.0"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1834,34 +1854,34 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: webview_flutter
|
name: webview_flutter
|
||||||
sha256: c1ab9b81090705c6069197d9fdc1625e587b52b8d70cdde2339d177ad0dbb98e
|
sha256: "42393b4492e629aa3a88618530a4a00de8bb46e50e7b3993fedbfdc5352f0dbf"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.1"
|
version: "4.4.2"
|
||||||
webview_flutter_android:
|
webview_flutter_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_android
|
name: webview_flutter_android
|
||||||
sha256: b0cd33dd7d3dd8e5f664e11a19e17ba12c352647269921a3b568406b001f1dff
|
sha256: "8326ee235f87605a2bfc444a4abc897f4abc78d83f054ba7d3d1074ce82b4fbf"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.12.0"
|
version: "3.12.1"
|
||||||
webview_flutter_platform_interface:
|
webview_flutter_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_platform_interface
|
name: webview_flutter_platform_interface
|
||||||
sha256: "6d9213c65f1060116757a7c473247c60f3f7f332cac33dc417c9e362a9a13e4f"
|
sha256: "68e86162aa8fc646ae859e1585995c096c95fc2476881fa0c4a8d10f56013a5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.0"
|
version: "2.8.0"
|
||||||
webview_flutter_wkwebview:
|
webview_flutter_wkwebview:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_wkwebview
|
name: webview_flutter_wkwebview
|
||||||
sha256: "30b9af6bdd457b44c08748b9190d23208b5165357cc2eb57914fee1366c42974"
|
sha256: accdaaa49a2aca2dc3c3230907988954cdd23fed0a19525d6c9789d380f4dc76
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.9.1"
|
version: "3.9.4"
|
||||||
widget_kit_plugin:
|
widget_kit_plugin:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1874,10 +1894,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
|
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.9"
|
version: "5.1.1"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1906,10 +1926,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xml
|
name: xml
|
||||||
sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
|
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.0"
|
version: "6.5.0"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1919,5 +1939,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.1.0 <4.0.0"
|
dart: ">=3.2.0 <4.0.0"
|
||||||
flutter: ">=3.13.0"
|
flutter: ">=3.16.0"
|
||||||
|
|
|
||||||
32
pubspec.yaml
32
pubspec.yaml
|
|
@ -39,7 +39,8 @@ dependencies:
|
||||||
built_value: ^8.1.2
|
built_value: ^8.1.2
|
||||||
built_collection: ^5.1.0
|
built_collection: ^5.1.0
|
||||||
memoize: ^3.0.0
|
memoize: ^3.0.0
|
||||||
cached_network_image: 3.0.0 # imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
|
#cached_network_image: 3.0.0 # imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
|
||||||
|
cached_network_image: ^3.3.0
|
||||||
url_launcher: ^6.0.20
|
url_launcher: ^6.0.20
|
||||||
share_plus: ^7.1.0
|
share_plus: ^7.1.0
|
||||||
intl: 0.17.0
|
intl: 0.17.0
|
||||||
|
|
@ -72,13 +73,14 @@ dependencies:
|
||||||
contacts_service: ^0.6.3
|
contacts_service: ^0.6.3
|
||||||
diacritic: ^0.1.3
|
diacritic: ^0.1.3
|
||||||
states_rebuilder: ^6.2.0
|
states_rebuilder: ^6.2.0
|
||||||
super_editor: ^0.2.6
|
#super_editor: ^0.2.6
|
||||||
super_editor_markdown: ^0.1.5
|
#super_editor_markdown: ^0.1.5
|
||||||
#markdown: ^5.0.0 # REMOVE THIS
|
#markdown: ^5.0.0 # REMOVE THIS
|
||||||
#super_editor:
|
#super_editor_markdown:
|
||||||
# git:
|
# git:
|
||||||
# url: https://github.com/superlistapp/super_editor.git
|
# url: https://github.com/superlistapp/super_editor.git
|
||||||
# path: super_editor
|
# path: super_editor_markdown
|
||||||
|
# ref: stable
|
||||||
html2md: ^1.2.6
|
html2md: ^1.2.6
|
||||||
printing: ^5.11.0
|
printing: ^5.11.0
|
||||||
image_cropper: ^4.0.1
|
image_cropper: ^4.0.1
|
||||||
|
|
@ -101,6 +103,26 @@ dependency_overrides:
|
||||||
intl: any
|
intl: any
|
||||||
navigation_builder: ^0.0.3
|
navigation_builder: ^0.0.3
|
||||||
states_rebuilder: ^6.3.0
|
states_rebuilder: ^6.3.0
|
||||||
|
super_editor:
|
||||||
|
git:
|
||||||
|
url: https://github.com/superlistapp/super_editor
|
||||||
|
path: super_editor
|
||||||
|
ref: stable
|
||||||
|
super_editor_markdown:
|
||||||
|
git:
|
||||||
|
url: https://github.com/superlistapp/super_editor
|
||||||
|
path: super_editor_markdown
|
||||||
|
ref: stable
|
||||||
|
super_text_layout:
|
||||||
|
git:
|
||||||
|
url: https://github.com/superlistapp/super_editor
|
||||||
|
path: super_text_layout
|
||||||
|
ref: stable
|
||||||
|
attributed_text:
|
||||||
|
git:
|
||||||
|
url: https://github.com/superlistapp/super_editor
|
||||||
|
path: attributed_text
|
||||||
|
ref: stable
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_driver:
|
flutter_driver:
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake)
|
||||||
# https://github.com/flutter/flutter/issues/57146.
|
# https://github.com/flutter/flutter/issues/57146.
|
||||||
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
|
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
|
||||||
|
|
||||||
|
# Set fallback configurations for older versions of the flutter tool.
|
||||||
|
if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
|
||||||
|
set(FLUTTER_TARGET_PLATFORM "windows-x64")
|
||||||
|
endif()
|
||||||
|
|
||||||
# === Flutter Library ===
|
# === Flutter Library ===
|
||||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
|
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
|
||||||
|
|
||||||
|
|
@ -92,7 +97,7 @@ add_custom_command(
|
||||||
COMMAND ${CMAKE_COMMAND} -E env
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
${FLUTTER_TOOL_ENVIRONMENT}
|
${FLUTTER_TOOL_ENVIRONMENT}
|
||||||
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
|
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
|
||||||
windows-x64 $<CONFIG>
|
${FLUTTER_TARGET_PLATFORM} $<CONFIG>
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
add_custom_target(flutter_assemble DEPENDS
|
add_custom_target(flutter_assemble DEPENDS
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue