fix: can't input url in Grid (#2737)

* fix: launch url in url cell

* fix: can't input url in Grid

* feat: support selecting or deselecting all items in export page

* fix: remove the circle shape

* fix: light mode toolbar color

* chore: update language and adjust the launch page
This commit is contained in:
Lucas.Xu
2023-06-08 15:46:33 +08:00
committed by GitHub
parent 37547a6485
commit 02b7149514
12 changed files with 149 additions and 108 deletions

View File

@ -10,7 +10,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart';
import '../../../../grid/presentation/layout/sizes.dart';
import '../../accessory/cell_accessory.dart';
import '../../cell_builder.dart';
@ -36,13 +36,11 @@ enum GridURLCellAccessoryType {
}
class GridURLCell extends GridCellWidget {
final CellControllerBuilder cellControllerBuilder;
late final GridURLCellStyle? cellStyle;
GridURLCell({
super.key,
required this.cellControllerBuilder,
GridCellStyle? style,
Key? key,
}) : super(key: key) {
}) {
if (style != null) {
cellStyle = (style as GridURLCellStyle);
} else {
@ -50,6 +48,9 @@ class GridURLCell extends GridCellWidget {
}
}
final CellControllerBuilder cellControllerBuilder;
late final GridURLCellStyle? cellStyle;
@override
GridCellState<GridURLCell> createState() => _GridURLCellState();
@ -104,28 +105,35 @@ class GridURLCell extends GridCellWidget {
};
}
class _GridURLCellState extends GridCellState<GridURLCell> {
class _GridURLCellState extends GridFocusNodeCellState<GridURLCell> {
final _popoverController = PopoverController();
late URLCellBloc _cellBloc;
late TextEditingController _controller;
late FocusNode _focusNode;
late final URLCellBloc _cellBloc;
late final TextEditingController _controller;
@override
void initState() {
super.initState();
final cellController =
widget.cellControllerBuilder.build() as URLCellController;
_cellBloc = URLCellBloc(cellController: cellController);
_cellBloc.add(const URLCellEvent.initial());
_cellBloc = URLCellBloc(cellController: cellController)
..add(const URLCellEvent.initial());
_controller = TextEditingController(text: _cellBloc.state.content);
_focusNode = FocusNode();
super.initState();
}
@override
Future<void> dispose() async {
_cellBloc.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<URLCellBloc, URLCellState>(
child: BlocConsumer<URLCellBloc, URLCellState>(
listenWhen: (previous, current) => previous.content != current.content,
listener: (context, state) => _controller.text = state.content,
builder: (context, state) {
final urlEditor = Padding(
padding: EdgeInsets.only(
@ -134,7 +142,7 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
),
child: TextField(
controller: _controller,
focusNode: _focusNode,
focusNode: focusNode,
maxLines: 1,
style: (widget.cellStyle?.textStyle ??
Theme.of(context).textTheme.bodyMedium)
@ -143,8 +151,6 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
decoration: TextDecoration.underline,
),
autofocus: false,
onEditingComplete: focusChanged,
onSubmitted: (value) => focusChanged(isUrlSubmitted: true),
decoration: InputDecoration(
contentPadding: EdgeInsets.only(
top: GridSize.cellContentInsets.top,
@ -162,24 +168,10 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
);
}
void focusChanged({
bool isUrlSubmitted = false,
}) {
if (mounted) {
if (_cellBloc.isClosed == false &&
_controller.text != _cellBloc.state.content) {
_cellBloc.add(URLCellEvent.updateURL(_controller.text));
}
if (isUrlSubmitted) {
_focusNode.unfocus();
}
}
}
@override
Future<void> dispose() async {
_cellBloc.close();
super.dispose();
Future<void> focusChanged() async {
_cellBloc.add(URLCellEvent.updateURL(_controller.text));
return super.focusChanged();
}
@override
@ -192,19 +184,17 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
String? onCopy() => _cellBloc.state.content;
@override
void onInsert(String value) {
_cellBloc.add(URLCellEvent.updateURL(value));
}
void onInsert(String value) => _cellBloc.add(URLCellEvent.updateURL(value));
}
class _EditURLAccessory extends StatefulWidget {
final CellControllerBuilder cellControllerBuilder;
final BuildContext anchorContext;
const _EditURLAccessory({
required this.cellControllerBuilder,
required this.anchorContext,
Key? key,
}) : super(key: key);
});
final CellControllerBuilder cellControllerBuilder;
final BuildContext anchorContext;
@override
State<StatefulWidget> createState() => _EditURLAccessoryState();
@ -212,20 +202,14 @@ class _EditURLAccessory extends StatefulWidget {
class _EditURLAccessoryState extends State<_EditURLAccessory>
with GridCellAccessoryState {
late PopoverController _popoverController;
@override
void initState() {
_popoverController = PopoverController();
super.initState();
}
final popoverController = PopoverController();
@override
Widget build(BuildContext context) {
return AppFlowyPopover(
margin: EdgeInsets.zero,
constraints: BoxConstraints.loose(const Size(300, 160)),
controller: _popoverController,
controller: popoverController,
direction: PopoverDirection.bottomWithLeftAligned,
offset: const Offset(0, 8),
child: svgWidget(
@ -236,7 +220,7 @@ class _EditURLAccessoryState extends State<_EditURLAccessory>
return URLEditorPopover(
cellController:
widget.cellControllerBuilder.build() as URLCellController,
onExit: () => _popoverController.close(),
onExit: () => popoverController.close(),
);
},
);
@ -244,14 +228,17 @@ class _EditURLAccessoryState extends State<_EditURLAccessory>
@override
void onTap() {
_popoverController.show();
popoverController.show();
}
}
class _CopyURLAccessory extends StatefulWidget {
const _CopyURLAccessory({
super.key,
required this.cellContext,
});
final URLCellController cellContext;
const _CopyURLAccessory({required this.cellContext, Key? key})
: super(key: key);
@override
State<StatefulWidget> createState() => _CopyURLAccessoryState();
@ -270,16 +257,22 @@ class _CopyURLAccessoryState extends State<_CopyURLAccessory>
@override
void onTap() {
final content =
widget.cellContext.getCellData(loadIfNotExist: false)?.content ?? "";
widget.cellContext.getCellData(loadIfNotExist: false)?.content;
if (content == null) {
return;
}
Clipboard.setData(ClipboardData(text: content));
showMessageToast(LocaleKeys.grid_row_copyProperty.tr());
}
}
class _VisitURLAccessory extends StatefulWidget {
const _VisitURLAccessory({
super.key,
required this.cellContext,
});
final URLCellController cellContext;
const _VisitURLAccessory({required this.cellContext, Key? key})
: super(key: key);
@override
State<StatefulWidget> createState() => _VisitURLAccessoryState();
@ -297,14 +290,14 @@ class _VisitURLAccessoryState extends State<_VisitURLAccessory>
@override
void onTap() {
var content =
widget.cellContext.getCellData(loadIfNotExist: false)?.content ?? "";
if (!content.startsWith('http://') && !content.startsWith('https://')) {
content = 'http://$content';
}
final uri = Uri.parse(content);
if (content.isNotEmpty) {
canLaunchUrl(uri).then((value) => launchUrl(uri));
final content =
widget.cellContext.getCellData(loadIfNotExist: false)?.content;
if (content == null) {
return;
}
final shouldAddScheme =
!['http', 'https'].any((pattern) => content.startsWith(pattern));
final url = shouldAddScheme ? 'http://$content' : content;
canLaunchUrlString(url).then((value) => launchUrlString(url));
}
}

View File

@ -57,24 +57,24 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
late final Map<String, BlockComponentBuilder> blockComponentBuilders =
_customAppFlowyBlockComponentBuilders();
late final List<CharacterShortcutEvent> characterShortcutEvents = [
// code block
...codeBlockCharacterEvents,
List<CharacterShortcutEvent> get characterShortcutEvents => [
// code block
...codeBlockCharacterEvents,
// toggle list
// formatGreaterToToggleList,
// toggle list
// formatGreaterToToggleList,
// customize the slash menu command
customSlashCommand(
slashMenuItems,
style: styleCustomizer.selectionMenuStyleBuilder(),
),
// customize the slash menu command
customSlashCommand(
slashMenuItems,
style: styleCustomizer.selectionMenuStyleBuilder(),
),
...standardCharacterShortcutEvents
..removeWhere(
(element) => element == slashCommand,
), // remove the default slash command.
];
...standardCharacterShortcutEvents
..removeWhere(
(element) => element == slashCommand,
), // remove the default slash command.
];
late final showSlashMenu = customSlashCommand(
slashMenuItems,
@ -82,7 +82,9 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
style: styleCustomizer.selectionMenuStyleBuilder(),
).handler;
late final styleCustomizer = EditorStyleCustomizer(context: context);
EditorStyleCustomizer get styleCustomizer => EditorStyleCustomizer(
context: context,
);
DocumentBloc get documentBloc => context.read<DocumentBloc>();
@override

View File

@ -140,7 +140,7 @@ class EditorStyleCustomizer {
FloatingToolbarStyle floatingToolbarStyleBuilder() {
final theme = Theme.of(context);
return FloatingToolbarStyle(
backgroundColor: theme.cardColor,
backgroundColor: theme.colorScheme.onTertiary,
);
}
}