Skip to content

Commit

Permalink
feat(demo-app): add fake data
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjamin-Frost committed Jul 1, 2022
1 parent 079269e commit 0492b12
Show file tree
Hide file tree
Showing 14 changed files with 42,337 additions and 223 deletions.
1,449 changes: 1,449 additions & 0 deletions miscellaneous/demo-app/assets/data/diplotypes.json

Large diffs are not rendered by default.

40,778 changes: 40,778 additions & 0 deletions miscellaneous/demo-app/assets/data/lookups.json

Large diffs are not rendered by default.

97 changes: 70 additions & 27 deletions miscellaneous/demo-app/lib/common/models/medication/medication.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import 'dart:convert';

import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive/hive.dart';
import 'package:http/http.dart';

import '../../module.dart';

Expand Down Expand Up @@ -78,29 +75,75 @@ class MedicationWithGuidelines {

@override
int get hashCode => hashValues(name, guidelines);
}

List<Medication> medicationsFromHTTPResponse(Response resp) {
final json = jsonDecode(resp.body) as List<dynamic>;
return json.map<Medication>(Medication.fromJson).toList();
}

List<MedicationWithGuidelines> medicationsWithGuidelinesFromHTTPResponse(
Response resp,
) {
final json = jsonDecode(resp.body) as List<dynamic>;
return json
.map<MedicationWithGuidelines>(MedicationWithGuidelines.fromJson)
.toList();
}

MedicationWithGuidelines medicationWithGuidelinesFromHTTPResponse(
Response resp,
) {
return MedicationWithGuidelines.fromJson(jsonDecode(resp.body));
}

List<int> idsFromHTTPResponse(Response resp) {
final idsList = jsonDecode(resp.body) as List<dynamic>;
return idsList.map((e) => e['id'] as int).toList();
Medication toMedication() {
return Medication(
id,
name,
description ?? '',
drugclass,
indication,
);
}

static final fakeData = [
MedicationWithGuidelines(
id: 1,
name: 'Ibuprofen',
description: 'Lorem ipsum',
pharmgkbId: 'PA449957',
rxcui: '5640',
synonyms: ['Ibuprofen'],
drugclass: 'Pain killer',
indication: 'Ibuprofen is used to treat pain and arthritis',
guidelines: [
Guideline(
id: 1,
implication:
'You have normal CYP2C9 gene function. This makes you activate Ibuprofen as normal',
recommendation:
'You can use Ibuprofen at standard doses. Consult your doctor for more information',
warningLevel: 'ok',
cpicRecommendation:
'Initiate therapy with recommended starting dose. In accordance with the prescribing information, use the lowest effective dosage for shortest duration consistent with individual patient treatment goals.',
cpicImplication: 'Normal metabolism',
cpicClassification: 'Strong',
cpicComment: null,
cpicGuidelineUrl:
'https://cpicpgx.org/guidelines/cpic-guideline-for-nsaids-based-on-cyp2c9-genotype/',
phenotype: Phenotype(
id: 1,
cpicConsulationText:
'This result signifies that the patient has two copies of a normal function allele. Based on the genotype result, this patient is predicted to be a CYP2C9 Normal metabolizer. Based only on the CYP2C9 genotype, there is no reason to adjust the dose of most medications that are affected by CYP2C9. Please consult a clinical pharmacist for more specific information about how CYP2C9 function influences drug dosing.',
geneResult: GeneResult(id: 1, name: 'Normal Metabolizer'),
geneSymbol: GeneSymbol(id: 2, name: 'CYP2C9'),
),
),
Guideline(
id: 1,
implication:
'You have decreased CYP2C9 gene function. This makes your body slow in clearing Ibuprofen from your system',
recommendation:
'Ibuprofen may be used at a different dose. Consult your doctor for more informaton',
warningLevel: 'danger',
cpicRecommendation:
'Initiate therapy with 25-50% of the lowest recommended starting dose. Titrate dose upward to clinical effect or 25-50% of the maximum recommended dose with caution. In accordance with the prescribing information, use the lowest effective dosage for shortest duration consistent with individual patient treatment goals. Upward dose titration should not occur until after steady state is reached (at least 8 days for celecoxib after first dose in PMs). Carefully monitor adverse events such as blood pressure and kidney function during course of therapy. Alternatively, consider an alternate therapy not metabolized by CYP2C9 or not significantly impacted by CYP2C9 genetic variants in vivo.',
cpicImplication:
'Significantly reduced metabolism and prolonged half-life; higher plasma concentrations may increase probability and/or severity of toxicities',
cpicClassification: 'Moderate',
cpicComment:
'Alternative therapies not primarily metabolized by CYP2C9 include aspirin, ketorolac, naproxen and sulindac. Selection of therapy will depend on individual patient treatment goals and risks for toxicity.',
cpicGuidelineUrl:
'https://cpicpgx.org/guidelines/cpic-guideline-for-nsaids-based-on-cyp2c9-genotype/',
phenotype: Phenotype(
id: 2,
cpicConsulationText:
'This result signifies that the patient has one copy of a decreased function allele and one copy of a no function allele. Based on the genotype result, this patient is predicted to be a CYP2C9 poor metabolizer. This patient may be at high risk for an adverse response to medications that are affected by CYP2C9. Please consult a clinical pharmacist for more specific information about how CYP2C9 intermediate metabolizer status influences drug dosing.',
geneResult: GeneResult(id: 3, name: 'Poor Metabolizer'),
geneSymbol: GeneSymbol(id: 4, name: 'CYP2C9'),
),
),
],
),
];
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import 'dart:convert';

import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive/hive.dart';
import 'package:http/http.dart';

part 'diplotype.g.dart';

Expand Down Expand Up @@ -43,9 +40,3 @@ extension FilteredList on List<Diplotype> {
.toList();
}
}

