From 35e786824b99815bbbf74558570bdf69b86a7220 Mon Sep 17 00:00:00 2001 From: Greg Stanton Marra Date: Thu, 12 Feb 2026 18:06:58 -0500 Subject: [PATCH] Add profile photo, overflow menu, and sign-out confirmation to MyTBA Show the user's Google profile photo as a circular avatar (with a person-icon fallback), move sign-out behind a MoreVert dropdown menu, and require confirmation via an AlertDialog before signing out. Co-Authored-By: Claude Opus 4.6 --- .../android/ui/mytba/MyTBAScreen.kt | 74 +++++++++++++++++-- .../android/ui/mytba/MyTBAUiState.kt | 1 + .../android/ui/mytba/MyTBAViewModel.kt | 1 + 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAScreen.kt b/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAScreen.kt index 45f71c018..11b717c39 100644 --- a/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAScreen.kt +++ b/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAScreen.kt @@ -5,33 +5,51 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.icons.filled.Person +import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedButton import androidx.compose.material3.PrimaryScrollableTabRow import androidx.compose.material3.Tab import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import coil.compose.AsyncImage import com.thebluealliance.android.domain.model.Favorite import com.thebluealliance.android.domain.model.ModelType import com.thebluealliance.android.domain.model.Subscription @@ -70,15 +88,44 @@ fun MyTBAScreen( } } + var showSignOutDialog by remember { mutableStateOf(false) } + var menuExpanded by remember { mutableStateOf(false) } + + if (showSignOutDialog) { + AlertDialog( + onDismissRequest = { showSignOutDialog = false }, + title = { Text("Sign out?") }, + text = { Text("You will no longer receive notifications for your favorites and subscriptions.") }, + confirmButton = { + TextButton(onClick = { + showSignOutDialog = false + viewModel.signOut() + }) { Text("Sign out") } + }, + dismissButton = { + TextButton(onClick = { showSignOutDialog = false }) { Text("Cancel") } + }, + ) + } + Column(modifier = Modifier.fillMaxSize()) { Row( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), - horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { - Column { + val personIcon = rememberVectorPainter(Icons.Default.Person) + AsyncImage( + model = uiState.userPhotoUrl, + contentDescription = "Profile photo", + modifier = Modifier.size(40.dp).clip(CircleShape), + placeholder = personIcon, + error = personIcon, + fallback = personIcon, + ) + Spacer(modifier = Modifier.width(16.dp)) + Column(modifier = Modifier.weight(1f)) { Text( text = uiState.userName ?: "Signed in", style = MaterialTheme.typography.bodyLarge, @@ -91,8 +138,25 @@ fun MyTBAScreen( ) } } - OutlinedButton(onClick = viewModel::signOut) { - Text("Sign out") + Box { + IconButton(onClick = { menuExpanded = true }) { + Icon( + imageVector = Icons.Default.MoreVert, + contentDescription = "More options", + ) + } + DropdownMenu( + expanded = menuExpanded, + onDismissRequest = { menuExpanded = false }, + ) { + DropdownMenuItem( + text = { Text("Sign out") }, + onClick = { + menuExpanded = false + showSignOutDialog = true + }, + ) + } } } diff --git a/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAUiState.kt b/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAUiState.kt index 07b594fd4..7be7cdacb 100644 --- a/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAUiState.kt +++ b/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAUiState.kt @@ -7,6 +7,7 @@ data class MyTBAUiState( val isSignedIn: Boolean = false, val userName: String? = null, val userEmail: String? = null, + val userPhotoUrl: String? = null, val favorites: List = emptyList(), val subscriptions: List = emptyList(), ) diff --git a/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAViewModel.kt b/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAViewModel.kt index 8bef0e92b..3abc917fd 100644 --- a/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAViewModel.kt +++ b/app/src/main/kotlin/com/thebluealliance/android/ui/mytba/MyTBAViewModel.kt @@ -36,6 +36,7 @@ class MyTBAViewModel @Inject constructor( isSignedIn = user != null, userName = user?.displayName, userEmail = user?.email, + userPhotoUrl = user?.photoUrl?.toString(), favorites = favorites, subscriptions = subscriptions, )