chore: set time

This commit is contained in:
appflowy 2022-05-10 10:26:40 +08:00
parent 81d75147d5
commit a2dfc8bc03
4 changed files with 123 additions and 74 deletions

View File

@ -1,5 +1,6 @@
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell;
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -16,13 +17,17 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
final GridDefaultCellContext cellContext; final GridDefaultCellContext cellContext;
void Function()? _onCellChangedFn; void Function()? _onCellChangedFn;
DateCalBloc({required this.cellContext}) : super(DateCalState.initial(cellContext)) { DateCalBloc({
required DateTypeOption dateTypeOption,
required DateTime? selectedDay,
required this.cellContext,
}) : super(DateCalState.initial(dateTypeOption, selectedDay)) {
on<DateCalEvent>( on<DateCalEvent>(
(event, emit) async { (event, emit) async {
await event.map( await event.map(
initial: (_Initial value) async { initial: (_Initial value) async {
_startListening(); _startListening();
await _loadDateTypeOption(emit); // await _loadDateTypeOption(emit);
}, },
selectDay: (_SelectDay value) { selectDay: (_SelectDay value) {
if (!isSameDay(state.selectedDay, value.day)) { if (!isSameDay(state.selectedDay, value.day)) {
@ -46,6 +51,7 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
setTimeFormat: (_TimeFormat value) async { setTimeFormat: (_TimeFormat value) async {
await _updateTypeOption(emit, timeFormat: value.timeFormat); await _updateTypeOption(emit, timeFormat: value.timeFormat);
}, },
setTime: (_Time value) {},
); );
}, },
); );
@ -71,12 +77,12 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
); );
} }
// ignore: unused_element
Future<void> _loadDateTypeOption(Emitter<DateCalState> emit) async { Future<void> _loadDateTypeOption(Emitter<DateCalState> emit) async {
final result = await cellContext.getTypeOptionData(); final result = await cellContext.getTypeOptionData();
result.fold( result.fold(
(data) { (data) {
final typeOptionData = DateTypeOption.fromBuffer(data); final typeOptionData = DateTypeOption.fromBuffer(data);
DateTime? selectedDay; DateTime? selectedDay;
final cellData = cellContext.getCellData()?.data; final cellData = cellContext.getCellData()?.data;
@ -86,7 +92,7 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
} }
emit(state.copyWith( emit(state.copyWith(
dateTypeOption: some(typeOptionData), dateTypeOption: typeOptionData,
selectedDay: selectedDay, selectedDay: selectedDay,
)); ));
}, },
@ -105,35 +111,31 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
TimeFormat? timeFormat, TimeFormat? timeFormat,
bool? includeTime, bool? includeTime,
}) async { }) async {
final newDateTypeOption = state.dateTypeOption.fold(() => null, (dateTypeOption) { state.dateTypeOption.freeze();
dateTypeOption.freeze(); final newDateTypeOption = state.dateTypeOption.rebuild((typeOption) {
return dateTypeOption.rebuild((typeOption) { if (dateFormat != null) {
if (dateFormat != null) { typeOption.dateFormat = dateFormat;
typeOption.dateFormat = dateFormat; }
}
if (timeFormat != null) { if (timeFormat != null) {
typeOption.timeFormat = timeFormat; typeOption.timeFormat = timeFormat;
} }
if (includeTime != null) { if (includeTime != null) {
typeOption.includeTime = includeTime; typeOption.includeTime = includeTime;
} }
});
}); });
if (newDateTypeOption != null) { final result = await FieldService.updateFieldTypeOption(
final result = await FieldService.updateFieldTypeOption( gridId: cellContext.gridId,
gridId: cellContext.gridId, fieldId: cellContext.field.id,
fieldId: cellContext.field.id, typeOptionData: newDateTypeOption.writeToBuffer(),
typeOptionData: newDateTypeOption.writeToBuffer(), );
);
result.fold( result.fold(
(l) => emit(state.copyWith(dateTypeOption: Some(newDateTypeOption))), (l) => emit(state.copyWith(dateTypeOption: newDateTypeOption)),
(err) => Log.error(err), (err) => Log.error(err),
); );
}
} }
} }
@ -146,23 +148,31 @@ class DateCalEvent with _$DateCalEvent {
const factory DateCalEvent.setTimeFormat(TimeFormat timeFormat) = _TimeFormat; const factory DateCalEvent.setTimeFormat(TimeFormat timeFormat) = _TimeFormat;
const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat; const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat;
const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime; const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime;
const factory DateCalEvent.setTime(String time) = _Time;
const factory DateCalEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; const factory DateCalEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate;
} }
@freezed @freezed
class DateCalState with _$DateCalState { class DateCalState with _$DateCalState {
const factory DateCalState({ const factory DateCalState({
required Option<DateTypeOption> dateTypeOption, required DateTypeOption dateTypeOption,
required CalendarFormat format, required CalendarFormat format,
required DateTime focusedDay, required DateTime focusedDay,
required Option<String> time, required String time,
required Option<FlowyError> inputTimeError,
DateTime? selectedDay, DateTime? selectedDay,
}) = _DateCalState; }) = _DateCalState;
factory DateCalState.initial(GridCellContext context) => DateCalState( factory DateCalState.initial(
dateTypeOption: none(), DateTypeOption dateTypeOption,
DateTime? selectedDay,
) =>
DateCalState(
dateTypeOption: dateTypeOption,
format: CalendarFormat.month, format: CalendarFormat.month,
focusedDay: DateTime.now(), focusedDay: DateTime.now(),
time: none(), selectedDay: selectedDay,
time: "",
inputTimeError: none(),
); );
} }