// assumes http reponse from lab server
List<Diplotype> diplotypesFromHTTPResponse(Response resp) {
final json = jsonDecode(resp.body)['diplotypes'] as List<dynamic>;
return json.map<Diplotype>(Diplotype.fromJson).toList();
}
55 changes: 3 additions & 52 deletions miscellaneous/demo-app/lib/common/pages/medications/cubit.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:http/http.dart';

import '../../models/medication/cached_medications.dart';
import '../../module.dart';

part 'cubit.freezed.dart';
Expand All @@ -15,61 +13,14 @@ class MedicationsCubit extends Cubit<MedicationsState> {

Future<void> loadMedications() async {
emit(MedicationsState.loading());
final isOnline = await hasConnectionTo(annotationServerUrl.authority);
if (!isOnline) {
_findCachedMedication(_id);
return;
}
final response = await sendRequest();
if (response == null) {
final medication =
MedicationWithGuidelines.fakeData.firstWhereOrNull((e) => e.id == _id);
if (medication == null) {
emit(MedicationsState.error());
return;
}
final medication = medicationWithGuidelinesFromHTTPResponse(response);
await CachedMedications.cache(medication);
emit(MedicationsState.loaded(medication));
}

void _findCachedMedication(int id) {
CachedMedications.instance.medications ??= [];
try {
final foundMedication = CachedMedications.instance.medications!
.firstWhere((element) => element.id == id);
emit(MedicationsState.loaded(foundMedication));
} catch (e) {
emit(MedicationsState.error());
}
}

Future<Response?> sendRequest() async {
final requestIdsUri = annotationServerUrl.replace(
path: 'api/v1/medications',
queryParameters: {'onlyIds': 'true'},
);
final idsResponse = await get(requestIdsUri);
if (idsResponse.statusCode != 200) {
emit(MedicationsState.error());
return null;
}
final randomIds = idsFromHTTPResponse(idsResponse).sample(2);
randomIds.add(_id);
randomIds.shuffle();
Response? response;
for (final id in randomIds) {
final requestMedicationUri = annotationServerUrl.replace(
path: 'api/v1/medications/$id',
queryParameters: {'getGuidelines': 'true'},
);

final tempResponse = await get(requestMedicationUri);
if (tempResponse.statusCode != 200) {
emit(MedicationsState.error());
return null;
}
if (id == _id) response = tempResponse;
}
return response;
}
}

@freezed
Expand Down
30 changes: 8 additions & 22 deletions miscellaneous/demo-app/lib/common/utilities/genome_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,28 @@ import 'dart:collection';
import 'dart:convert';

import 'package:dartx/dartx.dart';
import 'package:http/http.dart';
import 'package:flutter/services.dart';

import '../constants.dart';
import '../models/module.dart';

Future<void> fetchAndSaveDiplotypes(String token, String url) async {
Future<void> fetchAndSaveDiplotypes() async {
if (!shouldFetchDiplotypes()) return;
final response = await getDiplotypes(token, url);
if (response.statusCode == 200) {
await _saveDiplotypeResponse(response);
} else {
throw Exception();
}
}

Future<Response> getDiplotypes(String? token, String url) async {
return get(Uri.parse(url), headers: {'Authorization': 'Bearer $token'});
}

Future<void> _saveDiplotypeResponse(Response response) async {
// parse response to list of user's diplotypes
final jsonFile = await rootBundle.loadString('assets/data/diplotypes.json');
final json = jsonDecode(jsonFile)['diplotypes'] as List<dynamic>;
final diplotypes =
diplotypesFromHTTPResponse(response).filterValidDiplotypes();

json.map<Diplotype>(Diplotype.fromJson).toList().filterValidDiplotypes();
UserData.instance.diplotypes = diplotypes;
return UserData.save();
await UserData.save();
}

Future<void> fetchAndSaveLookups() async {
if (!shouldFetchLookups()) return;
final response = await get(Uri.parse(cpicLookupUrl));
if (response.statusCode != 200) throw Exception();

// the returned json is a list of lookups which we wish to individually map
// to a concrete CpicLookup instance, hence the cast to a List
final json = jsonDecode(response.body) as List<dynamic>;
final jsonFile = await rootBundle.loadString('assets/data/lookups.json');
final json = jsonDecode(jsonFile) as List<dynamic>;
final lookups = json.map<CpicLookup>(CpicLookup.fromJson);
final usersDiplotypes = UserData.instance.diplotypes;
if (usersDiplotypes == null) throw Exception();
Expand Down
1 change: 0 additions & 1 deletion miscellaneous/demo-app/lib/common/utilities/module.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export 'genome_data.dart';
export 'medication_utils.dart';
export 'networking_utils.dart';
5 changes: 5 additions & 0 deletions miscellaneous/demo-app/lib/login/pages/cubit.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:freezed_annotation/freezed_annotation.dart';

import '../../../common/module.dart';
import '../../common/utilities/genome_data.dart';

part 'cubit.freezed.dart';

Expand All @@ -10,6 +11,10 @@ class LoginPageCubit extends Cubit<LoginPageState> {
Future<void> fakeLoadGeneticData() async {
emit(LoginPageState.loading());

// get data
await fetchAndSaveDiplotypes();
await fetchAndSaveLookups();

MetaData.instance.isLoggedIn = true;
await MetaData.save();
await Future.delayed(Duration(seconds: 3));
Expand Down
1 change: 0 additions & 1 deletion miscellaneous/demo-app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'common/module.dart';

Future<void> main() async {
await initServices();
await fetchAndSaveLookups();
runApp(PharmeApp());
await cleanupServices();
}
26 changes: 1 addition & 25 deletions miscellaneous/demo-app/lib/reports/pages/cubit.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:http/http.dart';

import '../../common/models/medication/cached_medications.dart';
import '../../common/module.dart';
Expand All @@ -13,30 +12,7 @@ class ReportsCubit extends Cubit<ReportsState> {
}

Future<void> loadMedications() async {
final requestUri = annotationServerUrl.replace(
path: 'api/v1/medications',
queryParameters: {
'withGuidelines': 'true',
'getGuidelines': 'true',
},
);

final isOnline = await hasConnectionTo(requestUri.authority);
if (!isOnline) {
emit(
ReportsState.loaded(
_filterMedications(CachedMedications.instance.medications ?? []),
),
);
return;
}
emit(ReportsState.loading());
final response = await get(requestUri);
if (response.statusCode != 200) {
emit(ReportsState.error());
return;
}
final medications = medicationsWithGuidelinesFromHTTPResponse(response);
final medications = MedicationWithGuidelines.fakeData;
final filteredMedications = _filterMedications(medications);
await CachedMedications.cacheAll(filteredMedications);
await CachedMedications.save();
Expand Down
12 changes: 10 additions & 2 deletions miscellaneous/demo-app/lib/reports/pages/reports.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,18 @@ class SliverReportsHeaderDelegate extends SliverPersistentHeaderDelegate {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
color: PharmeTheme.secondaryColor,
clipBehavior: Clip.hardEdge,
child: Padding(
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
PharmeTheme.primaryColor.shade500,
PharmeTheme.primaryColor.shade800,
],
),
borderRadius: BorderRadius.circular(16),
),
child: Column(children: [
Text(
context.l10n.reports_page_disclaimer_title,
Expand Down
Loading

0 comments on commit 0492b12

Please sign in to comment.