timetracker/lib/time_tracking_service.dart
2025-04-09 21:59:26 +02:00

187 lines
5.1 KiB
Dart

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<Tag> _tags = [];
bool get isInitialized => _isInitialized;
bool get isLoading => _isLoading;
TimeEntry? get currentTracking => _currentTracking;
List<Tag> get tags => _tags;
// TimeTrackingService({required this.api}) {
TimeTrackingService() {
_loadInitialData();
}
Future<void> _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<void> refreshData() async {
await _loadInitialData();
}
Future<bool> 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<bool> 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<bool> 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<ReportData?> 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<bool> 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<bool> 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;
}
}
}