Refactor UI components to utilize design system colors and typography
- Removed deprecated app_colors.dart file. - Updated AttendanceCard widget to use design system colors and typography. - Refactored CommuteTracker widget for consistent styling with design system. - Modified DateSelector widget to apply design system styles. - Adjusted LocationMapPlaceholder widget to align with design system. - Enhanced LunchBreakDialog with design system colors and typography. - Updated SwipeToCheckIn widget to utilize design system for colors and text styles.
This commit is contained in:
@@ -9,7 +9,6 @@ import 'package:lucide_icons/lucide_icons.dart';
|
||||
import '../bloc/clock_in_bloc.dart';
|
||||
import '../bloc/clock_in_event.dart';
|
||||
import '../bloc/clock_in_state.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
import '../widgets/commute_tracker.dart';
|
||||
import '../widgets/date_selector.dart';
|
||||
import '../widgets/lunch_break_modal.dart';
|
||||
@@ -39,9 +38,11 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
listener: (BuildContext context, ClockInState state) {
|
||||
if (state.status == ClockInStatus.failure &&
|
||||
state.errorMessage != null) {
|
||||
ScaffoldMessenger.of(
|
||||
UiSnackbar.show(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(state.errorMessage!)));
|
||||
message: state.errorMessage!,
|
||||
type: UiSnackbarType.error,
|
||||
);
|
||||
}
|
||||
},
|
||||
builder: (BuildContext context, ClockInState state) {
|
||||
@@ -110,14 +111,10 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Your Activity Header
|
||||
const Text(
|
||||
Text(
|
||||
"Your Activity",
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.krowCharcoal,
|
||||
),
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
@@ -135,15 +132,15 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
margin:
|
||||
const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(
|
||||
12,
|
||||
),
|
||||
border: Border.all(
|
||||
color: shift.id ==
|
||||
selectedShift?.id
|
||||
? AppColors.krowBlue
|
||||
: const Color(0xFFE2E8F0),
|
||||
? UiColors.primary
|
||||
: UiColors.border,
|
||||
width:
|
||||
shift.id == selectedShift?.id
|
||||
? 2
|
||||
@@ -164,34 +161,25 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
selectedShift?.id
|
||||
? "SELECTED SHIFT"
|
||||
: "TODAY'S SHIFT",
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight:
|
||||
FontWeight.w600,
|
||||
style: UiTypography
|
||||
.titleUppercase4b
|
||||
.copyWith(
|
||||
color: shift.id ==
|
||||
selectedShift?.id
|
||||
? AppColors.krowBlue
|
||||
: AppColors
|
||||
.krowCharcoal,
|
||||
letterSpacing: 0.5,
|
||||
? UiColors.primary
|
||||
: UiColors
|
||||
.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
shift.title,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
FontWeight.w600,
|
||||
color: Color(0xFF1E293B),
|
||||
),
|
||||
style: UiTypography.body2b,
|
||||
),
|
||||
Text(
|
||||
"${shift.clientName} • ${shift.location}",
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF64748B),
|
||||
),
|
||||
style: UiTypography.body3r
|
||||
.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -202,18 +190,14 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
"${_formatTime(shift.startTime)} - ${_formatTime(shift.endTime)}",
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF475569),
|
||||
),
|
||||
style: UiTypography.body3m
|
||||
.textSecondary,
|
||||
),
|
||||
Text(
|
||||
"\$${shift.hourlyRate}/hr",
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.krowBlue,
|
||||
style: UiTypography.body3m
|
||||
.copyWith(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -234,7 +218,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F5F9), // slate-100
|
||||
color: UiColors.bgSecondary,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Column(
|
||||
@@ -242,24 +226,17 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
const Icon(
|
||||
LucideIcons.clock,
|
||||
size: 48,
|
||||
color: Color(0xFF94A3B8), // slate-400
|
||||
color: UiColors.iconThird,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
Text(
|
||||
"You're early!",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF475569), // slate-600
|
||||
),
|
||||
style: UiTypography.body1m.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
"Check-in available at ${_getCheckInAvailabilityTime(selectedShift)}",
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF64748B), // slate-500
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
@@ -304,11 +281,11 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFECFDF5), // emerald-50
|
||||
color: UiColors.tagSuccess,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: const Color(0xFFA7F3D0),
|
||||
), // emerald-200
|
||||
color: UiColors.success.withValues(alpha: 0.3),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
@@ -316,31 +293,24 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFD1FAE5), // emerald-100
|
||||
color: UiColors.tagActive,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
LucideIcons.check,
|
||||
color: Color(0xFF059669), // emerald-600
|
||||
color: UiColors.textSuccess,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
Text(
|
||||
"Shift Completed!",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF065F46), // emerald-800
|
||||
),
|
||||
style: UiTypography.body1b.textSuccess,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const Text(
|
||||
Text(
|
||||
"Great work today",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF059669), // emerald-600
|
||||
),
|
||||
style: UiTypography.body2r.textSuccess,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -351,27 +321,20 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F5F9), // slate-100
|
||||
color: UiColors.bgSecondary,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: const Column(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
"No confirmed shifts for today",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF475569), // slate-600
|
||||
),
|
||||
style: UiTypography.body1m.textSecondary,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
"Accept a shift to clock in",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF64748B), // slate-500
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
@@ -385,11 +348,11 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFECFDF5), // emerald-50
|
||||
color: UiColors.tagSuccess,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: const Color(0xFFA7F3D0),
|
||||
), // emerald-200
|
||||
color: UiColors.success.withValues(alpha: 0.3),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
@@ -399,23 +362,15 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const Text(
|
||||
Text(
|
||||
"Checked in at",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF059669),
|
||||
),
|
||||
style: UiTypography.body3m.textSuccess,
|
||||
),
|
||||
Text(
|
||||
DateFormat(
|
||||
'h:mm a',
|
||||
).format(checkInTime),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF065F46),
|
||||
),
|
||||
style: UiTypography.body1b.textSuccess,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -423,12 +378,12 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFD1FAE5),
|
||||
color: UiColors.tagActive,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
LucideIcons.check,
|
||||
color: Color(0xFF059669),
|
||||
color: UiColors.textSuccess,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -466,12 +421,12 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? Colors.white : Colors.transparent,
|
||||
color: isSelected ? UiColors.white : UiColors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: isSelected
|
||||
? <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
@@ -484,15 +439,15 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
Icon(
|
||||
icon,
|
||||
size: 16,
|
||||
color: isSelected ? Colors.black : Colors.grey,
|
||||
color: isSelected ? UiColors.foreground : UiColors.iconThird,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: isSelected ? Colors.black : Colors.grey,
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: isSelected
|
||||
? UiColors.foreground
|
||||
: UiColors.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -521,26 +476,19 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
width: 96,
|
||||
height: 96,
|
||||
decoration: BoxDecoration(
|
||||
color: scanned
|
||||
? Colors.green.shade50
|
||||
: Colors.blue.shade50,
|
||||
color: scanned ? UiColors.tagSuccess : UiColors.tagInProgress,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
scanned ? LucideIcons.check : LucideIcons.nfc,
|
||||
size: 48,
|
||||
color: scanned
|
||||
? Colors.green.shade600
|
||||
: Colors.blue.shade600,
|
||||
color: scanned ? UiColors.textSuccess : UiColors.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
scanned ? 'Processing check-in...' : 'Ready to scan',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
@@ -548,7 +496,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
? 'Please wait...'
|
||||
: 'Hold your phone near the NFC tag at the clock-in station',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey.shade600),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
if (!scanned) ...<Widget>[
|
||||
const SizedBox(height: 24),
|
||||
@@ -573,16 +521,13 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
// It's safer to just return a result
|
||||
},
|
||||
icon: const Icon(LucideIcons.nfc, size: 24),
|
||||
label: const Text(
|
||||
label: Text(
|
||||
'Tap to Scan',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
style: UiTypography.headline4m.white,
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0047FF),
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: UiColors.primary,
|
||||
foregroundColor: UiColors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppColors {
|
||||
static const Color krowBlue = Color(0xFF0A39DF);
|
||||
static const Color krowYellow = Color(0xFFFFED4A);
|
||||
static const Color krowCharcoal = Color(0xFF121826);
|
||||
static const Color krowMuted = Color(0xFF6A7382);
|
||||
static const Color krowBorder = Color(0xFFE3E6E9);
|
||||
static const Color krowBackground = Color(0xFFFAFBFC);
|
||||
|
||||
static const Color white = Colors.white;
|
||||
static const Color black = Colors.black;
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
enum AttendanceType { checkin, checkout, breaks, days }
|
||||
|
||||
class AttendanceCard extends StatelessWidget {
|
||||
|
||||
const AttendanceCard({
|
||||
super.key,
|
||||
required this.type,
|
||||
@@ -26,12 +26,12 @@ class AttendanceCard extends StatelessWidget {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: Colors.grey.shade100),
|
||||
border: Border.all(color: UiColors.bgSecondary),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
@@ -53,10 +53,7 @@ class AttendanceCard extends StatelessWidget {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
color: Color(0xFF64748B), // slate-500
|
||||
),
|
||||
style: UiTypography.titleUppercase4m.textSecondary,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -65,27 +62,20 @@ class AttendanceCard extends StatelessWidget {
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF0F172A), // slate-900
|
||||
),
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
),
|
||||
if (scheduledTime != null) ...<Widget>[
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
"Scheduled: $scheduledTime",
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
color: Color(0xFF94A3B8), // slate-400
|
||||
),
|
||||
style: UiTypography.footnote2r.textInactive,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
subtitle,
|
||||
style: const TextStyle(fontSize: 12, color: Color(0xFF0032A0)),
|
||||
style: UiTypography.footnote1r.copyWith(color: UiColors.primary),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -97,26 +87,26 @@ class AttendanceCard extends StatelessWidget {
|
||||
case AttendanceType.checkin:
|
||||
return _AttendanceStyle(
|
||||
icon: LucideIcons.logIn,
|
||||
bgColor: const Color(0xFF0032A0).withOpacity(0.1),
|
||||
iconColor: const Color(0xFF0032A0),
|
||||
bgColor: UiColors.primary.withValues(alpha: 0.1),
|
||||
iconColor: UiColors.primary,
|
||||
);
|
||||
case AttendanceType.checkout:
|
||||
return _AttendanceStyle(
|
||||
icon: LucideIcons.logOut,
|
||||
bgColor: const Color(0xFF333F48).withOpacity(0.1),
|
||||
iconColor: const Color(0xFF333F48),
|
||||
bgColor: UiColors.foreground.withValues(alpha: 0.1),
|
||||
iconColor: UiColors.foreground,
|
||||
);
|
||||
case AttendanceType.breaks:
|
||||
return _AttendanceStyle(
|
||||
icon: LucideIcons.coffee,
|
||||
bgColor: const Color(0xFFF9E547).withOpacity(0.2),
|
||||
iconColor: const Color(0xFF4C460D),
|
||||
bgColor: UiColors.accent.withValues(alpha: 0.2),
|
||||
iconColor: UiColors.accentForeground,
|
||||
);
|
||||
case AttendanceType.days:
|
||||
return _AttendanceStyle(
|
||||
icon: LucideIcons.calendar,
|
||||
bgColor: Colors.green.withOpacity(0.1),
|
||||
iconColor: Colors.green,
|
||||
bgColor: UiColors.success.withValues(alpha: 0.1),
|
||||
iconColor: UiColors.textSuccess,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
enum CommuteMode {
|
||||
lockedNoShift,
|
||||
@@ -161,18 +161,18 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: <Color>[
|
||||
Color(0xFFEFF6FF), // blue-50
|
||||
Color(0xFFECFEFF), // cyan-50
|
||||
UiColors.primary.withValues(alpha: 0.05),
|
||||
UiColors.primary.withValues(alpha: 0.1),
|
||||
],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
@@ -188,35 +188,28 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFF2563EB), // blue-600
|
||||
color: UiColors.primary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
LucideIcons.mapPin,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
color: UiColors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Expanded(
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Enable Commute Tracking?',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF0F172A), // slate-900
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Share location 1hr before shift so your manager can see you\'re on the way.',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF475569), // slate-600
|
||||
),
|
||||
style: UiTypography.body4r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -233,9 +226,9 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
side: const BorderSide(color: Color(0xFFE2E8F0)),
|
||||
side: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
child: const Text('Not Now', style: TextStyle(fontSize: 12)),
|
||||
child: Text('Not Now', style: UiTypography.footnote1m),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
@@ -245,12 +238,12 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
setState(() => _localHasConsent = true);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2563EB), // blue-600
|
||||
backgroundColor: UiColors.primary,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
),
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'Enable',
|
||||
style: TextStyle(fontSize: 12, color: Colors.white),
|
||||
style: UiTypography.footnote1m.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -266,11 +259,11 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
@@ -282,13 +275,13 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFF1F5F9), // slate-100
|
||||
color: UiColors.bgSecondary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
LucideIcons.navigation,
|
||||
size: 16,
|
||||
color: Color(0xFF475569), // slate-600
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
@@ -298,13 +291,9 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Text(
|
||||
Text(
|
||||
'On My Way',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF0F172A), // slate-900
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Row(
|
||||
@@ -312,26 +301,20 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
const Icon(
|
||||
LucideIcons.clock,
|
||||
size: 12,
|
||||
color: Color(0xFF64748B), // slate-500
|
||||
color: UiColors.textInactive,
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
'Shift starts in ${_getMinutesUntilShift()} min',
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
color: Color(0xFF64748B), // slate-500
|
||||
),
|
||||
style: UiTypography.titleUppercase4m.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const Text(
|
||||
Text(
|
||||
'Track arrival',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Color(0xFF64748B), // slate-500
|
||||
),
|
||||
style: UiTypography.titleUppercase4m.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -342,7 +325,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
setState(() => _localIsCommuteOn = value);
|
||||
widget.onCommuteToggled?.call(value);
|
||||
},
|
||||
activeThumbColor: AppColors.krowBlue,
|
||||
activeThumbColor: UiColors.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -357,8 +340,8 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: <Color>[
|
||||
Color(0xFF2563EB), // blue-600
|
||||
Color(0xFF0891B2), // cyan-600
|
||||
UiColors.primary,
|
||||
UiColors.iconActive,
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -383,13 +366,13 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
width: 96,
|
||||
height: 96,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
color: UiColors.white.withValues(alpha: 0.2),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
LucideIcons.navigation,
|
||||
size: 48,
|
||||
color: Colors.white,
|
||||
color: UiColors.white,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -400,20 +383,15 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const Text(
|
||||
Text(
|
||||
'On My Way',
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
style: UiTypography.displayMb.white,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Your manager can see you\'re heading to the site',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.blue.shade100,
|
||||
style: UiTypography.body2r.copyWith(
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -424,29 +402,24 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
constraints: const BoxConstraints(maxWidth: 300),
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.1),
|
||||
color: UiColors.white.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
color: UiColors.white.withValues(alpha: 0.2),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Distance to Site',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.blue.shade100,
|
||||
style: UiTypography.body2r.copyWith(
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
_formatDistance(widget.distanceMeters!),
|
||||
style: const TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
style: UiTypography.displayM.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -458,29 +431,24 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
constraints: const BoxConstraints(maxWidth: 300),
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.1),
|
||||
color: UiColors.white.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
color: UiColors.white.withValues(alpha: 0.2),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Estimated Arrival',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.blue.shade100,
|
||||
style: UiTypography.body2r.copyWith(
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${widget.etaMinutes} min',
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
style: UiTypography.headline1m.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -490,9 +458,8 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
const SizedBox(height: 32),
|
||||
Text(
|
||||
'Most app features are locked while commute mode is on. You\'ll be able to clock in once you arrive.',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.blue.shade100,
|
||||
style: UiTypography.footnote1r.copyWith(
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -508,12 +475,12 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
setState(() => _localIsCommuteOn = false);
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
side: BorderSide(color: Colors.white.withOpacity(0.3)),
|
||||
foregroundColor: UiColors.white,
|
||||
side: BorderSide(color: UiColors.white.withValues(alpha: 0.3)),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: const Text('Turn Off Commute Mode'),
|
||||
child: Text('Turn Off Commute Mode', style: UiTypography.buttonL),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -527,18 +494,18 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: <Color>[
|
||||
Color(0xFFECFDF5), // emerald-50
|
||||
Color(0xFFD1FAE5), // green-50
|
||||
UiColors.tagSuccess,
|
||||
UiColors.tagActive,
|
||||
],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
color: UiColors.black.withValues(alpha: 0.1),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -550,31 +517,24 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFF10B981), // emerald-500
|
||||
color: UiColors.success,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
LucideIcons.checkCircle,
|
||||
size: 32,
|
||||
color: Colors.white,
|
||||
color: UiColors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
Text(
|
||||
'You\'ve Arrived! 🎉',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF0F172A), // slate-900
|
||||
),
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
Text(
|
||||
'You\'re at the shift location. Ready to clock in?',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF475569), // slate-600
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class DateSelector extends StatelessWidget {
|
||||
|
||||
const DateSelector({
|
||||
super.key,
|
||||
required this.selectedDate,
|
||||
@@ -36,12 +36,12 @@ class DateSelector extends StatelessWidget {
|
||||
duration: const Duration(milliseconds: 200),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? const Color(0xFF0032A0) : Colors.white,
|
||||
color: isSelected ? UiColors.primary : UiColors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: isSelected
|
||||
? <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: const Color(0xFF0032A0).withOpacity(0.3),
|
||||
color: UiColors.primary.withValues(alpha: 0.3),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
@@ -53,22 +53,18 @@ class DateSelector extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
DateFormat('d').format(date),
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
style: UiTypography.title1m.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: isSelected
|
||||
? Colors.white
|
||||
: const Color(0xFF0F172A),
|
||||
color: isSelected ? UiColors.white : UiColors.foreground,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
DateFormat('E').format(date),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
style: UiTypography.footnote2r.copyWith(
|
||||
color: isSelected
|
||||
? Colors.white.withOpacity(0.8)
|
||||
: const Color(0xFF94A3B8),
|
||||
? UiColors.white.withValues(alpha: 0.8)
|
||||
: UiColors.textInactive,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
@@ -77,9 +73,7 @@ class DateSelector extends StatelessWidget {
|
||||
width: 6,
|
||||
height: 6,
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? Colors.white
|
||||
: const Color(0xFF0032A0),
|
||||
color: isSelected ? UiColors.white : UiColors.primary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
)
|
||||
@@ -87,8 +81,8 @@ class DateSelector extends StatelessWidget {
|
||||
Container(
|
||||
width: 6,
|
||||
height: 6,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.border,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
class LocationMapPlaceholder extends StatelessWidget {
|
||||
@@ -18,7 +18,7 @@ class LocationMapPlaceholder extends StatelessWidget {
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFE2E8F0),
|
||||
color: UiColors.border,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
image: DecorationImage(
|
||||
image: const NetworkImage(
|
||||
@@ -33,17 +33,18 @@ class LocationMapPlaceholder extends StatelessWidget {
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
// Fallback UI if image fails (which it will without key)
|
||||
const Center(
|
||||
Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Icon(LucideIcons.mapPin, size: 48, color: UiColors.iconSecondary),
|
||||
SizedBox(height: 8),
|
||||
Text('Map View (GPS)', style: TextStyle(color: UiColors.textSecondary)),
|
||||
const Icon(LucideIcons.mapPin,
|
||||
size: 48, color: UiColors.iconSecondary),
|
||||
const SizedBox(height: 8),
|
||||
Text('Map View (GPS)', style: UiTypography.body2r.textSecondary),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
// Status Overlay
|
||||
Positioned(
|
||||
bottom: 16,
|
||||
@@ -52,11 +53,11 @@ class LocationMapPlaceholder extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
color: UiColors.black.withValues(alpha: 0.1),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
@@ -65,8 +66,12 @@ class LocationMapPlaceholder extends StatelessWidget {
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
isVerified ? LucideIcons.checkCircle : LucideIcons.alertCircle,
|
||||
color: isVerified ? UiColors.textSuccess : UiColors.destructive,
|
||||
isVerified
|
||||
? LucideIcons.checkCircle
|
||||
: LucideIcons.alertCircle,
|
||||
color: isVerified
|
||||
? UiColors.textSuccess
|
||||
: UiColors.destructive,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
@@ -76,12 +81,12 @@ class LocationMapPlaceholder extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
isVerified ? 'Location Verified' : 'Location Check',
|
||||
style: UiTypography.body1b.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body1b.textPrimary,
|
||||
),
|
||||
if (distance != null)
|
||||
Text(
|
||||
'${distance!.toStringAsFixed(0)}m from venue',
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
class LunchBreakDialog extends StatefulWidget {
|
||||
|
||||
const LunchBreakDialog({super.key, required this.onComplete});
|
||||
final VoidCallback onComplete;
|
||||
|
||||
@@ -47,7 +47,7 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: UiColors.white,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
@@ -82,25 +82,21 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.bgSecondary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
LucideIcons.coffee,
|
||||
size: 40,
|
||||
color: Color(0xFF6A7382),
|
||||
color: UiColors.iconSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const Text(
|
||||
Text(
|
||||
"Did You Take\na Lunch?",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF121826),
|
||||
),
|
||||
style: UiTypography.headline1m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
@@ -116,18 +112,14 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
border: Border.all(color: UiColors.border),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.transparent,
|
||||
color: UiColors.transparent,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: const Text(
|
||||
child: Text(
|
||||
"No",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF121826),
|
||||
),
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -142,19 +134,15 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0032A0),
|
||||
backgroundColor: UiColors.primary,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
child: Text(
|
||||
"Yes",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
style: UiTypography.body1m.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -172,76 +160,51 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const Text(
|
||||
Text(
|
||||
"When did you take lunch?",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
// Mock Inputs
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: DropdownButtonFormField<String>(
|
||||
isExpanded: true,
|
||||
initialValue: _breakStart,
|
||||
items: _timeOptions.map((String t) => DropdownMenuItem(value: t, child: Text(t, style: const TextStyle(fontSize: 13)))).toList(),
|
||||
onChanged: (String? v) => setState(() => _breakStart = v),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Start',
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: DropdownButtonFormField<String>(
|
||||
isExpanded: true,
|
||||
initialValue: _breakEnd,
|
||||
items: _timeOptions.map((String t) => DropdownMenuItem(value: t, child: Text(t, style: const TextStyle(fontSize: 13)))).toList(),
|
||||
onChanged: (String? v) => setState(() => _breakEnd = v),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'End',
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() => _step = 3);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0032A0),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
// Mock Inputs
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: DropdownButtonFormField<String>(
|
||||
isExpanded: true,
|
||||
value: _breakStart,
|
||||
items: _timeOptions
|
||||
.map((String t) => DropdownMenuItem(
|
||||
value: t,
|
||||
child: Text(t, style: UiTypography.body3r)))
|
||||
.toList(),
|
||||
onChanged: (String? v) => setState(() => _breakStart = v),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Start',
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Text("Next", style: TextStyle(color: Colors.white)),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: DropdownButtonFormField<String>(
|
||||
isExpanded: true,
|
||||
value: _breakEnd,
|
||||
items: _timeOptions
|
||||
.map((String t) => DropdownMenuItem(
|
||||
value: t,
|
||||
child: Text(t, style: UiTypography.body3r)))
|
||||
.toList(),
|
||||
onChanged: (String? v) => setState(() => _breakEnd = v),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'End',
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildStep2b() {
|
||||
// No lunch reason
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
const Text(
|
||||
"Why didn't you take lunch?",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
..._noLunchReasons.map((String reason) => RadioListTile<String>(
|
||||
title: Text(reason),
|
||||
value: reason,
|
||||
groupValue: _noLunchReason,
|
||||
onChanged: (String? val) => setState(() => _noLunchReason = val),
|
||||
)),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
@@ -249,10 +212,47 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
setState(() => _step = 3);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0032A0),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: const Text("Next", style: TextStyle(color: Colors.white)),
|
||||
backgroundColor: UiColors.primary,
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: Text("Next", style: UiTypography.body1m.white),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildStep2b() {
|
||||
// No lunch reason
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
"Why didn't you take lunch?",
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
..._noLunchReasons.map((String reason) => RadioListTile<String>(
|
||||
title: Text(reason, style: UiTypography.body2r),
|
||||
value: reason,
|
||||
groupValue: _noLunchReason,
|
||||
onChanged: (String? val) =>
|
||||
setState(() => _noLunchReason = val),
|
||||
activeColor: UiColors.primary,
|
||||
)),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() => _step = 3);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: Text("Next", style: UiTypography.body1m.white),
|
||||
),
|
||||
],
|
||||
));
|
||||
@@ -260,35 +260,36 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
|
||||
Widget _buildStep3() {
|
||||
// Additional Notes
|
||||
return Padding(
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const Text(
|
||||
Text(
|
||||
"Additional Notes",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
onChanged: (String v) => _additionalNotes = v,
|
||||
style: UiTypography.body2r,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Add any details...',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
maxLines: 3,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
onChanged: (String v) => _additionalNotes = v,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Add any details...',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
maxLines: 3,
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() => _step = 4);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0032A0),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: const Text("Submit", style: TextStyle(color: Colors.white)),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: Text("Submit", style: UiTypography.body1m.white),
|
||||
),
|
||||
],
|
||||
));
|
||||
@@ -296,25 +297,26 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
|
||||
Widget _buildStep4() {
|
||||
// Success
|
||||
return Padding(
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const Icon(LucideIcons.checkCircle, size: 64, color: Colors.green),
|
||||
const Icon(LucideIcons.checkCircle,
|
||||
size: 64, color: UiColors.success),
|
||||
const SizedBox(height: 24),
|
||||
const Text(
|
||||
Text(
|
||||
"Break Logged!",
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
style: UiTypography.headline1m,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
onPressed: widget.onComplete,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0032A0),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: const Text("Close", style: TextStyle(color: Colors.white)),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: Text("Close", style: UiTypography.body1m.white),
|
||||
),
|
||||
],
|
||||
));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
@@ -72,9 +73,8 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Color baseColor = widget.isCheckedIn
|
||||
? const Color(0xFF10B981)
|
||||
: const Color(0xFF0032A0);
|
||||
final Color baseColor =
|
||||
widget.isCheckedIn ? UiColors.success : UiColors.primary;
|
||||
|
||||
if (widget.mode == 'nfc') {
|
||||
return GestureDetector(
|
||||
@@ -96,7 +96,7 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: baseColor.withOpacity(0.4),
|
||||
color: baseColor.withValues(alpha: 0.4),
|
||||
blurRadius: 25,
|
||||
offset: const Offset(0, 10),
|
||||
spreadRadius: -5,
|
||||
@@ -106,7 +106,7 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Icon(LucideIcons.wifi, color: Colors.white),
|
||||
const Icon(LucideIcons.wifi, color: UiColors.white),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
widget.isLoading
|
||||
@@ -114,11 +114,7 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
? "Checking out..."
|
||||
: "Checking in...")
|
||||
: (widget.isCheckedIn ? "NFC Check Out" : "NFC Check In"),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
style: UiTypography.body1b.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -133,12 +129,10 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
|
||||
// Calculate background color based on drag
|
||||
final double progress = _dragValue / maxDrag;
|
||||
final Color startColor = widget.isCheckedIn
|
||||
? const Color(0xFF10B981)
|
||||
: const Color(0xFF0032A0);
|
||||
final Color endColor = widget.isCheckedIn
|
||||
? const Color(0xFF0032A0)
|
||||
: const Color(0xFF10B981);
|
||||
final Color startColor =
|
||||
widget.isCheckedIn ? UiColors.success : UiColors.primary;
|
||||
final Color endColor =
|
||||
widget.isCheckedIn ? UiColors.primary : UiColors.success;
|
||||
final Color currentColor =
|
||||
Color.lerp(startColor, endColor, progress) ?? startColor;
|
||||
|
||||
@@ -149,7 +143,7 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
color: UiColors.black.withValues(alpha: 0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -164,11 +158,7 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
widget.isCheckedIn
|
||||
? "Swipe to Check Out"
|
||||
: "Swipe to Check In",
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 18,
|
||||
),
|
||||
style: UiTypography.body1b,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -176,11 +166,7 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
Center(
|
||||
child: Text(
|
||||
widget.isCheckedIn ? "Check Out!" : "Check In!",
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 18,
|
||||
),
|
||||
style: UiTypography.body1b,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
@@ -193,11 +179,11 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
width: _handleSize,
|
||||
height: _handleSize,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
color: UiColors.black.withValues(alpha: 0.1),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user