244 lines
6.6 KiB
Dart
244 lines
6.6 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:my_attendance/models/attendance_entry.dart';
|
|
import 'package:my_attendance/utils/database_helper.dart';
|
|
|
|
class AttendanceService with ChangeNotifier {
|
|
final DatabaseHelper _dbHelper = DatabaseHelper();
|
|
|
|
AttendanceEntry? _todayEntry;
|
|
AttendanceEntry? get todayEntry => _todayEntry;
|
|
|
|
List<AttendanceEntry> _history = [];
|
|
List<AttendanceEntry> get history => _history;
|
|
|
|
Map<String, int> _monthlyStats = {};
|
|
Map<String, int> get monthlyStats => _monthlyStats;
|
|
|
|
Map<String, int> _yearlyStats = {};
|
|
Map<String, int> get yearlyStats => _yearlyStats;
|
|
|
|
bool _isLoading = true;
|
|
bool get isLoading => _isLoading;
|
|
|
|
AttendanceService() {
|
|
loadTodayEntry();
|
|
}
|
|
|
|
Future<void> logIn() async {
|
|
_isLoading = true;
|
|
notifyListeners();
|
|
try {
|
|
final now = DateTime.now();
|
|
final date = DateTime(now.year, now.month, now.day);
|
|
|
|
final entry = AttendanceEntry(
|
|
date: date,
|
|
loginTime: now,
|
|
entryType: EntryType.work,
|
|
);
|
|
|
|
final id = await _dbHelper.insertAttendance(entry);
|
|
_todayEntry = entry.copyWith(id: id);
|
|
} catch (e) {
|
|
debugPrint("Error logging in: $e");
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> logOut() async {
|
|
if (_todayEntry == null || _todayEntry!.logoutTime != null) return;
|
|
|
|
_isLoading = true;
|
|
notifyListeners();
|
|
try {
|
|
final now = DateTime.now();
|
|
final updatedEntry = _todayEntry!.copyWith(logoutTime: now);
|
|
await _dbHelper.updateAttendance(updatedEntry);
|
|
_todayEntry = updatedEntry;
|
|
} catch (e) {
|
|
debugPrint("Error logging out: $e");
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> loadTodayEntry() async {
|
|
_isLoading = true;
|
|
notifyListeners();
|
|
try {
|
|
final now = DateTime.now();
|
|
final date = DateTime(now.year, now.month, now.day);
|
|
_todayEntry = await _dbHelper.getAttendanceForDate(date);
|
|
} catch (e) {
|
|
debugPrint("Error loading today's entry: $e");
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> loadHistory({int limit = 10}) async {
|
|
_isLoading = true;
|
|
notifyListeners();
|
|
try {
|
|
_history = await _dbHelper.getAttendanceHistory(limit: limit);
|
|
} catch (e) {
|
|
debugPrint("Error loading history: $e");
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> updateNotes(int entryId, String notes) async {
|
|
try {
|
|
AttendanceEntry? entryToUpdate;
|
|
if (_todayEntry?.id == entryId) {
|
|
entryToUpdate = _todayEntry;
|
|
} else {
|
|
entryToUpdate = _history.firstWhere((e) => e.id == entryId);
|
|
}
|
|
|
|
if (entryToUpdate != null) {
|
|
final updated = entryToUpdate.copyWith(notes: notes);
|
|
await _dbHelper.updateAttendance(updated);
|
|
await loadTodayEntry();
|
|
await loadHistory();
|
|
await calculateStats();
|
|
}
|
|
} catch (e) {
|
|
debugPrint("Error updating notes: $e");
|
|
}
|
|
}
|
|
|
|
Future<void> markAsWfh() async {
|
|
_isLoading = true;
|
|
notifyListeners();
|
|
try {
|
|
final now = DateTime.now();
|
|
final date = DateTime(now.year, now.month, now.day);
|
|
final entry = AttendanceEntry(date: date, entryType: EntryType.wfh);
|
|
final id = await _dbHelper.insertAttendance(entry);
|
|
_todayEntry = entry.copyWith(id: id);
|
|
await calculateStats();
|
|
} catch (e) {
|
|
debugPrint("Error marking as WFH: $e");
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> markAsLeave(LeaveType leaveType) async {
|
|
_isLoading = true;
|
|
notifyListeners();
|
|
try {
|
|
final now = DateTime.now();
|
|
final date = DateTime(now.year, now.month, now.day);
|
|
final entry = AttendanceEntry(
|
|
date: date,
|
|
entryType: EntryType.leave,
|
|
leaveType: leaveType,
|
|
);
|
|
final id = await _dbHelper.insertAttendance(entry);
|
|
_todayEntry = entry.copyWith(id: id);
|
|
await calculateStats();
|
|
} catch (e) {
|
|
debugPrint("Error marking as leave: $e");
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> resetData() async {
|
|
_isLoading = true;
|
|
notifyListeners();
|
|
try {
|
|
await _dbHelper.resetDatabase();
|
|
_todayEntry = null;
|
|
_history = [];
|
|
await calculateStats();
|
|
} catch (e) {
|
|
debugPrint("Error resetting data: $e");
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> updateOrCreateEntry(AttendanceEntry entry) async {
|
|
final existingEntry = await _dbHelper.getAttendanceForDate(entry.date);
|
|
if (existingEntry != null) {
|
|
// Preserve the original ID when updating
|
|
await _dbHelper.updateAttendance(entry.copyWith(id: existingEntry.id));
|
|
} else {
|
|
await _dbHelper.insertAttendance(entry);
|
|
}
|
|
// Refresh data to reflect changes
|
|
await loadTodayEntry();
|
|
await loadHistory();
|
|
await calculateStats();
|
|
}
|
|
|
|
Future<AttendanceEntry?> getEntryForDate(DateTime date) async {
|
|
return await _dbHelper.getAttendanceForDate(date);
|
|
}
|
|
|
|
Future<void> calculateStats() async {
|
|
final now = DateTime.now();
|
|
|
|
// Monthly stats
|
|
final monthStart = DateTime(now.year, now.month, 1);
|
|
final monthEnd = DateTime(now.year, now.month + 1, 0);
|
|
final monthlyEntries = await _dbHelper.getAttendanceInRange(
|
|
monthStart,
|
|
monthEnd,
|
|
);
|
|
_monthlyStats = _calculateCounts(monthlyEntries);
|
|
|
|
// Yearly stats
|
|
final yearStart = DateTime(now.year, 1, 1);
|
|
final yearEnd = DateTime(now.year, 12, 31);
|
|
final yearlyEntries = await _dbHelper.getAttendanceInRange(
|
|
yearStart,
|
|
yearEnd,
|
|
);
|
|
_yearlyStats = _calculateCounts(yearlyEntries);
|
|
|
|
notifyListeners();
|
|
}
|
|
|
|
Map<String, int> _calculateCounts(List<AttendanceEntry> entries) {
|
|
final counts = <String, int>{};
|
|
for (final entry in entries) {
|
|
if (entry.entryType == EntryType.wfh) {
|
|
counts['Work From Home'] = (counts['Work From Home'] ?? 0) + 1;
|
|
} else if (entry.entryType == EntryType.leave) {
|
|
final leaveName = _getLeaveTypeName(entry.leaveType);
|
|
counts[leaveName] = (counts[leaveName] ?? 0) + 1;
|
|
}
|
|
}
|
|
return counts;
|
|
}
|
|
|
|
String _getLeaveTypeName(LeaveType? type) {
|
|
switch (type) {
|
|
case LeaveType.sick:
|
|
return 'Sick Leave';
|
|
case LeaveType.annual:
|
|
return 'Annual Leave';
|
|
case LeaveType.nationalHoliday:
|
|
return 'National Holiday';
|
|
case LeaveType.companyWfh:
|
|
return 'Company WFH';
|
|
default:
|
|
return 'On Leave';
|
|
}
|
|
}
|
|
}
|