View File

@ -8,13 +8,15 @@ import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.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/button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:table_calendar/table_calendar.dart'; import 'package:table_calendar/table_calendar.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart';
import 'package:dartz/dartz.dart' show Option; import 'package:fixnum/fixnum.dart' as $fixnum;
final kToday = DateTime.now(); final kToday = DateTime.now();
final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day);
@ -35,22 +37,38 @@ class CellCalendar with FlowyOverlayDelegate {
}) async { }) async {
CellCalendar.remove(context); CellCalendar.remove(context);
final calendar = _CellCalendarWidget( final result = await cellContext.getTypeOptionData();
onSelected: onSelected, result.fold(
includeTime: false, (data) {
cellContext: cellContext, final typeOptionData = DateTypeOption.fromBuffer(data);
); DateTime? selectedDay;
final cellData = cellContext.getCellData()?.data;
FlowyOverlay.of(context).insertWithAnchor( if (cellData != null) {
widget: OverlayContainer( final timestamp = $fixnum.Int64.parseInt(cellData).toInt();
child: calendar, selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
constraints: BoxConstraints.loose(const Size(320, 500)), }
),
identifier: CellCalendar.identifier(), final calendar = _CellCalendarWidget(
anchorContext: context, onSelected: onSelected,
anchorDirection: AnchorDirection.leftWithCenterAligned, cellContext: cellContext,
style: FlowyOverlayStyle(blur: false), dateTypeOption: typeOptionData,
delegate: this, selectedDay: selectedDay,
);
FlowyOverlay.of(context).insertWithAnchor(
widget: OverlayContainer(
child: calendar,
constraints: BoxConstraints.loose(const Size(320, 500)),
),
identifier: CellCalendar.identifier(),
anchorContext: context,
anchorDirection: AnchorDirection.leftWithCenterAligned,
style: FlowyOverlayStyle(blur: false),
delegate: this,
);
},
(err) => Log.error(err),
); );
} }
@ -70,14 +88,16 @@ class CellCalendar with FlowyOverlayDelegate {
} }
class _CellCalendarWidget extends StatelessWidget { class _CellCalendarWidget extends StatelessWidget {
final bool includeTime;
final GridDefaultCellContext cellContext; final GridDefaultCellContext cellContext;
final DateTypeOption dateTypeOption;
final DateTime? selectedDay;
final void Function(DateTime) onSelected; final void Function(DateTime) onSelected;
const _CellCalendarWidget({ const _CellCalendarWidget({
required this.onSelected, required this.onSelected,
required this.includeTime,
required this.cellContext, required this.cellContext,
required this.dateTypeOption,
this.selectedDay,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@ -85,7 +105,11 @@ class _CellCalendarWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return BlocProvider( return BlocProvider(
create: (context) => DateCalBloc(cellContext: cellContext)..add(const DateCalEvent.initial()), create: (context) => DateCalBloc(
dateTypeOption: dateTypeOption,
selectedDay: selectedDay,
cellContext: cellContext,
)..add(const DateCalEvent.initial()),
child: BlocConsumer<DateCalBloc, DateCalState>( child: BlocConsumer<DateCalBloc, DateCalState>(
listener: (context, state) { listener: (context, state) {
if (state.selectedDay != null) { if (state.selectedDay != null) {
@ -101,12 +125,11 @@ class _CellCalendarWidget extends StatelessWidget {
const VSpace(10), const VSpace(10),
]); ]);
state.dateTypeOption.foldRight(null, (dateTypeOption, _) { if (state.dateTypeOption.includeTime) {
children.addAll([ children.addAll([
const _TimeTextField(), const _TimeTextField(),
const VSpace(10),
]); ]);
}); }
children.addAll([ children.addAll([
Divider(height: 1, color: theme.shader5), Divider(height: 1, color: theme.shader5),
@ -189,7 +212,7 @@ class _IncludeTimeButton extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return BlocSelector<DateCalBloc, DateCalState, bool>( return BlocSelector<DateCalBloc, DateCalState, bool>(
selector: (state) => state.dateTypeOption.foldRight(false, (option, _) => option.includeTime), selector: (state) => state.dateTypeOption.includeTime,
builder: (context, includeTime) { builder: (context, includeTime) {
return SizedBox( return SizedBox(
height: 50, height: 50,
@ -219,7 +242,19 @@ class _TimeTextField extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container(); final theme = context.watch<AppTheme>();
return Padding(
padding: kMargin,
child: RoundedInputField(
height: 40,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
normalBorderColor: theme.shader4,
errorBorderColor: theme.red,
cursorColor: theme.main1,
errorText: context.read<DateCalBloc>().state.inputTimeError.fold(() => "", (error) => error.toString()),
onEditingComplete: (value) => context.read<DateCalBloc>().add(DateCalEvent.setTime(value)),
),
);
} }
} }
@ -230,29 +265,33 @@ class _DateTypeOptionButton extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
final title = LocaleKeys.grid_field_dateFormat.tr() + " &" + LocaleKeys.grid_field_timeFormat.tr(); final title = LocaleKeys.grid_field_dateFormat.tr() + " &" + LocaleKeys.grid_field_timeFormat.tr();
return BlocSelector<DateCalBloc, DateCalState, Option<DateTypeOption>>( return BlocSelector<DateCalBloc, DateCalState, DateTypeOption>(
selector: (state) => state.dateTypeOption, selector: (state) => state.dateTypeOption,
builder: (context, dateTypeOption) { builder: (context, dateTypeOption) {
return FlowyButton( return FlowyButton(
text: FlowyText.medium(title, fontSize: 12), text: FlowyText.medium(title, fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
margin: kMargin, margin: kMargin,
onTap: () { onTap: () => _showTimeSetting(dateTypeOption, context),
dateTypeOption.fold(() => null, (dateTypeOption) {
final setting = _CalDateTimeSetting(dateTypeOption: dateTypeOption);
setting.show(context);
});
},
rightIcon: svgWidget("grid/more", color: theme.iconColor), rightIcon: svgWidget("grid/more", color: theme.iconColor),
); );
}, },
); );
} }
void _showTimeSetting(DateTypeOption dateTypeOption, BuildContext context) {
final setting = _CalDateTimeSetting(
dateTypeOption: dateTypeOption,
onEvent: (event) => context.read<DateCalBloc>().add(event),
);
setting.show(context);
}
} }
class _CalDateTimeSetting extends StatefulWidget { class _CalDateTimeSetting extends StatefulWidget {
final DateTypeOption dateTypeOption; final DateTypeOption dateTypeOption;
const _CalDateTimeSetting({required this.dateTypeOption, Key? key}) : super(key: key); final Function(DateCalEvent) onEvent;
const _CalDateTimeSetting({required this.dateTypeOption, required this.onEvent, Key? key}) : super(key: key);
@override @override
State<_CalDateTimeSetting> createState() => _CalDateTimeSettingState(); State<_CalDateTimeSetting> createState() => _CalDateTimeSettingState();
@ -283,9 +322,7 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
DateFormatButton(onTap: () { DateFormatButton(onTap: () {
final list = DateFormatList( final list = DateFormatList(
selectedFormat: widget.dateTypeOption.dateFormat, selectedFormat: widget.dateTypeOption.dateFormat,
onSelected: (format) { onSelected: (format) => widget.onEvent(DateCalEvent.setDateFormat(format)),
context.read<DateCalBloc>().add(DateCalEvent.setDateFormat(format));
},
); );
_showOverlay(context, list); _showOverlay(context, list);
}), }),
@ -294,9 +331,7 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
onTap: () { onTap: () {
final list = TimeFormatList( final list = TimeFormatList(
selectedFormat: widget.dateTypeOption.timeFormat, selectedFormat: widget.dateTypeOption.timeFormat,
onSelected: (format) { onSelected: (format) => widget.onEvent(DateCalEvent.setTimeFormat(format)),
context.read<DateCalBloc>().add(DateCalEvent.setTimeFormat(format));
},
); );
_showOverlay(context, list); _showOverlay(context, list);
}, },

View File

@ -53,7 +53,7 @@ class _InputTextFieldState extends State<InputTextField> {
widget.onChanged!(text); widget.onChanged!(text);
} }
}, },
onEditingComplete: () { onEditingComplete: (_) {
if (widget.onDone != null) { if (widget.onDone != null) {
widget.onDone!(_controller.text); widget.onDone!(_controller.text);
} }

View File

@ -15,7 +15,7 @@ class RoundedInputField extends StatefulWidget {
final String errorText; final String errorText;
final TextStyle style; final TextStyle style;
final ValueChanged<String>? onChanged; final ValueChanged<String>? onChanged;
final VoidCallback? onEditingComplete; final Function(String)? onEditingComplete;
final String? initialValue; final String? initialValue;
final EdgeInsets margin; final EdgeInsets margin;
final EdgeInsets padding; final EdgeInsets padding;
@ -90,7 +90,11 @@ class _RoundedInputFieldState extends State<RoundedInputField> {
} }
setState(() {}); setState(() {});
}, },
onEditingComplete: widget.onEditingComplete, onEditingComplete: () {
if (widget.onEditingComplete != null) {
widget.onEditingComplete!(inputText);
}
},
cursorColor: widget.cursorColor, cursorColor: widget.cursorColor,
obscureText: obscuteText, obscureText: obscuteText,
style: widget.style, style: widget.style,