Prapare
A patient-facing Flutter app that allows for entry of Social Determinants of Health (SDOH) data in their own native language.
Install / Use
/learn @FireJuun/PrapareREADME
PRAPARE
A patient-facing Flutter app that allows for entry of Social Determinants of Health (SDOH) data in their own native language.
This app directly builds off of the work pioneered in the [PRAPARE] project, though at this time it is not formally affiliated with PRAPARE.
A related [Youtube playlist] and a [demo repository] exist to teach the concepts & components used when building this app.
<img align="right" src="demo.gif" width="250"/>Design
A basic [prototype] and relevant [wireframes] were created in Figma prior to app creation.
Architecture
This app loosely follows the [Model-View-Controller+Services] (MVC+S) architecture, which has both [simple] and [production-level] examples of use. Whereas the above examples make heavy use of Provider, ChangeNotifier, and StatefulWidgets, we are instead using [Get] and some of the [Getx pattern] to simplify state management, routing, and dependency injection.
Our take on MVC+S is as follows:
model: Class/objects created specifically for this appviews: The UI layer, which is separated into multiplepagesand may optionally be managed via aviewcontrollercontroller: Manages state of the model and resultant data. Controller classes typically extendGetxController(automatically disposed) andGetxService(rarely/never disposed)service: Connects your app with the outside world (e.g. internet or local file system).command: A high level function that performs a specific task, such as login/logout. It may utilize controllers, APIs, models, etc as necessary. <img align="center" src="getMVCS.png" width="550"/>
Folder Structure
The following is the folder structure under the /lib folder:
| Folder | Subfolder | Description | | ------------ | -------------------------------------- | ------------------------------------------------------------------------------------------------------ | | /_internal | | custom modifications, constants / enums, utility classes | | | /components | custom components / variations on Flutter widgets | | | /constants | local constants created for the app | | | /enums | predefined, named constants | | | /utils | local functions that do things like formatting | | /api | | optional API key location | | | <custom>.dart | private API keys | | | api_public.dart | public API keys (no gitignore) | | | api.dart | generic export file | | /controllers | | manages state of the model and resultant data | | | /commands | performs a specific global task (login, logout, change password) | | | ../<custom>_command.dart | custom command class | | | ../abstract_command.dart | abstract class for commonly used controllers, placeholder execute() method for commands | | | <custom>_controller.dart | custom controller, typically used for state management | | /models | | classes / objects created specifically for this app | | | <custom>_data.dart | custom data class | | | <custom>model.dart | data model that typically modifies or shapes a data class | | /routes | | maps route to screen widgets | | | app_pages.dart | the directory of each page within an app | | | app_routes.dart | string route names used in the app | | /services | | interaction with the outside world (REST, FHIR, http, file storage) | | /ui | | essentially all things a user sees in the app | | | /styled_components | shared widgets that use a common design system / theme so that the app seems consistent across screens | | | ../styled<widget_name>.dart | | | | /views | top level widgets that are loaded via a route | | | ../<screen_name>/ | | | | ../../<screen_name>.dart | the screen widget, may optionally include 'page', 'card', or 'panel' at the end based on view type | | | ../../<screen_name>_binding.dart | controllers/services that are loaded (or lazy-loaded) in a view | | | ../../<screen_name>_controller.dart | the viewcontroller that only affects this screen widget | | | ../../<screen_name>_test.dart | any relevant tests for the screen widget or its viewcontroller | | | icons.dart | icon asset locations | | | localization.dart | strings with multiple translations | | | strings.dart | strings used throughout an app | | | themes.dart | custom themes and font sizes | | main.dart | | the first file a Dart app runs |
Questionnaire vs Survey
To differentiate between FHIR and our local data model, we have employed the term Survey
- When an item is specifically related to FHIR and it's formatting, the term Questionnaire is used, along with the formatting for that FHIR resource
- When it is part of the local model (including locally stored surveys/questionnaires) the term survey is used
To Use the Questionnaire Package
You would create a new object:
var questionnaire = FhirQuestionnaire();
Load the survey (currently hardcoded into the app, but will soon have ability to download from url)
questionnaire.loadAndCreateSurvey();
Anytime that a user has answered questions that you would like to keep track of, you can pass them back like this:
final responses = [
UserResponse(
surveyCode: '/93043-8',
questionCode: '/93043-8/56051-6',
answerCode: 'LA33-6'),
UserResponse(
surveyCode: '/93043-8',
questionCode: '/93043-8/32624-9',
answerCode: 'LA14042-8'),
];
questionnaire.getUserResponses(responses);
This can be done multiple times or once, the object will simply keep it as a list until you are finished. Then, when you're ready to create the final response, call the method:
questionnaire.createResponse();
Now you have a QuestionnaireResponse item that you can do with as you will. To print for instance:
print(questionnaire.response.toJson());
Fix Compile Time API Errors
With the exception of /api/api_public.dart, all files and classes in the /api folder are ignored by Git. Unless you're intentionally planning for an API key to exist in the public domain, DO NOT COMMIT YOUR API KEYS DIRECTLY INTO YOUR GITHUB REPOSITORY. Deleting them from your Git cache does nothing if the key has already been committed. They can still be found. If you did this accidentally, just inactivate that key (so others can't use it) and register a new one for use. Also, be careful of where and how you share your keys, since that may also serve as a point of failure.
Because our app connects to multiple FHIR servers, checking out this repository as is will give you compile time errors. To fix this, create the following files in the `
