Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into issue/677-privacy-screen
Browse files Browse the repository at this point in the history
  • Loading branch information
tamslo committed Dec 22, 2023
2 parents e409089 + 195de4d commit 52f1605
Show file tree
Hide file tree
Showing 97 changed files with 1,610 additions and 1,498 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ defaults:
working-directory: ./app

env:
JAVA_VERSION: 12.x
JAVA_VERSION: 17.x
FLUTTER_CHANNEL: stable
FLUTTER_VERSION: 3.7.6
FLUTTER_VERSION: 3.16.4

jobs:
lint:
Expand Down
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
.pub-cache/
.pub/
/build/
devtools_options.yaml

# Web related
lib/generated_plugin_registrant.dart
Expand Down
77 changes: 53 additions & 24 deletions app/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ Please also see the [contribution guide in the root folder](../CONTRIBUTING.md).
- Run `dart pub get` to fetch all dart dependencies
- Run `flutter pub get` to fetch all flutter dependencies and setup all
generated code
- Run `flutter pub run build_runner build --delete-conflicting-outputs` or
`flutter pub run build_runner watch --delete-conflicting-outputs` to
- 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
Expand All @@ -24,42 +24,71 @@ For (cleaning) generated code, you might want to add the following aliases to
your shell configuration:

```bash
alias flutter-generate='flutter pub run build_runner build --delete-conflicting-outputs'
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'
```

## Architecture

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

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

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

- `my_module`
- `module.dart`:
- exports everything that is required by other modules
- declares all routes as a const variable (`myModuleRoutes`)
- `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 reeturning `AutoRoute`
- may contain initialization code (`initMyModule()`)
- `cubit.dart`: contains `MyModuleCubit` and `MyModuleState`s
- `widgets`:
- `my_widget.dart`: contains `MyWidget` and helpers
- `pages`:
- `my_first.dart`: contains `MyFirstPage` and helpers
- `my_complex`: create a folder for complex pages (e.g., tabbed ones)
- `page.dart`: contains `MyComplexPage`
- `tab_first.dart`: contains `FirstTab` and helpers
- `tab_second.dart`: contains `SecondTab` and helpers
- `utils.dart`: contains utilities used by multiple files in this page
- `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
- `submodule_one`
- `submodule_two`

