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) { return false; } final trimmedName = name.trim(); try { final tagId = await createTag(name: trimmedName); log("Tag created with ID: $tagId"); await _loadUpdatedTags(); return true; } on FrbException catch (e) { log("Error creating tag: $e"); return false; } catch (e) { log("Unexpected error creating tag: $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; } } Future flUpdateTag(int tagId, String newName) async { if (newName.trim().isEmpty) { log('Service: Cannot update tag $tagId: New name is empty.'); return false; } final trimmedName = newName.trim(); log('Service: Attempting to update tag $tagId to "$trimmedName"'); try { await updateTag(id: tagId.toInt(), newName: trimmedName); log('Service: Successfully updated tag $tagId'); await _loadUpdatedTags(); return true; // Erfolg } on FrbException catch (e, s) { log('Service: Error updating tag $tagId: $e\n$s'); return false; } catch (e, s) { log('Service: Unexpected error updating tag $tagId: $e\n$s'); return false; } } Future flDeleteTag(int tagId) async { log('Service: Attempting to delete tag $tagId'); try { await deleteTag(id: tagId.toInt()); log('Service: Successfully deleted tag $tagId'); await _loadUpdatedTags(); return true; } on FrbException catch (e, s) { log('Service: Error deleting tag $tagId: $e\n$s'); return false; } catch (e, s) { log('Service: Unexpected error deleting tag $tagId: $e\n$s'); return false; } } Future _loadUpdatedTags() async { try { _tags = await getTags(); notifyListeners(); } catch (e) { log("Error refreshing tags after CUD operation: $e"); } } }