Improve focus traversal

This commit is contained in:
Hillel Coren 2021-09-12 22:28:54 +03:00
parent 0eefa84c2f
commit bf8a056117
2 changed files with 130 additions and 135 deletions

View File

@ -23,22 +23,20 @@ class SettingsScreen extends StatelessWidget {
final store = StoreProvider.of<AppState>(context); final store = StoreProvider.of<AppState>(context);
final state = store.state; final state = store.state;
return FocusTraversalGroup( return ListScaffold(
child: ListScaffold( entityType: EntityType.settings,
appBarTitle: ListFilter(
key:
ValueKey('__cleared_at_${state.settingsUIState.filterClearedAt}__'),
entityType: EntityType.settings, entityType: EntityType.settings,
appBarTitle: ListFilter( entityIds: [],
key: ValueKey( filter: state.settingsUIState.filter,
'__cleared_at_${state.settingsUIState.filterClearedAt}__'), onFilterChanged: (value) {
entityType: EntityType.settings, store.dispatch(FilterSettings(value));
entityIds: [], },
filter: state.settingsUIState.filter,
onFilterChanged: (value) {
store.dispatch(FilterSettings(value));
},
),
appBarActions: <Widget>[],
body: SettingsListBuilder(),
), ),
appBarActions: <Widget>[],
body: SettingsListBuilder(),
); );
} }
} }

View File

