build method
- BuildContext context
override
Builds the main UI for the disease information screen.
Creates a responsive layout with:
- App bar with screen title
- Search text field for filtering diseases
- List/Grid view of disease cards based on search results
- Loading, error, and empty state handling
The layout uses Consumer widgets to react to state changes in the DiseaseInfoViewModel and updates the UI accordingly.
context The build context for accessing theme and localization data.
Returns a Widget representing the complete disease info screen UI.
Implementation
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
final searchController = TextEditingController();
return ChangeNotifierProvider<DiseaseInfoViewModel>.value(
value: locator<DiseaseInfoViewModel>()..loadDiseases(localizations),
child: Scaffold(
appBar: AppBar(
title: Text(localizations.diseaseInfoScreenTitle),
centerTitle: true,
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Consumer<DiseaseInfoViewModel>(
builder: (context, viewModel, child) {
return TextField(
controller: searchController,
decoration: InputDecoration(
hintText: localizations.searchDiseasesHint,
prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.grey.shade300),
),
filled: true,
fillColor: Colors.grey.shade100,
contentPadding: const EdgeInsets.symmetric(vertical: 0),
suffixIcon: searchController.text.isNotEmpty
? IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
searchController.clear();
viewModel.updateSearchQuery('');
},
)
: null,
),
onChanged: (value) {
viewModel.updateSearchQuery(value);
},
);
},
),
),
Expanded(
child: Consumer<DiseaseInfoViewModel>(
builder: (context, viewModel, child) {
if (viewModel.isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (viewModel.state == DiseaseInfoState.error) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
color: Colors.red,
size: 48,
),
const SizedBox(height: 16),
Text(
viewModel.errorMessage ??
localizations.anErrorOccurred,
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.red),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
viewModel.loadDiseases(localizations);
},
child: Text(localizations.retryButton),
),
],
),
);
}
final filteredDiseases = viewModel.filteredDiseases;
if (filteredDiseases.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.search_off,
size: 64,
color: Colors.grey.shade400,
),
const SizedBox(height: 16),
Text(
localizations.noDiseasesFound,
style: TextStyle(
fontSize: 18,
color: Colors.grey.shade600,
),
),
if (searchController.text.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
localizations.tryDifferentSearchTerm,
style: TextStyle(color: Colors.grey.shade500),
),
),
],
),
);
}
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: filteredDiseases.length,
itemBuilder: (context, index) {
final disease = filteredDiseases[index];
return _buildDiseaseCard(context, disease, localizations);
},
);
},
),
),
],
),
),
);
}