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: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/date_type_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -16,13 +17,17 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
final GridDefaultCellContext cellContext;
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>(
(event, emit) async {
await event.map(
initial: (_Initial value) async {
_startListening();
await _loadDateTypeOption(emit);
// await _loadDateTypeOption(emit);
},
selectDay: (_SelectDay value) {
if (!isSameDay(state.selectedDay, value.day)) {
@ -46,6 +51,7 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
setTimeFormat: (_TimeFormat value) async {
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 {
final result = await cellContext.getTypeOptionData();
result.fold(
(data) {
final typeOptionData = DateTypeOption.fromBuffer(data);
DateTime? selectedDay;
final cellData = cellContext.getCellData()?.data;
@ -86,7 +92,7 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
}
emit(state.copyWith(
dateTypeOption: some(typeOptionData),
dateTypeOption: typeOptionData,
selectedDay: selectedDay,
));
},
@ -105,35 +111,31 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
TimeFormat? timeFormat,
bool? includeTime,
}) async {
final newDateTypeOption = state.dateTypeOption.fold(() => null, (dateTypeOption) {
dateTypeOption.freeze();
return dateTypeOption.rebuild((typeOption) {
if (dateFormat != null) {
typeOption.dateFormat = dateFormat;
}
state.dateTypeOption.freeze();
final newDateTypeOption = state.dateTypeOption.rebuild((typeOption) {
if (dateFormat != null) {
typeOption.dateFormat = dateFormat;
}
if (timeFormat != null) {
typeOption.timeFormat = timeFormat;
}
if (timeFormat != null) {
typeOption.timeFormat = timeFormat;
}
if (includeTime != null) {
typeOption.includeTime = includeTime;
}
});
if (includeTime != null) {
typeOption.includeTime = includeTime;
}
});
if (newDateTypeOption != null) {
final result = await FieldService.updateFieldTypeOption(
gridId: cellContext.gridId,
fieldId: cellContext.field.id,
typeOptionData: newDateTypeOption.writeToBuffer(),
);
final result = await FieldService.updateFieldTypeOption(
gridId: cellContext.gridId,
fieldId: cellContext.field.id,
typeOptionData: newDateTypeOption.writeToBuffer(),
);
result.fold(
(l) => emit(state.copyWith(dateTypeOption: Some(newDateTypeOption))),
(err) => Log.error(err),
);
}
result.fold(
(l) => emit(state.copyWith(dateTypeOption: newDateTypeOption)),
(err) => Log.error(err),
);
}
}
@ -146,23 +148,31 @@ class DateCalEvent with _$DateCalEvent {
const factory DateCalEvent.setTimeFormat(TimeFormat timeFormat) = _TimeFormat;
const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat;
const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime;
const factory DateCalEvent.setTime(String time) = _Time;
const factory DateCalEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate;
}
@freezed
class DateCalState with _$DateCalState {
const factory DateCalState({
required Option<DateTypeOption> dateTypeOption,
required DateTypeOption dateTypeOption,
required CalendarFormat format,
required DateTime focusedDay,
required Option<String> time,
required String time,
required Option<FlowyError> inputTimeError,
DateTime? selectedDay,
}) = _DateCalState;
factory DateCalState.initial(GridCellContext context) => DateCalState(
dateTypeOption: none(),
factory DateCalState.initial(
DateTypeOption dateTypeOption,
DateTime? selectedDay,
) =>
DateCalState(
dateTypeOption: dateTypeOption,
format: CalendarFormat.month,
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/style_widget/button.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_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:table_calendar/table_calendar.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 kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day);
@ -35,22 +37,38 @@ class CellCalendar with FlowyOverlayDelegate {
}) async {
CellCalendar.remove(context);
final calendar = _CellCalendarWidget(
onSelected: onSelected,
includeTime: false,
cellContext: cellContext,
);
final result = await cellContext.getTypeOptionData();
result.fold(
(data) {
final typeOptionData = DateTypeOption.fromBuffer(data);
DateTime? selectedDay;
final cellData = cellContext.getCellData()?.data;
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,
if (cellData != null) {
final timestamp = $fixnum.Int64.parseInt(cellData).toInt();
selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
}
final calendar = _CellCalendarWidget(
onSelected: onSelected,
cellContext: cellContext,
dateTypeOption: typeOptionData,
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 {
final bool includeTime;
final GridDefaultCellContext cellContext;
final DateTypeOption dateTypeOption;
final DateTime? selectedDay;
final void Function(DateTime) onSelected;
const _CellCalendarWidget({
required this.onSelected,
required this.includeTime,
required this.cellContext,
required this.dateTypeOption,
this.selectedDay,
Key? key,
}) : super(key: key);
@ -85,7 +105,11 @@ class _CellCalendarWidget extends StatelessWidget {
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
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>(
listener: (context, state) {
if (state.selectedDay != null) {
@ -101,12 +125,11 @@ class _CellCalendarWidget extends StatelessWidget {
const VSpace(10),
]);
state.dateTypeOption.foldRight(null, (dateTypeOption, _) {
if (state.dateTypeOption.includeTime) {
children.addAll([
const _TimeTextField(),
const VSpace(10),
]);
});
}
children.addAll([
Divider(height: 1, color: theme.shader5),
@ -189,7 +212,7 @@ class _IncludeTimeButton extends StatelessWidget {
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return BlocSelector<DateCalBloc, DateCalState, bool>(
selector: (state) => state.dateTypeOption.foldRight(false, (option, _) => option.includeTime),
selector: (state) => state.dateTypeOption.includeTime,
builder: (context, includeTime) {
return SizedBox(
height: 50,
@ -219,7 +242,19 @@ class _TimeTextField extends StatelessWidget {
@override
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) {
final theme = context.watch<AppTheme>();
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,
builder: (context, dateTypeOption) {
return FlowyButton(
text: FlowyText.medium(title, fontSize: 12),
hoverColor: theme.hover,
margin: kMargin,
onTap: () {
dateTypeOption.fold(() => null, (dateTypeOption) {
final setting = _CalDateTimeSetting(dateTypeOption: dateTypeOption);
setting.show(context);
});
},
onTap: () => _showTimeSetting(dateTypeOption, context),
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 {
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
State<_CalDateTimeSetting> createState() => _CalDateTimeSettingState();
@ -283,9 +322,7 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
DateFormatButton(onTap: () {
final list = DateFormatList(
selectedFormat: widget.dateTypeOption.dateFormat,
onSelected: (format) {
context.read<DateCalBloc>().add(DateCalEvent.setDateFormat(format));
},
onSelected: (format) => widget.onEvent(DateCalEvent.setDateFormat(format)),
);
_showOverlay(context, list);
}),
@ -294,9 +331,7 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
onTap: () {
final list = TimeFormatList(
selectedFormat: widget.dateTypeOption.timeFormat,
onSelected: (format) {
context.read<DateCalBloc>().add(DateCalEvent.setTimeFormat(format));
},
onSelected: (format) => widget.onEvent(DateCalEvent.setTimeFormat(format)),
);
_showOverlay(context, list);
},

View File

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

View File

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