mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: kanban UX bugs (#5227)
* chore: improve title editing behavior * chore: fix editable text field * chore: fix autoscroll
This commit is contained in:
parent
33802fa62d
commit
f3544375c9
@ -11,6 +11,8 @@ const uint8_t *sync_event(const uint8_t *input, uintptr_t len);
|
||||
|
||||
int32_t set_stream_port(int64_t port);
|
||||
|
||||
int32_t set_log_stream_port(int64_t port);
|
||||
|
||||
void link_me_please(void);
|
||||
|
||||
void rust_log(int64_t level, const char *data);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/plugins/database/board/presentation/widgets/board_column_header.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/card/container/card_container.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/card/card.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_board/appflowy_board.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -22,13 +22,15 @@ void main() {
|
||||
|
||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
|
||||
|
||||
final findFirstCard = find.descendant(
|
||||
of: find.byType(AppFlowyGroupCard),
|
||||
matching: find.byType(Text),
|
||||
);
|
||||
final firstCard = find.byType(RowCard).first;
|
||||
|
||||
Text firstCardText = tester.firstWidget(findFirstCard);
|
||||
expect(firstCardText.data, defaultFirstCardName);
|
||||
expect(
|
||||
find.descendant(
|
||||
of: firstCard,
|
||||
matching: find.text(defaultFirstCardName),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
||||
await tester.tap(
|
||||
find
|
||||
@ -45,7 +47,7 @@ void main() {
|
||||
const newCardName = 'Card 4';
|
||||
await tester.enterText(
|
||||
find.descendant(
|
||||
of: find.byType(RowCardContainer),
|
||||
of: firstCard,
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
newCardName,
|
||||
@ -55,8 +57,13 @@ void main() {
|
||||
await tester.tap(find.byType(AppFlowyBoard));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
firstCardText = tester.firstWidget(findFirstCard);
|
||||
expect(firstCardText.data, newCardName);
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(RowCard).first,
|
||||
matching: find.text(newCardName),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('from footer', (tester) async {
|
||||
@ -65,13 +72,15 @@ void main() {
|
||||
|
||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
|
||||
|
||||
final findLastCard = find.descendant(
|
||||
of: find.byType(AppFlowyGroupCard),
|
||||
matching: find.byType(Text),
|
||||
);
|
||||
final lastCard = find.byType(RowCard).last;
|
||||
|
||||
Text? lastCardText = tester.widgetList(findLastCard).last as Text;
|
||||
expect(lastCardText.data, defaultLastCardName);
|
||||
expect(
|
||||
find.descendant(
|
||||
of: lastCard,
|
||||
matching: find.text(defaultLastCardName),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
||||
await tester.tap(
|
||||
find
|
||||
@ -81,12 +90,11 @@ void main() {
|
||||
)
|
||||
.at(1),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
const newCardName = 'Card 4';
|
||||
await tester.enterText(
|
||||
find.descendant(
|
||||
of: find.byType(RowCardContainer),
|
||||
of: lastCard,
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
newCardName,
|
||||
@ -96,8 +104,13 @@ void main() {
|
||||
await tester.tap(find.byType(AppFlowyBoard));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
lastCardText = tester.widgetList(findLastCard).last as Text;
|
||||
expect(lastCardText.data, newCardName);
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(RowCard).last,
|
||||
matching: find.text(newCardName),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import 'package:appflowy/plugins/database/widgets/card/card.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/row/row_property.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:appflowy_board/appflowy_board.dart';
|
||||
|
||||
import '../../shared/util.dart';
|
||||
|
||||
@ -20,7 +20,7 @@ void main() {
|
||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
|
||||
final card1 = find.ancestor(
|
||||
of: find.text(card1Name),
|
||||
matching: find.byType(AppFlowyGroupCard),
|
||||
matching: find.byType(RowCard),
|
||||
);
|
||||
final doingGroup = find.text('Doing');
|
||||
final doingGroupCenter = tester.getCenter(doingGroup);
|
||||
|
@ -68,6 +68,8 @@ class CellController<T, D> {
|
||||
Timer? _loadDataOperation;
|
||||
Timer? _saveDataOperation;
|
||||
|
||||
Completer? _completer;
|
||||
|
||||
RowId get rowId => _cellContext.rowId;
|
||||
String get fieldId => _cellContext.fieldId;
|
||||
FieldInfo get fieldInfo => _fieldController.getField(_cellContext.fieldId)!;
|
||||
@ -192,6 +194,7 @@ class CellController<T, D> {
|
||||
_loadDataOperation?.cancel();
|
||||
if (debounce) {
|
||||
_saveDataOperation?.cancel();
|
||||
_completer = Completer();
|
||||
_saveDataOperation = Timer(const Duration(milliseconds: 300), () async {
|
||||
final result = await _cellDataPersistence.save(
|
||||
viewId: viewId,
|
||||
@ -199,6 +202,7 @@ class CellController<T, D> {
|
||||
data: data,
|
||||
);
|
||||
onFinish?.call(result);
|
||||
_completer?.complete();
|
||||
});
|
||||
} else {
|
||||
final result = await _cellDataPersistence.save(
|
||||
@ -241,6 +245,7 @@ class CellController<T, D> {
|
||||
);
|
||||
|
||||
_loadDataOperation?.cancel();
|
||||
await _completer?.future;
|
||||
_saveDataOperation?.cancel();
|
||||
_cellDataNotifier?.dispose();
|
||||
_cellDataNotifier = null;
|
||||
|
@ -59,7 +59,7 @@ class FieldCellState with _$FieldCellState {
|
||||
factory FieldCellState.initial(FieldInfo fieldInfo) => FieldCellState(
|
||||
fieldInfo: fieldInfo,
|
||||
isResizing: false,
|
||||
width: fieldInfo.fieldSettings!.width.toDouble(),
|
||||
width: fieldInfo.width!.toDouble(),
|
||||
resizeStart: 0,
|
||||
);
|
||||
|
||||
|
@ -102,11 +102,12 @@ class BoardPage extends StatelessWidget {
|
||||
)..add(const BoardEvent.initial()),
|
||||
child: BlocBuilder<BoardBloc, BoardState>(
|
||||
buildWhen: (p, c) => p.loadingState != c.loadingState,
|
||||
builder: (context, state) => state.loadingState.map(
|
||||
loading: (_) => const Center(
|
||||
builder: (context, state) => state.loadingState.when(
|
||||
loading: () => const Center(
|
||||
child: CircularProgressIndicator.adaptive(),
|
||||
),
|
||||
finish: (result) => result.successOrFail.fold(
|
||||
idle: () => const SizedBox.shrink(),
|
||||
finish: (result) => result.fold(
|
||||
(_) => PlatformExtension.isMobile
|
||||
? const MobileBoardContent()
|
||||
: DesktopBoardContent(onEditStateChanged: onEditStateChanged),
|
||||
@ -121,7 +122,6 @@ class BoardPage extends StatelessWidget {
|
||||
howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(),
|
||||
),
|
||||
),
|
||||
idle: (_) => const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -154,6 +154,10 @@ class _DesktopBoardContentState extends State<DesktopBoardContent> {
|
||||
stretchGroupHeight: false,
|
||||
);
|
||||
|
||||
late final cellBuilder = CardCellBuilder(
|
||||
databaseController: context.read<BoardBloc>().databaseController,
|
||||
);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
scrollController.dispose();
|
||||
@ -164,7 +168,6 @@ class _DesktopBoardContentState extends State<DesktopBoardContent> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocListener<BoardBloc, BoardState>(
|
||||
listener: (context, state) {
|
||||
_handleEditStateChanged(state, context);
|
||||
widget.onEditStateChanged?.call();
|
||||
},
|
||||
child: BlocBuilder<BoardBloc, BoardState>(
|
||||
@ -182,7 +185,7 @@ class _DesktopBoardContentState extends State<DesktopBoardContent> {
|
||||
leading: HiddenGroupsColumn(margin: config.groupHeaderPadding),
|
||||
trailing: showCreateGroupButton
|
||||
? BoardTrailing(scrollController: scrollController)
|
||||
: null,
|
||||
: const HSpace(40),
|
||||
headerBuilder: (_, groupData) => BlocProvider<BoardBloc>.value(
|
||||
value: context.read<BoardBloc>(),
|
||||
child: BoardColumnHeader(
|
||||
@ -203,16 +206,6 @@ class _DesktopBoardContentState extends State<DesktopBoardContent> {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleEditStateChanged(BoardState state, BuildContext context) {
|
||||
if (state.isEditingRow && state.editingRow != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (state.editingRow!.index == null) {
|
||||
scrollManager.scrollToBottom(state.editingRow!.group.groupId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildFooter(BuildContext context, AppFlowyGroupData columnData) {
|
||||
return Padding(
|
||||
padding: config.groupFooterPadding,
|
||||
@ -257,14 +250,13 @@ class _DesktopBoardContentState extends State<DesktopBoardContent> {
|
||||
final databaseController = boardBloc.databaseController;
|
||||
final viewId = boardBloc.viewId;
|
||||
|
||||
final cellBuilder = CardCellBuilder(databaseController: databaseController);
|
||||
final isEditing = boardBloc.state.isEditingRow &&
|
||||
boardBloc.state.editingRow?.row.id == groupItem.row.id;
|
||||
|
||||
final groupItemId = "${groupData.group.groupId}${groupItem.row.id}";
|
||||
final rowMeta = rowInfo?.rowMeta ?? groupItem.row;
|
||||
|
||||
return AppFlowyGroupCard(
|
||||
return Container(
|
||||
key: ValueKey(groupItemId),
|
||||
margin: config.cardMargin,
|
||||
decoration: _makeBoxDecoration(context),
|
||||
@ -412,52 +404,50 @@ class _BoardTrailingState extends State<BoardTrailing> {
|
||||
}
|
||||
});
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0, top: 12),
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.topStart,
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: isEditing
|
||||
? SizedBox(
|
||||
width: 256,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextField(
|
||||
controller: _textController,
|
||||
focusNode: _focusNode,
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: Padding(
|
||||
padding: const EdgeInsets.only(left: 4, bottom: 8.0),
|
||||
child: FlowyIconButton(
|
||||
icon: const FlowySvg(FlowySvgs.close_filled_m),
|
||||
hoverColor: Colors.transparent,
|
||||
onPressed: () => _textController.clear(),
|
||||
),
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(left: 8.0, top: 12, right: 40),
|
||||
alignment: AlignmentDirectional.topStart,
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: isEditing
|
||||
? SizedBox(
|
||||
width: 256,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextField(
|
||||
controller: _textController,
|
||||
focusNode: _focusNode,
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: Padding(
|
||||
padding: const EdgeInsets.only(left: 4, bottom: 8.0),
|
||||
child: FlowyIconButton(
|
||||
icon: const FlowySvg(FlowySvgs.close_filled_m),
|
||||
hoverColor: Colors.transparent,
|
||||
onPressed: () => _textController.clear(),
|
||||
),
|
||||
suffixIconConstraints:
|
||||
BoxConstraints.loose(const Size(20, 24)),
|
||||
border: const UnderlineInputBorder(),
|
||||
contentPadding: const EdgeInsets.fromLTRB(8, 4, 8, 8),
|
||||
isDense: true,
|
||||
),
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
onSubmitted: (groupName) => context
|
||||
.read<BoardBloc>()
|
||||
.add(BoardEvent.createGroup(groupName)),
|
||||
suffixIconConstraints:
|
||||
BoxConstraints.loose(const Size(20, 24)),
|
||||
border: const UnderlineInputBorder(),
|
||||
contentPadding: const EdgeInsets.fromLTRB(8, 4, 8, 8),
|
||||
isDense: true,
|
||||
),
|
||||
),
|
||||
)
|
||||
: FlowyTooltip(
|
||||
message: LocaleKeys.board_column_createNewColumn.tr(),
|
||||
child: FlowyIconButton(
|
||||
width: 26,
|
||||
icon: const FlowySvg(FlowySvgs.add_s),
|
||||
iconColorOnHover: Theme.of(context).colorScheme.onSurface,
|
||||
onPressed: () => setState(() => isEditing = true),
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
onSubmitted: (groupName) => context
|
||||
.read<BoardBloc>()
|
||||
.add(BoardEvent.createGroup(groupName)),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: FlowyTooltip(
|
||||
message: LocaleKeys.board_column_createNewColumn.tr(),
|
||||
child: FlowyIconButton(
|
||||
width: 26,
|
||||
icon: const FlowySvg(FlowySvgs.add_s),
|
||||
iconColorOnHover: Theme.of(context).colorScheme.onSurface,
|
||||
onPressed: () => setState(() => isEditing = true),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -45,14 +45,14 @@ class HiddenGroupsColumn extends StatelessWidget {
|
||||
? SizedBox(
|
||||
height: 50,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 40, right: 8),
|
||||
padding: const EdgeInsets.only(left: 80, right: 8),
|
||||
child: Center(
|
||||
child: _collapseExpandIcon(context, isCollapsed),
|
||||
),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
width: 234,
|
||||
width: 274,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -60,7 +60,7 @@ class HiddenGroupsColumn extends StatelessWidget {
|
||||
height: 50,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 40 + margin.left,
|
||||
left: 80 + margin.left,
|
||||
right: margin.right + 4,
|
||||
),
|
||||
child: Row(
|
||||
|
@ -167,10 +167,13 @@ class _EventCardState extends State<EventCard> {
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
padding: widget.padding,
|
||||
decoration: decoration,
|
||||
child: card,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Container(
|
||||
padding: widget.padding,
|
||||
decoration: decoration,
|
||||
child: card,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -188,7 +188,8 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
return Padding(
|
||||
padding: PlatformExtension.isMobile
|
||||
? CalendarSize.contentInsetsMobile
|
||||
: CalendarSize.contentInsets,
|
||||
: CalendarSize.contentInsets +
|
||||
const EdgeInsets.symmetric(horizontal: 40),
|
||||
child: ScrollConfiguration(
|
||||
behavior:
|
||||
ScrollConfiguration.of(context).copyWith(scrollbars: false),
|
||||
|
@ -154,7 +154,11 @@ class _GridPageState extends State<GridPage> {
|
||||
loading: (_) =>
|
||||
const Center(child: CircularProgressIndicator.adaptive()),
|
||||
finish: (result) => result.successOrFail.fold(
|
||||
(_) => GridShortcuts(child: GridPageContent(view: widget.view)),
|
||||
(_) => GridShortcuts(
|
||||
child: GridPageContent(
|
||||
view: widget.view,
|
||||
),
|
||||
),
|
||||
(err) => FlowyErrorPage.message(
|
||||
err.toString(),
|
||||
howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(),
|
||||
@ -234,7 +238,9 @@ class _GridPageContentState extends State<GridPageContent> {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_GridHeader(headerScrollController: headerScrollController),
|
||||
_GridHeader(
|
||||
headerScrollController: headerScrollController,
|
||||
),
|
||||
_GridRows(
|
||||
viewId: widget.view.id,
|
||||
scrollController: _scrollController,
|
||||
@ -498,7 +504,7 @@ class _PositionedCalculationsRowState
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(left: GridSize.horizontalHeaderPadding),
|
||||
margin: EdgeInsets.only(left: GridSize.horizontalHeaderPadding + 40),
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).canvasColor,
|
||||
|
@ -12,11 +12,12 @@ class GridLayout {
|
||||
element.visibility != null &&
|
||||
element.visibility != FieldVisibility.AlwaysHidden,
|
||||
)
|
||||
.map((fieldInfo) => fieldInfo.fieldSettings!.width.toDouble())
|
||||
.map((fieldInfo) => fieldInfo.width!.toDouble())
|
||||
.reduce((value, element) => value + element);
|
||||
|
||||
return fieldsWidth +
|
||||
GridSize.horizontalHeaderPadding +
|
||||
40 +
|
||||
GridSize.trailHeaderPadding;
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class GridCalculationsRow extends StatelessWidget {
|
||||
key: Key(
|
||||
'${field.id}-${state.calculationsByFieldId[field.id]?.id}',
|
||||
),
|
||||
width: field.fieldSettings!.width.toDouble(),
|
||||
width: field.width!.toDouble(),
|
||||
fieldInfo: field,
|
||||
calculation: state.calculationsByFieldId[field.id],
|
||||
),
|
||||
|
@ -42,9 +42,8 @@ class GridRowBottomBar extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: GridSize.footerContentInsets,
|
||||
padding: GridSize.footerContentInsets + const EdgeInsets.only(left: 40),
|
||||
height: GridSize.footerHeight,
|
||||
// margin: const EdgeInsets.only(bottom: 8, top: 8),
|
||||
child: const GridAddRowButton(),
|
||||
);
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class _GridHeaderState extends State<_GridHeader> {
|
||||
}
|
||||
|
||||
Widget _cellLeading() {
|
||||
return SizedBox(width: GridSize.horizontalHeaderPadding);
|
||||
return SizedBox(width: GridSize.horizontalHeaderPadding + 40);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ class _RowLeadingState extends State<_RowLeading> {
|
||||
child: Consumer<RegionStateNotifier>(
|
||||
builder: (context, state, _) {
|
||||
return SizedBox(
|
||||
width: GridSize.horizontalHeaderPadding,
|
||||
width: GridSize.horizontalHeaderPadding + 40,
|
||||
child: state.onEnter ? _activeWidget() : null,
|
||||
);
|
||||
},
|
||||
@ -122,7 +122,7 @@ class _RowLeadingState extends State<_RowLeading> {
|
||||
|
||||
Widget _activeWidget() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
const InsertRowButton(),
|
||||
if (isDraggable)
|
||||
@ -246,7 +246,7 @@ class RowContent extends StatelessWidget {
|
||||
EditableCellStyle.desktopGrid,
|
||||
);
|
||||
return CellContainer(
|
||||
width: fieldInfo.fieldSettings!.width.toDouble(),
|
||||
width: fieldInfo.width!.toDouble(),
|
||||
isPrimary: fieldInfo.field.isPrimary,
|
||||
accessoryBuilder: (buildContext) {
|
||||
final builder = child.accessoryBuilder;
|
||||
|
@ -24,7 +24,7 @@ class TabBarHeader extends StatelessWidget {
|
||||
return Container(
|
||||
height: 30,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: GridSize.horizontalHeaderPadding,
|
||||
horizontal: GridSize.horizontalHeaderPadding + 40,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
|
@ -286,4 +286,7 @@ class DatabasePluginWidgetBuilder extends PluginWidgetBuilder {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
EdgeInsets get contentPadding => const EdgeInsets.only(top: 28);
|
||||
}
|
||||
|
@ -83,7 +83,9 @@ class _TextCellState extends State<TextCardCell> {
|
||||
|
||||
void _bindEditableNotifier() {
|
||||
widget.editableNotifier?.isCellEditing.addListener(() {
|
||||
if (!mounted) return;
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
final isEditing = widget.editableNotifier?.isCellEditing.value ?? false;
|
||||
if (isEditing) {
|
||||
@ -106,15 +108,14 @@ class _TextCellState extends State<TextCardCell> {
|
||||
return BlocProvider.value(
|
||||
value: cellBloc,
|
||||
child: BlocConsumer<TextCellBloc, TextCellState>(
|
||||
listenWhen: (previous, current) =>
|
||||
previous.content != current.content && !current.enableEdit,
|
||||
listener: (context, state) {
|
||||
if (_textEditingController.text != state.content) {
|
||||
_textEditingController.text = state.content;
|
||||
}
|
||||
_textEditingController.text = state.content;
|
||||
},
|
||||
buildWhen: (previous, current) {
|
||||
if (previous.content != current.content &&
|
||||
_textEditingController.text == current.content &&
|
||||
current.enableEdit) {
|
||||
_textEditingController.text == current.content) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -129,10 +130,10 @@ class _TextCellState extends State<TextCardCell> {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final icon = _buildIcon(state, isTitle);
|
||||
final child = state.enableEdit || focusWhenInit
|
||||
? _buildTextField()
|
||||
: _buildText(state, isTitle);
|
||||
final icon = isTitle ? _buildIcon(state) : null;
|
||||
final child = isTitle
|
||||
? _buildTextField(state.enableEdit || focusWhenInit)
|
||||
: _buildText(state.content);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
@ -156,10 +157,7 @@ class _TextCellState extends State<TextCardCell> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Widget? _buildIcon(TextCellState state, bool isTitle) {
|
||||
if (!isTitle) {
|
||||
return null;
|
||||
}
|
||||
Widget? _buildIcon(TextCellState state) {
|
||||
if (state.emoji.isNotEmpty) {
|
||||
return Text(
|
||||
state.emoji,
|
||||
@ -178,43 +176,52 @@ class _TextCellState extends State<TextCardCell> {
|
||||
return null;
|
||||
}
|
||||
|
||||
Widget _buildText(TextCellState state, bool isTitle) {
|
||||
final text = state.content.isEmpty
|
||||
? isTitle
|
||||
? LocaleKeys.grid_row_titlePlaceholder.tr()
|
||||
: LocaleKeys.grid_row_textPlaceholder.tr()
|
||||
: state.content;
|
||||
final color = state.content.isEmpty ? Theme.of(context).hintColor : null;
|
||||
final textStyle =
|
||||
isTitle ? widget.style.titleTextStyle : widget.style.textStyle;
|
||||
Widget _buildText(String content) {
|
||||
final text =
|
||||
content.isEmpty ? LocaleKeys.grid_row_textPlaceholder.tr() : content;
|
||||
final color = content.isEmpty ? Theme.of(context).hintColor : null;
|
||||
|
||||
return Padding(
|
||||
padding: widget.style.padding,
|
||||
child: Text(
|
||||
text,
|
||||
style: textStyle.copyWith(color: color),
|
||||
style: widget.style.textStyle.copyWith(color: color),
|
||||
maxLines: widget.style.maxLines,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTextField() {
|
||||
Widget _buildTextField(bool isEditing) {
|
||||
final padding =
|
||||
widget.style.padding.add(const EdgeInsets.symmetric(vertical: 4.0));
|
||||
return TextField(
|
||||
controller: _textEditingController,
|
||||
focusNode: focusNode,
|
||||
onChanged: (_) =>
|
||||
cellBloc.add(TextCellEvent.updateText(_textEditingController.text)),
|
||||
onEditingComplete: () => focusNode.unfocus(),
|
||||
maxLines: null,
|
||||
style: widget.style.titleTextStyle,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: padding,
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
isCollapsed: true,
|
||||
hintText: LocaleKeys.grid_row_titlePlaceholder.tr(),
|
||||
return IgnorePointer(
|
||||
ignoring: !isEditing,
|
||||
child: TextField(
|
||||
controller: _textEditingController,
|
||||
focusNode: focusNode,
|
||||
onChanged: (_) {
|
||||
if (_textEditingController.value.composing.isCollapsed) {
|
||||
cellBloc.add(TextCellEvent.updateText(_textEditingController.text));
|
||||
}
|
||||
},
|
||||
onEditingComplete: () => focusNode.unfocus(),
|
||||
maxLines: isEditing ? null : 2,
|
||||
minLines: 1,
|
||||
textInputAction: TextInputAction.done,
|
||||
readOnly: !isEditing,
|
||||
enableInteractiveSelection: isEditing,
|
||||
style: widget.style.titleTextStyle,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: padding,
|
||||
border: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
isDense: true,
|
||||
isCollapsed: true,
|
||||
hintText: LocaleKeys.grid_row_titlePlaceholder.tr(),
|
||||
hintStyle: widget.style.titleTextStyle.copyWith(
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ CardCellStyleMap desktopBoardCardCellStyleMap(BuildContext context) {
|
||||
FieldType.RichText: TextCardCellStyle(
|
||||
padding: padding,
|
||||
textStyle: textStyle,
|
||||
maxLines: null,
|
||||
maxLines: 2,
|
||||
titleTextStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
@ -180,8 +180,7 @@ class _DatabasePropertyCellState extends State<DatabasePropertyCell> {
|
||||
return;
|
||||
}
|
||||
|
||||
final newVisiblity =
|
||||
widget.fieldInfo.fieldSettings!.visibility.toggle();
|
||||
final newVisiblity = widget.fieldInfo.visibility!.toggle();
|
||||
context.read<DatabasePropertyBloc>().add(
|
||||
DatabasePropertyEvent.setFieldVisibility(
|
||||
widget.fieldInfo.id,
|
||||
|
@ -44,11 +44,11 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "15a3a50"
|
||||
resolved-ref: "15a3a5071ffdb002ffaefda9df343b6800844d8d"
|
||||
ref: f88b4ce01d2728c05125cbe9170013f4a7c85a31
|
||||
resolved-ref: f88b4ce01d2728c05125cbe9170013f4a7c85a31
|
||||
url: "https://github.com/AppFlowy-IO/appflowy-board.git"
|
||||
source: git
|
||||
version: "0.1.1"
|
||||
version: "0.1.2"
|
||||
appflowy_editor:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1405,10 +1405,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: provider
|
||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.1"
|
||||
version: "6.1.2"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -41,9 +41,10 @@ dependencies:
|
||||
flowy_svg:
|
||||
path: packages/flowy_svg
|
||||
appflowy_board:
|
||||
# path: ../../../appflowy-board
|
||||
git:
|
||||
url: https://github.com/AppFlowy-IO/appflowy-board.git
|
||||
ref: 15a3a50
|
||||
ref: f88b4ce01d2728c05125cbe9170013f4a7c85a31
|
||||
appflowy_result:
|
||||
path: packages/appflowy_result
|
||||
appflowy_editor_plugins: ^0.0.2
|
||||
|
Loading…
Reference in New Issue
Block a user