Refine views for mobile-first and responsive layouts
This commit is contained in:
@@ -21,15 +21,21 @@ class RemindersView extends ConsumerWidget {
|
||||
for (final PersonProfile person in data.people) person.id: person,
|
||||
};
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(28, 24, 28, 28),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
return LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
final bool compact = constraints.maxWidth < 760;
|
||||
return Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
compact ? 16 : 28,
|
||||
compact ? 16 : 24,
|
||||
compact ? 16 : 28,
|
||||
compact ? 20 : 28,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
if (compact)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
@@ -42,90 +48,222 @@ class RemindersView extends ConsumerWidget {
|
||||
style: Theme.of(context).textTheme.bodyLarge
|
||||
?.copyWith(color: AppTheme.textSecondary),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
FilledButton.icon(
|
||||
onPressed: () =>
|
||||
_addReminder(context, ref, data.people),
|
||||
icon: const Icon(Icons.alarm_add_rounded),
|
||||
label: const Text('Add Reminder'),
|
||||
),
|
||||
],
|
||||
)
|
||||
else
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Reminders',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.headlineMedium,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
'Set recurring nudges so good intentions become habits.',
|
||||
style: Theme.of(context).textTheme.bodyLarge
|
||||
?.copyWith(color: AppTheme.textSecondary),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
FilledButton.icon(
|
||||
onPressed: () =>
|
||||
_addReminder(context, ref, data.people),
|
||||
icon: const Icon(Icons.alarm_add_rounded),
|
||||
label: const Text('Add Reminder'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
FilledButton.icon(
|
||||
onPressed: () => _addReminder(context, ref, data.people),
|
||||
icon: const Icon(Icons.alarm_add_rounded),
|
||||
label: const Text('Add Reminder'),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ListView.separated(
|
||||
itemCount: reminders.length,
|
||||
separatorBuilder: (_, _) => const SizedBox(height: 12),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final ReminderRule reminder = reminders[index];
|
||||
final PersonProfile? person = reminder.personId == null
|
||||
? null
|
||||
: peopleById[reminder.personId!];
|
||||
|
||||
return FrostedCard(
|
||||
child: compact
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
reminder.title,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleMedium,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: reminder.enabled,
|
||||
onChanged: (_) {
|
||||
ref
|
||||
.read(
|
||||
localRepositoryProvider
|
||||
.notifier,
|
||||
)
|
||||
.toggleReminderEnabled(
|
||||
reminder.id,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'${_labelForCadence(reminder.cadence)} • ${_formatDateTime(reminder.nextAt)}',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
person == null
|
||||
? 'Unassigned'
|
||||
: person.name,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelLarge
|
||||
?.copyWith(
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
children: <Widget>[
|
||||
OutlinedButton.icon(
|
||||
onPressed: () => _editReminder(
|
||||
context,
|
||||
ref,
|
||||
data.people,
|
||||
reminder,
|
||||
),
|
||||
icon: const Icon(Icons.edit_rounded),
|
||||
label: const Text('Edit'),
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(
|
||||
localRepositoryProvider
|
||||
.notifier,
|
||||
)
|
||||
.deleteReminder(reminder.id);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.delete_outline_rounded,
|
||||
),
|
||||
label: const Text('Delete'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
reminder.title,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${_labelForCadence(reminder.cadence)} • ${_formatDateTime(reminder.nextAt)}',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
person == null
|
||||
? 'Unassigned'
|
||||
: person.name,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelLarge
|
||||
?.copyWith(
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: reminder.enabled,
|
||||
onChanged: (_) {
|
||||
ref
|
||||
.read(
|
||||
localRepositoryProvider.notifier,
|
||||
)
|
||||
.toggleReminderEnabled(reminder.id);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => _editReminder(
|
||||
context,
|
||||
ref,
|
||||
data.people,
|
||||
reminder,
|
||||
),
|
||||
icon: const Icon(Icons.edit_rounded),
|
||||
tooltip: 'Edit',
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(
|
||||
localRepositoryProvider.notifier,
|
||||
)
|
||||
.deleteReminder(reminder.id);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.delete_outline_rounded,
|
||||
),
|
||||
tooltip: 'Delete',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ListView.separated(
|
||||
itemCount: reminders.length,
|
||||
separatorBuilder: (_, _) => const SizedBox(height: 12),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final ReminderRule reminder = reminders[index];
|
||||
final PersonProfile? person = reminder.personId == null
|
||||
? null
|
||||
: peopleById[reminder.personId!];
|
||||
|
||||
return FrostedCard(
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
reminder.title,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${_labelForCadence(reminder.cadence)} • ${_formatDateTime(reminder.nextAt)}',
|
||||
style: Theme.of(context).textTheme.bodyMedium
|
||||
?.copyWith(color: AppTheme.textSecondary),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
person == null ? 'Unassigned' : person.name,
|
||||
style: Theme.of(context).textTheme.labelLarge
|
||||
?.copyWith(color: AppTheme.textSecondary),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: reminder.enabled,
|
||||
onChanged: (_) {
|
||||
ref
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.toggleReminderEnabled(reminder.id);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => _editReminder(
|
||||
context,
|
||||
ref,
|
||||
data.people,
|
||||
reminder,
|
||||
),
|
||||
icon: const Icon(Icons.edit_rounded),
|
||||
tooltip: 'Edit',
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.deleteReminder(reminder.id);
|
||||
},
|
||||
icon: const Icon(Icons.delete_outline_rounded),
|
||||
tooltip: 'Delete',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
@@ -238,9 +376,9 @@ class _ReminderEditorDialogState extends State<_ReminderEditorDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(widget.title),
|
||||
content: SizedBox(
|
||||
width: 420,
|
||||
child: SingleChildScrollView(
|
||||
content: SingleChildScrollView(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 420),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
@@ -291,20 +429,43 @@ class _ReminderEditorDialogState extends State<_ReminderEditorDialog> {
|
||||
decoration: const InputDecoration(labelText: 'Person'),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
_formatDateTime(_nextAt),
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: _pickDateTime,
|
||||
icon: const Icon(Icons.schedule_rounded),
|
||||
label: const Text('Pick Time'),
|
||||
),
|
||||
],
|
||||
LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
final bool compact = constraints.maxWidth < 360;
|
||||
if (compact) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
_formatDateTime(_nextAt),
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
OutlinedButton.icon(
|
||||
onPressed: _pickDateTime,
|
||||
icon: const Icon(Icons.schedule_rounded),
|
||||
label: const Text('Pick Time'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
_formatDateTime(_nextAt),
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: _pickDateTime,
|
||||
icon: const Icon(Icons.schedule_rounded),
|
||||
label: const Text('Pick Time'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user