import 'dart:async'; import 'dart:developer'; import 'package:flutter/cupertino.dart' show CupertinoColors; import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:timetracker/src/rust/api.dart'; import 'package:timetracker/time_tracking_service.dart'; int dateTimeToUnixSeconds(DateTime dt) => dt.toUtc().millisecondsSinceEpoch ~/ 1000; DateTime unixSecondsToDateTime(int ts) => DateTime.fromMillisecondsSinceEpoch(ts * 1000, isUtc: true).toLocal(); class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { Timer? _timer; Duration _elapsedTime = Duration.zero; @override void initState() { super.initState(); final initialTracking = context.read().currentTracking; if (initialTracking != null) { _startTimer(unixSecondsToDateTime(initialTracking.startTime)); } } @override void dispose() { _stopTimer(); super.dispose(); } void _startTimer(DateTime startTime) { _stopTimer(); _calculateElapsedTime(startTime); _timer = Timer.periodic(const Duration(seconds: 1), (_) { final currentTracking = context.read().currentTracking; if (currentTracking != null) { _calculateElapsedTime(unixSecondsToDateTime(currentTracking.startTime)); } else { _stopTimer(); } }); } void _stopTimer() { if (_timer != null) { _timer!.cancel(); _timer = null; } } void _calculateElapsedTime(DateTime startTime) { final now = DateTime.now(); final duration = now.difference(startTime); if (mounted) { setState(() { _elapsedTime = duration.isNegative ? Duration.zero : duration; }); } } String _formatDuration(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, "0"); final hours = twoDigits(duration.inHours); final minutes = twoDigits(duration.inMinutes.remainder(60)); final seconds = twoDigits(duration.inSeconds.remainder(60)); return "$hours:$minutes:$seconds"; } void _checkAndManageTimerState(TimeEntry? currentTracking) { if (currentTracking != null) { if (_timer == null || !_timer!.isActive) { log("Timer wird gestartet..."); _startTimer(unixSecondsToDateTime(currentTracking.startTime)); } } else { if (_timer != null && _timer!.isActive) { log("Timer wird gestoppt..."); _stopTimer(); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted && _elapsedTime != Duration.zero) { setState(() { _elapsedTime = Duration.zero; }); } }); } } } @override Widget build(BuildContext context) { final timeService = context.watch(); final currentTracking = timeService.currentTracking; _checkAndManageTimerState(currentTracking); return PlatformScaffold( appBar: PlatformAppBar(title: PlatformText('Tracking')), body: _buildBodyContent(context, currentTracking, timeService), ); } Widget _buildBodyContent( BuildContext context, TimeEntry? currentTracking, TimeTrackingService timeService, ) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ if (currentTracking != null) _buildRunningTrackingInfo(context, currentTracking) else PlatformText('Kein aktives Tracking.'), const SizedBox(height: 20), PlatformElevatedButton( onPressed: () async { if (currentTracking != null) { final success = await timeService.flStopTracking(); if (!success && context.mounted) { _showPlatformFeedbackDialog( context, 'Fehler', 'Fehler beim Stoppen des Trackings.', ); } } else { _showPlatformTagSelection(context); } }, child: PlatformText( currentTracking != null ? 'Tracking Stoppen' : 'Tracking Starten', ), material: (_, __) => MaterialElevatedButtonData( style: ElevatedButton.styleFrom( backgroundColor: currentTracking != null ? Colors.red : Colors.green, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 50, vertical: 20, ), textStyle: const TextStyle(fontSize: 20), ), ), cupertino: (_, __) => CupertinoElevatedButtonData( color: currentTracking != null ? CupertinoColors.destructiveRed : CupertinoColors.activeGreen, padding: const EdgeInsets.symmetric( horizontal: 50, vertical: 20, ), ), ), ], ), ); } void _showPlatformTagSelection(BuildContext context) { final timeService = context.read(); final List options = [ ListTile( title: PlatformText('Ohne Tag'), onTap: () { Navigator.of(context).pop(); timeService.flStartTracking(0); }, ), const Divider(height: 1), ...timeService.tags.map( (tag) => ListTile( title: PlatformText(tag.name), onTap: () { Navigator.of(context).pop(); timeService.flStartTracking(tag.id); }, ), ), ]; showPlatformModalSheet( context: context, material: MaterialModalSheetData(), cupertino: CupertinoModalSheetData(), builder: (_) => Material( child: SafeArea( child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: options, ), ), ), ), ); } Widget _buildRunningTrackingInfo(BuildContext context, TimeEntry entry) { final tagName = entry.tagName ?? 'Ohne Tag'; return Column( children: [ PlatformText( _formatDuration(_elapsedTime), style: platformThemeData( context, material: (data) => data.textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.bold, fontFeatures: const [FontFeature.tabularFigures()], ), cupertino: (data) => data.textTheme.navLargeTitleTextStyle.copyWith( fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 5), PlatformText('Aktives Tracking: $tagName'), PlatformText( 'Gestartet: ${DateFormat('HH:mm:ss').format(unixSecondsToDateTime(entry.startTime))}', style: platformThemeData( context, material: (data) => data.textTheme.bodySmall, cupertino: (data) => data.textTheme.actionSmallTextStyle, ), ), ], ); } void _showPlatformFeedbackDialog( BuildContext context, String title, String message, ) { showPlatformDialog( context: context, builder: (_) => PlatformAlertDialog( title: PlatformText(title), content: PlatformText(message), actions: [ PlatformDialogAction( child: PlatformText('OK'), onPressed: () => Navigator.pop(context), ), ], ), ); } }