R/record_midi_or_audio_ui.R

Defines functions present_record_button happy_with_response_message return_correct_attempts_left loading send_page_label_to_js create_db_vars_template set_answer_meta_data_for_db_as_js_vars record_midi_or_audio_ui

# common ui template for midi and audio pages
record_midi_or_audio_ui <- function(body = "",
                                    label = "record_audio_page",
                                    stimuli = NULL,
                                    stimuli_reactive = FALSE,
                                    page_text = " ",
                                    page_title = " ",
                                    page_type = "record_audio_page",
                                    interactive = FALSE,
                                    get_answer,
                                    answer_meta_data = tibble::tibble(),
                                    record_button_text = psychTestR::i18n("Record"),
                                    stop_button_text = psychTestR::i18n("Stop"),
                                    record_duration = NULL,
                                    on_complete = NULL,
                                    save_answer = TRUE,
                                    page_text_first = TRUE,
                                    happy_with_response =  FALSE,
                                    attempts_left = 1L,
                                    max_goes_forced = FALSE,
                                    autoInstantiate = TRUE,
                                    midi_device = " ",
                                    max_goes = 1L,
                                    show_progress = FALSE,
                                    melody_no = 0,
                                    total_no_melodies = 0,
                                    volume_meter = FALSE,
                                    volume_meter_type = 'default',
                                    show_sheet_music_after_record = FALSE,
                                    show_record_button = TRUE,
                                    reactive_melody_no = FALSE,
                                    mute_midi_playback = FALSE,
                                    db_vars = NULL,
                                    lyrics = NULL,
                                    feedback = FALSE,
                                    asynchronous_api_mode = FALSE, ...) {


  if(max_goes > 1L) {
    happy_with_response <- TRUE
  }


  if(is.character(page_text)) {
    page_text <- shiny::tags$p(page_text)
  }

  attempt <- jsonlite::toJSON(max_goes - attempts_left)

  section_progress <- if(reactive_melody_no) paste0(psychTestR::i18n("Section_Progress"), ': ', melody_no) else paste0(psychTestR::i18n("Section_Progress"), ': ', melody_no, "/", total_no_melodies)

  if(is.list(db_vars)) {
    db_vars$page_label <- label
  }

  psychTestR::page(ui = shiny::tags$div(

      # We force this to keep turning on to make sure it doesn't get unset e.g., if there is a reload
      if(asynchronous_api_mode) turn_on_upload_to_s3_mode(log = TRUE),

      # Set attempts
      shiny::tags$script(
        shiny::HTML(paste0('Shiny.setInputValue("attempt", ', attempt, ');
                           console.log(\"This is a ', page_type, '\");'))
      ),

      if(page_type == "record_midi_page") autoInstantiateMidi(autoInstantiate, midi_device, interactive, mute_midi_playback),

      send_page_label_to_js(label),

      shiny::tags$script(set_answer_meta_data(answer_meta_data)),

      # Set JS vars for musicassessrdb
      if(!is.scalar.null(db_vars)) set_answer_meta_data_for_db_as_js_vars(db_vars),

      if(show_progress) shiny::tags$h4(section_progress),

      shiny::tags$h2(id = "trial_page_title", page_title),

      if(page_text_first) shiny::tags$div(id = "trial_page_text", page_text),

      shiny::tags$div(id = "bodyArea", body),

      if(!is.null(lyrics)) {
        shiny::tags$div(id = "lyrics",
          shiny::tags$h3(psychTestR::i18n("Lyrics")),
          convert_to_html_paragraphs(lyrics)
        )
      },

      if(!is.null(stimuli)) shiny::tags$div(id = "stimuliArea", stimuli),

      if(volume_meter) shiny::tags$div(volume_meter(volume_meter_type, start_hidden = TRUE), shiny::includeScript(path=system.file("www/js/microphone_signal_test.js", package = "musicassessr"))),

      present_record_button(show_record_button, page_type, record_button_text, stop_button_text, show_sheet_music_after_record, stop_recording_automatically_after_ms = record_duration * 1000),

      #if(page_type == "record_audio_page") loading(),

      happy_with_response_message(happy_with_response, attempts_left, max_goes_forced, max_goes),

      if(is_function_or_true(feedback) && asynchronous_api_mode) feedback_melodic_production_async_ui(),

      if(!page_text_first) page_text,

      shiny::tags$script(htmltools::HTML(paste0('apiUrl = "', Sys.getenv("ENDPOINT_URL"), '\"')))
  ),
  label = label,
  get_answer = get_answer,
  save_answer = save_answer,
  on_complete = on_complete
  )

}


set_answer_meta_data_for_db_as_js_vars <- function(db_vars) {

  if(is.null(db_vars$onset)) {
    db_vars$onset <- FALSE
  }

  # Replace nulls with NAs
  db_vars <- purrr::map(db_vars, replace_nulls)

  # Leave the is.nulls() above before the stopifnot, so that e.g., onset is created, if it doesn't already exist

  print(setdiff(db_var_names, names(db_vars)))
  stopifnot(length(setdiff(db_var_names, names(db_vars))) == 0)

  additional <- if(is.scalar.character(db_vars$additional)) db_vars$additional else jsonlite::toJSON(db_vars$additional, auto_unbox = TRUE)

  js_holder <- db_var_names %>%
    purrr::map(function(name) {
      htmltools::HTML(paste0("db_", name, " = \'", db_vars[[name]], "\';"))
    })


  scr <- htmltools::HTML(paste0(js_holder))

  shiny::tags$script(scr)

}

db_var_names <- c("stimuli",
  "stimuli_durations",
  "trial_time_started",
  "instrument",
  "attempt",
  "item_id",
  "display_modality",
  "phase",
  "rhythmic",
  "session_id",
  "test_id",
  "onset",
  "new_items_id",
  "review_items_id",
  "user_id",
  "feedback",
  "feedback_type",
  "trial_paradigm",
  "additional",
  "melody_block_paradigm",
  "file_type",
  "noise_filename",
  "page_label",
  "module")

create_db_vars_template <- function(init_with_time_started = TRUE) {
  empty_obj <- setNames(as.list(rep(NA, length(db_var_names))), db_var_names)
  empty_obj$trial_time_started <- Sys.time()
  empty_obj$trial_paradigm <- "call_and_response"
  return(empty_obj)
}

send_page_label_to_js <- function(label) {
  shiny::tags$script(
    paste0('page_label = \"', label, '\";
           Shiny.setInputValue("page_label", page_label);'
           )
    )
}


loading <- function() {
  htmltools::HTML('
  <div id="hollowDotsSpinner" class="hollow-dots-spinner" :style="spinnerStyle;">
    <div class="dot"></div>
      <div class="dot"></div>
        <div class="dot"></div>
          </div>
    <div id="loading"></div>
    ')
}


return_correct_attempts_left <- function(attempts_left, max_goes_forced = FALSE) {

  if(max_goes_forced) {
    attempts_remaining_1 <- psychTestR::i18n("attempts_remaining_1_max_goes_forced")
    attempts_remaining_several.2 <- psychTestR::i18n("attempts_remaining_several.2_max_goes_forced")
  } else {
    attempts_remaining_1 <- psychTestR::i18n("attempts_remaining_1")
    attempts_remaining_several.2 <- psychTestR::i18n("attempts_remaining_several.2")
  }

  if(attempts_left == 0L) {
    shiny::tags$div(id = "happy_with_response", style = "display:none;",
                    shiny::tags$p(psychTestR::i18n("no_more_attempts_next")),
                    shiny::tags$button(psychTestR::i18n("Continue"), id = psychTestR::i18n("Continue"), label = psychTestR::i18n("Continue"), onclick = "hide_happy_with_response_message();Shiny.setInputValue('user_satisfied', this.id); next_page();", class="btn btn-default action-button")
    )
  } else if (attempts_left == 1L) {
    shiny::tags$div(id = "happy_with_response", style = "display:none;",
                    shiny::tags$p(shiny::HTML(psychTestR::i18n("happy_with_response_message"))),
                    shiny::tags$p(psychTestR::i18n("attempts_remaining_1")),
                    shiny::tags$button(psychTestR::i18n("Try_Again"), id = "Try Again", label = "Try Again", onclick = "hide_happy_with_response_message();Shiny.setInputValue('user_satisfied', this.id); next_page();", class="btn btn-default action-button"),
                    if(!max_goes_forced) shiny::tags$button(psychTestR::i18n("Continue"), id = psychTestR::i18n("Continue"), label = psychTestR::i18n("Continue"), onclick = "hide_happy_with_response_message();Shiny.setInputValue('user_satisfied', this.id); next_page();", class="btn btn-default action-button")
    )
  } else if (is.infinite(attempts_left)) {
    shiny::tags$div(id = "happy_with_response", style = "display:none;",
                    shiny::tags$p(psychTestR::i18n("happy_with_response_message")),
                    shiny::tags$button(psychTestR::i18n("Try_Again"), id = "Try Again", label = "Try Again", onclick = "hide_happy_with_response_message();Shiny.setInputValue('user_satisfied', this.id); next_page();", class="btn btn-default action-button"),
                    if(!max_goes_forced) shiny::tags$button(psychTestR::i18n("Continue"), id = psychTestR::i18n("Continue"), label = psychTestR::i18n("Continue"), onclick = "hide_happy_with_response_message();Shiny.setInputValue('user_satisfied', this.id); next_page();", class="btn btn-default action-button")
    )
  } else {
    shiny::tags$div(id = "happy_with_response", style = "display:none;",
                    shiny::tags$p(psychTestR::i18n("were_you_happy")),
                    if(!is.infinite(attempts_left)) shiny::tags$p(paste0(psychTestR::i18n("You_have"), ' ', " ", attempts_left, ' ', psychTestR::i18n("attempts_remaining_if_like"))),
                    shiny::tags$button(psychTestR::i18n("Try_Again"), id = 'Try Again', label = 'Try Again', onclick = "hide_happy_with_response_message();Shiny.setInputValue('user_satisfied', this.id); next_page();", class="btn btn-default action-button"),
                    if(!max_goes_forced) shiny::tags$button(psychTestR::i18n("Continue"), id = 'Continue', label = 'Continue', onclick = "hide_happy_with_response_message();Shiny.setInputValue('user_satisfied', this.id); next_page();", class="btn btn-default action-button")
    )
  }
}


happy_with_response_message <- function(happy_with_response_message, attempts_left, max_goes_forced = FALSE, max_goes = 1) {

  if(max_goes == 1) {
    happy_with_response_message <- FALSE
  }

  if(happy_with_response_message) {
    shiny::tags$div(
      return_correct_attempts_left(attempts_left, max_goes_forced),
      shiny::tags$script('show_happy_with_response = true;')
    )
  } else {
    shiny::tags$div(
      shiny::tags$script('show_happy_with_response = false;')
    )
  }
}



present_record_button <- function(show_record_button,
                                  page_type,
                                  record_button_text =  psychTestR::i18n("Record"),
                                  stop_button_text = psychTestR::i18n("Stop"),
                                  show_sheet_music_after_record = FALSE,
                                  sheet_music_id = "sheet_music",
                                  stop_recording_automatically_after_ms = NULL) {

  stopifnot(
    is.null.or(stop_recording_automatically_after_ms, is.numeric)
  )

  if(length(stop_recording_automatically_after_ms) == 0)  {
    stop_recording_automatically_after_ms <- "null"
    show_stop <-  TRUE_to_js_true(TRUE)
  } else {
    show_stop <-  TRUE_to_js_true(FALSE)
  }

  shiny::tags$div(id = "button_area",
                  shiny::tags$script(paste0("stop_button_text = \"", stop_button_text, "\"")),
                  shiny::tags$button(record_button_text, id = "recordButton", class = "btn btn-default action-button", style = if(show_record_button) "visibility: visible;" else "visibility: hidden"),
                  shiny::tags$button(stop_button_text, id = "stopButton", class = "btn btn-default action-button", style = "visibility: hidden;"),
                  shiny::tags$script(shiny::HTML(paste0('document.getElementById("recordButton").addEventListener("click", function() {
                            startRecording(type = \"', page_type, '\", ', stop_recording_automatically_after_ms, ');
                            recordUpdateUI(type = \"', page_type, '\", ', show_stop, ');',
                                                        if(show_sheet_music_after_record) paste0("showSheetMusic('", sheet_music_id, "');") else "",
                                                        '});'))),
  )

}
syntheso/musicassessr documentation built on April 5, 2025, 8:11 a.m.