Merge pull request #957 from AppFlowy-IO/feat/board_setting

chore: show board setting
This commit is contained in:
Nathan.fooo 2022-08-31 16:58:37 +08:00 committed by GitHub
commit a0d253b889
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 320 additions and 17 deletions

View File

@ -0,0 +1,46 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import 'package:dartz/dartz.dart';
part 'board_setting_bloc.freezed.dart';
class BoardSettingBloc extends Bloc<BoardSettingEvent, BoardSettingState> {
final String gridId;
BoardSettingBloc({required this.gridId})
: super(BoardSettingState.initial()) {
on<BoardSettingEvent>(
(event, emit) async {
event.when(performAction: (action) {
emit(state.copyWith(selectedAction: Some(action)));
});
},
);
}
@override
Future<void> close() async {
return super.close();
}
}
@freezed
class BoardSettingEvent with _$BoardSettingEvent {
const factory BoardSettingEvent.performAction(BoardSettingAction action) =
_PerformAction;
}
@freezed
class BoardSettingState with _$BoardSettingState {
const factory BoardSettingState({
required Option<BoardSettingAction> selectedAction,
}) = _BoardSettingState;
factory BoardSettingState.initial() => BoardSettingState(
selectedAction: none(),
);
}
enum BoardSettingAction {
properties,
}

View File

