refactor: add optional subtitle to various widgets for enhanced context
This commit is contained in:
@@ -74,23 +74,32 @@ class ClientHomePage extends StatelessWidget {
|
||||
|
||||
/// Builds the widget list in normal mode with visibility filters.
|
||||
Widget _buildNormalModeList(ClientHomeState state) {
|
||||
return ListView(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
UiConstants.space4,
|
||||
0,
|
||||
UiConstants.space4,
|
||||
100,
|
||||
),
|
||||
children: state.widgetOrder.map((String id) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: UiConstants.space4),
|
||||
child: DashboardWidgetBuilder(
|
||||
id: id,
|
||||
state: state,
|
||||
isEditMode: false,
|
||||
),
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.only(bottom: 100),
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return const Divider(color: UiColors.border, height: 0.2);
|
||||
},
|
||||
itemCount: state.widgetOrder.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final String id = state.widgetOrder[index];
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
if (index != 0) const SizedBox(height: UiConstants.space8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
),
|
||||
child: DashboardWidgetBuilder(
|
||||
id: id,
|
||||
state: state,
|
||||
isEditMode: false,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space8),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,15 @@ class ActionsWidget extends StatelessWidget {
|
||||
/// Callback when Create Order is pressed.
|
||||
final VoidCallback onCreateOrderPressed;
|
||||
|
||||
/// Optional subtitle for the section.
|
||||
final String? subtitle;
|
||||
|
||||
/// Creates an [ActionsWidget].
|
||||
const ActionsWidget({
|
||||
super.key,
|
||||
required this.onRapidPressed,
|
||||
required this.onCreateOrderPressed,
|
||||
this.subtitle,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -22,8 +26,11 @@ class ActionsWidget extends StatelessWidget {
|
||||
// Check if client_home exists in t
|
||||
final TranslationsClientHomeActionsEn i18n = t.client_home.actions;
|
||||
|
||||
return Row(
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
/// TODO: FEATURE_NOT_YET_IMPLEMENTED
|
||||
// Expanded(
|
||||
// child: _ActionCard(
|
||||
@@ -55,6 +62,8 @@ class ActionsWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,22 @@ class CoverageWidget extends StatelessWidget {
|
||||
/// The percentage of coverage (0-100).
|
||||
final int coveragePercent;
|
||||
|
||||
/// Optional subtitle for the section.
|
||||
final String? subtitle;
|
||||
|
||||
/// Creates a [CoverageWidget].
|
||||
const CoverageWidget({
|
||||
super.key,
|
||||
this.totalNeeded = 0,
|
||||
this.totalConfirmed = 0,
|
||||
this.coveragePercent = 0,
|
||||
this.subtitle,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -53,6 +58,12 @@ class CoverageWidget extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (subtitle != null) ...<Widget>[
|
||||
Text(
|
||||
subtitle!,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
|
||||
@@ -56,11 +56,15 @@ class DashboardWidgetBuilder extends StatelessWidget {
|
||||
|
||||
/// Builds the actual widget content based on the widget ID.
|
||||
Widget _buildWidgetContent(BuildContext context) {
|
||||
// Only show subtitle in normal mode
|
||||
final String? subtitle = !isEditMode ? _getWidgetSubtitle(id) : null;
|
||||
|
||||
switch (id) {
|
||||
case 'actions':
|
||||
return ActionsWidget(
|
||||
onRapidPressed: () => Modular.to.pushRapidOrder(),
|
||||
onCreateOrderPressed: () => Modular.to.pushCreateOrder(),
|
||||
subtitle: subtitle,
|
||||
);
|
||||
case 'reorder':
|
||||
return ReorderWidget(
|
||||
@@ -88,6 +92,7 @@ class DashboardWidgetBuilder extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
},
|
||||
subtitle: subtitle,
|
||||
);
|
||||
case 'spending':
|
||||
return SpendingWidget(
|
||||
@@ -95,6 +100,7 @@ class DashboardWidgetBuilder extends StatelessWidget {
|
||||
next7DaysSpending: state.dashboardData.next7DaysSpending,
|
||||
weeklyShifts: state.dashboardData.weeklyShifts,
|
||||
next7DaysScheduled: state.dashboardData.next7DaysScheduled,
|
||||
subtitle: subtitle,
|
||||
);
|
||||
case 'coverage':
|
||||
return CoverageWidget(
|
||||
@@ -106,10 +112,12 @@ class DashboardWidgetBuilder extends StatelessWidget {
|
||||
100)
|
||||
.toInt()
|
||||
: 0,
|
||||
subtitle: subtitle,
|
||||
);
|
||||
case 'liveActivity':
|
||||
return LiveActivityWidget(
|
||||
onViewAllPressed: () => Modular.to.navigate('/client-main/coverage/'),
|
||||
subtitle: subtitle,
|
||||
);
|
||||
default:
|
||||
return const SizedBox.shrink();
|
||||
@@ -133,4 +141,21 @@ class DashboardWidgetBuilder extends StatelessWidget {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
String _getWidgetSubtitle(String id) {
|
||||
switch (id) {
|
||||
case 'actions':
|
||||
return 'Quick access to create and manage orders';
|
||||
case 'reorder':
|
||||
return 'Easily reorder from your past activity';
|
||||
case 'spending':
|
||||
return 'Track your spending and budget in real-time';
|
||||
case 'coverage':
|
||||
return 'Overview of your current shift coverage';
|
||||
case 'liveActivity':
|
||||
return 'Real-time updates on your active shifts';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,15 @@ class LiveActivityWidget extends StatefulWidget {
|
||||
/// Callback when "View all" is pressed.
|
||||
final VoidCallback onViewAllPressed;
|
||||
|
||||
/// Optional subtitle for the section.
|
||||
final String? subtitle;
|
||||
|
||||
/// Creates a [LiveActivityWidget].
|
||||
const LiveActivityWidget({super.key, required this.onViewAllPressed});
|
||||
const LiveActivityWidget({
|
||||
super.key,
|
||||
required this.onViewAllPressed,
|
||||
this.subtitle
|
||||
});
|
||||
|
||||
@override
|
||||
State<LiveActivityWidget> createState() => _LiveActivityWidgetState();
|
||||
@@ -100,6 +107,7 @@ class _LiveActivityWidgetState extends State<LiveActivityWidget> {
|
||||
final TranslationsClientHomeEn i18n = t.client_home;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -121,6 +129,13 @@ class _LiveActivityWidgetState extends State<LiveActivityWidget> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.subtitle != null) ...<Widget>[
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
widget.subtitle!,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
FutureBuilder<_LiveActivityData>(
|
||||
future: _liveActivityFuture,
|
||||
|
||||
@@ -11,11 +11,15 @@ class ReorderWidget extends StatelessWidget {
|
||||
/// Callback when a reorder button is pressed.
|
||||
final Function(Map<String, dynamic> shiftData) onReorderPressed;
|
||||
|
||||
/// Optional subtitle for the section.
|
||||
final String? subtitle;
|
||||
|
||||
/// Creates a [ReorderWidget].
|
||||
const ReorderWidget({
|
||||
super.key,
|
||||
required this.orders,
|
||||
required this.onReorderPressed,
|
||||
this.subtitle,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -33,6 +37,13 @@ class ReorderWidget extends StatelessWidget {
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
if (subtitle != null) ...<Widget>[
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
subtitle!,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
SizedBox(
|
||||
height: 140,
|
||||
|
||||
@@ -16,6 +16,9 @@ class SpendingWidget extends StatelessWidget {
|
||||
/// The number of scheduled shifts for next 7 days.
|
||||
final int next7DaysScheduled;
|
||||
|
||||
/// Optional subtitle for the section.
|
||||
final String? subtitle;
|
||||
|
||||
/// Creates a [SpendingWidget].
|
||||
const SpendingWidget({
|
||||
super.key,
|
||||
@@ -23,6 +26,7 @@ class SpendingWidget extends StatelessWidget {
|
||||
required this.next7DaysSpending,
|
||||
required this.weeklyShifts,
|
||||
required this.next7DaysScheduled,
|
||||
this.subtitle,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -38,6 +42,13 @@ class SpendingWidget extends StatelessWidget {
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
if (subtitle != null) ...<Widget>[
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
subtitle!,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space3),
|
||||
|
||||
Reference in New Issue
Block a user