Back to index
The user interface mainly consists of sequential views that take users through boarding, scenario selection, hardware preparation, recording and upload. Some additional, non-sequential elements include error messages, help and settings screens, and the wait view. The controllers that contain the business logic for these views are contained in the Views
folder. The interface itself is realized in Main.storyboard
. More complex visual objects with custom functionalities, like the HomeViewCell
in scenario selection, are stored in Visuals
. The AppDelegate
initiates the first view, either LoginView
if the app was reset or first launched, or MainView
, which is a container for global navigation and instantiates HomeViewController
, the "default" first view of the application. See models for details on how progress is handled.
The LoginView
is essentially the sign-up view of the application. It sets a current study, initiates boarding if the subject presses the button, and transitions to the MainView
once boarding was completed. In developer-mode, the view can be tapped anywhere to skip sign-up (a UUID will be generated anyways). The BoardingView
embeds the ResearchKit ORKTaskViewController
that manages the consent steps and other options. It also passes any setup choices and prepares the consent for storage as PDF.
MainView
is the container that is instantiated when the the app is launched and the subject enrolled in the study. It contains a navigation controller and embeds the HomeView
, from which the user takes most of their actions. The home view is essentially a table with a timer. Upon loading, it retrieves scenarios for the current study day, the completed scenarios of the current study day, the remaining time to complete those scenarios, and any announcement on the download webdav. Further, if all scenarios were completed, it immediately instantiates the WaitView
, and advances the study to the next day if the waiting time passed (DayTimeOutListener
extension). See "Models -> Study progression" for more details.
One HomeViewCell
represents one scenario for a given day. A collection of home view cells are loaded by the home view when the app is launched. The home view cell changes its appearance when the corresponding scenario is set to "active" (i.e., the next scenario that the subject should record), and if an announcement can be displayed. This is toggled with the setActive
function. Clicking the button in this cell will call an action of the HomeViewCellDelegate
protocol that is implemented by HomeViewController
. The round thumbnail is defined in ScenarioBubble
. It features progress display and can be used as a button in developer-mode to advance or reset progress quickly.
In addition to the regular interaction with the home view, developer mode enabled skipping scenarios by tapping the circular thumbnail, or resetting a scenario progress by long-pressing the circular ScenarioBubble
. This also resets the current run count and therefore it can lead to complications with the file database, so it is advised to only use these options for testing. Further, the WaitView
that appears after completing all scenarios of a day can be dismissed in developer mode without waiting for the time to pass.
These two functions can be accessed with the navigation bar on top when in home view. Settings are described more extensively in Setup
. Additionally, the SettingsView
includes functions to reset the application, it contains credits, and links to the DataTableView
where past recordings can be seen, deleted, and shared (in dev-mode). The HelpView
is a simple way to display frequently asked questions to all subjects. HelpTableView
contains an overview of questions represented by HelpTableViewCell
, and tapping leads to the HelpDetailView
. Frequently asked questions are stored as JSON. Please refer to help_en.json
for an example structure.
Home view executes actions after the subject taps on the "Start session" button in a HomeViewCell
, either by showing a new announcement or by instantiating an EEG recording or questionnaire session (HomeViewCellDelegate
extension). Recording and questionnaire views will be stacked on top of the navigation bar of the MainView
container, which means popping all upcoming views will return the user to this screen. Internally, controllers for both scenario types use a page view controller to instantiate and present their sequential steps (MNDSessionFlowView
). Available step types, end reasons, and results are found as enums in MNDSessionVCBase
. Both scenarios start with a DetailView
, which outlines the current task, and shows remaining trials. Both scenarios end with an UploadView
, that visually represents the progress of uploading files and a StepView
that displays potential steps for clean-up, after the session concludes. The logic in between differs. All view controllers that are used in scenarios feature a completion
function that is passed when they are instantiated. This completion function usually set by the container views as {goTo(phase)}
to link views in the right order and transition once the respective requirement is fulfilled.
If the selected scenario is a questionnaire, Home view instantiates a QuestionView
container. In addition to the shared views, presenting the questionnaire items is handled by a ResearchKit ORKTaskViewController
, and collecting results is implemented in ORKTaskViewControllerDelegate
. Results are merged with some meta-information from the session and passed to StorageController
to be stored as JSON. If data was stored successfully, the study is advanced. See models and study content for more details, and initial_en.json
for an example questionnaire.
If the selected scenario is a recording session, Home view instantiates a SessionView
container. In addition to the shared views, EEG recordings feature the StepView
in which hardware preparation or clean-up steps are presented, the FittingView
which is used for headset fitting, the ScenarioView
that displays prompts during the actual recording, and PauseView
that allows subjects to end with a completed block of trials or continue to the next one.
Note: The following views were designed in combination with the Muse EEG headset. Different headset designs may require you to change location, number, and visibility of signal quality indicators during fitting, and change hardware preparation and clean-up steps accordingly.
SessionView
is the container view for all views that are presented during an EEG recording. In terms of EEG data, it instantiates DataController
with the chosen recording device, ProcessingDelegate
, and RecordingDelegate
during initialization. It also instantiates all views that appear during the recording (see above), including an ErrorView
that is called if something goes wrong, and a RawDataView
that can be accessed in developer-mode. It collects meta-information during the session, e.g., fitting time (see logItems
), and handles cancellation, errors, or successful completions (see stop
). The setSession
function sets a specific recording scenario and alters completion
functions if necessary: If the user transitions from one scenario (e.g., rest) to another (e.g., memories), without taken the headset off, all hardware preparation steps are skipped. If the user opts-in for regular instructions, a step is presented that reminds them to enable shortened instructions if they feel comfortable.
The StepView
is used to display text and an optional picture or video for hardware preparation and cleanup. The steps that are to be displayed are defined by the mode
parameter: A string that is looked up by the DocumentController
in the steps JSON file to find the right set of instructions. At the time of development, steps_en.json
included Start
for hardware preparation, noise
for electromagnetic noise detection, initialFitting
, checkUp
for fitting between blocks, introCompleted
to remind subjects to enable shortened instructions after their first recording, Finish
for clean-up after recording, QuestionnaireFinish
for clean-up after questionnaires, and cancel
when subjects cancel the current session. noise
, initialFitting
, and checkUp
are meant to be displayed within the FittingView
. MNDVisualInstructionView
is the object that handles display of the optional visuals for each step in StepView
and FittingView
. Videos, images, gifs, and nothing are supported.
A second feature of StepView
is that it can respond to completion signals. These signals can be anything in the DeviceState
enum in DataController
, e.g., connected
, if the headset was connected. The DataController
, and in turn the specific DataSource
are responsible for sending these signals when appropriate. Subjects will be unable to complete the step (in this case turnOn
) until this signal was sent. To trigger this behavior, a completionSignal
String is set in the JSON with the same name. This is then converted by the DocumentController->evaluteSignal
function to its corresponding enum entry, and attached to the StepModel
object. See "model -> questionnaires" for more information. In developer-mode, waiting for these required signals can be skipped.
Lastly, StepView
can trigger a banner announcement if a step was completed successfully. The signal is forwarded to BannerController
, which looks up and displays the appropriate message with makeGeneralAnnouncement
. This was implemented to make it easier to notice when the headset was found and connected successfully, for example.
The FittingView
helps subject to check for noisy environments, fit the headset, and check the connectivity between blocks. It shares several similarities in the way it handles preparation steps with StepModel
objects, so you could refer to "Step view" for more information. Here, FittingMode
represents the mode
of this view. The three differences are its layout, its response to signal quality estimates sent by ProcessingDelegate
, and execution of completion functions after successfully completing a fitting step.
FittingView
uses 4 (or 5, if the aux electrode is enabled) SignalQualityRingView
s to display signal quality in real-time. They can be in idle
state, in which case they are just presented as outlines, inactive
, where they get updated in gray color, and active
, where they reflect signal quality with red, yellow, and green colors. The also feature a checkbox that can be enabled to display when progress reaches 100. The FittingMode
and completion functions, defined in completionIfAny()
, mainly control which signal quality ring views are visible at a time to guide subjects efficiently.
FittingView
subscribes to signal quality updates from ProcessingDelegate
and calls updateProgress
whenever it receives new values. Similar to StepView
, if all steps were executed and requirements were fulfilled (in this case 100% signal quality, 75% after 3 minutes), fitting view finishes and transitions to the next view. In dev-mode, these requirements are disabled.
In developer-mode, RawDataView
can be accessed from the navigation bar once the headset was connected. It features the display of either raw EEG time series, or the EEG band-power spectrum.
After fitting completed, ScenarioView
contains the actual display of experimental prompts and recording of EEG data. Please refer to "model -> EEG recordings" for details on how scenarios are structured. Scenario view is essentially a timed text display. Scenarios are presented as follows:
start
: get the trial at the next global index, always reset phase to zero in case the subject cancelled a recording somewhere in between before.updateVisuals
: set the prompt, set feedback if desired (not implemented), send the currentmarker
to theRecordingDelegate
, and set a timer with the duration of this phase, after which the phase count progresses. If duration is zero, the current phase is variable in lengthL: Listen toTTSController
withttsChanged
, and proceed to the next phase once it is done talking.nextPhase
: called when the timer runs out. Disables the timer and callsupdatePhase
(This two step update was done to enable developers to advance the phase by just tapping the screen in dev-mode).updatePhase
: callScenarioModel->advance()
to move to the next phase. Scenario model will set a flag if we reached the end of the trial, or the end of the whole scenario. The trial index is tracked globally to start at the right block of a scenario, and locally, to check if the current amount of trials equals thecheckAtIndex
property ofScenarioModel
. If this is true, a block was completed and the signal quality check up is triggered.updateVisuals
: see 2.- If all trials of the block were completed
finishRunAndStore
will stop the execution and inform the containerSessionView
that data was recorded successfully. TheSessionView
will in turn check if the whole scenario was completed, and alter the text in the upcomingPauseView
.
Note: Scenario view instantiates FeedbackView
during initialization, which covers the whole screen during execution. This view was designed to display feedback as a slowly moving waveform, but was not used at the time of development. It is left in the code as blueprint for future extensions.
PauseView
informs subjects about their progress, once they successfully completed one block of trials in a scenario. They can choose to continue with the next block of trials, in which case they will be forwarded to FittingView
in checkUp
mode. If they finished all blocks in a scenario and decide to continue with the next scenario, shortFitting
mode will be enabled, preparation will be skipped, and the EEG recording process begins again with DetailView
. If they finished all scenarios for the day, they will be returned to the HomeView
, and a WaitView
will lock the screen until the time out has passed.
This is essentially an error message. This view is almost identical to Stepview
but can be called and presented any time during the EEG recording procedure if the battery is low or the headset disconnected. Color schemes for error
, success
and info
are implemented.