@ -24,6 +24,7 @@ import '../../grid/application/row/row_cache.dart';
import '../application/board_bloc.dart';
import 'card/card.dart';
import 'card/card_cell_builder.dart';
import 'toolbar/board_toolbar.dart';
class BoardPage extends StatelessWidget {
final ViewPB view;
@ -100,25 +101,34 @@ class _BoardContentState extends State<BoardContent> {
buildWhen: (previous, current) =>
previous.groupIds.length != current.groupIds.length,
builder: (context, state) {
final theme = context.read<AppTheme>();
return Container(
color: Colors.white,
color: theme.surface,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: AFBoard(
scrollManager: scrollManager,
scrollController: scrollController,
dataController: context.read<BoardBloc>().boardController,
headerBuilder: _buildHeader,
footBuilder: _buildFooter,
cardBuilder: (_, column, columnItem) => _buildCard(
context,
column,
columnItem,
),
columnConstraints: const BoxConstraints.tightFor(width: 300),
config: AFBoardConfig(
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
),
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
const _ToolbarBlocAdaptor(),
Expanded(
child: AFBoard(
scrollManager: scrollManager,
scrollController: scrollController,
dataController: context.read<BoardBloc>().boardController,
headerBuilder: _buildHeader,
footBuilder: _buildFooter,
cardBuilder: (_, column, columnItem) => _buildCard(
context,
column,
columnItem,
),
columnConstraints:
const BoxConstraints.tightFor(width: 300),
config: AFBoardConfig(
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
),
),
),
],
),
),
);
@ -277,6 +287,25 @@ class _BoardContentState extends State<BoardContent> {
}
}
class _ToolbarBlocAdaptor extends StatelessWidget {
const _ToolbarBlocAdaptor({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<BoardBloc, BoardState>(
builder: (context, state) {
final bloc = context.read<BoardBloc>();
final toolbarContext = BoardToolbarContext(
viewId: bloc.gridId,
fieldCache: bloc.fieldCache,
);
return BoardToolbar(toolbarContext: toolbarContext);
},
);
}
}
extension HexColor on Color {
static Color fromHex(String hexString) {
final buffer = StringBuffer();

View File

@ -0,0 +1,168 @@
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/plugins/board/application/toolbar/board_setting_bloc.dart';
import 'package:app_flowy/plugins/grid/application/field/field_cache.dart';
import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/toolbar/grid_property.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'board_toolbar.dart';
class BoardSettingContext {
final String viewId;
final GridFieldCache fieldCache;
BoardSettingContext({
required this.viewId,
required this.fieldCache,
});
factory BoardSettingContext.from(BoardToolbarContext toolbarContext) =>
BoardSettingContext(
viewId: toolbarContext.viewId,
fieldCache: toolbarContext.fieldCache,
);
}
class BoardSettingList extends StatelessWidget {
final BoardSettingContext settingContext;
final Function(BoardSettingAction, BoardSettingContext) onAction;
const BoardSettingList({
required this.settingContext,
required this.onAction,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => BoardSettingBloc(gridId: settingContext.viewId),
child: BlocListener<BoardSettingBloc, BoardSettingState>(
listenWhen: (previous, current) =>
previous.selectedAction != current.selectedAction,
listener: (context, state) {
state.selectedAction.foldLeft(null, (_, action) {
FlowyOverlay.of(context).remove(identifier());
onAction(action, settingContext);
});
},
child: BlocBuilder<BoardSettingBloc, BoardSettingState>(
builder: (context, state) {
return _renderList();
},
),
),
);
}
Widget _renderList() {
final cells = BoardSettingAction.values.map((action) {
return _SettingItem(action: action);
}).toList();
return SizedBox(
width: 140,
child: ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
itemCount: cells.length,
separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight);
},
physics: StyledScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return cells[index];
},
),
);
}
static void show(BuildContext context, BoardSettingContext settingContext) {
final list = BoardSettingList(
settingContext: settingContext,
onAction: (action, settingContext) {
switch (action) {
case BoardSettingAction.properties:
GridPropertyList(
gridId: settingContext.viewId,
fieldCache: settingContext.fieldCache)
.show(context);
break;
}
},
);
FlowyOverlay.of(context).insertWithAnchor(
widget: OverlayContainer(
constraints: BoxConstraints.loose(const Size(140, 400)),
child: list,
),
identifier: identifier(),
anchorContext: context,
anchorDirection: AnchorDirection.bottomRight,
style: FlowyOverlayStyle(blur: false),
);
}
static String identifier() {
return (BoardSettingList).toString();
}
}
class _SettingItem extends StatelessWidget {
final BoardSettingAction action;
const _SettingItem({
required this.action,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.read<AppTheme>();
final isSelected = context
.read<BoardSettingBloc>()
.state
.selectedAction
.foldLeft(false, (_, selectedAction) => selectedAction == action);
return SizedBox(
height: 30,
child: FlowyButton(
isSelected: isSelected,
text: FlowyText.medium(action.title(),
fontSize: 12, color: theme.textColor),
hoverColor: theme.hover,
onTap: () {
context
.read<BoardSettingBloc>()
.add(BoardSettingEvent.performAction(action));
},
leftIcon: svgWidget(action.iconName(), color: theme.iconColor),
),
);
}
}
extension _GridSettingExtension on BoardSettingAction {
String iconName() {
switch (this) {
case BoardSettingAction.properties:
return 'grid/setting/properties';
}
}
String title() {
switch (this) {
case BoardSettingAction.properties:
return LocaleKeys.grid_settings_Properties.tr();
}
}
}

View File

@ -0,0 +1,60 @@
import 'package:app_flowy/plugins/grid/application/field/field_cache.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/widgets.dart';
import 'package:provider/provider.dart';
import 'board_setting.dart';
class BoardToolbarContext {
final String viewId;
final GridFieldCache fieldCache;
BoardToolbarContext({
required this.viewId,
required this.fieldCache,
});
}
class BoardToolbar extends StatelessWidget {
final BoardToolbarContext toolbarContext;
const BoardToolbar({
required this.toolbarContext,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: 40,
child: Row(
children: [
_SettingButton(
settingContext: BoardSettingContext.from(toolbarContext),
),
],
),
);
}
}
class _SettingButton extends StatelessWidget {
final BoardSettingContext settingContext;
const _SettingButton({required this.settingContext, Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.read<AppTheme>();
return FlowyIconButton(
hoverColor: theme.hover,
width: 22,
onPressed: () => BoardSettingList.show(context, settingContext),
icon: Padding(
padding: const EdgeInsets.symmetric(vertical: 3.0, horizontal: 3.0),
child: svgWidget("grid/setting/setting"),
),
);
}
}