Skip to content

Commit

Permalink
[mdigits] Create basic package that runs
Browse files Browse the repository at this point in the history
The base code is taken from the package
https://github.com/mario-bermonti/mspelling
  • Loading branch information
mario-bermonti committed Aug 7, 2023
1 parent 6fc965e commit e44880a
Show file tree
Hide file tree
Showing 37 changed files with 1,034 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
revision: a494a12bb0c42b05d110dc7d3082ca6585f1c6ff
channel: master

project_type: package
4 changes: 4 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include: package:flutter_lints/flutter.yaml

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
30 changes: 30 additions & 0 deletions lib/activity/audio_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/// Provides an audio player manager
import 'dart:io';
import 'package:get/get.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:mdigits/errors/errors.dart';
import 'package:mdigits/errors/error_view.dart';

/// Manager for the audio player
/// Is is used to present the stim to participants
class AudioController extends GetxController {
final AudioPlayer _audioplayer = AudioPlayer();

/// Play audio from [path]
Future<void> playAudio(String path) async {
await _audioplayer.play(DeviceFileSource(path));
}

/// Validate the audio file specified in [path] exists
Future<void> validateAudioStimFile(String path) async {
File file = File(path);
if (await file.exists() == false) {
Get.to(
() => ErrorView(
message: GenericmdigitsException('Error playing the audio stim file'),
),
);
}
}
}
41 changes: 41 additions & 0 deletions lib/activity/begin_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
import 'package:get/instance_manager.dart';
import 'package:mdigits/common/centeredbox.dart';
import 'package:mdigits/common/default_appbar.dart';
import 'package:mdigits/common/default_text.dart';
import 'package:mdigits/common/spacing_holder.dart';
import 'package:mdigits/mdigits.dart';

/// Screen that allows participants to indicate when to start task.
class BeginView extends StatelessWidget {
const BeginView({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
return false;
},
child: Scaffold(
appBar: createAppBar(context: context, showActionButtons: true),
body: CenteredBox(
column: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const DefaultText(
text: 'Comencemos',
),
const BetweenWidgetsSpace(),
ElevatedButton(
onPressed: () {
// Get.put(MDigits());
},
child: const DefaultText(text: 'Seguir'),
),
],
),
),
),
);
}
}
2 changes: 2 additions & 0 deletions lib/activity/step.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// Id the current step for the task sequence
enum Step { stim, response, rest, completed }
45 changes: 45 additions & 0 deletions lib/activity/stim_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'package:get/get.dart';
import 'package:mdigits/activity/audio_controller.dart';
import 'package:mdigits/mdigits.dart';
import 'package:mdigits/errors/errors.dart';
import 'package:stimuli/errors.dart';
import 'package:stimuli/stimuli.dart';

/// Manage the stim
class StimController extends GetxController {
late Stimuli stim;
// final AudioController _audioController = AudioController();
final List<String> stimList;

StimController({required this.stimList});

@override
void onInit() async {
// await prepareStim();
super.onInit();
}

/// Prepare stim to be used
/// Includes building from file, create object, and randomize stim
Future<void> prepareStim() async {
try {
// Stimuli stimuli = await createStimFromFile(path);
Stimuli stimuli = Stimuli(stimuli: stimList);
stimuli.randomize();
stim = stimuli;
} on StimFileAccessException catch (e) {
throw GenericmdigitsException(e.toString());
}
}

/// Present the stim once to the participant and go back after 1s ISI
Future<void> presentStim() async {
stim.next();
MDigits mdigits = Get.find();
// /
Future.delayed(
const Duration(seconds: 1),
() => mdigits.run(),
);
}
}
27 changes: 27 additions & 0 deletions lib/activity/trial_response_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mdigits/mdigits.dart';

/// Manage responses
class TrialResponseController extends GetxController {
TextEditingController textController = TextEditingController();
final MDigits _mDigits = Get.find();

@override
void dispose() {
textController.dispose();
super.dispose();
}

void submit() {
// spaces are meaningless as in paper and pencil measures
String response = textController.text.trim();

textController.clear();
// _mDigits.addTrialData(result: response);
}

void toNextScreen() {
_mDigits.run();
}
}
49 changes: 49 additions & 0 deletions lib/activity/trial_response_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mdigits/common/centeredbox.dart';
import 'package:mdigits/common/default_appbar.dart';
import 'package:mdigits/common/default_text.dart';
import 'package:mdigits/common/default_textfield.dart';
import 'package:mdigits/common/spacing_holder.dart';
import 'package:mdigits/activity/trial_response_controller.dart';

