Refine: Add real-time countdown timer and display settings to Pad Tracker
This commit is contained in:
@@ -38,7 +38,7 @@ class _PadTrackerScreenState extends ConsumerState<PadTrackerScreen> {
|
||||
}
|
||||
|
||||
void _startTimer() {
|
||||
_timer = Timer.periodic(const Duration(minutes: 1), (timer) {
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_updateTimeSinceChange();
|
||||
@@ -342,17 +342,19 @@ class _PadTrackerScreenState extends ConsumerState<PadTrackerScreen> {
|
||||
const SizedBox(height: 8),
|
||||
if (_timeSinceLastChange != Duration.zero) ...[
|
||||
Text(
|
||||
isOverdue
|
||||
? '${(-remainingHours).toString()}h overdue'
|
||||
: '${remainingHours}h ${((_recommendedHours * 60) - _timeSinceLastChange.inMinutes) % 60}m',
|
||||
_formatRemainingTime(
|
||||
Duration(hours: _recommendedHours) - _timeSinceLastChange,
|
||||
user!
|
||||
),
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: isOverdue ? AppColors.rose : AppColors.navyBlue,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
'Last changed: ${_formatDuration(_timeSinceLastChange)} ago',
|
||||
'Last changed: ${_formatDuration(_timeSinceLastChange, user)} ago',
|
||||
style: GoogleFonts.outfit(fontSize: 12, color: AppColors.warmGray),
|
||||
),
|
||||
] else ...[
|
||||
@@ -468,9 +470,46 @@ class _PadTrackerScreenState extends ConsumerState<PadTrackerScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
String _formatDuration(Duration d) {
|
||||
if (d.inHours > 0) return '${d.inHours}h ${d.inMinutes % 60}m';
|
||||
return '${d.inMinutes}m';
|
||||
String _formatDuration(Duration d, UserProfile user) {
|
||||
final hours = d.inHours;
|
||||
final minutes = d.inMinutes % 60;
|
||||
final seconds = d.inSeconds % 60;
|
||||
|
||||
List<String> parts = [];
|
||||
if (hours > 0) parts.add('${hours}h');
|
||||
if (user.showPadTimerMinutes) parts.add('${minutes}m');
|
||||
if (user.showPadTimerSeconds) parts.add('${seconds}s');
|
||||
|
||||
if (parts.isEmpty) {
|
||||
if (hours == 0 && minutes == 0 && seconds == 0) return 'Just now';
|
||||
return '${d.inMinutes}m'; // Fallback
|
||||
}
|
||||
return parts.join(' ');
|
||||
}
|
||||
|
||||
String _formatRemainingTime(Duration remaining, UserProfile user) {
|
||||
final isOverdue = remaining.isNegative;
|
||||
final absRemaining = remaining.abs();
|
||||
|
||||
final hours = absRemaining.inHours;
|
||||
final minutes = absRemaining.inMinutes % 60;
|
||||
final seconds = absRemaining.inSeconds % 60;
|
||||
|
||||
List<String> parts = [];
|
||||
if (hours > 0) parts.add('${hours}h');
|
||||
if (user.showPadTimerMinutes) {
|
||||
parts.add('${minutes}m');
|
||||
}
|
||||
if (user.showPadTimerSeconds) {
|
||||
parts.add('${seconds}s');
|
||||
}
|
||||
|
||||
if (parts.isEmpty) {
|
||||
return isOverdue ? 'Overdue' : 'Change Now';
|
||||
}
|
||||
|
||||
String timeStr = parts.join(' ');
|
||||
return isOverdue ? '$timeStr overdue' : timeStr;
|
||||
}
|
||||
|
||||
Widget _buildSectionHeader(String title) {
|
||||
|
||||
Reference in New Issue
Block a user