mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: mobile card detail screen (#3935)
* feat: add CardDetailScreen and CardPropertyEditScreen - add basic UI layout for these two screens - add MobileTextCell as the GridCellWidget adapts to mobile * feat: add MobileNumberCell and MobileTimestampCell * feat: Add MobileDateCell and MobileCheckboxCell - Add MobileDateCellEditScreen - Add dateStr and endDateStr in DateCellCalendarState * feat: add MobileFieldTypeOptionEditor - Add placeholder for different TypeOptionMobileWidgetBuilders - Add _MobileSwitchFieldButton * feat: add property delete feature in CardPropertyEditScreen * fix: fix VisibilitySwitch didn't update * feat: add MobileCreateRowFieldScreen - Refactor MobileFieldEditor to used in CardPropertyEditScreen and MobileCreateRowFieldScreen - Add MobileCreateRowFieldScreen * chore: localization and improve spacing * feat: add TimestampTypeOptionMobileWidget - Refactor TimeFormatListTile to be used in TimestampTypeOptionMobileWidget and _DateCellEditBody - Add IncludeTimeSwitch to be used in TimestampTypeOptionMobileWidget and _DateCellEditBody * feat: add checkbox and DateTypeOptionMobileWidget * chore: improve UI * chore: improve spacing * fix: fix end time shown issue * fix: minor issues * fix: flutter analyze * chore: delete unused TextEditingController * fix: prevent group field from deleting * feat: add NumberTypeOptionMobileWidget * chore: rename and clean code * chore: clean code * chore: extract class * chore: refactor reorder cells * chore: improve super.key * chore: refactor MobileFieldTypeList * chore: reorginize code * chore: remove unused import file * chore: clean code * chore: add commas due to flutter upgrade * feat: add MobileURLCell * fix: close keyboard when user tap outside of textfield * chore: update go_router version * fix: add missing GridCellStyle --------- Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/card/card.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/database_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
||||
@ -10,6 +10,7 @@ import 'package:appflowy/plugins/database_view/board/presentation/widgets/board_
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_extension.dart';
|
||||
import 'package:appflowy/plugins/database_view/tab_bar/tab_bar_view.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
|
||||
import 'package:appflowy/util/platform_extension.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
|
||||
import 'package:appflowy_board/appflowy_board.dart';
|
||||
@ -21,6 +22,7 @@ import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flutter/material.dart' hide Card;
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../widgets/card/cells/card_cell.dart';
|
||||
import '../../widgets/card/card_cell_builder.dart';
|
||||
@ -319,13 +321,23 @@ class _BoardContentState extends State<BoardContent> {
|
||||
groupId: groupId,
|
||||
);
|
||||
|
||||
FlowyOverlay.show(
|
||||
context: context,
|
||||
builder: (_) => RowDetailPage(
|
||||
cellBuilder: GridCellBuilder(cellCache: dataController.cellCache),
|
||||
rowController: dataController,
|
||||
),
|
||||
);
|
||||
// navigate to card detail screen when it is in mobile
|
||||
if (PlatformExtension.isMobile) {
|
||||
context.push(
|
||||
MobileCardDetailScreen.routeName,
|
||||
extra: {
|
||||
'rowController': dataController,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
FlowyOverlay.show(
|
||||
context: context,
|
||||
builder: (_) => RowDetailPage(
|
||||
cellBuilder: GridCellBuilder(cellCache: dataController.cellCache),
|
||||
rowController: dataController,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,5 +123,5 @@ class SwitchFieldButton extends StatelessWidget {
|
||||
}
|
||||
|
||||
abstract class TypeOptionWidget extends StatelessWidget {
|
||||
const TypeOptionWidget({Key? key}) : super(key: key);
|
||||
const TypeOptionWidget({super.key});
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import 'package:appflowy/plugins/database_view/application/row/row_controller.da
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/application/row/row_bloc.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cell_builder.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_property.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
@ -273,7 +274,8 @@ class RowContent extends StatelessWidget {
|
||||
) {
|
||||
return cellByFieldId.values.map(
|
||||
(cellId) {
|
||||
final GridCellWidget child = builder.build(cellId);
|
||||
final cellStyle = customCellStyle(cellId.fieldType);
|
||||
final GridCellWidget child = builder.build(cellId, style: cellStyle);
|
||||
|
||||
return CellContainer(
|
||||
width: cellId.fieldInfo.fieldSettings?.width.toDouble() ?? 140,
|
||||
|
@ -2,6 +2,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/row/action.dart';
|
||||
import 'package:appflowy/util/platform_extension.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
|
||||
@ -122,6 +123,27 @@ class _RowCardState<T> extends State<RowCard<T>> {
|
||||
return !listEquals(previous.cells, current.cells);
|
||||
},
|
||||
builder: (context, state) {
|
||||
// mobile
|
||||
if (PlatformExtension.isMobile) {
|
||||
// TODO(yijing): refactor it in mobile to display card in database view
|
||||
return RowCardContainer(
|
||||
buildAccessoryWhen: () => state.isEditing == false,
|
||||
accessoryBuilder: (context) {
|
||||
return [];
|
||||
},
|
||||
openAccessory: (p0) {},
|
||||
openCard: (context) => widget.openCard(context),
|
||||
child: _CardContent<T>(
|
||||
rowNotifier: rowNotifier,
|
||||
cellBuilder: widget.cellBuilder,
|
||||
styleConfiguration: widget.styleConfiguration,
|
||||
cells: state.cells,
|
||||
renderHook: widget.renderHook,
|
||||
cardData: widget.cardData,
|
||||
),
|
||||
);
|
||||
}
|
||||
// desktop
|
||||
return AppFlowyPopover(
|
||||
controller: popoverController,
|
||||
triggerActions: PopoverTriggerFlags.none,
|
||||
|
@ -1,4 +1,6 @@
|
||||
import 'package:appflowy/mobile/presentation/database/card/row/cells/cells.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy/util/platform_extension.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -23,7 +25,7 @@ class GridCellBuilder {
|
||||
|
||||
GridCellWidget build(
|
||||
DatabaseCellContext cellContext, {
|
||||
GridCellStyle? style,
|
||||
required GridCellStyle? style,
|
||||
}) {
|
||||
final cellControllerBuilder = CellControllerBuilder(
|
||||
cellContext: cellContext,
|
||||
@ -31,6 +33,30 @@ class GridCellBuilder {
|
||||
);
|
||||
|
||||
final key = cellContext.key();
|
||||
|
||||
if (PlatformExtension.isMobile) {
|
||||
return _getMobileCardCellWidget(
|
||||
key,
|
||||
cellContext,
|
||||
cellControllerBuilder,
|
||||
style,
|
||||
);
|
||||
}
|
||||
|
||||
return _getDesktopGridCellWidget(
|
||||
key,
|
||||
cellContext,
|
||||
cellControllerBuilder,
|
||||
style,
|
||||
);
|
||||
}
|
||||
|
||||
GridCellWidget _getDesktopGridCellWidget(
|
||||
ValueKey key,
|
||||
DatabaseCellContext cellContext,
|
||||
CellControllerBuilder cellControllerBuilder,
|
||||
GridCellStyle? style,
|
||||
) {
|
||||
switch (cellContext.fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
return GridCheckboxCell(
|
||||
@ -94,6 +120,74 @@ class GridCellBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// editable cell/(card's propery value) widget
|
||||
GridCellWidget _getMobileCardCellWidget(
|
||||
ValueKey key,
|
||||
DatabaseCellContext cellContext,
|
||||
CellControllerBuilder cellControllerBuilder,
|
||||
GridCellStyle? style,
|
||||
) {
|
||||
switch (cellContext.fieldType) {
|
||||
case FieldType.RichText:
|
||||
style as GridTextCellStyle;
|
||||
return MobileTextCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
hintText: style.placeholder,
|
||||
);
|
||||
case FieldType.Number:
|
||||
style as GridNumberCellStyle;
|
||||
return MobileNumberCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
hintText: style.placeholder,
|
||||
);
|
||||
case FieldType.LastEditedTime:
|
||||
case FieldType.CreatedTime:
|
||||
return MobileTimestampCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.Checkbox:
|
||||
return MobileCheckboxCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
style as DateCellStyle;
|
||||
return MobileDateCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
hintText: style.placeholder,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.URL:
|
||||
style as GridURLCellStyle;
|
||||
return MobileURLCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
hintText: style.placeholder,
|
||||
key: key,
|
||||
);
|
||||
// TODO(yijing): implement the following mobile select option cell
|
||||
case FieldType.SingleSelect:
|
||||
return GridSingleSelectCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.MultiSelect:
|
||||
return GridMultiSelectCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.Checklist:
|
||||
return GridChecklistCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key,
|
||||
);
|
||||
}
|
||||
throw UnimplementedError;
|
||||
}
|
||||
|
||||
class BlankCell extends StatelessWidget {
|
||||
const BlankCell({Key? key}) : super(key: key);
|
||||
|
||||
|
@ -38,20 +38,23 @@ class DateCellCalendarBloc
|
||||
await event.when(
|
||||
initial: () async => _startListening(),
|
||||
didReceiveCellUpdate: (DateCellDataPB? cellData) {
|
||||
final (dateTime, endDateTime, time, endTime, includeTime, isRange) =
|
||||
_dateDataFromCellData(cellData);
|
||||
final dateCellData = _dateDataFromCellData(cellData);
|
||||
final endDay =
|
||||
isRange == state.isRange && isRange ? endDateTime : null;
|
||||
dateCellData.isRange == state.isRange && dateCellData.isRange
|
||||
? dateCellData.endDateTime
|
||||
: null;
|
||||
emit(
|
||||
state.copyWith(
|
||||
dateTime: dateTime,
|
||||
time: time,
|
||||
endDateTime: endDateTime,
|
||||
endTime: endTime,
|
||||
includeTime: includeTime,
|
||||
isRange: isRange,
|
||||
startDay: isRange ? dateTime : null,
|
||||
dateTime: dateCellData.dateTime,
|
||||
timeStr: dateCellData.timeStr,
|
||||
endDateTime: dateCellData.endDateTime,
|
||||
endTimeStr: dateCellData.endTimeStr,
|
||||
includeTime: dateCellData.includeTime,
|
||||
isRange: dateCellData.isRange,
|
||||
startDay: dateCellData.isRange ? dateCellData.dateTime : null,
|
||||
endDay: endDay,
|
||||
dateStr: dateCellData.dateStr,
|
||||
endDateStr: dateCellData.endDateStr,
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -76,21 +79,31 @@ class DateCellCalendarBloc
|
||||
setIsRange: (isRange) async {
|
||||
await _updateDateData(isRange: isRange);
|
||||
},
|
||||
setTime: (time) async {
|
||||
await _updateDateData(time: time);
|
||||
setTime: (timeStr) async {
|
||||
await _updateDateData(timeStr: timeStr);
|
||||
},
|
||||
selectDateRange: (DateTime? start, DateTime? end) async {
|
||||
if (end == null && state.startDay != null && state.endDay == null) {
|
||||
final (newStart, newEnd) = state.startDay!.isBefore(start!)
|
||||
? (state.startDay!, start)
|
||||
: (start, state.startDay!);
|
||||
emit(state.copyWith(startDay: null, endDay: null));
|
||||
emit(
|
||||
state.copyWith(
|
||||
startDay: null,
|
||||
endDay: null,
|
||||
),
|
||||
);
|
||||
await _updateDateData(
|
||||
date: newStart.date,
|
||||
endDate: newEnd.date,
|
||||
);
|
||||
} else if (end == null) {
|
||||
emit(state.copyWith(startDay: start, endDay: null));
|
||||
emit(
|
||||
state.copyWith(
|
||||
startDay: start,
|
||||
endDay: null,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
await _updateDateData(
|
||||
date: start!.date,
|
||||
@ -98,8 +111,54 @@ class DateCellCalendarBloc
|
||||
);
|
||||
}
|
||||
},
|
||||
setStartDay: (DateTime startDay) async {
|
||||
if (state.endDay == null) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
startDay: startDay,
|
||||
),
|
||||
);
|
||||
} else if (startDay.isAfter(state.endDay!)) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
startDay: startDay,
|
||||
endDay: null,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
emit(
|
||||
state.copyWith(
|
||||
startDay: startDay,
|
||||
),
|
||||
);
|
||||
_updateDateData(date: startDay.date, endDate: state.endDay!.date);
|
||||
}
|
||||
},
|
||||
setEndDay: (DateTime endDay) async {
|
||||
if (state.startDay == null) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
endDay: endDay,
|
||||
),
|
||||
);
|
||||
} else if (endDay.isBefore(state.startDay!)) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
startDay: null,
|
||||
endDay: endDay,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
emit(
|
||||
state.copyWith(
|
||||
endDay: endDay,
|
||||
),
|
||||
);
|
||||
_updateDateData(date: state.startDay!.date, endDate: endDay.date);
|
||||
}
|
||||
},
|
||||
setEndTime: (String endTime) async {
|
||||
await _updateDateData(endTime: endTime);
|
||||
await _updateDateData(endTimeStr: endTime);
|
||||
},
|
||||
setDateFormat: (dateFormat) async {
|
||||
await _updateTypeOption(emit, dateFormat: dateFormat);
|
||||
@ -117,30 +176,31 @@ class DateCellCalendarBloc
|
||||
|
||||
Future<void> _updateDateData({
|
||||
DateTime? date,
|
||||
String? time,
|
||||
String? timeStr,
|
||||
DateTime? endDate,
|
||||
String? endTime,
|
||||
String? endTimeStr,
|
||||
bool? includeTime,
|
||||
bool? isRange,
|
||||
}) async {
|
||||
// make sure that not both date and time are updated at the same time
|
||||
assert(
|
||||
!(date != null && time != null) || !(endDate != null && endTime != null),
|
||||
!(date != null && timeStr != null) ||
|
||||
!(endDate != null && endTimeStr != null),
|
||||
);
|
||||
|
||||
// if not updating the time, use the old time in the state
|
||||
final String? newTime = time ?? state.time;
|
||||
final String? newTime = timeStr ?? state.timeStr;
|
||||
DateTime? newDate;
|
||||
if (time != null && time.isNotEmpty) {
|
||||
if (timeStr != null && timeStr.isNotEmpty) {
|
||||
newDate = state.dateTime ?? DateTime.now();
|
||||
} else {
|
||||
newDate = _utcToLocalAndAddCurrentTime(date);
|
||||
}
|
||||
|
||||
// if not updating the time, use the old time in the state
|
||||
final String? newEndTime = endTime ?? state.endTime;
|
||||
final String? newEndTime = endTimeStr ?? state.endTimeStr;
|
||||
DateTime? newEndDate;
|
||||
if (endTime != null && endTime.isNotEmpty) {
|
||||
if (endTimeStr != null && endTimeStr.isNotEmpty) {
|
||||
newEndDate = state.endDateTime ?? DateTime.now();
|
||||
} else {
|
||||
newEndDate = _utcToLocalAndAddCurrentTime(endDate);
|
||||
@ -306,6 +366,12 @@ class DateCellCalendarEvent with _$DateCellCalendarEvent {
|
||||
DateTime? start,
|
||||
DateTime? end,
|
||||
) = _SelectDateRange;
|
||||
const factory DateCellCalendarEvent.setStartDay(
|
||||
DateTime startDay,
|
||||
) = _SetStartDay;
|
||||
const factory DateCellCalendarEvent.setEndDay(
|
||||
DateTime endDay,
|
||||
) = _SetEndDay;
|
||||
const factory DateCellCalendarEvent.setTime(String time) = _Time;
|
||||
const factory DateCellCalendarEvent.setEndTime(String endTime) = _EndTime;
|
||||
const factory DateCellCalendarEvent.setIncludeTime(bool includeTime) =
|
||||
@ -334,10 +400,12 @@ class DateCellCalendarState with _$DateCellCalendarState {
|
||||
// cell data from the backend
|
||||
required DateTime? dateTime,
|
||||
required DateTime? endDateTime,
|
||||
required String? time,
|
||||
required String? endTime,
|
||||
required String? timeStr,
|
||||
required String? endTimeStr,
|
||||
required bool includeTime,
|
||||
required bool isRange,
|
||||
required String? dateStr,
|
||||
required String? endDateStr,
|
||||
|
||||
// error and hint text
|
||||
required String? parseTimeError,
|
||||
@ -349,18 +417,19 @@ class DateCellCalendarState with _$DateCellCalendarState {
|
||||
DateTypeOptionPB dateTypeOptionPB,
|
||||
DateCellDataPB? cellData,
|
||||
) {
|
||||
final (dateTime, endDateTime, time, endTime, includeTime, isRange) =
|
||||
_dateDataFromCellData(cellData);
|
||||
final dateCellData = _dateDataFromCellData(cellData);
|
||||
return DateCellCalendarState(
|
||||
dateTypeOptionPB: dateTypeOptionPB,
|
||||
startDay: isRange ? dateTime : null,
|
||||
endDay: isRange ? endDateTime : null,
|
||||
dateTime: dateTime,
|
||||
endDateTime: endDateTime,
|
||||
time: time,
|
||||
endTime: endTime,
|
||||
includeTime: includeTime,
|
||||
isRange: isRange,
|
||||
startDay: dateCellData.isRange ? dateCellData.dateTime : null,
|
||||
endDay: dateCellData.isRange ? dateCellData.endDateTime : null,
|
||||
dateTime: dateCellData.dateTime,
|
||||
endDateTime: dateCellData.endDateTime,
|
||||
timeStr: dateCellData.timeStr,
|
||||
endTimeStr: dateCellData.endTimeStr,
|
||||
dateStr: dateCellData.dateStr,
|
||||
endDateStr: dateCellData.endDateStr,
|
||||
includeTime: dateCellData.includeTime,
|
||||
isRange: dateCellData.isRange,
|
||||
parseTimeError: null,
|
||||
parseEndTimeError: null,
|
||||
timeHintText: _timeHintText(dateTypeOptionPB),
|
||||
@ -379,31 +448,78 @@ String _timeHintText(DateTypeOptionPB typeOption) {
|
||||
}
|
||||
}
|
||||
|
||||
(DateTime?, DateTime?, String?, String?, bool, bool) _dateDataFromCellData(
|
||||
DateCellData _dateDataFromCellData(
|
||||
DateCellDataPB? cellData,
|
||||
) {
|
||||
// a null DateCellDataPB may be returned, indicating that all the fields are
|
||||
// their default values: empty strings and false booleans
|
||||
if (cellData == null) {
|
||||
return (null, null, null, null, false, false);
|
||||
return DateCellData(
|
||||
dateTime: null,
|
||||
endDateTime: null,
|
||||
timeStr: null,
|
||||
endTimeStr: null,
|
||||
includeTime: false,
|
||||
isRange: false,
|
||||
dateStr: null,
|
||||
endDateStr: null,
|
||||
);
|
||||
}
|
||||
|
||||
DateTime? dateTime;
|
||||
String? time;
|
||||
String? timeStr;
|
||||
DateTime? endDateTime;
|
||||
String? endTime;
|
||||
String? endTimeStr;
|
||||
|
||||
String? endDateStr;
|
||||
if (cellData.hasTimestamp()) {
|
||||
final timestamp = cellData.timestamp * 1000;
|
||||
dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt());
|
||||
time = cellData.time;
|
||||
timeStr = cellData.time;
|
||||
if (cellData.hasEndTimestamp()) {
|
||||
final endTimestamp = cellData.endTimestamp * 1000;
|
||||
endDateTime = DateTime.fromMillisecondsSinceEpoch(endTimestamp.toInt());
|
||||
endTime = cellData.endTime;
|
||||
endTimeStr = cellData.endTime;
|
||||
}
|
||||
}
|
||||
final bool includeTime = cellData.includeTime;
|
||||
final bool isRange = cellData.isRange;
|
||||
|
||||
return (dateTime, endDateTime, time, endTime, includeTime, isRange);
|
||||
if (cellData.isRange) {
|
||||
endDateStr = cellData.endDate;
|
||||
}
|
||||
final String dateStr = cellData.date;
|
||||
|
||||
return DateCellData(
|
||||
dateTime: dateTime,
|
||||
endDateTime: endDateTime,
|
||||
timeStr: timeStr,
|
||||
endTimeStr: endTimeStr,
|
||||
includeTime: includeTime,
|
||||
isRange: isRange,
|
||||
dateStr: dateStr,
|
||||
endDateStr: endDateStr,
|
||||
);
|
||||
}
|
||||
|
||||
class DateCellData {
|
||||
final DateTime? dateTime;
|
||||
final DateTime? endDateTime;
|
||||
final String? timeStr;
|
||||
final String? endTimeStr;
|
||||
final bool includeTime;
|
||||
final bool isRange;
|
||||
final String? dateStr;
|
||||
final String? endDateStr;
|
||||
|
||||
DateCellData({
|
||||
required this.dateTime,
|
||||
required this.endDateTime,
|
||||
required this.timeStr,
|
||||
required this.endTimeStr,
|
||||
required this.includeTime,
|
||||
required this.isRange,
|
||||
required this.dateStr,
|
||||
required this.endDateStr,
|
||||
});
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ class StartTextField extends StatelessWidget {
|
||||
child: state.includeTime
|
||||
? _TimeTextField(
|
||||
isEndTime: false,
|
||||
timeStr: state.time,
|
||||
timeStr: state.timeStr,
|
||||
popoverMutex: popoverMutex,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
@ -161,7 +161,7 @@ class EndTextField extends StatelessWidget {
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: _TimeTextField(
|
||||
isEndTime: true,
|
||||
timeStr: state.endTime,
|
||||
timeStr: state.endTimeStr,
|
||||
popoverMutex: popoverMutex,
|
||||
),
|
||||
)
|
||||
@ -413,17 +413,17 @@ class _TimeTextFieldState extends State<_TimeTextField> {
|
||||
return BlocConsumer<DateCellCalendarBloc, DateCellCalendarState>(
|
||||
listener: (context, state) {
|
||||
if (widget.isEndTime) {
|
||||
_textController.text = state.endTime ?? "";
|
||||
_textController.text = state.endTimeStr ?? "";
|
||||
} else {
|
||||
_textController.text = state.time ?? "";
|
||||
_textController.text = state.timeStr ?? "";
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
String text = "";
|
||||
if (!widget.isEndTime && state.time != null) {
|
||||
text = state.time!;
|
||||
} else if (state.endTime != null) {
|
||||
text = state.endTime!;
|
||||
if (!widget.isEndTime && state.timeStr != null) {
|
||||
text = state.timeStr!;
|
||||
} else if (state.endTimeStr != null) {
|
||||
text = state.endTimeStr!;
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
|
@ -134,7 +134,7 @@ class _PropertyCellState extends State<_PropertyCell> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final style = _customCellStyle(widget.cellContext.fieldType);
|
||||
final style = customCellStyle(widget.cellContext.fieldType);
|
||||
final cell = widget.cellBuilder.build(widget.cellContext, style: style);
|
||||
|
||||
final dragThumb = MouseRegion(
|
||||
@ -247,7 +247,7 @@ class _PropertyCellState extends State<_PropertyCell> {
|
||||
}
|
||||
}
|
||||
|
||||
GridCellStyle? _customCellStyle(FieldType fieldType) {
|
||||
GridCellStyle? customCellStyle(FieldType fieldType) {
|
||||
switch (fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
return GridCheckboxCellStyle(
|
||||
|
Reference in New Issue
Block a user