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