/// Screen for collecting response from participant
class TrialResponseView extends StatelessWidget {
final TrialResponseController _trialResponseController =
Get.put(TrialResponseController());

TrialResponseView({super.key});

@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
return false;
},
child: Scaffold(
appBar: createAppBar(context: context),
body: CenteredBox(
column: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const DefaultText(
text: 'Escribe la palabra:',
),
const BetweenWidgetsSpace(),
DefaultTextField(
controller: _trialResponseController.textController),
const BetweenWidgetsSpace(),
ElevatedButton(
onPressed: () {
_trialResponseController.submit();
_trialResponseController.toNextScreen();
},
child: const DefaultText(text: 'Seguir'),
),
],
),
),
),
);
}
}
36 changes: 36 additions & 0 deletions lib/activity/trial_stim_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mdigits/common/default_appbar.dart';
import 'package:mdigits/common/centeredbox.dart';
import 'package:mdigits/activity/stim_controller.dart';
import 'package:mdigits/common/default_text.dart';

/// Screen to present stim to participants
class TrialStimView extends StatelessWidget {
TrialStimView({
Key? key,
}) : super(key: key);

final StimController _stimController = Get.find();

@override
Widget build(BuildContext context) {
_stimController.presentStim();
return WillPopScope(
onWillPop: () async {
return false;
},
child: Scaffold(
appBar: createAppBar(context: context),
body: CenteredBox(
column: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DefaultText(
text: _stimController.stim.currentStim,
)
],
),
)));
}
}
16 changes: 16 additions & 0 deletions lib/common/centeredbox.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:flutter/material.dart';

/// Custom widget to present widgets centered
class CenteredBox extends StatelessWidget {
final Column column;

@override
const CenteredBox({Key? key, required this.column}) : super(key: key);

@override
Widget build(BuildContext context) {
return Center(
child: SizedBox(width: 250.00, height: 300.00, child: column),
);
}
}
1 change: 1 addition & 0 deletions lib/common/constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const String appBarTitle = "mdigits";
24 changes: 24 additions & 0 deletions lib/common/default_appbar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mdigits/common/constants.dart';

/// Custom app bar that shows that can show predefined action buttons
createAppBar({required BuildContext context, bool showActionButtons = false}) {
return AppBar(
title: const Text(appBarTitle),
automaticallyImplyLeading: false,
centerTitle: true,
// actions: showActionButtons ? createActionButtons(context: context) : null,
);
}

// List<Widget> createActionButtons({required BuildContext context}) {
// List<Widget> actionButtons = <Widget>[
// IconButton(
// icon: const Icon(Icons.home),
// tooltip: 'Inicio',
// onPressed: (() => Get.to(MyHomePage())),
// ),
// ];
// return actionButtons;
// }
19 changes: 19 additions & 0 deletions lib/common/default_text.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';

/// Custom text widget with predefined style
class DefaultText extends StatelessWidget {
final String text;

const DefaultText({Key? key, required this.text}) : super(key: key);

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
text,
style: Theme.of(context).textTheme.button,
),
);
}
}
21 changes: 21 additions & 0 deletions lib/common/default_textfield.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:mdigits/common/styles.dart';

/// Custom text field with predefined style
class DefaultTextField extends StatelessWidget {
final TextEditingController controller;

const DefaultTextField({
Key? key,
required this.controller,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return TextField(
decoration: textFieldStyle,
autofocus: true,
controller: controller,
);
}
}
16 changes: 16 additions & 0 deletions lib/common/loading_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
import 'package:mdigits/common/default_appbar.dart';

class LoadingView extends StatelessWidget {
const LoadingView({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: createAppBar(context: context),
body: const Center(
child: CircularProgressIndicator(),
),
);
}
}
13 changes: 13 additions & 0 deletions lib/common/spacing_holder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';

/// Custom widget for including standardized space between widgets
class BetweenWidgetsSpace extends StatelessWidget {
const BetweenWidgetsSpace({
Key? key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return const SizedBox(height: 10);
}
}
13 changes: 13 additions & 0 deletions lib/common/styles.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';

const InputDecoration textFieldStyle = InputDecoration(
border: OutlineInputBorder(),
);

ThemeData themeData = ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.light,
textTheme: const TextTheme(
button: TextStyle(fontSize: 20),
),
);
Loading

0 comments on commit e44880a

Please sign in to comment.