Skip to content

Latest commit

 

History

History
231 lines (186 loc) · 7.64 KB

CONTRIBUTING.md

File metadata and controls

231 lines (186 loc) · 7.64 KB

Contributing

Please also see the contribution guide in the root folder.

Local Setup

  • Install flutter-logo Flutter
  • Open a terminal in VSCode in the app directory
    • Run dart pub get to fetch all dart dependencies
    • Run flutter pub get to fetch all flutter dependencies and setup all generated code
    • Run dart run build_runner build --delete-conflicting-outputs or dart run build_runner watch --delete-conflicting-outputs to re-generate code upon file changes while developing

You should now be able to run the app by opening the debug panel on the left and pressing the green triangle at the top (or using the shortcut F5).

Useful Shortcuts

For (cleaning) generated code, you might want to add the following aliases to your shell configuration:

alias flutter-generate='dart run build_runner build --delete-conflicting-outputs'
alias flutter-clean='find . -maxdepth 20 -type f \( -name "*.inject.summary" -o -name "*.inject.dart" -o  -name "*.g.dart" \) -delete'

Updating Flutter and Android

... can be super painful, because Java, Gradle, and Kotlin versions may be wrong.

Often problems in packages arise that rely on older Gradle versions.

The places to check are:

  • Your Flutter version
  • Your JAVA_HOME version
  • The Gradle version in gradle-wrapper.properties; the recommended versions are "between 7.3 and 7.6.1." (see Android Java Gradle migration guide)
  • The Java version in android/app/build/gradle
  • The Java version used for Gradle (check in Android Studio)
  • The Kotlin version in settings.gradle

Architecture

The app consists of multiple so-called modules. Our main modules (usually app screens) correspond to the direct subfolders of lib/.

Common functions used by modules such as models, widgets, and utilities are living in common. All such functions are exported from common/module.dart.

The structure of an example module lib/my_module should look as follows:

  • my_module
    • module.dart (see example below):
      • exports everything that is required by other modules, i.e., page(s) and possibly the cubit
      • declares all routes as functions returning AutoRoute
      • may contain initialization code (initMyModule())
    • widgets:
      • my_widget.dart: contains MyWidget and helpers
    • pages:
      • my_module.dart: contains MyModulePage and helpers
      • my_child_page.dart: contains
      • my_complex_page: create a folder for complex pages (e.g., tabbed ones); might want to create an own module if getting too complex
    • utils.dart: contains utilities used throughout this module
    • cubit.dart: contains MyModuleCubit and MyModuleStates (if needed)

Example for my_module/module.dart; the page is used as a root page in the tab router, which is why the empty router MyModuleRootPage and adding AutoRoute(path: '', page: MyModuleRoute.page) to children is needed.

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

// For generated routes
export 'cubit.dart';
export 'pages/my_module.dart';
export 'pages/my_child_page.dart';
export 'pages/my_complex_page/page.dart';

@RoutePage()      
class MyModuleRootPage extends AutoRouter {}

AutoRoute myChildRoute() => AutoRoute(
  path: 'my_child',
  page: MyChildRoute.page,
);
AutoRoute myComplexRoute() => AutoRoute(
  path: 'my_complex',
  page: MyComplexRoute.page,
);

AutoRoute myModuleRoute({ required List<AutoRoute> children }) => AutoRoute(
  path: 'my_module',
  page: MyModuleRootRoute.page,
  children: [
    AutoRoute(path: '', page: MyModuleRoute.page),
    ...children, // includes myChildRoute()
  ],
);

Making app icons

Add the icon as assets/icon/icon.png (configured in pubspec.yaml) and run

flutter pub run flutter_launcher_icons:main

This will generate icons for both iOS as well as Android.

Updating screencast and screenshots

🙅 Not working yet due to login redirect, but keeping script for Sinai version (login without redirect) – can adopt once different login types are supported.

Scripts were created to click through the app using tests and record the screen.

A simulator with the app in its initial state (or not installed) needs to be running.

Screencasts

The generate_screendocs/generate_screencast.sh script will create screencast. It uses Xcode to record the screencast and ffmpeg to cut the full.mov to relevant subsets (needs to be installed).

To generate GIFs used in the Tutorial, ImageMagick is used (which also needs to be installed).

Run the script with bash generate_screendocs/generate_screencast.sh.

Screenshots

To update the screenshots in ../docs/screenshots (used in 📑 App screens, 📑 User instructions, and the README), run the following command: bash generate_screendocs/generate_screenshots.sh.

If the error The following MissingPluginException was thrown running a test: MissingPluginException(No implementation found for method captureScreenshot on channel plugins.flutter.io/integration_test) occurs, the registration in the file ios/.symlinks/plugins/integration_test/ios/Classes/IntegrationTestPlugin.m needs to be adapted (see issue):

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
  [[IntegrationTestPlugin instance] setupChannels:registrar.messenger];
}

Adapting test data

If you would like to test with specific test data but you don't have a user with suitable data available, adapt the code in utilities/genome_data.dart as shown below.

// TODO(after-testing): remove test data adaption
  UserData.instance.labData = UserData.instance.labData!.filter(
    (labResult) => labResult.gene != 'UGT1A1'
  ).toList();
  UserData.instance.labData!.add(LabResult(
    gene: 'UGT1A1',
    variant: '*28/*28',
    phenotype: 'Poor Metabolizer',
    allelesTested: '',
  ));
  UserData.instance.labData = UserData.instance.labData!.filter(
    (labResult) => labResult.gene != 'HLA-B' && labResult.variant != '*57:01 negative'
  ).toList();
  UserData.instance.labData!.add(LabResult(
    gene: 'HLA-B',
    variant: '*57:01 positive',
    phenotype: '*57:01 positive',
    allelesTested: '',
  ));

You can use the CPIC API to get reasonable genotype-phenotype pairings, e.g., with https://api.cpicpgx.org/v1/diplotype?genesymbol=eq.CYP2C9&select=genesymbol,diplotype,generesult.

Some more examples are collected below (this is for testing what is shown for Warfarin):

  UserData.instance.diplotypes!['CYP2C9'] = Diplotype(
    gene: 'CYP2C9',
    resultType: 'Diplotype',
    genotype: '*11/*13',
    phenotype: 'Poor Metabolizer',
    allelesTested: '',
  );
  UserData.instance.diplotypes!['VKORC1'] = Diplotype(
    gene: 'VKORC1',
    resultType: 'Diplotype',
    genotype: '-1639G>A variant carriers',
    phenotype: '-1639G>A variant carriers',
    allelesTested: '',
  );
  UserData.instance.diplotypes!['CYP4F2'] = Diplotype(
    gene: 'CYP4F2',
    resultType: 'Diplotype',
    genotype: 'rs2108622 T carriers',
    phenotype: 'rs2108622 T carriers',
    allelesTested: '',
  );
  UserData.instance.diplotypes!['CYP2C'] = Diplotype(
    gene: 'CYP2C',
    resultType: 'Diplotype',
    genotype: 'rs12777823 A carriers',
    phenotype: 'rs12777823 A carriers',
    allelesTested: '',
  );