Skip to content

Commit 02b7149

Browse files
authored
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
1 parent 37547a6 commit 02b7149

File tree

12 files changed

+149
-108
lines changed

12 files changed

+149
-108
lines changed

frontend/appflowy_flutter/assets/translations/en.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@
196196
"restartApp": "Please restart app for the changes to take effect.",
197197
"exportDatabase": "Export database",
198198
"selectFiles": "Select the files that need to be export",
199+
"selectAll": "Select all",
200+
"deselectAll": "Deselect all",
199201
"createNewFolder": "Create a new folder",
200202
"createNewFolderDesc": "Tell us where you want to store your data",
201203
"defineWhereYourDataIsStored": "Define where your data is stored",
@@ -211,12 +213,13 @@
211213
"folderPath": "Path to store your folder",
212214
"locationCannotBeEmpty": "Path cannot be empty",
213215
"pathCopiedSnackbar": "File storage path copied to clipboard!",
214-
"changeLocationTooltips": "Change the files read the data directory",
216+
"changeLocationTooltips": "Change the data directory",
215217
"change": "Change",
216-
"openLocationTooltips": "Open the files read the data directory",
217-
"recoverLocationTooltips": "Recover the files read the data directory",
218+
"openLocationTooltips": "Open another data directory",
219+
"recoverLocationTooltips": "Reset to AppFlowy's default data directory",
218220
"exportFileSuccess": "Export file successfully!",
219-
"exportFileFail": "Export file failed!"
221+
"exportFileFail": "Export file failed!",
222+
"export": "Export"
220223
},
221224
"user": {
222225
"name": "Name",

frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/url_cell/url_cell.dart

Lines changed: 57 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
1010
import 'package:flutter/material.dart';
1111
import 'package:flutter/services.dart';
1212
import 'package:flutter_bloc/flutter_bloc.dart';
13-
import 'package:url_launcher/url_launcher.dart';
13+
import 'package:url_launcher/url_launcher_string.dart';
1414
import '../../../../grid/presentation/layout/sizes.dart';
1515
import '../../accessory/cell_accessory.dart';
1616
import '../../cell_builder.dart';
@@ -36,20 +36,21 @@ enum GridURLCellAccessoryType {
3636
}
3737

3838
class 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

200190
class _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

213203
class _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

251235
class _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

279269
class _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
}

frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,32 +57,34 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
5757

5858
late final Map<String, BlockComponentBuilder> blockComponentBuilders =
5959
_customAppFlowyBlockComponentBuilders();
60-
late final List<CharacterShortcutEvent> characterShortcutEvents = [
61-
// code block
62-
...codeBlockCharacterEvents,
60+
List<CharacterShortcutEvent> get characterShortcutEvents => [
61+
// code block
62+
...codeBlockCharacterEvents,
6363

64-
// toggle list
65-
// formatGreaterToToggleList,
64+
// toggle list
65+
// formatGreaterToToggleList,
6666

67-
// customize the slash menu command
68-
customSlashCommand(
69-
slashMenuItems,
70-
style: styleCustomizer.selectionMenuStyleBuilder(),
71-
),
67+
// customize the slash menu command
68+
customSlashCommand(
69+
slashMenuItems,
70+
style: styleCustomizer.selectionMenuStyleBuilder(),
71+
),
7272

73-
...standardCharacterShortcutEvents
74-
..removeWhere(
75-
(element) => element == slashCommand,
76-
), // remove the default slash command.
77-
];
73+
...standardCharacterShortcutEvents
74+
..removeWhere(
75+
(element) => element == slashCommand,
76+
), // remove the default slash command.
77+
];
7878

7979
late final showSlashMenu = customSlashCommand(
8080
slashMenuItems,
8181
shouldInsertSlash: false,
8282
style: styleCustomizer.selectionMenuStyleBuilder(),
8383
).handler;
8484

85-
late final styleCustomizer = EditorStyleCustomizer(context: context);
85+
EditorStyleCustomizer get styleCustomizer => EditorStyleCustomizer(
86+
context: context,
87+
);
8688
DocumentBloc get documentBloc => context.read<DocumentBloc>();
8789

8890
@override

frontend/appflowy_flutter/lib/plugins/document/presentation/editor_style.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class EditorStyleCustomizer {
140140
FloatingToolbarStyle floatingToolbarStyleBuilder() {
141141
final theme = Theme.of(context);
142142
return FloatingToolbarStyle(
143-
backgroundColor: theme.cardColor,
143+
backgroundColor: theme.colorScheme.onTertiary,
144144
);
145145
}
146146
}

frontend/appflowy_flutter/lib/user/presentation/folder/folder_widget.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,13 @@ Widget _buildTextButton(
218218
String title,
219219
VoidCallback onPressed,
220220
) {
221-
return SecondaryTextButton(
222-
title,
223-
mode: SecondaryTextButtonMode.small,
224-
onPressed: onPressed,
221+
return SizedBox(
222+
width: 60,
223+
child: SecondaryTextButton(
224+
title,
225+
mode: SecondaryTextButtonMode.small,
226+
onPressed: onPressed,
227+
),
225228
);
226229
}
227230

frontend/appflowy_flutter/lib/user/presentation/skip_log_in_screen.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
5353
mainAxisAlignment: MainAxisAlignment.center,
5454
crossAxisAlignment: CrossAxisAlignment.center,
5555
children: [
56+
const Spacer(),
5657
FlowyLogoTitle(
5758
title: LocaleKeys.welcomeText.tr(),
5859
logoSize: const Size.square(40),
@@ -68,8 +69,6 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
6869
},
6970
),
7071
const VSpace(32),
71-
_buildSubscribeButtons(context),
72-
const VSpace(32),
7372
SizedBox(
7473
width: MediaQuery.of(context).size.width * 0.5,
7574
child: FolderWidget(
@@ -78,7 +77,10 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
7877
},
7978
),
8079
),
81-
const VSpace(64),
80+
const Spacer(),
81+
const VSpace(48),
82+
_buildSubscribeButtons(context),
83+
const VSpace(24),
8284
],
8385
);
8486
}
@@ -182,6 +184,7 @@ class GoButton extends StatelessWidget {
182184
maxWidth: 340,
183185
maxHeight: 48,
184186
),
187+
radius: BorderRadius.circular(12),
185188
mainAxisAlignment: MainAxisAlignment.center,
186189
fontSize: FontSizes.s14,
187190
fontFamily: GoogleFonts.poppins(fontWeight: FontWeight.w500).fontFamily,

0 commit comments

Comments
 (0)