@ -290,145 +290,142 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
), ),
FormCard( FormCard(
padding: const EdgeInsets.symmetric(horizontal: kMobileDialogPadding), padding: const EdgeInsets.symmetric(horizontal: kMobileDialogPadding),
child: FocusTraversalGroup( child: Table(
policy: ReadingOrderTraversalPolicy(), key: ValueKey('__table_${_updatedAt}__'),
child: Table( columnWidths: {
key: ValueKey('__table_${_updatedAt}__'), showEndDate ? 5 : 4: FixedColumnWidth(kMinInteractiveDimension),
columnWidths: { },
showEndDate ? 5 : 4: FixedColumnWidth(kMinInteractiveDimension), children: [
}, TableRow(
children: [ children: [
TableRow( TableHeader(localization.startDate, isFirst: true),
children: [ TableHeader(localization.startTime),
TableHeader(localization.startDate, isFirst: true), if (showEndDate) TableHeader(localization.endDate),
TableHeader(localization.startTime), TableHeader(localization.endTime),
if (showEndDate) TableHeader(localization.endDate), TableHeader(localization.duration),
TableHeader(localization.endTime), TableHeader(''),
TableHeader(localization.duration), ],
TableHeader(''), decoration: tableHeaderColor.isNotEmpty
], ? BoxDecoration(
decoration: tableHeaderColor.isNotEmpty color: convertHexStringToColor(tableHeaderColor),
? BoxDecoration( )
color: convertHexStringToColor(tableHeaderColor), : null,
) ),
: null, for (var index = 0; index < taskTimes.length; index++)
), TableRow(children: [
for (var index = 0; index < taskTimes.length; index++) Padding(
TableRow(children: [ padding: const EdgeInsets.only(right: kTableColumnGap),
child: DatePicker(
key: ValueKey(
'__${_startTimeUpdatedAt}_${_durationUpdateAt}_${index}__'),
selectedDate: taskTimes[index].startDate == null
? null
: convertDateTimeToSqlDate(
taskTimes[index].startDate.toLocal()),
onSelected: (date) {
final taskTime = taskTimes[index]
.copyWithStartDate(date, syncDates: !showEndDate);
viewModel.onUpdatedTaskTime(taskTime, index);
setState(() {
_startDateUpdatedAt =
DateTime.now().millisecondsSinceEpoch;
});
},
),
),
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: TimePicker(
key: ValueKey('__${_durationUpdateAt}_${index}__'),
selectedDateTime: taskTimes[index].startDate,
onSelected: (timeOfDay) {
final taskTime =
taskTimes[index].copyWithStartTime(timeOfDay);
viewModel.onUpdatedTaskTime(taskTime, index);
setState(() {
_startTimeUpdatedAt =
DateTime.now().millisecondsSinceEpoch;
});
},
),
),
if (showEndDate)
Padding( Padding(
padding: const EdgeInsets.only(right: kTableColumnGap), padding: const EdgeInsets.only(right: kTableColumnGap),
child: DatePicker( child: DatePicker(
key: ValueKey( key: ValueKey(
'__${_startTimeUpdatedAt}_${_durationUpdateAt}_${index}__'), '__${_startDateUpdatedAt}_${_durationUpdateAt}_${_endTimeUpdatedAt}_${index}__'),
selectedDate: taskTimes[index].startDate == null selectedDate: taskTimes[index].endDate == null
? null ? null
: convertDateTimeToSqlDate( : convertDateTimeToSqlDate(
taskTimes[index].startDate.toLocal()), taskTimes[index].endDate.toLocal()),
onSelected: (date) { onSelected: (date) {
final taskTime = taskTimes[index]
.copyWithStartDate(date, syncDates: !showEndDate);
viewModel.onUpdatedTaskTime(taskTime, index);
setState(() {
_startDateUpdatedAt =
DateTime.now().millisecondsSinceEpoch;
});
},
),
),
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: TimePicker(
key: ValueKey('__${_durationUpdateAt}_${index}__'),
selectedDateTime: taskTimes[index].startDate,
onSelected: (timeOfDay) {
final taskTime = final taskTime =
taskTimes[index].copyWithStartTime(timeOfDay); taskTimes[index].copyWithEndDate(date);
viewModel.onUpdatedTaskTime(taskTime, index); viewModel.onUpdatedTaskTime(taskTime, index);
setState(() { setState(() {
_startTimeUpdatedAt = _endDateUpdatedAt =
DateTime.now().millisecondsSinceEpoch; DateTime.now().millisecondsSinceEpoch;
}); });
}, },
), ),
), ),
if (showEndDate) Padding(
Padding( padding: const EdgeInsets.only(right: kTableColumnGap),
padding: const EdgeInsets.only(right: kTableColumnGap), child: TimePicker(
child: DatePicker( key: ValueKey(
key: ValueKey( '__${_endDateUpdatedAt}_${_durationUpdateAt}_${index}__'),
'__${_startDateUpdatedAt}_${_durationUpdateAt}_${_endTimeUpdatedAt}_${index}__'), selectedDateTime: taskTimes[index].endDate,
selectedDate: taskTimes[index].endDate == null isEndTime: true,
? null onSelected: (timeOfDay) {
: convertDateTimeToSqlDate( final taskTime =
taskTimes[index].endDate.toLocal()), taskTimes[index].copyWithEndTime(timeOfDay);
onSelected: (date) { viewModel.onUpdatedTaskTime(taskTime, index);
final taskTime = setState(() {
taskTimes[index].copyWithEndDate(date); _endTimeUpdatedAt =
viewModel.onUpdatedTaskTime(taskTime, index); DateTime.now().millisecondsSinceEpoch;
setState(() { });
_endDateUpdatedAt = },
DateTime.now().millisecondsSinceEpoch;
});
},
),
),
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: TimePicker(
key: ValueKey(
'__${_endDateUpdatedAt}_${_durationUpdateAt}_${index}__'),
selectedDateTime: taskTimes[index].endDate,
isEndTime: true,
onSelected: (timeOfDay) {
final taskTime =
taskTimes[index].copyWithEndTime(timeOfDay);
viewModel.onUpdatedTaskTime(taskTime, index);
setState(() {
_endTimeUpdatedAt =
DateTime.now().millisecondsSinceEpoch;
});
},
),
), ),
Padding( ),
padding: const EdgeInsets.only(right: kTableColumnGap), Padding(
child: DurationPicker( padding: const EdgeInsets.only(right: kTableColumnGap),
key: ValueKey( child: DurationPicker(
'__${_startTimeUpdatedAt}_${_endTimeUpdatedAt}_${_startDateUpdatedAt}_${_endDateUpdatedAt}_${index}__'), key: ValueKey(
onSelected: (Duration duration) { '__${_startTimeUpdatedAt}_${_endTimeUpdatedAt}_${_startDateUpdatedAt}_${_endDateUpdatedAt}_${index}__'),
final taskTime = onSelected: (Duration duration) {
taskTimes[index].copyWithDuration(duration); final taskTime =
viewModel.onUpdatedTaskTime(taskTime, index); taskTimes[index].copyWithDuration(duration);
setState(() { viewModel.onUpdatedTaskTime(taskTime, index);
_durationUpdateAt = setState(() {
DateTime.now().millisecondsSinceEpoch; _durationUpdateAt =
}); DateTime.now().millisecondsSinceEpoch;
}, });
selectedDuration: (taskTimes[index].startDate == null || },
taskTimes[index].endDate == null) selectedDuration: (taskTimes[index].startDate == null ||
? null taskTimes[index].endDate == null)
: taskTimes[index].duration, ? null
), : taskTimes[index].duration,
), ),
Padding( ),
padding: const EdgeInsets.only(top: 4), Padding(
child: IconButton( padding: const EdgeInsets.only(top: 4),
icon: Icon(Icons.clear), child: IconButton(
tooltip: localization.remove, icon: Icon(Icons.clear),
onPressed: taskTimes[index].isEmpty tooltip: localization.remove,
? null onPressed: taskTimes[index].isEmpty
: () { ? null
viewModel.onRemoveTaskTime(index); : () {
setState(() { viewModel.onRemoveTaskTime(index);
_updatedAt = setState(() {
DateTime.now().millisecondsSinceEpoch; _updatedAt =
}); DateTime.now().millisecondsSinceEpoch;
}, });
), },
), ),
]), ),
], ]),
), ],
), ),
), ),
SizedBox( SizedBox(