Skip to content

Commit

Permalink
Merge pull request #68 from mario-bermonti:mario-bermonti/issue67
Browse files Browse the repository at this point in the history
Save demographics data to Firebase
  • Loading branch information
mario-bermonti authored Sep 3, 2024
2 parents b36ab4f + 1a8dd80 commit d454e79
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 43 deletions.
6 changes: 6 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:mdigit_span_tasks_ema/src/app.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:mdigit_span_tasks_ema/src/auth/auth.dart';
import 'package:mdigit_span_tasks_ema/src/auth/participant.dart';
import 'package:mdigit_span_tasks_ema/src/digit_span_tasks/config/config.dart';
import 'package:mdigit_span_tasks_ema/src/notifications/local_notifications.dart';
import 'package:mdigit_span_tasks_ema/src/notifications/firebase_notifications.dart';
Expand All @@ -16,6 +19,9 @@ Future<void> main() async {
await GetStorage.init();
Get.put(LocalNotifications());
Get.put(FirebaseNotifications());
final Participant participant =
await Auth(auth: FirebaseAuth.instance).signIn();
Get.put(participant);
Get.put(DigitSpanTaskConfig(), permanent: true);
runApp(const MyApp());
}
3 changes: 1 addition & 2 deletions lib/src/auth/auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ class Auth {
Future<Participant> signIn() async {
final UserCredential userCredential = await auth.signInAnonymously();
final Participant participant = Participant(
uid: userCredential.user?.uid,
registerDateTime: userCredential.user?.metadata.creationTime,
id: userCredential.user?.uid ?? '',
);
return participant;
}
Expand Down
23 changes: 23 additions & 0 deletions lib/src/auth/auth_participant_design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Design of Authentication and Participant

## Authentication
### Requirements
- Sign in to fcm (returns a Participant object)

## Participant
### Requirements
- Contains data about a single study Participant

### Structure

- Data
- id
- firebase cloud messaging (fcm) tokens
- registration time
- nickname
- avatar
- timezone
- location (country level)

- Behaviors
- Sign in to fcm
21 changes: 7 additions & 14 deletions lib/src/auth/participant.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
/// Represents a single study participant.
import 'package:get/get.dart';

/// Represents a single study participant and performs authentication
/// Can be used to keep track of participants' important info, including
/// "identifying" info.
class Participant {
late final String uid;
late final DateTime registerDateTime;
class Participant extends GetxController {
final String id;

Participant({
required String? uid,
required DateTime? registerDateTime,
}) {
if (uid == null || registerDateTime == null) {
throw Exception('Error creating participant model');
} else {
this.uid = uid;
this.registerDateTime = registerDateTime;
}
}
required this.id,
});
}
14 changes: 13 additions & 1 deletion lib/src/demographics/process_demographics_data.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:get/get.dart';
import 'package:mdigit_span_tasks_ema/src/auth/participant.dart';
import 'package:mdigit_span_tasks_ema/src/ema_data/ema_data.dart';
import 'package:research_package/research_package.dart';

import '../baseline/data/survey_data.dart';
Expand All @@ -8,5 +12,13 @@ void processDemographicsData(RPTaskResult results) {
rpSurveyData: results,
description: 'Baseline demographics survey',
);
print('survey data: ${surveyData.toJson()}');
final Participant participant = Get.find();
final EMAData emaData = EMAData(
FirebaseFirestore.instance,
participantID: participant.id,
);
emaData.addCrossSectionalSurveyData(
measureName: 'demographics',
data: surveyData,
);
}
68 changes: 68 additions & 0 deletions lib/src/ema_data/ema_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:mdigit_span_tasks_ema/src/baseline/data/survey_data.dart';
import 'package:mdigit_span_tasks_ema/src/baseline/data/survey_item_data.dart';

class EMAData {
final FirebaseFirestore db;
final String participantID;

EMAData(
this.db, {
required this.participantID,
});

/// Adds data from a cross-sectional survey data to Firebase
Future<void> addCrossSectionalSurveyData({
required String measureName,
required SurveyData data,
}) async {
final Map<String, dynamic> surveyData = data.toJson();

await addCrossSectionalSurveyItemData(
measureName: measureName,
data: surveyData['items'],
);

surveyData.remove('items');
await addCrossSectionalSurveyMetadata(
measureName: measureName,
data: surveyData,
);
}

/// Add data from cross-sectional items to Firebase
Future<void> addCrossSectionalSurveyItemData({
required String measureName,
required List<SurveyItemData> data,
}) async {
final CollectionReference itemsRef = db
.collection('cross_sectional')
.doc(measureName)
.collection('participants')
.doc(participantID)
.collection('items');

final WriteBatch batch = db.batch();

for (SurveyItemData item in data) {
Map<String, dynamic> jsonItem = item.toJson();
batch.set(itemsRef.doc(item.identifier), jsonItem);
}
await batch.commit();
}

/// Add metadata from a cross-sectional survey to Firebase
Future<void> addCrossSectionalSurveyMetadata({
required String measureName,
required Map<String, dynamic> data,
}) async {
final CollectionReference metadataRef = db
.collection('cross_sectional')
.doc(measureName)
.collection('participants')
.doc(participantID)
.collection('metadata');

await metadataRef.doc('metadata').set(data);
}
}
13 changes: 13 additions & 0 deletions lib/src/ema_data/ema_data_design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Design of ema data subpackage

## Requirements
- Handle data collected longitudinally (recurring) and cross-sectionally (one-time)
- Handle survey data
- Handle data cognitive tasks
- Adaptable to handle other types of data

## Structure

- Single object that manages the data
- Stores participantID
- Other required data passed as parameters to methods
2 changes: 1 addition & 1 deletion lib/src/services/run_session.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Future<void> runSession({
final DigitSpanTaskConfig config = Get.find();
final Participant participant =
await Auth(auth: FirebaseAuth.instance).signIn();
config.participantID = participant.uid;
config.participantID = participant.id;

/// We use the startTime for the practice session to create a single
/// session id for both practice and experimental data.
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ dev_dependencies:
build_runner: ^2.4.9
freezed: ^2.5.2
json_serializable: ^6.8.0
fake_cloud_firestore: ^2.5.2

flutter:
uses-material-design: true
Expand Down
3 changes: 1 addition & 2 deletions test/src/auth/auth_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ void main() {
"Auth.signIn() does not throw exceptions",
() async {
final Auth auth = Auth(auth: MockFirebaseAuth());
await auth.signIn();
expect(auth.signIn, returnsNormally);
expect(() async => await auth.signIn(), returnsNormally);
},
);
}
23 changes: 0 additions & 23 deletions test/src/auth/participant_test.dart

This file was deleted.

Loading

0 comments on commit d454e79

Please sign in to comment.