mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add cloumn bloc
This commit is contained in:
parent
808d848f62
commit
00db755c29
@ -12,6 +12,7 @@ import 'package:app_flowy/workspace/application/menu/prelude.dart';
|
||||
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
@ -102,6 +103,13 @@ class HomeDepsResolver {
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<ColumnBloc, List<Field>, void>(
|
||||
(data, _) => ColumnBloc(
|
||||
data: GridColumnData(fields: data),
|
||||
service: ColumnService(),
|
||||
),
|
||||
);
|
||||
|
||||
// trash
|
||||
getIt.registerLazySingleton<TrashService>(() => TrashService());
|
||||
getIt.registerLazySingleton<TrashListener>(() => TrashListener());
|
||||
|
@ -0,0 +1,43 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'dart:async';
|
||||
import 'column_service.dart';
|
||||
import 'data.dart';
|
||||
|
||||
part 'column_bloc.freezed.dart';
|
||||
|
||||
class ColumnBloc extends Bloc<ColumnEvent, ColumnState> {
|
||||
final ColumnService service;
|
||||
final GridColumnData data;
|
||||
|
||||
ColumnBloc({required this.data, required this.service}) : super(ColumnState.initial(data.fields)) {
|
||||
on<ColumnEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialColumn value) async {},
|
||||
createColumn: (_CreateColumn value) {},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class ColumnEvent with _$ColumnEvent {
|
||||
const factory ColumnEvent.initial() = _InitialColumn;
|
||||
const factory ColumnEvent.createColumn() = _CreateColumn;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class ColumnState with _$ColumnState {
|
||||
const factory ColumnState({required List<Field> fields}) = _ColumnState;
|
||||
|
||||
factory ColumnState.initial(List<Field> fields) => ColumnState(fields: fields);
|
||||
}
|
@ -0,0 +1 @@
|
||||
class ColumnService {}
|
@ -33,3 +33,9 @@ class GridRowData {
|
||||
required this.cellMap,
|
||||
});
|
||||
}
|
||||
|
||||
class GridColumnData {
|
||||
final List<Field> fields;
|
||||
|
||||
GridColumnData({required this.fields});
|
||||
}
|
||||
|
@ -3,3 +3,5 @@ export 'row_bloc.dart';
|
||||
export 'row_service.dart';
|
||||
export 'grid_service.dart';
|
||||
export 'data.dart';
|
||||
export 'column_service.dart';
|
||||
export 'column_bloc.dart';
|
||||
|
@ -111,7 +111,7 @@ class _GridBodyState extends State<GridBody> {
|
||||
slivers: <Widget>[
|
||||
_buildHeader(gridInfo.fields),
|
||||
_buildRows(gridInfo),
|
||||
_builderFooter(context),
|
||||
const GridFooter(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -145,12 +145,4 @@ class _GridBodyState extends State<GridBody> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _builderFooter(BuildContext context) {
|
||||
return GridFooter(
|
||||
onAddRow: () {
|
||||
context.read<GridBloc>().add(const GridEvent.createRow());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,6 @@ class GridLayout {
|
||||
|
||||
final fieldsWidth = fields.map((field) => field.width.toDouble()).reduce((value, element) => value + element);
|
||||
|
||||
return fieldsWidth + GridSize.startHeaderPadding;
|
||||
return fieldsWidth + GridSize.leadingHeaderPadding + GridSize.trailHeaderPadding;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,29 @@
|
||||
class GridInsets {
|
||||
static double scale = 1;
|
||||
|
||||
static double get horizontal => 8 * scale;
|
||||
static double get vertical => 8 * scale;
|
||||
}
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class GridSize {
|
||||
static double scale = 1;
|
||||
|
||||
static double get scrollBarSize => 12 * scale;
|
||||
static double get headerHeight => 50 * scale;
|
||||
static double get headerHeight => 40 * scale;
|
||||
static double get footerHeight => 40 * scale;
|
||||
static double get startHeaderPadding => 30 * scale;
|
||||
static double get leadingHeaderPadding => 30 * scale;
|
||||
static double get trailHeaderPadding => 140 * scale;
|
||||
static double get headerContentPadding => 8 * scale;
|
||||
static double get cellContentPadding => 8 * scale;
|
||||
//
|
||||
static EdgeInsets get headerContentInsets => EdgeInsets.symmetric(
|
||||
horizontal: GridSize.headerContentPadding,
|
||||
vertical: GridSize.headerContentPadding,
|
||||
);
|
||||
static EdgeInsets get cellContentInsets => EdgeInsets.symmetric(
|
||||
horizontal: GridSize.cellContentPadding,
|
||||
vertical: GridSize.cellContentPadding,
|
||||
);
|
||||
|
||||
static EdgeInsets get footerContentInsets => EdgeInsets.fromLTRB(
|
||||
0,
|
||||
GridSize.headerContentPadding,
|
||||
GridSize.headerContentPadding,
|
||||
GridSize.headerContentPadding,
|
||||
);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class CellContainer extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
border: Border(right: borderSide, bottom: borderSide),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: GridInsets.vertical, horizontal: GridInsets.horizontal),
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: Center(child: IntrinsicHeight(child: child)),
|
||||
),
|
||||
);
|
||||
|
@ -1,15 +1,4 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row_bloc.dart';
|
||||
import 'package:app_flowy/workspace/presentation/home/menu/app/header/add_button.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||
import 'package:flowy_infra_ui/widget/mouse_hover_builder.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import 'cell_decoration.dart';
|
||||
// ignore: import_of_legacy_library_into_null_safe
|
||||
|
||||
/// The interface of base cell.
|
||||
abstract class GridCellWidget extends StatelessWidget {
|
||||
@ -89,53 +78,3 @@ class BlankCell extends GridCellWidget {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
|
||||
class RowLeading extends StatelessWidget {
|
||||
final String rowId;
|
||||
const RowLeading({required this.rowId, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RowBloc, RowState>(
|
||||
builder: (context, state) {
|
||||
if (state.isHighlight) {
|
||||
return Row(
|
||||
children: const [
|
||||
CreateRowButton(),
|
||||
DrawRowButton(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return const SizedBox.expand();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CreateRowButton extends StatelessWidget {
|
||||
const CreateRowButton({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
return Tooltip(
|
||||
message: '',
|
||||
child: FlowyIconButton(
|
||||
hoverColor: theme.hover,
|
||||
width: 22,
|
||||
onPressed: () => context.read<RowBloc>().add(const RowEvent.createRow()),
|
||||
icon: svg("home/add"),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DrawRowButton extends StatelessWidget {
|
||||
const DrawRowButton({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||
import 'package:flowy_infra_ui/widget/mouse_hover_builder.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'cell_builder.dart';
|
||||
@ -42,7 +44,10 @@ class GridRowWidget extends StatelessWidget {
|
||||
|
||||
List<Widget> _buildCells() {
|
||||
return [
|
||||
SizedBox(width: GridSize.startHeaderPadding, child: RowLeading(rowId: data.row.id)),
|
||||
SizedBox(
|
||||
width: GridSize.leadingHeaderPadding,
|
||||
child: LeadingRow(rowId: data.row.id),
|
||||
),
|
||||
...data.fields.map(
|
||||
(field) {
|
||||
final cellData = data.cellMap[field.id];
|
||||
@ -51,7 +56,72 @@ class GridRowWidget extends StatelessWidget {
|
||||
child: GridCellBuilder.buildCell(field, cellData),
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(
|
||||
width: GridSize.trailHeaderPadding,
|
||||
child: TrailingRow(rowId: data.row.id),
|
||||
)
|
||||
].toList();
|
||||
}
|
||||
}
|
||||
|
||||
class LeadingRow extends StatelessWidget {
|
||||
final String rowId;
|
||||
const LeadingRow({required this.rowId, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RowBloc, RowState>(
|
||||
builder: (context, state) {
|
||||
if (state.isHighlight) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: const [
|
||||
CreateRowButton(),
|
||||
],
|
||||
);
|
||||
}
|
||||
return const SizedBox.expand();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TrailingRow extends StatelessWidget {
|
||||
final String rowId;
|
||||
const TrailingRow({required this.rowId, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
final borderSide = BorderSide(color: theme.shader4, width: 0.4);
|
||||
|
||||
return BlocBuilder<RowBloc, RowState>(
|
||||
builder: (context, state) {
|
||||
return Container(
|
||||
width: GridSize.trailHeaderPadding,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(bottom: borderSide),
|
||||
),
|
||||
padding: GridSize.cellContentInsets,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CreateRowButton extends StatelessWidget {
|
||||
const CreateRowButton({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
return FlowyIconButton(
|
||||
hoverColor: theme.hover,
|
||||
width: 22,
|
||||
onPressed: () => context.read<RowBloc>().add(const RowEvent.createRow()),
|
||||
iconPadding: const EdgeInsets.all(3),
|
||||
icon: svg("home/add"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,28 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row_bloc.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||
import 'package:flowy_infra_ui/widget/mouse_hover_builder.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../content/cell_decoration.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class GridFooter extends StatelessWidget {
|
||||
final VoidCallback? onAddRow;
|
||||
const GridFooter({Key? key, required this.onAddRow}) : super(key: key);
|
||||
const GridFooter({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: GridSize.footerHeight,
|
||||
child: Row(
|
||||
children: [
|
||||
AddRowButton(onTap: onAddRow),
|
||||
],
|
||||
child: Padding(
|
||||
padding: GridSize.headerContentInsets,
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(width: GridSize.leadingHeaderPadding),
|
||||
const SizedBox(width: 120, child: AddRowButton()),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -24,24 +30,16 @@ class GridFooter extends StatelessWidget {
|
||||
}
|
||||
|
||||
class AddRowButton extends StatelessWidget {
|
||||
final VoidCallback? onTap;
|
||||
const AddRowButton({Key? key, required this.onTap}) : super(key: key);
|
||||
const AddRowButton({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: onTap,
|
||||
child: MouseHoverBuilder(
|
||||
builder: (_, isHovered) => Container(
|
||||
width: GridSize.startHeaderPadding,
|
||||
height: GridSize.footerHeight,
|
||||
decoration: CellDecoration.box(
|
||||
color: isHovered ? Colors.red.withOpacity(.1) : Colors.white,
|
||||
),
|
||||
child: const Icon(Icons.add, size: 16),
|
||||
),
|
||||
),
|
||||
final theme = context.watch<AppTheme>();
|
||||
return FlowyButton(
|
||||
text: const FlowyText.medium('New row', fontSize: 12),
|
||||
hoverColor: theme.hover,
|
||||
onTap: () => context.read<RowBloc>().add(const RowEvent.createRow()),
|
||||
icon: svg("home/add"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/column_bloc.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import 'header_cell.dart';
|
||||
|
||||
@ -31,28 +38,77 @@ class GridHeaderDelegate extends SliverPersistentHeaderDelegate {
|
||||
|
||||
class GridHeader extends StatelessWidget {
|
||||
final List<Field> fields;
|
||||
|
||||
const GridHeader({required this.fields, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final headers = List<Widget>.empty(growable: true);
|
||||
fields.asMap().forEach((index, field) {
|
||||
final header = HeaderCellContainer(
|
||||
width: field.width.toDouble(),
|
||||
child: HeaderCell(field),
|
||||
);
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<ColumnBloc>(param1: fields),
|
||||
child: BlocBuilder<ColumnBloc, ColumnState>(
|
||||
builder: (context, state) {
|
||||
final headers = state.fields
|
||||
.map(
|
||||
(field) => HeaderCellContainer(
|
||||
width: field.width.toDouble(),
|
||||
child: HeaderCell(field),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
//
|
||||
headers.add(header);
|
||||
});
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const HeaderCellLeading(),
|
||||
...headers,
|
||||
],
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const LeadingHeaderCell(),
|
||||
...headers,
|
||||
const TrailingHeaderCell(),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LeadingHeaderCell extends StatelessWidget {
|
||||
const LeadingHeaderCell({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: GridSize.leadingHeaderPadding,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TrailingHeaderCell extends StatelessWidget {
|
||||
const TrailingHeaderCell({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
final borderSide = BorderSide(color: theme.shader4, width: 0.4);
|
||||
return Container(
|
||||
width: GridSize.trailHeaderPadding,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(top: borderSide, bottom: borderSide),
|
||||
),
|
||||
padding: GridSize.headerContentInsets,
|
||||
child: const CreateColumnButton(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CreateColumnButton extends StatelessWidget {
|
||||
const CreateColumnButton({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
return FlowyButton(
|
||||
text: const FlowyText.medium('New column', fontSize: 12),
|
||||
hoverColor: theme.hover,
|
||||
onTap: () => context.read<ColumnBloc>().add(const ColumnEvent.createColumn()),
|
||||
icon: svg("home/add"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'constants.dart';
|
||||
|
||||
class HeaderCell extends StatelessWidget {
|
||||
final Field field;
|
||||
@ -15,7 +14,7 @@ class HeaderCell extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
return FlowyButton(
|
||||
text: FlowyText.medium(field.name),
|
||||
text: FlowyText.medium(field.name, fontSize: 12),
|
||||
hoverColor: theme.hover,
|
||||
onTap: () {},
|
||||
);
|
||||
@ -40,19 +39,8 @@ class HeaderCellContainer extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
border: Border(top: borderSide, right: borderSide, bottom: borderSide),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: GridInsets.vertical, horizontal: GridInsets.horizontal),
|
||||
padding: GridSize.headerContentInsets,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HeaderCellLeading extends StatelessWidget {
|
||||
const HeaderCellLeading({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: GridSize.startHeaderPadding,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class FlowyButton extends StatelessWidget {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: FlowyHover(
|
||||
config: HoverDisplayConfig(borderRadius: Corners.s6Border, hoverColor: hoverColor),
|
||||
config: HoverDisplayConfig(borderRadius: Corners.s5Border, hoverColor: hoverColor),
|
||||
builder: (context, onHover) => _render(),
|
||||
),
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user