Refine views for mobile-first and responsive layouts
This commit is contained in:
@@ -19,71 +19,89 @@ class DashboardView extends ConsumerWidget {
|
||||
final DashboardSummary summary = data.summary();
|
||||
final List<DashboardTask> tasks = data.tasks;
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.fromLTRB(28, 24, 28, 36),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text('Today', style: Theme.of(context).textTheme.headlineMedium),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Focus on consistency over intensity. Small moments compound.',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.bodyLarge?.copyWith(color: AppTheme.textSecondary),
|
||||
return LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
final bool compact = constraints.maxWidth < 720;
|
||||
return SingleChildScrollView(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
compact ? 16 : 28,
|
||||
compact ? 16 : 24,
|
||||
compact ? 16 : 28,
|
||||
compact ? 24 : 36,
|
||||
),
|
||||
const SizedBox(height: 22),
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 16,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
_StatCard(
|
||||
label: 'Active People',
|
||||
value: '${summary.activePeople}',
|
||||
accent: const Color(0xFF16B8CA),
|
||||
Text(
|
||||
'Today',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
_StatCard(
|
||||
label: 'Upcoming Plans',
|
||||
value: '${summary.upcomingPlans}',
|
||||
accent: const Color(0xFF2B7FFF),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Focus on consistency over intensity. Small moments compound.',
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
_StatCard(
|
||||
label: 'Pending Ideas',
|
||||
value: '${summary.pendingIdeas}',
|
||||
accent: const Color(0xFFFFA447),
|
||||
const SizedBox(height: 22),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: <Widget>[
|
||||
_StatCard(
|
||||
label: 'Active People',
|
||||
value: '${summary.activePeople}',
|
||||
accent: const Color(0xFF16B8CA),
|
||||
compact: compact,
|
||||
),
|
||||
_StatCard(
|
||||
label: 'Upcoming Plans',
|
||||
value: '${summary.upcomingPlans}',
|
||||
accent: const Color(0xFF2B7FFF),
|
||||
compact: compact,
|
||||
),
|
||||
_StatCard(
|
||||
label: 'Pending Ideas',
|
||||
value: '${summary.pendingIdeas}',
|
||||
accent: const Color(0xFFFFA447),
|
||||
compact: compact,
|
||||
),
|
||||
_StatCard(
|
||||
label: 'Weekly Rhythm',
|
||||
value: '${summary.weeklyConsistency}%',
|
||||
accent: const Color(0xFF30B66A),
|
||||
compact: compact,
|
||||
),
|
||||
],
|
||||
),
|
||||
_StatCard(
|
||||
label: 'Weekly Rhythm',
|
||||
value: '${summary.weeklyConsistency}%',
|
||||
accent: const Color(0xFF30B66A),
|
||||
const SizedBox(height: 24),
|
||||
FrostedCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Next Moves',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
...tasks.map(
|
||||
(DashboardTask task) => _TaskRow(
|
||||
task: task,
|
||||
compact: compact,
|
||||
onToggleDone: () {
|
||||
ref
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.toggleTaskDone(task.id);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
FrostedCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Next Moves',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
...tasks.map(
|
||||
(DashboardTask task) => _TaskRow(
|
||||
task: task,
|
||||
onToggleDone: () {
|
||||
ref
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.toggleTaskDone(task.id);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
@@ -104,18 +122,20 @@ class _StatCard extends StatelessWidget {
|
||||
required this.label,
|
||||
required this.value,
|
||||
required this.accent,
|
||||
required this.compact,
|
||||
});
|
||||
|
||||
final String label;
|
||||
final String value;
|
||||
final Color accent;
|
||||
final bool compact;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FrostedCard(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: SizedBox(
|
||||
width: 188,
|
||||
width: compact ? double.infinity : 188,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
@@ -149,10 +169,15 @@ class _StatCard extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _TaskRow extends StatelessWidget {
|
||||
const _TaskRow({required this.task, required this.onToggleDone});
|
||||
const _TaskRow({
|
||||
required this.task,
|
||||
required this.onToggleDone,
|
||||
required this.compact,
|
||||
});
|
||||
|
||||
final DashboardTask task;
|
||||
final VoidCallback onToggleDone;
|
||||
final bool compact;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -200,13 +225,15 @@ class _TaskRow extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
_shortDate(task.when),
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.labelLarge?.copyWith(color: AppTheme.textSecondary),
|
||||
),
|
||||
if (!compact) ...<Widget>[
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
_shortDate(task.when),
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.labelLarge?.copyWith(color: AppTheme.textSecondary),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user