|
|
|
@ -66,28 +66,23 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
/// Get count of selected organs
|
|
|
|
/// Get count of selected organs
|
|
|
|
int get selectedOrgansCount => _selectedOrganIds.length;
|
|
|
|
int get selectedOrgansCount => _selectedOrganIds.length;
|
|
|
|
|
|
|
|
|
|
|
|
/// Get organ symptoms from API response
|
|
|
|
List<OrganSymptomResult> get organSymptomsResults {
|
|
|
|
List<OrganSymptomResult> get organSymptomsResults {
|
|
|
|
|
|
|
|
if (bodySymptomResponse?.dataDetails?.result == null) {
|
|
|
|
if (bodySymptomResponse?.dataDetails?.result == null) {
|
|
|
|
return [];
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bodySymptomResponse!.dataDetails!.result ?? [];
|
|
|
|
return bodySymptomResponse!.dataDetails!.result ?? [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Get total selected symptoms count across all organs
|
|
|
|
int get totalSelectedSymptomsCount {
|
|
|
|
int get totalSelectedSymptomsCount {
|
|
|
|
|
|
|
|
return _selectedSymptomsByOrgan.values.fold(0, (sum, symptomIds) => sum + symptomIds.length);
|
|
|
|
return _selectedSymptomsByOrgan.values.fold(0, (sum, symptomIds) => sum + symptomIds.length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Check if at least one symptom is selected
|
|
|
|
bool get hasSelectedSymptoms {
|
|
|
|
bool get hasSelectedSymptoms {
|
|
|
|
|
|
|
|
return _selectedSymptomsByOrgan.values.any((symptomIds) => symptomIds.isNotEmpty);
|
|
|
|
return _selectedSymptomsByOrgan.values.any((symptomIds) => symptomIds.isNotEmpty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Methods
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Toggle between front and back body view
|
|
|
|
void toggleView() {
|
|
|
|
void toggleView() {
|
|
|
|
|
|
|
|
_currentView = _currentView == BodyView.front ? BodyView.back : BodyView.front;
|
|
|
|
_currentView = _currentView == BodyView.front ? BodyView.back : BodyView.front;
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -97,8 +92,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Toggle organ selection (add if not selected, remove if selected)
|
|
|
|
void toggleOrganSelection(String organId) {
|
|
|
|
void toggleOrganSelection(String organId) {
|
|
|
|
|
|
|
|
if (_selectedOrganIds.contains(organId)) {
|
|
|
|
if (_selectedOrganIds.contains(organId)) {
|
|
|
|
_selectedOrganIds.remove(organId);
|
|
|
|
_selectedOrganIds.remove(organId);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
@ -111,13 +105,10 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Show tooltip for an organ
|
|
|
|
void _showTooltip(String organId) {
|
|
|
|
void _showTooltip(String organId) {
|
|
|
|
_tooltipTimer?.cancel();
|
|
|
|
// Cancel any existing timer
|
|
|
|
|
|
|
|
_tooltipTimer?.cancel();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set the tooltip organ
|
|
|
|
_tooltipOrganId = organId;
|
|
|
|
_tooltipOrganId = organId;
|
|
|
|
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
|
|
|
|
|
|
|
|
// Hide tooltip after 2 seconds
|
|
|
|
// Hide tooltip after 2 seconds
|
|
|
|
@ -134,47 +125,39 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Remove a specific organ from selection
|
|
|
|
void removeOrgan(String organId) {
|
|
|
|
void removeOrgan(String organId) {
|
|
|
|
|
|
|
|
_selectedOrganIds.remove(organId);
|
|
|
|
_selectedOrganIds.remove(organId);
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Clear all selected organs
|
|
|
|
void clearAllSelections() {
|
|
|
|
void clearAllSelections() {
|
|
|
|
|
|
|
|
_selectedOrganIds.clear();
|
|
|
|
_selectedOrganIds.clear();
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Toggle bottom sheet expanded/collapsed state
|
|
|
|
void toggleBottomSheet() {
|
|
|
|
void toggleBottomSheet() {
|
|
|
|
|
|
|
|
_isBottomSheetExpanded = !_isBottomSheetExpanded;
|
|
|
|
_isBottomSheetExpanded = !_isBottomSheetExpanded;
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Set bottom sheet expanded state
|
|
|
|
void setBottomSheetExpanded(bool isExpanded) {
|
|
|
|
void setBottomSheetExpanded(bool isExpanded) {
|
|
|
|
|
|
|
|
_isBottomSheetExpanded = isExpanded;
|
|
|
|
_isBottomSheetExpanded = isExpanded;
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Validate if at least one organ is selected
|
|
|
|
bool validateSelection() {
|
|
|
|
bool validateSelection() {
|
|
|
|
|
|
|
|
return _selectedOrganIds.isNotEmpty;
|
|
|
|
return _selectedOrganIds.isNotEmpty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Get selected organ IDs as a list
|
|
|
|
List<String> getSelectedOrganIds() {
|
|
|
|
List<String> getSelectedOrganIds() {
|
|
|
|
|
|
|
|
return _selectedOrganIds.toList();
|
|
|
|
return _selectedOrganIds.toList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Get selected organ names as a list
|
|
|
|
List<String> getSelectedOrganNames() {
|
|
|
|
List<String> getSelectedOrganNames() {
|
|
|
|
|
|
|
|
return selectedOrgans.map((organ) => organ.description).toList();
|
|
|
|
return selectedOrgans.map((organ) => organ.description).toList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Initialize symptoms from API based on selected organs
|
|
|
|
Future<void> initializeSymptomGroups({
|
|
|
|
Future<void> initializeSymptomGroups({
|
|
|
|
|
|
|
|
Function()? onSuccess,
|
|
|
|
Function()? onSuccess,
|
|
|
|
Function(String)? onError,
|
|
|
|
Function(String)? onError,
|
|
|
|
}) async {
|
|
|
|
}) async {
|
|
|
|
@ -185,15 +168,12 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the 'name' field from selected organs to send to API
|
|
|
|
List<String> organNames = selectedOrgans.map((organ) => organ.name).toList();
|
|
|
|
List<String> organNames = selectedOrgans.map((organ) => organ.name).toList();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fetch symptoms from API
|
|
|
|
await getBodySymptomsByName(
|
|
|
|
await getBodySymptomsByName(
|
|
|
|
|
|
|
|
organNames: organNames,
|
|
|
|
organNames: organNames,
|
|
|
|
onSuccess: (response) {
|
|
|
|
onSuccess: (response) {
|
|
|
|
// API response is already stored in bodySymptomResponse
|
|
|
|
if (onSuccess != null) {
|
|
|
|
if (onSuccess != null) {
|
|
|
|
|
|
|
|
onSuccess();
|
|
|
|
onSuccess();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
@ -205,8 +185,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Toggle symptom selection for a specific organ
|
|
|
|
void toggleSymptomSelection(String organId, String symptomId) {
|
|
|
|
void toggleSymptomSelection(String organId, String symptomId) {
|
|
|
|
|
|
|
|
if (!_selectedSymptomsByOrgan.containsKey(organId)) {
|
|
|
|
if (!_selectedSymptomsByOrgan.containsKey(organId)) {
|
|
|
|
_selectedSymptomsByOrgan[organId] = {};
|
|
|
|
_selectedSymptomsByOrgan[organId] = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -219,13 +198,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Check if a symptom is selected
|
|
|
|
bool isSymptomSelected(String organId, String symptomId) {
|
|
|
|
bool isSymptomSelected(String organId, String symptomId) {
|
|
|
|
|
|
|
|
return _selectedSymptomsByOrgan[organId]?.contains(symptomId) ?? false;
|
|
|
|
return _selectedSymptomsByOrgan[organId]?.contains(symptomId) ?? false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Get all selected symptoms across all organs (using API models)
|
|
|
|
List<BodySymptom> getAllSelectedSymptoms() {
|
|
|
|
List<BodySymptom> getAllSelectedSymptoms() {
|
|
|
|
|
|
|
|
List<BodySymptom> allSymptoms = [];
|
|
|
|
List<BodySymptom> allSymptoms = [];
|
|
|
|
|
|
|
|
|
|
|
|
if (bodySymptomResponse?.dataDetails?.result == null) {
|
|
|
|
if (bodySymptomResponse?.dataDetails?.result == null) {
|
|
|
|
@ -233,8 +210,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (var organResult in bodySymptomResponse!.dataDetails!.result!) {
|
|
|
|
for (var organResult in bodySymptomResponse!.dataDetails!.result!) {
|
|
|
|
// Find matching organ ID
|
|
|
|
String? matchingOrganId;
|
|
|
|
String? matchingOrganId;
|
|
|
|
|
|
|
|
for (var organ in selectedOrgans) {
|
|
|
|
for (var organ in selectedOrgans) {
|
|
|
|
if (organ.name == organResult.name) {
|
|
|
|
if (organ.name == organResult.name) {
|
|
|
|
matchingOrganId = organ.id;
|
|
|
|
matchingOrganId = organ.id;
|
|
|
|
@ -258,14 +234,12 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
return allSymptoms;
|
|
|
|
return allSymptoms;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Clear all symptom selections
|
|
|
|
void clearAllSymptomSelections() {
|
|
|
|
void clearAllSymptomSelections() {
|
|
|
|
|
|
|
|
_selectedSymptomsByOrgan.clear();
|
|
|
|
_selectedSymptomsByOrgan.clear();
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Reset the view model to initial state
|
|
|
|
void reset() {
|
|
|
|
void reset() {
|
|
|
|
|
|
|
|
_currentView = BodyView.front;
|
|
|
|
_currentView = BodyView.front;
|
|
|
|
_selectedOrganIds.clear();
|
|
|
|
_selectedOrganIds.clear();
|
|
|
|
_selectedSymptomsByOrgan.clear();
|
|
|
|
_selectedSymptomsByOrgan.clear();
|
|
|
|
@ -276,8 +250,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Fetch body symptoms by organ names from API
|
|
|
|
Future<void> getBodySymptomsByName({
|
|
|
|
Future<void> getBodySymptomsByName({
|
|
|
|
|
|
|
|
required List<String> organNames,
|
|
|
|
required List<String> organNames,
|
|
|
|
Function(BodySymptomResponseModel)? onSuccess,
|
|
|
|
Function(BodySymptomResponseModel)? onSuccess,
|
|
|
|
Function(String)? onError,
|
|
|
|
Function(String)? onError,
|
|
|
|
@ -290,8 +263,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
result.fold(
|
|
|
|
result.fold(
|
|
|
|
// Handle failure
|
|
|
|
(failure) async {
|
|
|
|
(failure) async {
|
|
|
|
|
|
|
|
isBodySymptomsLoading = false;
|
|
|
|
isBodySymptomsLoading = false;
|
|
|
|
notifyListeners();
|
|
|
|
notifyListeners();
|
|
|
|
await errorHandlerService.handleError(failure: failure);
|
|
|
|
await errorHandlerService.handleError(failure: failure);
|
|
|
|
@ -299,8 +271,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
|
|
|
|
onError(failure.toString());
|
|
|
|
onError(failure.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
// Handle success
|
|
|
|
(apiResponse) {
|
|
|
|
(apiResponse) {
|
|
|
|
|
|
|
|
isBodySymptomsLoading = false;
|
|
|
|
isBodySymptomsLoading = false;
|
|
|
|
if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
|
|
|
|
if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
|
|
|
|
bodySymptomResponse = apiResponse.data;
|
|
|
|
bodySymptomResponse = apiResponse.data;
|
|
|
|
|