refactor: Update UI theme and shift details layout for improved consistency

This commit is contained in:
Achintha Isuru
2026-02-16 13:09:10 -05:00
parent e6b512ee84
commit 2a0b39926a
2 changed files with 231 additions and 224 deletions

View File

@@ -40,7 +40,7 @@ class UiTheme {
dividerTheme: const DividerThemeData( dividerTheme: const DividerThemeData(
color: UiColors.separatorPrimary, color: UiColors.separatorPrimary,
space: 1, space: 1,
thickness: 1, thickness: 0.5,
), ),
// Card Theme // Card Theme

View File

@@ -72,9 +72,8 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: UiConstants.space3), padding: const EdgeInsets.symmetric(vertical: UiConstants.space3),
decoration: BoxDecoration( decoration: BoxDecoration(
color: UiColors.background, color: UiColors.bgThird,
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), borderRadius: BorderRadius.circular(UiConstants.radiusBase),
border: Border.all(color: UiColors.border),
), ),
child: Column( child: Column(
children: [ children: [
@@ -104,8 +103,8 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
return Container( return Container(
padding: const EdgeInsets.all(UiConstants.space3), padding: const EdgeInsets.all(UiConstants.space3),
decoration: BoxDecoration( decoration: BoxDecoration(
color: UiColors.background, color: UiColors.bgThird,
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), borderRadius: BorderRadius.circular(UiConstants.radiusBase),
), ),
child: Column( child: Column(
children: [ children: [
@@ -184,229 +183,265 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
children: [ children: [
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
padding: const EdgeInsets.all(UiConstants.space5),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Role & Client Section // Role & Client Section
Row( Padding(
crossAxisAlignment: CrossAxisAlignment.start, padding: const EdgeInsets.all(UiConstants.space5),
spacing: UiConstants.space4, child: Row(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Container( spacing: UiConstants.space4,
width: 48, children: [
height: 48, Container(
decoration: BoxDecoration( width: 48,
color: UiColors.background, height: 48,
borderRadius: BorderRadius.circular( decoration: BoxDecoration(
UiConstants.radiusBase, color: UiColors.background,
borderRadius: BorderRadius.circular(
UiConstants.radiusBase,
),
border: Border.all(color: UiColors.border),
), ),
border: Border.all(color: UiColors.border), child: const Center(
), child: Icon(
child: const Center( UiIcons.briefcase,
child: Icon( color: UiColors.primary,
UiIcons.briefcase, size: 24,
color: UiColors.primary, ),
size: 24,
), ),
), ),
), Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
displayShift.title,
style:
UiTypography.headline1b.textPrimary,
),
Text(
displayShift.clientName,
style:
UiTypography.body1m.textSecondary,
),
Text(
displayShift.locationAddress,
style:
UiTypography.body2r.textSecondary,
),
],
),
),
],
),
),
Expanded( const Divider(height: 1, thickness: 0.5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // Date Section
Padding(
padding: const EdgeInsets.all(UiConstants.space5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
i18n.shift_date,
style: UiTypography
.titleUppercase4b
.textSecondary,
),
const SizedBox(height: UiConstants.space2),
Row(
children: [ children: [
const Icon(
UiIcons.calendar,
size: 20,
color: UiColors.primary,
),
const SizedBox(width: UiConstants.space2),
Text( Text(
displayShift.title, _formatDate(displayShift.date),
style: style:
UiTypography.headline1b.textPrimary, UiTypography.headline5m.textPrimary,
),
Text(
displayShift.clientName,
style: UiTypography.body1m.textSecondary,
),
Text(
displayShift.locationAddress,
style: UiTypography.body2r.textSecondary,
), ),
], ],
), ),
), ],
], ),
), ),
const SizedBox(height: UiConstants.space6),
// Date Section const Divider(height: 1, thickness: 0.5),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
i18n.shift_date,
style:
UiTypography.titleUppercase4b.textSecondary,
),
const SizedBox(height: UiConstants.space2),
Row(
children: [
const Icon(
UiIcons.calendar,
size: 20,
color: UiColors.primary,
),
const SizedBox(width: UiConstants.space2),
Text(
_formatDate(displayShift.date),
style: UiTypography.headline5m.textPrimary,
),
],
),
],
),
const SizedBox(height: UiConstants.space6),
// Stats Row (New) // Stats Row (New)
Row( Padding(
children: [ padding: const EdgeInsets.all(UiConstants.space5),
Expanded( child: Row(
child: _buildStatCard( children: [
UiIcons.dollar, Expanded(
"\$${estimatedTotal.toStringAsFixed(0)}", child: _buildStatCard(
"Total", UiIcons.dollar,
"\$${estimatedTotal.toStringAsFixed(0)}",
"Total",
),
), ),
), const SizedBox(width: UiConstants.space4),
const SizedBox(width: UiConstants.space4), Expanded(
Expanded( child: _buildStatCard(
child: _buildStatCard( UiIcons.dollar,
UiIcons.dollar, "\$${displayShift.hourlyRate.toStringAsFixed(0)}",
"\$${displayShift.hourlyRate.toStringAsFixed(0)}", "Hourly Rate",
"Hourly Rate", ),
), ),
), const SizedBox(width: UiConstants.space4),
const SizedBox(width: UiConstants.space4), Expanded(
Expanded( child: _buildStatCard(
child: _buildStatCard( UiIcons.clock,
UiIcons.clock, duration.toStringAsFixed(1),
"${duration.toStringAsFixed(1)}", "Hours",
"Hours", ),
), ),
), ],
], ),
), ),
const SizedBox(height: UiConstants.space6),
const Divider(height: 1, thickness: 0.5),
// Time Section (New) // Time Section (New)
Row( Padding(
children: [ padding: const EdgeInsets.all(UiConstants.space5),
Expanded( child: Row(
child: _buildTimeBox( children: [
"CLOCK IN TIME", Expanded(
displayShift.startTime, child: _buildTimeBox(
"CLOCK IN TIME",
displayShift.startTime,
),
), ),
), const SizedBox(width: UiConstants.space4),
const SizedBox(width: UiConstants.space4), Expanded(
Expanded( child: _buildTimeBox(
child: _buildTimeBox( "CLOCK OUT TIME",
"CLOCK OUT TIME", displayShift.endTime,
displayShift.endTime, ),
), ),
), ],
], ),
), ),
const SizedBox(height: UiConstants.space6),
const Divider(height: 1, thickness: 0.5),
// Location Section (New with Map) // Location Section (New with Map)
Column( Padding(
crossAxisAlignment: CrossAxisAlignment.start, padding: const EdgeInsets.all(UiConstants.space5),
children: [ child: Column(
Text( crossAxisAlignment: CrossAxisAlignment.start,
"LOCATION", children: [
style: Text(
UiTypography.titleUppercase4b.textSecondary, "LOCATION",
), style: UiTypography
const SizedBox(height: UiConstants.space3), .titleUppercase4b
Row( .textSecondary,
mainAxisAlignment: ),
MainAxisAlignment.spaceBetween, const SizedBox(height: UiConstants.space3),
children: [ Row(
Expanded( mainAxisAlignment:
child: Text( MainAxisAlignment.spaceBetween,
displayShift.location.isEmpty children: [
? "TBD" Expanded(
: displayShift.location, child: Text(
style: UiTypography.title1m.textPrimary, displayShift.location.isEmpty
overflow: TextOverflow.ellipsis, ? "TBD"
: displayShift.location,
style: UiTypography.title1m.textPrimary,
overflow: TextOverflow.ellipsis,
),
), ),
), const SizedBox(width: UiConstants.space3),
const SizedBox(width: UiConstants.space3), OutlinedButton.icon(
OutlinedButton.icon( onPressed: () {
onPressed: () { ScaffoldMessenger.of(
ScaffoldMessenger.of( context,
context, ).showSnackBar(
).showSnackBar( SnackBar(
SnackBar( content: Text(
content: Text( displayShift!
displayShift! .locationAddress
.locationAddress .isNotEmpty
.isNotEmpty ? displayShift!
? displayShift!.locationAddress .locationAddress
: displayShift!.location, : displayShift!.location,
),
duration: const Duration(
seconds: 3,
),
), ),
duration: const Duration(seconds: 3), );
},
icon: const Icon(
UiIcons.navigation,
size: UiConstants.iconXs,
),
label: const Text("Get direction"),
style: OutlinedButton.styleFrom(
foregroundColor: UiColors.textPrimary,
side: const BorderSide(
color: UiColors.border,
), ),
); shape: RoundedRectangleBorder(
}, borderRadius: BorderRadius.circular(
icon: const Icon( UiConstants.radiusBase,
UiIcons.navigation, ),
size: UiConstants.iconXs,
),
label: const Text("Get direction"),
style: OutlinedButton.styleFrom(
foregroundColor: UiColors.textPrimary,
side: const BorderSide(
color: UiColors.border,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
UiConstants.radiusBase,
), ),
padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space3,
vertical: 0,
),
minimumSize: const Size(0, 32),
), ),
padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space3,
vertical: 0,
),
minimumSize: const Size(0, 32),
), ),
), ],
], ),
), const SizedBox(height: UiConstants.space3),
const SizedBox(height: UiConstants.space3), ShiftLocationMap(
ShiftLocationMap( shift: displayShift,
shift: displayShift, height: 160,
height: 160, borderRadius: UiConstants.radiusBase,
borderRadius: UiConstants.radiusBase, ),
), ],
], ),
), ),
const SizedBox(height: UiConstants.space8),
const Divider(height: 1, thickness: 0.5),
// Description / Instructions // Description / Instructions
if ((displayShift.description ?? '').isNotEmpty) ...[ if ((displayShift.description ?? '').isNotEmpty) ...[
Text( Padding(
i18n.job_description, padding: const EdgeInsets.all(UiConstants.space5),
style: child: Column(
UiTypography.titleUppercase4b.textSecondary, crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
i18n.job_description,
style: UiTypography
.titleUppercase4b
.textSecondary,
),
const SizedBox(height: UiConstants.space2),
Text(
displayShift.description!,
style: UiTypography.body2r.textSecondary,
),
],
),
), ),
const SizedBox(height: UiConstants.space2),
Text(
displayShift.description!,
style: UiTypography.body2r.textSecondary,
),
const SizedBox(height: UiConstants.space8),
], ],
], ],
), ),
), ),
), ),
// Bottom Action Bar // Bottom Action Bar
Container( Container(
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
@@ -421,7 +456,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
border: Border(top: BorderSide(color: UiColors.border)), border: Border(top: BorderSide(color: UiColors.border)),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: UiColors.black.withValues(alpha: 0.05), color: UiColors.popupShadow.withValues(alpha: 0.05),
blurRadius: 10, blurRadius: 10,
offset: const Offset(0, -4), offset: const Offset(0, -4),
), ),
@@ -628,46 +663,18 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
} }
if (status == 'open' || status == 'available') { if (status == 'open' || status == 'available') {
return Row( return ElevatedButton(
children: [ onPressed: () => _bookShift(context, shift),
Expanded( style: ElevatedButton.styleFrom(
child: OutlinedButton( backgroundColor: UiColors.primary,
onPressed: () => _declineShift(context, shift.id), foregroundColor: UiColors.white,
style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: UiConstants.space4),
foregroundColor: UiColors.textSecondary, shape: RoundedRectangleBorder(
padding: const EdgeInsets.symmetric( borderRadius: BorderRadius.circular(UiConstants.radiusBase),
vertical: UiConstants.space4,
),
side: const BorderSide(color: UiColors.border),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
),
child: Text(
i18n.decline,
style: UiTypography.body2b.textSecondary,
),
),
), ),
const SizedBox(width: UiConstants.space4), elevation: 0,
Expanded( ),
child: ElevatedButton( child: Text(i18n.apply_now, style: UiTypography.body2b.white),
onPressed: () => _bookShift(context, shift),
style: ElevatedButton.styleFrom(
backgroundColor: UiColors.primary,
foregroundColor: UiColors.white,
padding: const EdgeInsets.symmetric(
vertical: UiConstants.space4,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
elevation: 0,
),
child: Text(i18n.apply_now, style: UiTypography.body2b.white),
),
),
],
); );
} }