refactor: Projektstruktur in app/ und backend/ aufgeteilt
This commit is contained in:
173
app/lib/app_state.dart
Normal file
173
app/lib/app_state.dart
Normal file
@@ -0,0 +1,173 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'models/job.dart';
|
||||
import 'services/database_service.dart';
|
||||
import 'services/dart_mq.dart';
|
||||
import 'l10n/app_localizations.dart';
|
||||
|
||||
/// Global notifier for language changes
|
||||
final ValueNotifier<Locale> localeNotifier = ValueNotifier<Locale>(const Locale('de'));
|
||||
|
||||
class AppState {
|
||||
static final AppState _instance = AppState._internal();
|
||||
factory AppState() => _instance;
|
||||
AppState._internal();
|
||||
|
||||
String? _loggedInEmail;
|
||||
List<Job> _assignedJobs = [];
|
||||
final DatabaseService _databaseService = DatabaseService();
|
||||
|
||||
// Language settings
|
||||
String _languageCode = 'de';
|
||||
String get languageCode => _languageCode;
|
||||
|
||||
/// Get current locale
|
||||
Locale get currentLocale => Locale(_languageCode);
|
||||
|
||||
/// Set language and update the global notifier
|
||||
Future<void> setLanguage(String languageCode) async {
|
||||
if (supportedLanguageCodes.contains(languageCode)) {
|
||||
_languageCode = languageCode;
|
||||
await _databaseService.saveLanguagePreference(languageCode);
|
||||
localeNotifier.value = Locale(languageCode);
|
||||
}
|
||||
}
|
||||
|
||||
/// Load language preference from database
|
||||
Future<void> loadLanguagePreference() async {
|
||||
final savedLanguage = await _databaseService.loadLanguagePreference();
|
||||
if (savedLanguage != null && supportedLanguageCodes.contains(savedLanguage)) {
|
||||
_languageCode = savedLanguage;
|
||||
localeNotifier.value = Locale(savedLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize persistence to avoid overlapping DB save/load cycles
|
||||
bool _isPersistingJobs = false;
|
||||
List<Job>? _pendingJobs; // holds the latest jobs to persist if calls overlap
|
||||
|
||||
// Jobs update notification (emitted once after DB was updated)
|
||||
final StreamController<void> _jobsUpdatedController = StreamController<void>.broadcast();
|
||||
Stream<void> get jobsUpdated => _jobsUpdatedController.stream;
|
||||
|
||||
/// The logged-in user's email (used as local identifier for chats)
|
||||
String? get loggedInEmail => _loggedInEmail;
|
||||
|
||||
List<Job> get assignedJobs => List.unmodifiable(_assignedJobs);
|
||||
|
||||
void setLoggedInEmail(String email) {
|
||||
_loggedInEmail = email;
|
||||
}
|
||||
|
||||
Future<void> clearLogin() async {
|
||||
_loggedInEmail = null;
|
||||
_assignedJobs.clear();
|
||||
// Clear database
|
||||
await _databaseService.clearAllData();
|
||||
// Notify listeners/UI that jobs were cleared
|
||||
_jobsUpdatedController.add(null);
|
||||
DartMQ().publish<void>(MQTopics.jobsUpdated, null);
|
||||
}
|
||||
|
||||
bool get isLoggedIn => _loggedInEmail != null;
|
||||
|
||||
Future<void> setAssignedJobs(List<Job> jobs) async {
|
||||
// Coalesce overlapping calls: if a persist is already running, remember only the latest
|
||||
if (_isPersistingJobs) {
|
||||
_pendingJobs = jobs;
|
||||
return;
|
||||
}
|
||||
|
||||
_isPersistingJobs = true;
|
||||
try {
|
||||
// Start with the initial batch to persist
|
||||
var toPersist = jobs;
|
||||
while (true) {
|
||||
// Normalize first
|
||||
final normalized = toPersist.map((j) => j.normalized()).toList();
|
||||
|
||||
// Persist normalized list to DB only (no UI notifications here)
|
||||
await _databaseService.saveJobs(normalized);
|
||||
|
||||
// If another request came in during persistence, handle only the latest once
|
||||
if (_pendingJobs != null) {
|
||||
toPersist = _pendingJobs!;
|
||||
_pendingJobs = null;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// After DB is updated with the latest data, notify listeners once to refresh UI
|
||||
_jobsUpdatedController.add(null);
|
||||
// Also publish via dart_mq for app-wide decoupled messaging
|
||||
DartMQ().publish<void>(MQTopics.jobsUpdated, null);
|
||||
} finally {
|
||||
_isPersistingJobs = false;
|
||||
}
|
||||
}
|
||||
|
||||
void addJob(Job job) {
|
||||
if (!_assignedJobs.contains(job)) {
|
||||
_assignedJobs.add(job);
|
||||
}
|
||||
}
|
||||
|
||||
void removeJob(String jobId) {
|
||||
_assignedJobs.removeWhere((job) => job.id == jobId);
|
||||
// Update database
|
||||
_databaseService.saveJobs(_assignedJobs);
|
||||
}
|
||||
|
||||
/// Delete a job by ID (called when server sends job_deleted event)
|
||||
Future<void> deleteJob(String jobId) async {
|
||||
_assignedJobs.removeWhere((job) => job.id == jobId);
|
||||
// Delete from database
|
||||
await _databaseService.deleteJob(jobId);
|
||||
// Notify listeners
|
||||
_jobsUpdatedController.add(null);
|
||||
DartMQ().publish<void>(MQTopics.jobsUpdated, null);
|
||||
}
|
||||
|
||||
/// Add a new job (called when server sends job_created event)
|
||||
Future<void> addNewJob(Job job) async {
|
||||
// Check if job already exists
|
||||
if (_assignedJobs.any((j) => j.id == job.id)) {
|
||||
return;
|
||||
}
|
||||
// Add to memory
|
||||
_assignedJobs.insert(0, job);
|
||||
// Persist to database
|
||||
await _databaseService.saveOrUpdateJob(job);
|
||||
// Notify listeners
|
||||
_jobsUpdatedController.add(null);
|
||||
DartMQ().publish<void>(MQTopics.jobsUpdated, null);
|
||||
}
|
||||
|
||||
/// Load login state from saved credentials on app start
|
||||
Future<void> loadLoginFromDatabase() async {
|
||||
final credentials = await _databaseService.loadCredentials();
|
||||
if (credentials != null) {
|
||||
_loggedInEmail = credentials.email;
|
||||
}
|
||||
}
|
||||
|
||||
void updateJob(Job updatedJob) {
|
||||
final index = _assignedJobs.indexWhere((job) => job.id == updatedJob.id);
|
||||
if (index != -1) {
|
||||
_assignedJobs[index] = updatedJob;
|
||||
}
|
||||
}
|
||||
|
||||
/// Refresh in-memory jobs from the database without emitting other notifications
|
||||
Future<void> refreshJobsFromDatabase() async {
|
||||
final jobs = await _databaseService.loadJobs();
|
||||
_assignedJobs = jobs;
|
||||
}
|
||||
|
||||
/// Persistently upsert a single job and refresh in-memory list
|
||||
Future<void> upsertJob(Job job) async {
|
||||
await _databaseService.saveOrUpdateJob(job);
|
||||
final persisted = await _databaseService.loadJobs();
|
||||
_assignedJobs = persisted.isNotEmpty ? persisted : _assignedJobs;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user