mirror of
				https://github.com/AppFlowy-IO/AppFlowy.git
				synced 2025-11-03 19:43:52 +00:00 
			
		
		
		
	chore: set time
This commit is contained in:
		
							parent
							
								
									81d75147d5
								
							
						
					
					
						commit
						a2dfc8bc03
					
				@ -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(),
 | 
			
		||||
      );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,7 @@ class _InputTextFieldState extends State<InputTextField> {
 | 
			
		||||
          widget.onChanged!(text);
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      onEditingComplete: () {
 | 
			
		||||
      onEditingComplete: (_) {
 | 
			
		||||
        if (widget.onDone != null) {
 | 
			
		||||
          widget.onDone!(_controller.text);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user