@@ -10,7 +10,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
1010import 'package:flutter/material.dart' ;
1111import 'package:flutter/services.dart' ;
1212import 'package:flutter_bloc/flutter_bloc.dart' ;
13- import 'package:url_launcher/url_launcher .dart' ;
13+ import 'package:url_launcher/url_launcher_string .dart' ;
1414import '../../../../grid/presentation/layout/sizes.dart' ;
1515import '../../accessory/cell_accessory.dart' ;
1616import '../../cell_builder.dart' ;
@@ -36,20 +36,21 @@ enum GridURLCellAccessoryType {
3636}
3737
3838class GridURLCell extends GridCellWidget {
39- final CellControllerBuilder cellControllerBuilder;
40- late final GridURLCellStyle ? cellStyle;
4139 GridURLCell ({
40+ super .key,
4241 required this .cellControllerBuilder,
4342 GridCellStyle ? style,
44- Key ? key,
45- }) : super (key: key) {
43+ }) {
4644 if (style != null ) {
4745 cellStyle = (style as GridURLCellStyle );
4846 } else {
4947 cellStyle = null ;
5048 }
5149 }
5250
51+ final CellControllerBuilder cellControllerBuilder;
52+ late final GridURLCellStyle ? cellStyle;
53+
5354 @override
5455 GridCellState <GridURLCell > createState () => _GridURLCellState ();
5556
@@ -104,28 +105,35 @@ class GridURLCell extends GridCellWidget {
104105 };
105106}
106107
107- class _GridURLCellState extends GridCellState <GridURLCell > {
108+ class _GridURLCellState extends GridFocusNodeCellState <GridURLCell > {
108109 final _popoverController = PopoverController ();
109- late URLCellBloc _cellBloc;
110- late TextEditingController _controller;
111- late FocusNode _focusNode;
110+ late final URLCellBloc _cellBloc;
111+ late final TextEditingController _controller;
112112
113113 @override
114114 void initState () {
115+ super .initState ();
116+
115117 final cellController =
116118 widget.cellControllerBuilder.build () as URLCellController ;
117- _cellBloc = URLCellBloc (cellController: cellController);
118- _cellBloc .add (const URLCellEvent .initial ());
119+ _cellBloc = URLCellBloc (cellController: cellController)
120+ . .add (const URLCellEvent .initial ());
119121 _controller = TextEditingController (text: _cellBloc.state.content);
120- _focusNode = FocusNode ();
121- super .initState ();
122+ }
123+
124+ @override
125+ Future <void > dispose () async {
126+ _cellBloc.close ();
127+ super .dispose ();
122128 }
123129
124130 @override
125131 Widget build (BuildContext context) {
126132 return BlocProvider .value (
127133 value: _cellBloc,
128- child: BlocBuilder <URLCellBloc , URLCellState >(
134+ child: BlocConsumer <URLCellBloc , URLCellState >(
135+ listenWhen: (previous, current) => previous.content != current.content,
136+ listener: (context, state) => _controller.text = state.content,
129137 builder: (context, state) {
130138 final urlEditor = Padding (
131139 padding: EdgeInsets .only (
@@ -134,7 +142,7 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
134142 ),
135143 child: TextField (
136144 controller: _controller,
137- focusNode: _focusNode ,
145+ focusNode: focusNode ,
138146 maxLines: 1 ,
139147 style: (widget.cellStyle? .textStyle ??
140148 Theme .of (context).textTheme.bodyMedium)
@@ -143,8 +151,6 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
143151 decoration: TextDecoration .underline,
144152 ),
145153 autofocus: false ,
146- onEditingComplete: focusChanged,
147- onSubmitted: (value) => focusChanged (isUrlSubmitted: true ),
148154 decoration: InputDecoration (
149155 contentPadding: EdgeInsets .only (
150156 top: GridSize .cellContentInsets.top,
@@ -162,24 +168,10 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
162168 );
163169 }
164170
165- void focusChanged ({
166- bool isUrlSubmitted = false ,
167- }) {
168- if (mounted) {
169- if (_cellBloc.isClosed == false &&
170- _controller.text != _cellBloc.state.content) {
171- _cellBloc.add (URLCellEvent .updateURL (_controller.text));
172- }
173- if (isUrlSubmitted) {
174- _focusNode.unfocus ();
175- }
176- }
177- }
178-
179171 @override
180- Future <void > dispose () async {
181- _cellBloc.close ( );
182- super .dispose ();
172+ Future <void > focusChanged () async {
173+ _cellBloc.add ( URLCellEvent . updateURL (_controller.text) );
174+ return super .focusChanged ();
183175 }
184176
185177 @override
@@ -192,40 +184,32 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
192184 String ? onCopy () => _cellBloc.state.content;
193185
194186 @override
195- void onInsert (String value) {
196- _cellBloc.add (URLCellEvent .updateURL (value));
197- }
187+ void onInsert (String value) => _cellBloc.add (URLCellEvent .updateURL (value));
198188}
199189
200190class _EditURLAccessory extends StatefulWidget {
201- final CellControllerBuilder cellControllerBuilder;
202- final BuildContext anchorContext;
203191 const _EditURLAccessory ({
204192 required this .cellControllerBuilder,
205193 required this .anchorContext,
206- Key ? key,
207- }) : super (key: key);
194+ });
195+
196+ final CellControllerBuilder cellControllerBuilder;
197+ final BuildContext anchorContext;
208198
209199 @override
210200 State <StatefulWidget > createState () => _EditURLAccessoryState ();
211201}
212202
213203class _EditURLAccessoryState extends State <_EditURLAccessory >
214204 with GridCellAccessoryState {
215- late PopoverController _popoverController;
216-
217- @override
218- void initState () {
219- _popoverController = PopoverController ();
220- super .initState ();
221- }
205+ final popoverController = PopoverController ();
222206
223207 @override
224208 Widget build (BuildContext context) {
225209 return AppFlowyPopover (
226210 margin: EdgeInsets .zero,
227211 constraints: BoxConstraints .loose (const Size (300 , 160 )),
228- controller: _popoverController ,
212+ controller: popoverController ,
229213 direction: PopoverDirection .bottomWithLeftAligned,
230214 offset: const Offset (0 , 8 ),
231215 child: svgWidget (
@@ -236,22 +220,25 @@ class _EditURLAccessoryState extends State<_EditURLAccessory>
236220 return URLEditorPopover (
237221 cellController:
238222 widget.cellControllerBuilder.build () as URLCellController ,
239- onExit: () => _popoverController .close (),
223+ onExit: () => popoverController .close (),
240224 );
241225 },
242226 );
243227 }
244228
245229 @override
246230 void onTap () {
247- _popoverController .show ();
231+ popoverController .show ();
248232 }
249233}
250234
251235class _CopyURLAccessory extends StatefulWidget {
236+ const _CopyURLAccessory ({
237+ super .key,
238+ required this .cellContext,
239+ });
240+
252241 final URLCellController cellContext;
253- const _CopyURLAccessory ({required this .cellContext, Key ? key})
254- : super (key: key);
255242
256243 @override
257244 State <StatefulWidget > createState () => _CopyURLAccessoryState ();
@@ -270,16 +257,22 @@ class _CopyURLAccessoryState extends State<_CopyURLAccessory>
270257 @override
271258 void onTap () {
272259 final content =
273- widget.cellContext.getCellData (loadIfNotExist: false )? .content ?? "" ;
260+ widget.cellContext.getCellData (loadIfNotExist: false )? .content;
261+ if (content == null ) {
262+ return ;
263+ }
274264 Clipboard .setData (ClipboardData (text: content));
275265 showMessageToast (LocaleKeys .grid_row_copyProperty.tr ());
276266 }
277267}
278268
279269class _VisitURLAccessory extends StatefulWidget {
270+ const _VisitURLAccessory ({
271+ super .key,
272+ required this .cellContext,
273+ });
274+
280275 final URLCellController cellContext;
281- const _VisitURLAccessory ({required this .cellContext, Key ? key})
282- : super (key: key);
283276
284277 @override
285278 State <StatefulWidget > createState () => _VisitURLAccessoryState ();
@@ -297,14 +290,14 @@ class _VisitURLAccessoryState extends State<_VisitURLAccessory>
297290
298291 @override
299292 void onTap () {
300- var content =
301- widget.cellContext.getCellData (loadIfNotExist: false )? .content ?? "" ;
302- if (! content.startsWith ('http://' ) && ! content.startsWith ('https://' )) {
303- content = 'http://$content ' ;
304- }
305- final uri = Uri .parse (content);
306- if (content.isNotEmpty) {
307- canLaunchUrl (uri).then ((value) => launchUrl (uri));
293+ final content =
294+ widget.cellContext.getCellData (loadIfNotExist: false )? .content;
295+ if (content == null ) {
296+ return ;
308297 }
298+ final shouldAddScheme =
299+ ! ['http' , 'https' ].any ((pattern) => content.startsWith (pattern));
300+ final url = shouldAddScheme ? 'http://$content ' : content;
301+ canLaunchUrlString (url).then ((value) => launchUrlString (url));
309302 }
310303}
0 commit comments