If a single file gets too complex for routes, the `Cubit`, a widget, a page,
etc., you can create a folder with the same name and split the original file
into different files. An example of that is `MyComplexPage` in the file tree
above.
- `cubit.dart`: contains `MyModuleCubit` and `MyModuleState`s (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.

```dart
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() and priva
],
);
```

## Making app icons

Expand Down
13 changes: 7 additions & 6 deletions app/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,25 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
compileSdkVersion 33
namespace 'de.hpi.pharme'

compileSdk 33

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '17'
}

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "de.hpi.pharme"
applicationId 'de.hpi.pharme'
minSdkVersion 19
targetSdkVersion 33
multiDexEnabled true
Expand Down
3 changes: 1 addition & 2 deletions app/android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.hpi.pharme">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
Expand Down
3 changes: 1 addition & 2 deletions app/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.hpi.pharme">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<!-- If you wish to run the app on a local setup (i.e local lab server, annotation server,
etc.) set the parameter 'android:usesCleartextTraffic' to 'true' -->
Expand Down
3 changes: 1 addition & 2 deletions app/android/app/src/profile/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.hpi.pharme">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
Expand Down
6 changes: 3 additions & 3 deletions app/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.6.21'
ext.kotlin_version = '1.8.0'
repositories {
google()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand All @@ -24,6 +24,6 @@ subprojects {
project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
3 changes: 3 additions & 0 deletions app/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false
5 changes: 3 additions & 2 deletions app/android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
3 changes: 3 additions & 0 deletions app/generate_screenshots/app_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import 'dart:io';

import 'package:app/app.dart';
import 'package:app/common/module.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
Expand Down Expand Up @@ -51,6 +52,8 @@ void main() {
await takeScreenshot(tester, binding, 'login');

// login-redirect (not working; only taking screenshot of loading screen)
// could try to use cubit function to directly sign in which will only
// open the webview and close it again
// await tester.tap(find.byType(FullWidthButton).first);
// await Future.delayed(Duration(seconds: 3)); // wait for dialog
// await takeScreenshot(tester, binding, 'login-redirect');
Expand Down
2 changes: 1 addition & 1 deletion app/generate_screenshots/test_driver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:integration_test/integration_test_driver_extended.dart';
Future<void> main() async {
try {
await integrationDriver(
onScreenshot: (screenshotName, screenshotBytes) async {
onScreenshot: (screenshotName, screenshotBytes, [_]) async {
final image =
await File(
'../docs/screenshots/$screenshotName.png'
Expand Down
23 changes: 12 additions & 11 deletions app/integration_test/drugs_test.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// ignore_for_file: cast_nullable_to_non_nullable

import 'package:app/common/module.dart';
import 'package:app/common/pages/drug/widgets/module.dart';
import 'package:app/search/module.dart';
import 'package:app/drug/module.dart';
import 'package:app/drug/widgets/annotation_cards/disclaimer.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
Expand Down Expand Up @@ -126,7 +126,7 @@ void main() {

// test the right color of the card
// ignore: omit_local_variable_types
final Card card = tester.firstWidget(
final RoundedCard card = tester.firstWidget(
find.byKey(
ValueKey('annotationCard'),
),
Expand All @@ -136,14 +136,14 @@ void main() {
testDrug.guidelines.first.annotations.warningLevel.color,
);

context = tester.element(find.byType(Tooltip).first);

// test that drug activity can be set
final checkbox = tester.widget(find.byType(CheckboxListTile))
as CheckboxListTile;
expect(checkbox.onChanged, isNotNull);
final activitySelection = tester.firstWidget(
find.byType(DropdownButton<bool>)
) as DropdownButton<bool>;
expect(activitySelection.onChanged, isNotNull);

// test tooltips
context = tester.element(find.byType(Tooltip).first);
expect(
find.byTooltip(context.l10n.drugs_page_tooltip_guideline),
findsOneWidget,
Expand Down Expand Up @@ -202,9 +202,10 @@ void main() {
),
);

final checkbox = tester.widget(find.byType(CheckboxListTile))
as CheckboxListTile;
expect(checkbox.onChanged, isNull);
final activitySelection = tester.firstWidget(
find.byType(DropdownButton<bool>)
) as DropdownButton<bool>;
expect(activitySelection.onChanged, isNull);
});
});
}
2 changes: 1 addition & 1 deletion app/integration_test/faq_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ void main() {
final faqWidget = MaterialApp.router(
routeInformationParser: appRouter.defaultRouteParser(),
routerDelegate: appRouter.delegate(
initialDeepLink: 'main/faq',
deepLinkBuilder: (_) => DeepLink.path('/main/faq'),
),
localizationsDelegates: [
AppLocalizations.delegate,
Expand Down
12 changes: 6 additions & 6 deletions app/integration_test/login_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import 'package:integration_test/integration_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:provider/provider.dart';

class MockLoginCubit extends MockCubit<LoginPageState>
implements LoginPageCubit {}
class MockLoginCubit extends MockCubit<LoginState>
implements LoginCubit {}

void main() {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
Expand All @@ -20,7 +20,7 @@ void main() {
group('integration tests for the login page', () {
testWidgets('test loading state', (tester) async {
when(() => mockLoginCubit.state).thenReturn(
LoginPageState.loadingUserData(),
LoginState.loadingUserData(),
);

await tester.pumpWidget(
Expand All @@ -44,7 +44,7 @@ void main() {

testWidgets('test error state', (tester) async {
when(() => mockLoginCubit.state).thenReturn(
LoginPageState.error('Some error'),
LoginState.error('Some error'),
);

await tester.pumpWidget(
Expand All @@ -70,7 +70,7 @@ void main() {

testWidgets('test loaded state', (tester) async {
when(() => mockLoginCubit.state).thenReturn(
LoginPageState.loadedUserData(),
LoginState.loadedUserData(),
);

await tester.pumpWidget(
Expand All @@ -97,7 +97,7 @@ void main() {

testWidgets('test initial state', (tester) async {
when(() => mockLoginCubit.state).thenReturn(
LoginPageState.initial(),
LoginState.initial(),
);

await tester.pumpWidget(
Expand Down
3 changes: 1 addition & 2 deletions app/integration_test/main_page_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'package:app/common/models/drug/cached_drugs.dart';
import 'package:app/common/module.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
Expand All @@ -25,7 +24,7 @@ void main() {
child: MaterialApp.router(
routeInformationParser: appRouter.defaultRouteParser(),
routerDelegate: appRouter.delegate(
initialDeepLink: 'main',
deepLinkBuilder: (_) => DeepLink.path('/main'),
),
localizationsDelegates: [
AppLocalizations.delegate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void main() {
debugShowCheckedModeBanner: false,
routeInformationParser: appRouter.defaultRouteParser(),
routerDelegate: appRouter.delegate(
initialDeepLink: 'main/settings',
deepLinkBuilder: (_) => DeepLink.path('/main/more'),
),
localizationsDelegates: [
AppLocalizations.delegate,
Expand Down Expand Up @@ -65,7 +65,7 @@ void main() {
findsOneWidget,
);

context.router.navigateBack();
context.router.back();
await tester.pumpAndSettle();

// test privacy policy
Expand All @@ -77,7 +77,7 @@ void main() {
findsOneWidget,
);

context.router.navigateBack();
context.router.back();
await tester.pumpAndSettle();

// test terms and conditions
Expand Down
Loading

0 comments on commit 52f1605

Please sign in to comment.