chore: show edit field

This commit is contained in:
appflowy 2022-03-31 19:45:54 +08:00
parent 7c6a857a69
commit c3c75dde9f
5 changed files with 80 additions and 134 deletions

View File

@ -2,7 +2,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import 'package:protobuf/protobuf.dart';
part 'date_bloc.freezed.dart';
class DateTypeOptionBloc extends Bloc<DateTypeOptionEvent, DateTypeOptionState> {
@ -11,18 +11,30 @@ class DateTypeOptionBloc extends Bloc<DateTypeOptionEvent, DateTypeOptionState>
(event, emit) async {
event.map(
didSelectDateFormat: (_DidSelectDateFormat value) {
state.typeOption.dateFormat = value.format;
emit(state);
emit(state.copyWith(typeOption: _updateDateFormat(value.format)));
},
didSelectTimeFormat: (_DidSelectTimeFormat value) {
state.typeOption.timeFormat = value.format;
emit(state);
emit(state.copyWith(typeOption: _updateTimeFormat(value.format)));
},
);
},
);
}
DateTypeOption _updateTimeFormat(TimeFormat format) {
state.typeOption.freeze();
return state.typeOption.rebuild((typeOption) {
typeOption.timeFormat = format;
});
}
DateTypeOption _updateDateFormat(DateFormat format) {
state.typeOption.freeze();
return state.typeOption.rebuild((typeOption) {
typeOption.dateFormat = format;
});
}
@override
Future<void> close() async {
return super.close();

View File

@ -2,6 +2,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import 'package:protobuf/protobuf.dart';
part 'number_bloc.freezed.dart';
@ -11,14 +12,20 @@ class NumberTypeOptionBloc extends Bloc<NumberTypeOptionEvent, NumberTypeOptionS
(event, emit) async {
event.map(
didSelectFormat: (_DidSelectFormat value) {
state.typeOption.format = value.format;
emit(state);
emit(state.copyWith(typeOption: _updateNumberFormat(value.format)));
},
);
},
);
}
NumberTypeOption _updateNumberFormat(NumberFormat format) {
state.typeOption.freeze();
return state.typeOption.rebuild((typeOption) {
typeOption.format = format;
});
}
@override
Future<void> close() async {
return super.close();

View File

@ -1,110 +0,0 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'field_name_input.dart';
import 'field_operation_list.dart';
import 'field_tyep_switcher.dart';
class EditFieldPannel extends StatelessWidget {
final GridFieldData fieldData;
const EditFieldPannel({required this.fieldData, Key? key}) : super(key: key);
static void show(BuildContext context, GridFieldData fieldData) {
final editor = EditFieldPannel(fieldData: fieldData);
FlowyOverlay.of(context).insertWithAnchor(
widget: OverlayContainer(
child: editor,
constraints: BoxConstraints.loose(const Size(300, 200)),
),
identifier: editor.identifier(),
anchorContext: context,
anchorDirection: AnchorDirection.bottomWithLeftAligned,
);
}
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<EditFieldBloc>(param1: fieldData)..add(const EditFieldEvent.initial()),
child: SingleChildScrollView(
child: Column(
children: [
const _FieldNameTextField(),
const VSpace(6),
const _FieldTypeSwitcher(),
const VSpace(6),
_FieldOperationList(fieldData, () => FlowyOverlay.of(context).remove(identifier())),
],
),
),
);
}
String identifier() {
return toString();
}
}
class _FieldOperationList extends StatelessWidget {
final GridFieldData fieldData;
final VoidCallback onDismissed;
const _FieldOperationList(this.fieldData, this.onDismissed, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final actions = FieldAction.values
.map(
(action) => FieldActionItem(
fieldId: fieldData.field.id,
action: action,
onTap: onDismissed,
),
)
.toList();
return FieldOperationList(actions: actions);
}
}
class _FieldTypeSwitcher extends StatelessWidget {
const _FieldTypeSwitcher({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<EditFieldBloc, EditFieldState>(
builder: (context, state) {
final editContext = context.read<EditFieldBloc>().state.editContext;
final switchContext = SwitchFieldContext(
editContext.gridId,
editContext.gridField,
editContext.typeOptionData,
);
return FieldTypeSwitcher(switchContext: switchContext, onSelected: (field, typeOptionData) {});
},
);
}
}
class _FieldNameTextField extends StatelessWidget {
const _FieldNameTextField({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<EditFieldBloc, EditFieldState>(
buildWhen: ((previous, current) => previous.fieldName == current.fieldName),
builder: (context, state) {
return FieldNameTextField(
name: state.fieldName,
errorText: state.errorText,
onNameChanged: (newName) {
context.read<EditFieldBloc>().add(EditFieldEvent.updateFieldName(newName));
},
);
},
);
}
}

View File

@ -7,7 +7,7 @@ import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'edit_field_pannel.dart';
import 'field_detail_pannel.dart';
class GridHeaderCell extends StatelessWidget {
final GridFieldData fieldData;
@ -18,7 +18,7 @@ class GridHeaderCell extends StatelessWidget {
final theme = context.watch<AppTheme>();
final button = FlowyButton(
hoverColor: theme.hover,
onTap: () => EditFieldPannel.show(context, fieldData),
onTap: () => FieldDetailPannel.show(context, fieldData),
rightIcon: svg("editor/details", color: theme.iconColor),
text: Padding(padding: GridSize.cellContentInsets, child: FlowyText.medium(fieldData.field.name, fontSize: 12)),
);

View File

@ -50,15 +50,15 @@ class DateTypeOptionWidget extends TypeOptionWidget {
listener: (context, state) => dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()),
builder: (context, state) {
return Column(children: [
_dateFormatButton(context),
_timeFormatButton(context),
_dateFormatButton(context, state.typeOption.dateFormat),
_timeFormatButton(context, state.typeOption.timeFormat),
]);
},
),
);
}
Widget _dateFormatButton(BuildContext context) {
Widget _dateFormatButton(BuildContext context, DateFormat dataFormat) {
final theme = context.watch<AppTheme>();
return SizedBox(
height: GridSize.typeOptionItemHeight,
@ -67,9 +67,12 @@ class DateTypeOptionWidget extends TypeOptionWidget {
padding: GridSize.typeOptionContentInsets,
hoverColor: theme.hover,
onTap: () {
final list = DateFormatList(onSelected: (format) {
context.read<DateTypeOptionBloc>().add(DateTypeOptionEvent.didSelectDateFormat(format));
});
final list = DateFormatList(
selectedFormat: dataFormat,
onSelected: (format) {
context.read<DateTypeOptionBloc>().add(DateTypeOptionEvent.didSelectDateFormat(format));
},
);
overlayDelegate.showOverlay(context, list);
},
rightIcon: svg("grid/more", color: theme.iconColor),
@ -77,7 +80,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
);
}
Widget _timeFormatButton(BuildContext context) {
Widget _timeFormatButton(BuildContext context, TimeFormat timeFormat) {
final theme = context.watch<AppTheme>();
return SizedBox(
height: GridSize.typeOptionItemHeight,
@ -86,9 +89,11 @@ class DateTypeOptionWidget extends TypeOptionWidget {
padding: GridSize.typeOptionContentInsets,
hoverColor: theme.hover,
onTap: () {
final list = TimeFormatList(onSelected: (format) {
context.read<DateTypeOptionBloc>().add(DateTypeOptionEvent.didSelectTimeFormat(format));
});
final list = TimeFormatList(
selectedFormat: timeFormat,
onSelected: (format) {
context.read<DateTypeOptionBloc>().add(DateTypeOptionEvent.didSelectTimeFormat(format));
});
overlayDelegate.showOverlay(context, list);
},
rightIcon: svg("grid/more", color: theme.iconColor),
@ -98,8 +103,9 @@ class DateTypeOptionWidget extends TypeOptionWidget {
}
class DateFormatList extends StatelessWidget {
final DateFormat selectedFormat;
final Function(DateFormat format) onSelected;
const DateFormatList({required this.onSelected, Key? key}) : super(key: key);
const DateFormatList({required this.selectedFormat, required this.onSelected, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -109,7 +115,8 @@ class DateFormatList extends StatelessWidget {
onSelected: (format) {
onSelected(format);
FlowyOverlay.of(context).remove(identifier());
});
},
isSelected: selectedFormat == format);
}).toList();
return SizedBox(
@ -134,18 +141,30 @@ class DateFormatList extends StatelessWidget {
}
class DateFormatItem extends StatelessWidget {
final bool isSelected;
final DateFormat dateFormat;
final Function(DateFormat format) onSelected;
const DateFormatItem({required this.dateFormat, required this.onSelected, Key? key}) : super(key: key);
const DateFormatItem({
required this.dateFormat,
required this.onSelected,
required this.isSelected,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
Widget? checkmark;
if (isSelected) {
checkmark = svg("grid/checkmark");
}
return SizedBox(
height: GridSize.typeOptionItemHeight,
child: FlowyButton(
text: FlowyText.medium(dateFormat.title(), fontSize: 12),
hoverColor: theme.hover,
rightIcon: checkmark,
onTap: () => onSelected(dateFormat),
),
);
@ -170,13 +189,19 @@ extension DateFormatExtension on DateFormat {
}
class TimeFormatList extends StatelessWidget {
final TimeFormat selectedFormat;
final Function(TimeFormat format) onSelected;
const TimeFormatList({required this.onSelected, Key? key}) : super(key: key);
const TimeFormatList({
required this.selectedFormat,
required this.onSelected,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final formatItems = TimeFormat.values.map((format) {
return TimeFormatItem(
isSelected: format == selectedFormat,
timeFormat: format,
onSelected: (format) {
onSelected(format);
@ -207,17 +232,29 @@ class TimeFormatList extends StatelessWidget {
class TimeFormatItem extends StatelessWidget {
final TimeFormat timeFormat;
final bool isSelected;
final Function(TimeFormat format) onSelected;
const TimeFormatItem({required this.timeFormat, required this.onSelected, Key? key}) : super(key: key);
const TimeFormatItem({
required this.timeFormat,
required this.onSelected,
required this.isSelected,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
Widget? checkmark;
if (isSelected) {
checkmark = svg("grid/checkmark");
}
return SizedBox(
height: GridSize.typeOptionItemHeight,
child: FlowyButton(
text: FlowyText.medium(timeFormat.title(), fontSize: 12),
hoverColor: theme.hover,
rightIcon: checkmark,
onTap: () => onSelected(timeFormat),
),
);