|
@@ -2,6 +2,7 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
|
|
|
import 'package:app_flowy/plugins/grid/application/cell/date_cal_bloc.dart';
|
|
|
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
|
|
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
|
|
+import 'package:dartz/dartz.dart' show Either;
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
|
import 'package:flowy_infra/image.dart';
|
|
|
import 'package:flowy_infra/theme.dart';
|
|
@@ -11,6 +12,7 @@ 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-error/errors.pbserver.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';
|
|
@@ -39,39 +41,42 @@ class DateCellEditor extends StatefulWidget {
|
|
|
}
|
|
|
|
|
|
class _DateCellEditor extends State<DateCellEditor> {
|
|
|
- DateTypeOptionPB? _dateTypeOptionPB;
|
|
|
-
|
|
|
- @override
|
|
|
- void initState() {
|
|
|
- super.initState();
|
|
|
- _fetchData();
|
|
|
- }
|
|
|
-
|
|
|
- _fetchData() async {
|
|
|
- final result = await widget.cellController
|
|
|
- .getFieldTypeOption(DateTypeOptionDataParser());
|
|
|
-
|
|
|
- result.fold((dateTypeOptionPB) {
|
|
|
- setState(() {
|
|
|
- _dateTypeOptionPB = dateTypeOptionPB;
|
|
|
- });
|
|
|
- }, (err) => Log.error(err));
|
|
|
- }
|
|
|
-
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
- if (_dateTypeOptionPB == null) {
|
|
|
- return Container();
|
|
|
- }
|
|
|
+ return FutureBuilder<Either<dynamic, FlowyError>>(
|
|
|
+ future: widget.cellController.getFieldTypeOption(
|
|
|
+ DateTypeOptionDataParser(),
|
|
|
+ ),
|
|
|
+ builder: (BuildContext context, snapshot) {
|
|
|
+ if (snapshot.hasData) {
|
|
|
+ return _buildWidget(snapshot);
|
|
|
+ } else {
|
|
|
+ return const SizedBox();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
- return _CellCalendarWidget(
|
|
|
- cellContext: widget.cellController,
|
|
|
- dateTypeOptionPB: _dateTypeOptionPB!,
|
|
|
+ Widget _buildWidget(AsyncSnapshot<Either<dynamic, FlowyError>> snapshot) {
|
|
|
+ return snapshot.data!.fold(
|
|
|
+ (dateTypeOptionPB) {
|
|
|
+ return Padding(
|
|
|
+ padding: const EdgeInsets.all(12),
|
|
|
+ child: _CellCalendarWidget(
|
|
|
+ cellContext: widget.cellController,
|
|
|
+ dateTypeOptionPB: dateTypeOptionPB,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ },
|
|
|
+ (err) {
|
|
|
+ Log.error(err);
|
|
|
+ return const SizedBox();
|
|
|
+ },
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-class _CellCalendarWidget extends StatelessWidget {
|
|
|
+class _CellCalendarWidget extends StatefulWidget {
|
|
|
final GridDateCellController cellContext;
|
|
|
final DateTypeOptionPB dateTypeOptionPB;
|
|
|
|
|
@@ -81,26 +86,43 @@ class _CellCalendarWidget extends StatelessWidget {
|
|
|
Key? key,
|
|
|
}) : super(key: key);
|
|
|
|
|
|
+ @override
|
|
|
+ State<_CellCalendarWidget> createState() => _CellCalendarWidgetState();
|
|
|
+}
|
|
|
+
|
|
|
+class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
|
|
|
+ late PopoverMutex popoverMutex;
|
|
|
+ late DateCalBloc bloc;
|
|
|
+
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ popoverMutex = PopoverMutex();
|
|
|
+
|
|
|
+ bloc = DateCalBloc(
|
|
|
+ dateTypeOptionPB: widget.dateTypeOptionPB,
|
|
|
+ cellData: widget.cellContext.getCellData(),
|
|
|
+ cellController: widget.cellContext,
|
|
|
+ )..add(const DateCalEvent.initial());
|
|
|
+ super.initState();
|
|
|
+ }
|
|
|
+
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
final theme = context.watch<AppTheme>();
|
|
|
- return BlocProvider(
|
|
|
- create: (context) {
|
|
|
- return DateCalBloc(
|
|
|
- dateTypeOptionPB: dateTypeOptionPB,
|
|
|
- cellData: cellContext.getCellData(),
|
|
|
- cellController: cellContext,
|
|
|
- )..add(const DateCalEvent.initial());
|
|
|
- },
|
|
|
+ return BlocProvider.value(
|
|
|
+ value: bloc,
|
|
|
child: BlocBuilder<DateCalBloc, DateCalState>(
|
|
|
buildWhen: (p, c) => false,
|
|
|
builder: (context, state) {
|
|
|
List<Widget> children = [
|
|
|
_buildCalendar(theme, context),
|
|
|
- _TimeTextField(bloc: context.read<DateCalBloc>()),
|
|
|
+ _TimeTextField(
|
|
|
+ bloc: context.read<DateCalBloc>(),
|
|
|
+ popoverMutex: popoverMutex,
|
|
|
+ ),
|
|
|
Divider(height: 1, color: theme.shader5),
|
|
|
const _IncludeTimeButton(),
|
|
|
- const _DateTypeOptionButton()
|
|
|
+ _DateTypeOptionButton(popoverMutex: popoverMutex)
|
|
|
];
|
|
|
|
|
|
return ListView.separated(
|
|
@@ -119,6 +141,13 @@ class _CellCalendarWidget extends StatelessWidget {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ bloc.close();
|
|
|
+ popoverMutex.dispose();
|
|
|
+ super.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
Widget _buildCalendar(AppTheme theme, BuildContext context) {
|
|
|
return BlocBuilder<DateCalBloc, DateCalState>(
|
|
|
builder: (context, state) {
|
|
@@ -218,8 +247,10 @@ class _IncludeTimeButton extends StatelessWidget {
|
|
|
|
|
|
class _TimeTextField extends StatefulWidget {
|
|
|
final DateCalBloc bloc;
|
|
|
+ final PopoverMutex popoverMutex;
|
|
|
const _TimeTextField({
|
|
|
required this.bloc,
|
|
|
+ required this.popoverMutex,
|
|
|
Key? key,
|
|
|
}) : super(key: key);
|
|
|
|
|
@@ -240,9 +271,18 @@ class _TimeTextFieldState extends State<_TimeTextField> {
|
|
|
if (mounted) {
|
|
|
widget.bloc.add(DateCalEvent.setTime(_controller.text));
|
|
|
}
|
|
|
+
|
|
|
+ if (_focusNode.hasFocus) {
|
|
|
+ widget.popoverMutex.close();
|
|
|
+ }
|
|
|
});
|
|
|
- }
|
|
|
|
|
|
+ widget.popoverMutex.listenOnPopoverChanged(() {
|
|
|
+ if (_focusNode.hasFocus) {
|
|
|
+ _focusNode.unfocus();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
super.initState();
|
|
|
}
|
|
|
|
|
@@ -290,7 +330,11 @@ class _TimeTextFieldState extends State<_TimeTextField> {
|
|
|
}
|
|
|
|
|
|
class _DateTypeOptionButton extends StatelessWidget {
|
|
|
- const _DateTypeOptionButton({Key? key}) : super(key: key);
|
|
|
+ final PopoverMutex popoverMutex;
|
|
|
+ const _DateTypeOptionButton({
|
|
|
+ required this.popoverMutex,
|
|
|
+ Key? key,
|
|
|
+ }) : super(key: key);
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
@@ -301,6 +345,7 @@ class _DateTypeOptionButton extends StatelessWidget {
|
|
|
selector: (state) => state.dateTypeOptionPB,
|
|
|
builder: (context, dateTypeOptionPB) {
|
|
|
return AppFlowyPopover(
|
|
|
+ mutex: popoverMutex,
|
|
|
triggerActions: PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
|
|
|
offset: const Offset(20, 0),
|
|
|
constraints: BoxConstraints.loose(const Size(140, 100)),
|
|
@@ -313,7 +358,10 @@ class _DateTypeOptionButton extends StatelessWidget {
|
|
|
popupBuilder: (BuildContext popContext) {
|
|
|
return _CalDateTimeSetting(
|
|
|
dateTypeOptionPB: dateTypeOptionPB,
|
|
|
- onEvent: (event) => context.read<DateCalBloc>().add(event),
|
|
|
+ onEvent: (event) {
|
|
|
+ context.read<DateCalBloc>().add(event);
|
|
|
+ popoverMutex.close();
|
|
|
+ },
|
|
|
);
|
|
|
},
|
|
|
);
|
|
@@ -325,46 +373,49 @@ class _DateTypeOptionButton extends StatelessWidget {
|
|
|
class _CalDateTimeSetting extends StatefulWidget {
|
|
|
final DateTypeOptionPB dateTypeOptionPB;
|
|
|
final Function(DateCalEvent) onEvent;
|
|
|
- const _CalDateTimeSetting(
|
|
|
- {required this.dateTypeOptionPB, required this.onEvent, Key? key})
|
|
|
- : super(key: key);
|
|
|
+ const _CalDateTimeSetting({
|
|
|
+ required this.dateTypeOptionPB,
|
|
|
+ required this.onEvent,
|
|
|
+ Key? key,
|
|
|
+ }) : super(key: key);
|
|
|
|
|
|
@override
|
|
|
State<_CalDateTimeSetting> createState() => _CalDateTimeSettingState();
|
|
|
}
|
|
|
|
|
|
class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
|
|
|
+ final timeSettingPopoverMutex = PopoverMutex();
|
|
|
String? overlayIdentifier;
|
|
|
- final _popoverMutex = PopoverMutex();
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
List<Widget> children = [
|
|
|
AppFlowyPopover(
|
|
|
- mutex: _popoverMutex,
|
|
|
- asBarrier: true,
|
|
|
+ mutex: timeSettingPopoverMutex,
|
|
|
triggerActions: PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
|
|
|
offset: const Offset(20, 0),
|
|
|
popupBuilder: (BuildContext context) {
|
|
|
return DateFormatList(
|
|
|
selectedFormat: widget.dateTypeOptionPB.dateFormat,
|
|
|
- onSelected: (format) =>
|
|
|
- widget.onEvent(DateCalEvent.setDateFormat(format)),
|
|
|
+ onSelected: (format) {
|
|
|
+ widget.onEvent(DateCalEvent.setDateFormat(format));
|
|
|
+ timeSettingPopoverMutex.close();
|
|
|
+ },
|
|
|
);
|
|
|
},
|
|
|
child: const DateFormatButton(),
|
|
|
),
|
|
|
AppFlowyPopover(
|
|
|
- mutex: _popoverMutex,
|
|
|
- asBarrier: true,
|
|
|
+ mutex: timeSettingPopoverMutex,
|
|
|
triggerActions: PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
|
|
|
offset: const Offset(20, 0),
|
|
|
popupBuilder: (BuildContext context) {
|
|
|
return TimeFormatList(
|
|
|
- selectedFormat: widget.dateTypeOptionPB.timeFormat,
|
|
|
- onSelected: (format) =>
|
|
|
- widget.onEvent(DateCalEvent.setTimeFormat(format)),
|
|
|
- );
|
|
|
+ selectedFormat: widget.dateTypeOptionPB.timeFormat,
|
|
|
+ onSelected: (format) {
|
|
|
+ widget.onEvent(DateCalEvent.setTimeFormat(format));
|
|
|
+ timeSettingPopoverMutex.close();
|
|
|
+ });
|
|
|
},
|
|
|
child: TimeFormatButton(timeFormat: widget.dateTypeOptionPB.timeFormat),
|
|
|
),
|