123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 |
- // Copyright (c) 2018, the Zefyr project authors. Please see the AUTHORS file
- // for details. All rights reserved. Use of this source code is governed by a
- // BSD-style license that can be found in the LICENSE file.
- import 'dart:io';
- import 'dart:typed_data';
-
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:notus/notus.dart';
- import 'package:photo_manager/photo_manager.dart';
- import 'package:url_launcher/url_launcher.dart';
- import 'package:zefyr/src/widgets/gallery_item.dart';
-
- import 'scope.dart';
- import 'theme.dart';
- import 'toolbar.dart';
-
- /// A button used in [ZefyrToolbar].
- ///
- /// Create an instance of this widget with [ZefyrButton.icon] or
- /// [ZefyrButton.text] constructors.
- ///
- /// Toolbar buttons are normally created by a [ZefyrToolbarDelegate].
- class ZefyrButton extends StatelessWidget {
- /// Creates a toolbar button with an icon.
- ZefyrButton.icon({
- @required this.action,
- @required IconData icon,
- double iconSize,
- this.onPressed,
- }) : assert(action != null),
- assert(icon != null),
- _icon = icon,
- _iconSize = iconSize,
- _text = null,
- _textStyle = null,
- super();
-
- /// Creates a toolbar button containing text.
- ///
- /// Note that [ZefyrButton] has fixed width and does not expand to accommodate
- /// long texts.
- ZefyrButton.text({
- @required this.action,
- @required String text,
- TextStyle style,
- this.onPressed,
- }) : assert(action != null),
- assert(text != null),
- _icon = null,
- _iconSize = null,
- _text = text,
- _textStyle = style,
- super();
-
- /// Toolbar action associated with this button.
- final ZefyrToolbarAction action;
- final IconData _icon;
- final double _iconSize;
- final String _text;
- final TextStyle _textStyle;
-
- /// Callback to trigger when this button is tapped.
- final VoidCallback onPressed;
-
- bool get isAttributeAction {
- return kZefyrToolbarAttributeActions.keys.contains(action);
- }
-
- @override
- Widget build(BuildContext context) {
- final toolbar = ZefyrToolbar.of(context);
- final editor = toolbar.editor;
- final toolbarTheme = ZefyrTheme.of(context).toolbarTheme;
- final pressedHandler = _getPressedHandler(editor, toolbar);
- final iconColor = (pressedHandler == null)
- ? toolbarTheme.disabledIconColor
- : toolbarTheme.iconColor;
- if (_icon != null) {
- return RawZefyrButton.icon(
- action: action,
- icon: _icon,
- size: _iconSize,
- iconColor: _getColor(editor, toolbarTheme),
- color: _getFillColor(action, toolbarTheme),
- onPressed: _getPressedHandler(editor, toolbar),
- );
- } else {
- assert(_text != null);
- var style = _textStyle ?? TextStyle();
- style = style.copyWith(color: _getColor(editor, toolbarTheme),);
- return RawZefyrButton(
- action: action,
- child: Text(_text, style: style),
- color: _getFillColor(action, toolbarTheme),
- onPressed: _getPressedHandler(editor, toolbar),
- );
- }
- }
-
- Color _getColor(ZefyrScope editor, ToolbarTheme theme) {
- if (isAttributeAction) {
- final attribute = kZefyrToolbarAttributeActions[action];
- final isToggled = (attribute is NotusAttribute)
- ? editor.selectionStyle.containsSame(attribute)
- : editor.selectionStyle.contains(attribute);
- return isToggled ? theme.toggleColor : null;
- }
- return null;
- }
-
- Color _getFillColor(ZefyrToolbarAction action, ToolbarTheme theme) {
- if (action == ZefyrToolbarAction.text || action == ZefyrToolbarAction.heading || action == ZefyrToolbarAction.hideKeyboard || action == ZefyrToolbarAction.emoji || action == ZefyrToolbarAction.image || action == ZefyrToolbarAction.link) {
- return theme.color;
- }
- return theme.iconFillColor;
- }
-
- VoidCallback _getPressedHandler(
- ZefyrScope editor, ZefyrToolbarState toolbar) {
- if (onPressed != null) {
- return onPressed;
- } else if (isAttributeAction) {
- final attribute = kZefyrToolbarAttributeActions[action];
- if (attribute is NotusAttribute) {
- return () => _toggleAttribute(attribute, editor);
- }
- } else if (action == ZefyrToolbarAction.close) {
- return () => toolbar.closeOverlay();
- } else if (action == ZefyrToolbarAction.hideKeyboard) {
- return () => editor.hideKeyboard();
- }
-
- return null;
- }
-
- void _toggleAttribute(NotusAttribute attribute, ZefyrScope editor) {
- final isToggled = editor.selectionStyle.containsSame(attribute);
- if (isToggled) {
- editor.formatSelection(attribute.unset);
- } else {
- editor.formatSelection(attribute);
- }
- }
- }
-
- /// Raw button widget used by [ZefyrToolbar].
- ///
- /// See also:
- ///
- /// * [ZefyrButton], which wraps this widget and implements most of the
- /// action-specific logic.
- class RawZefyrButton extends StatelessWidget {
- const RawZefyrButton({
- Key key,
- @required this.action,
- @required this.child,
- @required this.color,
- @required this.onPressed,
- }) : super(key: key);
-
- /// Creates a [RawZefyrButton] containing an icon.
- RawZefyrButton.icon({
- @required this.action,
- @required IconData icon,
- double size,
- Color iconColor,
- @required this.color,
- @required this.onPressed,
- }) : child = Icon(icon, size: size, color: iconColor),
- super();
-
- /// Toolbar action associated with this button.
- final ZefyrToolbarAction action;
-
- /// Child widget to show inside this button. Usually an icon.
- final Widget child;
-
- /// Background color of this button.
- final Color color;
-
- /// Callback to trigger when this button is pressed.
- final VoidCallback onPressed;
-
- /// Returns `true` if this button is currently toggled on.
- bool get isToggled => color != null;
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
- final constraints = theme.buttonTheme.constraints.copyWith(
- minWidth: 64, minHeight: 40, maxHeight: 40,
- );
- var radius = BorderRadius.all(Radius.circular(0));
- if (action == ZefyrToolbarAction.headingLevel1 || action == ZefyrToolbarAction.bold || action == ZefyrToolbarAction.numberList) {
- radius = BorderRadius.horizontal(left: Radius.circular(4));
- }
- if (action == ZefyrToolbarAction.headingLevel6 || action == ZefyrToolbarAction.deleteline || action == ZefyrToolbarAction.bulletList) {
- radius = BorderRadius.horizontal(left: Radius.circular(4));
- }
- if (action == ZefyrToolbarAction.quote || action == ZefyrToolbarAction.horizontalRule || action == ZefyrToolbarAction.code) {
- radius = BorderRadius.all(Radius.circular(4));
- }
- return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 1.0, vertical: 6.0).copyWith(
- left: action == ZefyrToolbarAction.code || action == ZefyrToolbarAction.quote ? 12.0 : 1.0,
- ),
- child: RawMaterialButton(
- shape: RoundedRectangleBorder(borderRadius: radius),
- elevation: 0.0,
- fillColor: color,
- constraints: constraints,
- onPressed: onPressed,
- child: child,
- ),
- );
- }
- }
-
- /// Controls heading styles.
- ///
- /// When pressed, this button displays overlay toolbar with three
- /// buttons for each heading level.
- class HeadingButton extends StatefulWidget {
- const HeadingButton({Key key}) : super(key: key);
-
- @override
- _HeadingButtonState createState() => _HeadingButtonState();
- }
-
- class _HeadingButtonState extends State<HeadingButton> {
- @override
- Widget build(BuildContext context) {
- final toolbar = ZefyrToolbar.of(context);
- return toolbar.buildButton(
- context,
- ZefyrToolbarAction.heading,
- onPressed: showOverlay,
- );
- }
-
- void showOverlay() {
- final toolbar = ZefyrToolbar.of(context);
- toolbar.showOverlay(buildOverlay);
- }
-
- Widget _buildButtonsView(List<Widget> buttons) {
- return Container(
- height: 52,
- child: ListView(
- scrollDirection: Axis.horizontal,
- children: buttons,
- physics: ClampingScrollPhysics(),
- ),
- );
- }
-
- Widget buildOverlay(BuildContext context) {
- final theme = ZefyrTheme.of(context).toolbarTheme;
- final toolbar = ZefyrToolbar.of(context);
- final headingButtons = <Widget>[
- toolbar.buildButton(context, ZefyrToolbarAction.headingLevel1),
- toolbar.buildButton(context, ZefyrToolbarAction.headingLevel2),
- toolbar.buildButton(context, ZefyrToolbarAction.headingLevel3),
- toolbar.buildButton(context, ZefyrToolbarAction.headingLevel4),
- toolbar.buildButton(context, ZefyrToolbarAction.headingLevel5),
- toolbar.buildButton(context, ZefyrToolbarAction.headingLevel6),
- ];
- final textButtons = <Widget>[
- toolbar.buildButton(context, ZefyrToolbarAction.bold),
- toolbar.buildButton(context, ZefyrToolbarAction.italic),
- toolbar.buildButton(context, ZefyrToolbarAction.underline),
- toolbar.buildButton(context, ZefyrToolbarAction.deleteline),
- toolbar.buildButton(context, ZefyrToolbarAction.quote),
- ];
- final listButtons = <Widget>[
- toolbar.buildButton(context, ZefyrToolbarAction.numberList),
- toolbar.buildButton(context, ZefyrToolbarAction.bulletList),
- ];
- final otherButtons = <Widget>[
- toolbar.buildButton(context, ZefyrToolbarAction.horizontalRule),
- toolbar.buildButton(context, ZefyrToolbarAction.code),
- ];
- return Material(
- color: theme.color,
- child: Container(
- decoration: BoxDecoration(
- border: Border(
- top: BorderSide(color: theme.dividerColor, width: 1)
- ),
- ),
- child: Column(
- children: [
- Container(
- padding: EdgeInsets.symmetric(vertical: 10, horizontal: 15),
- child: Column(
- children: [
- _buildButtonsView(headingButtons),
- _buildButtonsView(textButtons),
- _buildButtonsView(listButtons),
- _buildButtonsView(otherButtons),
- ],
- ),
- ),
- Container(
- decoration: BoxDecoration(
- border: Border(
- top: BorderSide(color: theme.dividerColor, width: 1)
- ),
- ),
- padding: EdgeInsets.symmetric(vertical: 16),
- margin: EdgeInsets.symmetric(horizontal: 16),
- child: Row(
- children: <Widget>[
- Padding(
- padding: EdgeInsets.only(right: 12),
- child: Text('文字色', style: Theme.of(context).textTheme.caption.copyWith(
- color: Theme.of(context).colorScheme.onSurface,
- fontSize: 14,
- fontWeight: FontWeight.w500,
- ),),
- ),
- Expanded(
- child: Container(
- height: 20,
- child: ListView(
- scrollDirection: Axis.horizontal,
- children: [
- Container(
- padding: EdgeInsets.all(1),
- decoration: ShapeDecoration(
- shape: CircleBorder(
- side: BorderSide(width: 1, color: theme.toggleColor),
- ),
- ),
- margin: EdgeInsets.symmetric(horizontal: 8),
- child: Container(
- width: 16,
- height: 16,
- decoration: ShapeDecoration(
- color: Color(0xFFE02020),
- shape: CircleBorder(),
- ),
- ),
- ),
- Container(
- padding: EdgeInsets.all(1),
- decoration: ShapeDecoration(
- shape: CircleBorder(
- side: BorderSide.none,
- ),
- ),
- margin: EdgeInsets.symmetric(horizontal: 8),
- child: Container(
- width: 16,
- height: 16,
- decoration: ShapeDecoration(
- color: Color(0xFFFA6400),
- shape: CircleBorder(),
- ),
- ),
- ),
- Container(
- padding: EdgeInsets.all(1),
- decoration: ShapeDecoration(
- shape: CircleBorder(
- side: BorderSide.none,
- ),
- ),
- margin: EdgeInsets.symmetric(horizontal: 8),
- child: Container(
- width: 16,
- height: 16,
- decoration: ShapeDecoration(
- color: Color(0xFF0091FF),
- shape: CircleBorder(),
- ),
- ),
- ),
- ],
- physics: ClampingScrollPhysics(),
- ),
- ),
- ),
- ],
- ),
- ),
- ],
- ),
- ),
- );
- // ZefyrToolbarScaffold(body: Container(
- // height: 200,
- // child: buttons,
- // ));
- }
- }
-
- // TODO(lucky1213): image预览这个无效
- extension AssetEntityExtension on AssetEntity {
- static String idd;
- static Uint8List _cacheThumbData;
-
- Future<Uint8List> getThumbData() async {
- print((idd ?? '') != id);
- print(id);
- if ((idd ?? '') != id) {
- idd = id;
- _cacheThumbData = await thumbData;
- return thumbData;
- } else {
- print(idd);
- return _cacheThumbData;
- }
- if (_cacheThumbData == null) {
- _cacheThumbData = await thumbData;
- return thumbData;
- } else {
- return _cacheThumbData;
- }
- }
- }
-
- /// Controls image attribute.
- ///
- /// When pressed, this button displays overlay toolbar with three
- /// buttons for each heading level.
- class ImageButton extends StatefulWidget {
- const ImageButton({Key key}) : super(key: key);
-
- @override
- _ImageButtonState createState() => _ImageButtonState();
- }
-
- class _ImageButtonState extends State<ImageButton> {
- List<AssetEntity> assetList = [];
- @override
- Widget build(BuildContext context) {
- final toolbar = ZefyrToolbar.of(context);
- return toolbar.buildButton(
- context,
- ZefyrToolbarAction.image,
- onPressed: showOverlay,
- );
- }
-
- Future<void> showOverlay() async {
- final toolbar = ZefyrToolbar.of(context);
- if (Platform.isIOS || Platform.isAndroid) {
- var result = await PhotoManager.requestPermission();
- if (result) {
- var list = await PhotoManager.getAssetPathList(onlyAll: true, type: RequestType.image);
- assetList = await list[0].assetList;
- return toolbar.showOverlay(buildOverlay);
- } else {
- PhotoManager.openSetting();
- }
- } else {
- print('打开file');
- }
- }
-
- Widget buildOverlay(BuildContext context) {
- final theme = ZefyrTheme.of(context).toolbarTheme;
- final toolbar = ZefyrToolbar.of(context);
- final buttons = Row(
- children: <Widget>[
- SizedBox(width: 8.0),
- toolbar.buildButton(context, ZefyrToolbarAction.cameraImage,
- onPressed: _pickFromCamera),
- toolbar.buildButton(context, ZefyrToolbarAction.galleryImage,
- onPressed: _pickFromGallery),
- ],
- );
- return Material(
- color: theme.color,
- child: Container(
- height: 260,
- child: Column(
- children: <Widget>[
- Expanded(
- child: Container(
- decoration: BoxDecoration(
- border: Border(
- top: BorderSide(color: theme.dividerColor, width: 1),
- bottom: BorderSide(color: theme.dividerColor, width: 1),
- ),
- ),
- child: Row(
- children: [
- Container(
- width: 58,
- child: Column(
- children: [
- Expanded(
- child: FlatButton(
- shape: RoundedRectangleBorder(),
- color: Color(0xFFF6F6F6),
- onPressed: () {
-
- },
- child: Container(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Icon(kDefaultButtonIcons[ZefyrToolbarAction.cameraImage], size: 24, color: Color(0xFFBFBFBF),),
- Padding(
- padding: EdgeInsets.only(top: 6),
- child: Text('拍照', style: TextStyle(
- fontSize: 12,
- color: Color(0xFF8C8C8C),
- ),),
- )
- ],
- ),
- )
- ),
- ),
- Expanded(
- child: FlatButton(
- shape: RoundedRectangleBorder(),
- color: Color(0xFFF6F6F6),
- onPressed: () {
-
- },
- child: Container(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Icon(kDefaultButtonIcons[ZefyrToolbarAction.galleryImage], size: 24, color: Color(0xFFBFBFBF),),
- Padding(
- padding: EdgeInsets.only(top: 6),
- child: Text('相册', style: TextStyle(
- fontSize: 12,
- color: Color(0xFF8C8C8C),
- ),),
- )
- ],
- ),
- )
- ),
- ),
- ],
- ),
- ),
- Expanded(
- child: ListView.builder(
- key: ValueKey(assetList.length),
- scrollDirection: Axis.horizontal,
- physics: ClampingScrollPhysics(),
- itemCount: assetList.length,
- itemExtent: 122,
- itemBuilder: (context, index) {
- return GalleryItem(key: ObjectKey(assetList[index].id), asset: assetList[index],);
- },
- ),
- ),
- ],
- ),
- ),
- ),
- Container(
- height: 50,
- color: theme.color,
- padding: EdgeInsets.symmetric(horizontal: 20),
- child: Row(
- children: [
- Expanded(
- child: Row(
- children: [
- SizedBox(
- width: 16,
- height: 16,
- child: Radio<bool>(
- value: false,
- groupValue: false,
- onChanged: (bool result) {
-
- },
- ),
- ),
- Padding(
- padding: EdgeInsets.symmetric(horizontal: 8),
- child: Text('原图', style: TextStyle(
- color: theme.iconColor,
- fontSize: 16
- ),),
- ),
- ],
- ),
- ),
- FlatButton(
- padding: EdgeInsets.zero,
- color: theme.toggleColor,
- shape: StadiumBorder(),
- onPressed: () {
-
- },
- child: Container(
- height: 30,
- alignment: Alignment.center,
- padding: EdgeInsets.symmetric(horizontal: 20),
- child: Text('上传 (2)', style: TextStyle(
- color: Colors.white,
- fontSize: 14,
- ),),
- ),
- ),
- ],
- ),
- )
- ],
- ),
- ),
- );
- }
-
- void _pickFromCamera() async {
- final editor = ZefyrToolbar.of(context).editor;
- final image =
- await editor.imageDelegate.pickImage(editor.imageDelegate.cameraSource);
- if (image != null) {
- editor.formatSelection(NotusAttribute.embed.image(image));
- }
- }
-
- void _pickFromGallery() async {
- final editor = ZefyrToolbar.of(context).editor;
- final image = await editor.imageDelegate
- .pickImage(editor.imageDelegate.gallerySource);
- if (image != null) {
- editor.formatSelection(NotusAttribute.embed.image(image));
- }
- }
- }
-
- class LinkButton extends StatefulWidget {
- const LinkButton({Key key}) : super(key: key);
-
- @override
- _LinkButtonState createState() => _LinkButtonState();
- }
-
- class _LinkButtonState extends State<LinkButton> {
- final TextEditingController _inputController = TextEditingController();
- Key _inputKey;
- bool _formatError = false;
-
- bool get isEditing => _inputKey != null;
-
- @override
- Widget build(BuildContext context) {
- final toolbar = ZefyrToolbar.of(context);
- final editor = toolbar.editor;
- final enabled =
- hasLink(editor.selectionStyle) || !editor.selection.isCollapsed;
-
- return toolbar.buildButton(
- context,
- ZefyrToolbarAction.link,
- onPressed: enabled ? showOverlay : null,
- );
- }
-
- bool hasLink(NotusStyle style) => style.contains(NotusAttribute.link);
-
- String getLink([String defaultValue]) {
- final editor = ZefyrToolbar.of(context).editor;
- final attrs = editor.selectionStyle;
- if (hasLink(attrs)) {
- return attrs.value(NotusAttribute.link);
- }
- return defaultValue;
- }
-
- void showOverlay() {
- final toolbar = ZefyrToolbar.of(context);
- toolbar.showOverlay(buildOverlay).whenComplete(cancelEdit);
- }
-
- void closeOverlay() {
- final toolbar = ZefyrToolbar.of(context);
- toolbar.closeOverlay();
- }
-
- void edit() {
- final toolbar = ZefyrToolbar.of(context);
- setState(() {
- _inputKey = UniqueKey();
- _inputController.text = getLink('https://');
- _inputController.addListener(_handleInputChange);
- toolbar.markNeedsRebuild();
- });
- }
-
- void doneEdit() {
- final toolbar = ZefyrToolbar.of(context);
- setState(() {
- var error = false;
- if (_inputController.text.isNotEmpty) {
- try {
- var uri = Uri.parse(_inputController.text);
- if ((uri.isScheme('https') || uri.isScheme('http')) &&
- uri.host.isNotEmpty) {
- toolbar.editor.formatSelection(
- NotusAttribute.link.fromString(_inputController.text));
- } else {
- error = true;
- }
- } on FormatException {
- error = true;
- }
- }
- if (error) {
- _formatError = error;
- toolbar.markNeedsRebuild();
- } else {
- _inputKey = null;
- _inputController.text = '';
- _inputController.removeListener(_handleInputChange);
- toolbar.markNeedsRebuild();
- toolbar.editor.focus();
- }
- });
- }
-
- void cancelEdit() {
- if (mounted) {
- final editor = ZefyrToolbar.of(context).editor;
- setState(() {
- _inputKey = null;
- _inputController.text = '';
- _inputController.removeListener(_handleInputChange);
- editor.focus();
- });
- }
- }
-
- void unlink() {
- final editor = ZefyrToolbar.of(context).editor;
- editor.formatSelection(NotusAttribute.link.unset);
- closeOverlay();
- }
-
- void copyToClipboard() {
- var link = getLink();
- assert(link != null);
- Clipboard.setData(ClipboardData(text: link));
- }
-
- void openInBrowser() async {
- final editor = ZefyrToolbar.of(context).editor;
- var link = getLink();
- assert(link != null);
- if (await canLaunch(link)) {
- editor.hideKeyboard();
- await launch(link, forceWebView: true);
- }
- }
-
- void _handleInputChange() {
- final toolbar = ZefyrToolbar.of(context);
- setState(() {
- _formatError = false;
- toolbar.markNeedsRebuild();
- });
- }
-
- Widget buildOverlay(BuildContext context) {
- final toolbar = ZefyrToolbar.of(context);
- final style = toolbar.editor.selectionStyle;
-
- String value = 'Tap to edit link';
- if (style.contains(NotusAttribute.link)) {
- value = style.value(NotusAttribute.link);
- }
- final clipboardEnabled = value != 'Tap to edit link';
- final body = !isEditing
- ? _LinkView(value: value, onTap: edit)
- : _LinkInput(
- key: _inputKey,
- controller: _inputController,
- formatError: _formatError,
- );
- final items = <Widget>[Expanded(child: body)];
- if (!isEditing) {
- final unlinkHandler = hasLink(style) ? unlink : null;
- final copyHandler = clipboardEnabled ? copyToClipboard : null;
- final openHandler = hasLink(style) ? openInBrowser : null;
- final buttons = <Widget>[
- toolbar.buildButton(context, ZefyrToolbarAction.unlink,
- onPressed: unlinkHandler),
- toolbar.buildButton(context, ZefyrToolbarAction.clipboardCopy,
- onPressed: copyHandler),
- toolbar.buildButton(
- context,
- ZefyrToolbarAction.openInBrowser,
- onPressed: openHandler,
- ),
- ];
- items.addAll(buttons);
- }
- final trailingPressed = isEditing ? doneEdit : closeOverlay;
- final trailingAction =
- isEditing ? ZefyrToolbarAction.confirm : ZefyrToolbarAction.close;
-
- return ZefyrToolbarScaffold(
- body: Row(children: items),
- trailing: toolbar.buildButton(
- context,
- trailingAction,
- onPressed: trailingPressed,
- ),
- );
- }
- }
-
- class _LinkInput extends StatefulWidget {
- final TextEditingController controller;
- final bool formatError;
-
- const _LinkInput(
- {Key key, @required this.controller, this.formatError = false})
- : super(key: key);
-
- @override
- _LinkInputState createState() {
- return _LinkInputState();
- }
- }
-
- class _LinkInputState extends State<_LinkInput> {
- final FocusNode _focusNode = FocusNode();
-
- ZefyrScope _editor;
- bool _didAutoFocus = false;
-
- @override
- void didChangeDependencies() {
- super.didChangeDependencies();
- if (!_didAutoFocus) {
- FocusScope.of(context).requestFocus(_focusNode);
- _didAutoFocus = true;
- }
-
- final toolbar = ZefyrToolbar.of(context);
-
- if (_editor != toolbar.editor) {
- _editor?.toolbarFocusNode = null;
- _editor = toolbar.editor;
- _editor.toolbarFocusNode = _focusNode;
- }
- }
-
- @override
- void dispose() {
- _editor?.toolbarFocusNode = null;
- _focusNode.dispose();
- _editor = null;
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
- final toolbarTheme = ZefyrTheme.of(context).toolbarTheme;
- final color =
- widget.formatError ? Colors.redAccent : toolbarTheme.iconColor;
- final style = theme.textTheme.subhead.copyWith(color: color);
- return TextField(
- style: style,
- keyboardType: TextInputType.url,
- focusNode: _focusNode,
- controller: widget.controller,
- autofocus: true,
- decoration: InputDecoration(
- hintText: 'https://',
- filled: true,
- fillColor: toolbarTheme.color,
- border: InputBorder.none,
- contentPadding: const EdgeInsets.all(10.0),
- ),
- );
- }
- }
-
- class _LinkView extends StatelessWidget {
- const _LinkView({Key key, @required this.value, this.onTap})
- : super(key: key);
- final String value;
- final VoidCallback onTap;
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
- final toolbarTheme = ZefyrTheme.of(context).toolbarTheme;
- Widget widget = ClipRect(
- child: ListView(
- scrollDirection: Axis.horizontal,
- children: <Widget>[
- Container(
- alignment: AlignmentDirectional.centerStart,
- constraints: BoxConstraints(minHeight: ZefyrToolbar.kToolbarHeight),
- padding: const EdgeInsets.all(10.0),
- child: Text(
- value,
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- style: theme.textTheme.subhead
- .copyWith(color: toolbarTheme.disabledIconColor),
- ),
- )
- ],
- ),
- );
- if (onTap != null) {
- widget = GestureDetector(
- child: widget,
- onTap: onTap,
- );
- }
- return widget;
- }
- }
|