import 'dart:developer'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; import 'package:timetracker/src/rust/api.dart'; import 'package:timetracker/src/rust/frb_generated.dart'; int dateTimeToUnixSeconds(DateTime dt) => dt.toUtc().millisecondsSinceEpoch ~/ 1000; DateTime unixSecondsToDateTime(int ts) => DateTime.fromMillisecondsSinceEpoch(ts * 1000, isUtc: true).toLocal(); class TimeTrackingService extends ChangeNotifier { // final RustLibApi api; bool _isInitialized = false; bool _isLoading = true; TimeEntry? _currentTracking; List _tags = []; bool get isInitialized => _isInitialized; bool get isLoading => _isLoading; TimeEntry? get currentTracking => _currentTracking; List get tags => _tags; // TimeTrackingService({required this.api}) { TimeTrackingService() { _loadInitialData(); } Future _loadInitialData() async { _isLoading = true; _isInitialized = false; notifyListeners(); try { _currentTracking = await getLastUnfinishedTracking(); _tags = await getTags(); _isInitialized = true; } on FrbException catch (e) { _isInitialized = false; log("error loading initial data: $e"); } catch (e) { log("unexpected error loading initial data: $e"); _isInitialized = false; } finally { _isLoading = false; notifyListeners(); } } Future refreshData() async { await _loadInitialData(); } Future flStartTracking(int? tagId) async { if (_currentTracking != null) { log("Cannot start tracking: Another tracking is already active."); return false; } final startTime = DateTime.now(); try { final newEntryId = await startTracking( tagId: tagId, startTimeUnixTs: dateTimeToUnixSeconds(startTime), ); log("Tracking started with new ID: $newEntryId"); await _loadInitialData(); return true; } on FrbException catch (e) { log("Error starting tracking: $e"); return false; } catch (e) { log("Unexpected error starting tracking: $e"); return false; } } Future flStopTracking() async { if (_currentTracking == null) { log("Cannot stop tracking: No tracking is active."); return false; } final endTime = DateTime.now(); final entryIdToStop = _currentTracking!.id; try { await stopTracking( entryId: entryIdToStop, endTimeUnixTs: dateTimeToUnixSeconds(endTime), ); log("Tracking stopped for ID: $entryIdToStop"); await _loadInitialData(); return true; } on FrbException catch (e) { log("Error stopping tracking: $e"); return false; } catch (e) { log("Unexpected error stopping tracking: $e"); return false; } } Future flCreateTag(String name) async { if (name.trim().isEmpty) { log("Cannot create tag: Name is empty."); return false; } final trimmedName = name.trim(); try { final tagId = await createTag(name: trimmedName); log("Tag created with ID: $tagId"); _tags = await getTags(); notifyListeners(); return true; } on FrbException catch (e) { log("Error creating tag: $e"); return false; } catch (e) { log("Unexpected error creating tag: $e"); return false; } } Future flGetReport( int? tagId, DateTime start, DateTime end, ) async { try { final report = await generateReport( tagIdFilter: tagId, startDateUnixTs: dateTimeToUnixSeconds(start), endDateUnixTs: dateTimeToUnixSeconds(end), ); return report; } on FrbException catch (e) { log("Error generating report: $e"); return null; } catch (e) { log("Unexpected error generating report: $e"); return null; } } Future flUpdateTimeEntry({ required int entryId, required int? tagId, required DateTime startTime, required DateTime? endTime, }) async { try { await updateTimeEntry( entryId: entryId, newTagId: tagId, newStartTimeUnixTs: dateTimeToUnixSeconds(startTime), newEndTimeUnixTs: dateTimeToUnixSeconds(endTime!), ); log("Time entry $entryId updated successfully via service."); return true; } on FrbException catch (e) { log("Error updating time entry $entryId: $e"); return false; } catch (e) { log("Unexpected error updating time entry $entryId: $e"); return false; } } Future flDeleteTimeEntry(int entryId) async { log('Service: Attempting to delete entry $entryId'); try { await deleteTimeEntry(id: entryId); log('Service: Successfully deleted entry $entryId'); return true; } on FrbException catch (e, s) { log('Service: Error deleting entry $entryId: $e\n$s'); return false; } catch (e, s) { log('Service: Unexpected error deleting entry $entryId: $e\n$s'); return false; } } }