Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore: Unify PushNoficationSettingsScreen and NotificationSettingsUi & unsaved changes dialog #287

Merged
merged 6 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import de.tum.informatics.www1.artemis.native_app.feature.login.register.Registe
import de.tum.informatics.www1.artemis.native_app.feature.login.saml2_login.Saml2LoginScreen
import de.tum.informatics.www1.artemis.native_app.feature.login.saml2_login.Saml2LoginViewModel
import de.tum.informatics.www1.artemis.native_app.feature.login.service.ServerNotificationStorageService
import de.tum.informatics.www1.artemis.native_app.feature.push.ui.PushNotificationSettingsScreen
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -175,8 +176,9 @@ fun NavGraphBuilder.loginScreen(
}

LoginScreenContent.NOTIFICATION_SETTINGS -> {
NotificationSettingsUi(
PushNotificationSettingsScreen(
modifier = Modifier.fillMaxSize(),
isInitialNotificationSettingsScreen = true,
onDone = {
scope.launch {
serverNotificationStorageService.setHasDisplayed(
Expand Down

This file was deleted.

5 changes: 0 additions & 5 deletions feature/login/src/main/res/values/account_ui_strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,4 @@
<string name="login_saml_screen_login_response_unexpected_error">An unexpected error occurred. Please try again or use a different login method.</string>
<string name="login_saml_screen_login_webview_loading">Loading authentication website…</string>
<string name="login_saml_screen_login_webview_try_again">Reload now</string>

<!-- Push notification settings -->
<string name="push_notification_settings_title">Notification configuration</string>
<string name="push_notification_settings_fab_text_with_save">Save &amp; Continue</string>
<string name="push_notification_settings_fab_text_without_save">Continue</string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package de.tum.informatics.www1.artemis.native_app.feature.push.ui

import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import de.tum.informatics.www1.artemis.native_app.core.ui.compose.JobAnimatedFloatingActionButton
import de.tum.informatics.www1.artemis.native_app.core.ui.compose.NavigationBackButton
import de.tum.informatics.www1.artemis.native_app.feature.push.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel

/**
* Displays the notification settings screen.
* Contains PushNotificationSettingsUi and is used in the settings screen and after login.
*/
@Composable
fun PushNotificationSettingsScreen(
modifier: Modifier = Modifier,
isInitialNotificationSettingsScreen: Boolean = false,
onDone: () -> Unit
) {
val viewModel: PushNotificationSettingsViewModel = koinViewModel()
val isDirty by viewModel.isDirty.collectAsState(initial = false)

var saveJob: Job? by remember { mutableStateOf(null) }
var displaySyncFailedDialog: Boolean by rememberSaveable { mutableStateOf(false) }
var displayUnsavedChangesDialog: Boolean by rememberSaveable { mutableStateOf(false) }

val onNavigateBack: () -> Unit = {
if (isDirty) {
displayUnsavedChangesDialog = true
} else {
onDone()
}
}
val saveChanges: () -> Unit = {
saveJob = viewModel.saveSettings()
CoroutineScope(Dispatchers.Main).launch {
try {
val isSuccessful = (saveJob as Deferred<Boolean>).await()
if (isSuccessful) {
onDone()
} else {
displayUnsavedChangesDialog = false
displaySyncFailedDialog = true
}
} catch (e: Exception) {
displayUnsavedChangesDialog = false
displaySyncFailedDialog = true
}
}
}

BackHandler {
onNavigateBack()
}

Scaffold(
modifier = modifier,
topBar = {
TopAppBar(
navigationIcon = {
if (isInitialNotificationSettingsScreen) return@TopAppBar

NavigationBackButton(onNavigateBack = {
onNavigateBack()
})
},
title = {
if (isInitialNotificationSettingsScreen) {
Text(text = stringResource(id = R.string.initial_push_notification_settings_title))
} else {
Text(text = stringResource(id = R.string.settings_push_notification_settings_screen_title))
}
}
)
},
floatingActionButton = {
if (isInitialNotificationSettingsScreen) {
ExtendedFloatingActionButton(
onClick = {
// If changes have been made, these need to be synced first.
if (isDirty) saveChanges() else onDone()
},
text = {
Text(
text = stringResource(
id =
if (isDirty) R.string.initial_push_notification_settings_fab_text_with_save
else R.string.initial_push_notification_settings_fab_text_without_save
)
)
},
icon = {
Icon(
imageVector = if (isDirty) Icons.Default.Save else Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = null
)
}
)
} else {
JobAnimatedFloatingActionButton(
enabled = isDirty,
startJob = { viewModel.saveSettings() },
onJobCompleted = { isSuccessful ->
if (!isSuccessful) {
displaySyncFailedDialog = true
}
}
) {
Icon(imageVector = Icons.Default.Save, contentDescription = null)
}
}
}
) { padding ->
PushNotificationSettingsUi(
modifier = Modifier
.fillMaxSize()
.padding(top = padding.calculateTopPadding())
.padding(horizontal = 16.dp)
.verticalScroll(rememberScrollState())
.padding(
bottom = WindowInsets.systemBars
.asPaddingValues()
.calculateBottomPadding()
),
viewModel = viewModel
)

if (displaySyncFailedDialog) {
PushNotificationSyncFailedDialog {
displaySyncFailedDialog = false
}
}

if (displayUnsavedChangesDialog) {
PushNotificationUnsavedChangesDialog(
onDismissRequest = {
displayUnsavedChangesDialog = false
onDone()
},
onSaveChanges = saveChanges
)
}

if (saveJob != null && isInitialNotificationSettingsScreen) {
FelberMartin marked this conversation as resolved.
Show resolved Hide resolved
PushNotificationSyncChangesDialog(
onDismissRequest = {
saveJob?.cancel()
saveJob = null
}
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,19 @@ fun PushNotificationSyncFailedDialog(onDismissRequest: () -> Unit) {
onPressPositiveButton = onDismissRequest,
onDismissRequest = onDismissRequest
)
}

@Composable
fun PushNotificationUnsavedChangesDialog(
onDismissRequest: () -> Unit,
onSaveChanges: () -> Unit
) {
TextAlertDialog(
title = stringResource(id = R.string.push_notification_settings_unsaved_changes_dialog_title),
text = stringResource(id = R.string.push_notification_settings_unsaved_changes_dialog_message),
confirmButtonText = stringResource(id = R.string.push_notification_settings_unsaved_changes_dialog_positive),
dismissButtonText = stringResource(id = R.string.push_notification_settings_unsaved_changes_dialog_negative),
onPressPositiveButton = onSaveChanges,
onDismissRequest = onDismissRequest
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,15 @@
<string name="push_notification_settings_sync_failed_dialog_title">Syncing failed!</string>
<string name="push_notification_settings_sync_failed_dialog_message">Something went wrong while syncing your settings.</string>
<string name="push_notification_settings_sync_failed_dialog_positive">@android:string/ok</string>

<string name="push_notification_settings_unsaved_changes_dialog_title">You have unsaved changes!</string>
<string name="push_notification_settings_unsaved_changes_dialog_message">Would you like to save your changes before continuing?</string>
<string name="push_notification_settings_unsaved_changes_dialog_positive">Save</string>
<string name="push_notification_settings_unsaved_changes_dialog_negative">Discard</string>

<string name="settings_push_notification_settings_screen_title">Notification settings</string>

<string name="initial_push_notification_settings_title">Notification configuration</string>
<string name="initial_push_notification_settings_fab_text_with_save">Save &amp; Continue</string>
<string name="initial_push_notification_settings_fab_text_without_save">Continue</string>
</resources>
Loading
Loading