Skip to main content

Settings Page

The Settings Page manages core application configurations, security, and testing parameters. This screen displays :

  • A custom top bar with the application logo, the title "Paramètres", and a user profile icon that navigates to the profile page,
  • Settings options,
  • The custom navigation bar with 4 icons to access the screens HomeScreen.kt, DemoScreen.kt, FilesPage.kt, and SettingsPage.kt (current screen).

There are different buttons on this page for each option of the settings. They all share the same composable function SettingsOption defined below to build the corresponding button for the user interface:

SettingsPage.kt
@Composable
fun SettingsOption(text: String, onClick: () -> Unit) {
Box(
modifier = Modifier
...
.clickable { onClick() },
contentAlignment = Alignment.CenterStart
) {
Text(
text = text,
modifier = Modifier.padding(start = 16.dp),
style = MaterialTheme.typography.bodyLarge.copy(
color = MaterialTheme.colorScheme.primary
)
)
}
}

Here are the different actions available in the settings page :

  • Managing app permissions ("Gérer les autorisations") :

    SettingsPage.kt
    SettingsOption(text = "Gérer les autorisations") { 	openAppSettings(navController.context) }

    ...

    fun openAppSettings(context: Context) {
    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
    data = android.net.Uri.fromParts("package", context.packageName, null)
    }
    context.startActivity(intent)
    }
  • Logging out ("Déconnexion") :

    SettingsPage.kt
    SettingsOption(text = "Déconnexion") { onLogout(); navController.navigate("login") }

    In MainActivity.kt, the function onLogout is defined as follows to successfully log out of the application :

    MainActivity.kt
    EpilepsyTestApp(
    ...
    onLogout = {
    isAuthenticated = false
    firebaseAuth.signOut()
    sharedPreferences.edit().putBoolean("isLoggedIn", false).apply()
    },
    ...
    )

    This ultimately navigates to the login screen.

  • Modifying the test configuration ("Modifier la configuration") :

    SettingsPage.kt
    SettingsOption(text = "Modifier la configuration") { showDialogConfig = true }

    ...

    if (showDialogConfig) {
    AlertDialog(
    onDismissRequest = { showDialogConfig = false },
    confirmButton = {
    TextButton(onClick = {
    showDialogConfig = false
    onModifyConfiguration() // Navigation to the configuration pages
    }) {
    Text("Continuer", color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold)
    }
    },
    dismissButton = {
    TextButton(onClick = { showDialogConfig = false }) {
    Text("Retour", color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold)
    }
    },
    title = {
    Row(verticalAlignment = Alignment.CenterVertically,
    horizontalArrangement = Arrangement.spacedBy(8.dp)
    ){
    Icon(
    imageVector = Icons.Default.Warning,
    contentDescription = "ATTENTION !",
    tint = Color(0xFFFFA726),
    modifier = Modifier
    .size(36.dp)
    .offset(y = (-1).dp)
    )
    Text("ATTENTION !", fontWeight = FontWeight.Bold)
    }
    },
    text = {
    Text("La page suivante permet de modifier la configuration des tests. \n\nCette configuration ne doit être modifiée qu'avec la présence ou l'autorisation de votre neurologue, veuillez retourner en arrière si ce n'est pas le cas.")
    },
    containerColor = MaterialTheme.colorScheme.surface,
    titleContentColor = MaterialTheme.colorScheme.primary,
    textContentColor = MaterialTheme.colorScheme.onSurface,
    )
    }

    The test configuration is a key aspect of seizure data collection. Modifying it therefore requires permission from a neurologist, which is why an alert dialog appears on the screen when the button is clicked. Clicking on "Continuer" on the alert dialog navigates to the configuration. You can learn more about how tests are configured here.

  • Editing the post-test questionnaire ("Modifier le questionnaire") :

    SettingsPage.kt
    SettingsOption(text = "Modifier le questionnaire") { showDialogQuestionnaire = true }

    ...

    if (showDialogQuestionnaire) {
    AlertDialog(
    onDismissRequest = { showDialogQuestionnaire = false },
    confirmButton = {
    TextButton(onClick = {
    showDialogQuestionnaire = false
    navController.navigate("survey_entry") // Navigation to the survey editing page
    }) {
    Text("Continuer", color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold)
    }
    },
    dismissButton = {
    TextButton(onClick = { showDialogQuestionnaire = false }) {
    Text("Retour", color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold)
    }
    },
    title = {
    Row(verticalAlignment = Alignment.CenterVertically,
    horizontalArrangement = Arrangement.spacedBy(8.dp)
    ){
    Icon(
    imageVector = Icons.Default.Warning,
    contentDescription = "ATTENTION !",
    tint = Color(0xFFFFA726),
    modifier = Modifier
    .size(36.dp)
    .offset(y = (-1).dp)
    )
    Text("ATTENTION !", fontWeight = FontWeight.Bold)
    }
    },
    text = {
    Text("La page suivante permet de modifier le questionnaire post-test. \n\nCe questionnaire ne doit être modifié qu'avec la présence ou l'autorisation de votre neurologue, veuillez retourner en arrière si ce n'est pas le cas.")
    },
    containerColor = MaterialTheme.colorScheme.surface,
    titleContentColor = MaterialTheme.colorScheme.primary,
    textContentColor = MaterialTheme.colorScheme.onSurface,
    )
    }

    Similarly to the test configuration, modifying the survey/questionnaire requires permission from a neurologist because it is a key element for getting additionnal information about a seizure. Clicking on "Continuer" on the alert dialog navigates to the questionnaire editing screen.

  • Switching the camera to use, with a switch ("Caméra Arrière - Avant") :

    SettingsPage.kt
    Row(...)
    {
    Text(
    text = "Caméra",
    style = MaterialTheme.typography.bodyLarge.copy(fontSize = 20.sp),
    color = MaterialTheme.colorScheme.primary
    )
    Row(...)
    {
    Text(
    text = "Arrière",
    style = MaterialTheme.typography.bodyLarge.copy(fontSize = 18.sp),
    color = if (!isFrontCamera.value) MaterialTheme.colorScheme.primary else Color.Gray
    )
    // switch button to change active camera
    Switch(
    checked = isFrontCamera.value,
    onCheckedChange = { isFrontCamera.value = it },
    colors = SwitchDefaults.colors(
    checkedThumbColor = Color.White,
    checkedTrackColor = MaterialTheme.colorScheme.primary,
    uncheckedThumbColor = Color.White,
    uncheckedTrackColor = Color.Gray
    )
    )
    Text(
    text = "Avant",
    style = MaterialTheme.typography.bodyLarge.copy(fontSize = 18.sp),
    color = if (isFrontCamera.value) MaterialTheme.colorScheme.primary else Color.Gray
    )
    }
    }

    Clicking on the switch button changes variable isFrontCamera (boolean) linked to the selection of the camera between Rear and Front. This is important as it sets the camera to use when starting a testing sequence, with the value of the variable being kept between pages via a ViewModel. The display of this setting (i.e. the switch button) also changes dynamically when the value of the variable is changed.

  • Deleting the account:

    The last button of the settings page deals with account deletion:

    SettingsPage.kt
    if (showDeleteConfirm) {
    AlertDialog(
    onDismissRequest = { showDeleteConfirm = false },
    confirmButton = {
    TextButton(onClick = {
    deleteFirebaseAccount(
    onSuccess = {
    FirebaseAuth.getInstance().signOut()
    Toast.makeText(
    navController.context,
    "Compte supprimé",
    Toast.LENGTH_SHORT
    ).show()
    navController.navigate("login") {
    popUpTo(0)
    }
    },
    onError = {
    Toast.makeText(
    navController.context,
    "Erreur lors de la suppression",
    Toast.LENGTH_LONG
    ).show()
    }
    )
    showDeleteConfirm = false
    }) {
    Text("Oui", color = MaterialTheme.colorScheme.primary)
    }
    },
    dismissButton = {
    TextButton(onClick = { showDeleteConfirm = false }) {
    Text("Non", color = MaterialTheme.colorScheme.primary)
    }
    },
    title = {
    Text("Confirmer la suppression")
    },
    text = {
    Text("Êtes-vous sûr de vouloir supprimer votre compte ? Cette action est irréversible.")
    },
    containerColor = MaterialTheme.colorScheme.surface,
    titleContentColor = MaterialTheme.colorScheme.primary,
    textContentColor = MaterialTheme.colorScheme.onSurface,
    )
    }

    This is also handled with an alert dialog that shows up when the button is clicked. Then, the user has the option to confirm (or not) their account's deletion.

    If the user chooses to delete their account, the function deleteFirebaseAccount below is called, and the user is signed out and directed to the login screen if the deletion is successful. If an error occurs during the deletion, a toast message appears on the screen to inform the user.

    SettingsPage.kt
    fun deleteFirebaseAccount(onSuccess: () -> Unit = {}, onError: (Exception) -> Unit = {}) {
    val user = FirebaseAuth.getInstance().currentUser

    user?.delete()
    ?.addOnCompleteListener { task ->
    if (task.isSuccessful) {
    Log.d("FirebaseAuth", "Compte supprimé de Firebase")
    onSuccess()
    } else {
    Log.e("FirebaseAuth", "Erreur suppression de compte", task.exception)
    task.exception?.let { onError(it) }
    }
    }
    }