refactor(cleanup): dead code + hygiene batch from games review

- Delete unused ui/theme/Color.kt (zero refs; live palette is Theme.kt).
- Remove orphaned EditProfileScreen wrapper composable (no route references it;
  AccountScreen embeds EditProfileContent, which stays).
- Debug-gate ArtPreviewScreen + PairedHomePreviewScreen out of the release nav
  graph (BuildConfig.DEBUG).
- Collapse duplicate wheel_history route into game_history (same screen; wheel
  surfaces now navigate to Past Games directly).
- CouplePremiumChecker: inject AuthRepository instead of raw
  FirebaseAuth.getInstance() (finishes the in-flight auth-DI refactor for
  non-data-layer call sites).
- Copy/UI polish: 'It's a match!' (matches the push copy), internal 'mc' token
  never renders in the Home daily pill ('Daily Fun Mc' → 'Daily Fun'),
  welcome/splash privacy tagline no longer clips mid-sentence (maxLines 4 +
  ellipsis, AUTH-TRUNC-001).

Unit + functions suites green; assembleDebug clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
null 2026-07-07 19:48:56 -05:00
parent e5868bd6b1
commit c36a101d38
10 changed files with 24 additions and 76 deletions

View File

@ -2,7 +2,7 @@ package app.closer.core.billing
import app.closer.data.remote.FirestoreCollections
import app.closer.domain.repository.CoupleRepository
import com.google.firebase.auth.FirebaseAuth
import app.closer.domain.repository.AuthRepository
import com.google.firebase.firestore.FirebaseFirestore
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@ -29,11 +29,12 @@ import javax.inject.Singleton
class CouplePremiumChecker @Inject constructor(
private val entitlementChecker: EntitlementChecker,
private val firestore: FirebaseFirestore,
private val coupleRepository: CoupleRepository
private val coupleRepository: CoupleRepository,
private val authRepository: AuthRepository
) {
/** Couple-shared premium for the current user (resolves the partner internally). Drop-in for EntitlementChecker. */
fun isPremium(): Flow<Boolean> = flow {
val uid = FirebaseAuth.getInstance().currentUser?.uid
val uid = authRepository.currentUserId
val partnerId = uid?.let {
runCatching { coupleRepository.getCoupleForUser(it)?.userIds?.firstOrNull { id -> id != it } }.getOrNull()
}

View File

@ -477,9 +477,6 @@ fun AppNavigation(
onNavigate = navigateRoute
)
}
composable(route = AppRoute.WHEEL_HISTORY) {
GameHistoryScreen(onNavigate = navigateRoute)
}
composable(route = AppRoute.GAME_HISTORY) {
GameHistoryScreen(onNavigate = navigateRoute)
}
@ -604,6 +601,8 @@ fun AppNavigation(
composable(route = AppRoute.ACTIVITY) {
ActivityScreen(onNavigate = navigateRoute)
}
// Dev-only art/layout previews: keep them out of the release nav graph.
if (app.closer.BuildConfig.DEBUG) {
composable(route = AppRoute.ART_PREVIEW) {
app.closer.ui.debug.ArtPreviewScreen(onNavigate = navigateRoute)
}
@ -612,6 +611,7 @@ fun AppNavigation(
}
}
}
}
// Floating in-app chat-head for incoming partner messages — drifts over every screen,
// draggable, tap to open the conversation.

View File

@ -43,7 +43,6 @@ object AppRoute {
const val DELETE_ACCOUNT = "delete_account"
const val SECURITY = "security_settings"
const val CHANGE_PASSWORD = "change_password"
const val WHEEL_HISTORY = "wheel_history"
const val GAME_HISTORY = "game_history"
const val THIS_OR_THAT_REPLAY = "this_or_that_replay/{sessionId}"
const val DESIRE_SYNC_REPLAY = "desire_sync_replay/{sessionId}"
@ -122,7 +121,6 @@ object AppRoute {
Definition(DELETE_ACCOUNT, "Delete Account", "settings"),
Definition(SECURITY, "Security", "settings"),
Definition(CHANGE_PASSWORD, "Change Password", "settings"),
Definition(WHEEL_HISTORY, "Wheel History", "wheel"),
Definition(GAME_HISTORY, "Past Games", "play"),
Definition(THIS_OR_THAT_REPLAY, "This or That Results", "play"),
Definition(DESIRE_SYNC_REPLAY, "Desire Sync Results", "play"),
@ -178,7 +176,6 @@ object AppRoute {
SPIN_WHEEL_RANDOM,
WHEEL_SESSION,
WHEEL_COMPLETE,
WHEEL_HISTORY,
GAME_HISTORY,
THIS_OR_THAT_REPLAY,
DESIRE_SYNC_REPLAY,

View File

@ -21,6 +21,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import app.closer.ui.brand.CloserBrandCopy
import kotlinx.coroutines.delay
@ -79,7 +80,10 @@ fun BrandMessageRotator(
style = style,
color = color,
textAlign = TextAlign.Center,
maxLines = 3
// The primary privacy message wraps to 4 lines at default font scale on the
// welcome/splash width; 3 clipped it mid-sentence with no ellipsis (AUTH-TRUNC-001).
maxLines = 4,
overflow = TextOverflow.Ellipsis
)
}
}

View File

@ -585,7 +585,7 @@ private fun MatchOverlay(
)
Text(
text = "It is a match!",
text = "Its a match!",
style = MaterialTheme.typography.headlineSmall.copy(fontWeight = FontWeight.SemiBold),
color = MaterialTheme.colorScheme.onSurface
)

View File

@ -1015,6 +1015,8 @@ class HomeViewModel @Inject constructor(
private fun String.toHomeLabel(): String =
split("_", "-")
.filter { part -> part.isNotBlank() }
// Internal format tokens (e.g. the "mc" in daily_fun_mc) must never face users.
.filterNot { part -> part.lowercase() in setOf("mc") }
.joinToString(" ") { part -> part.replaceFirstChar { it.uppercaseChar() } }
companion object {

View File

@ -76,44 +76,8 @@ import app.closer.ui.settings.SettingsPrimaryDeep
import app.closer.ui.components.CloserGlyphs
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditProfileScreen(
onNavigate: (String) -> Unit = {},
viewModel: EditProfileViewModel = hiltViewModel()
) {
val snackbar = remember { SnackbarHostState() }
Scaffold(
snackbarHost = { SnackbarHost(snackbar) },
containerColor = Color.Transparent,
modifier = Modifier.background(SettingsBackgroundBrush),
topBar = {
TopAppBar(
title = { Text("Edit profile", color = SettingsInk) },
navigationIcon = {
IconButton(onClick = { onNavigate("back") }) {
Icon(
CloserGlyphs.Back,
contentDescription = "Back",
tint = SettingsInk
)
}
},
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
)
}
) { padding ->
EditProfileContent(
modifier = Modifier
.fillMaxSize()
.padding(padding)
.verticalScroll(rememberScrollState()),
snackbar = snackbar,
viewModel = viewModel
)
}
}
// The routed EditProfileScreen wrapper was removed as dead code (no nav route references
// it); AccountScreen embeds EditProfileContent directly.
@Composable
fun EditProfileContent(
modifier: Modifier = Modifier,

View File

@ -1,20 +0,0 @@
package app.closer.ui.theme
import androidx.compose.ui.graphics.Color
// Dark theme colors (for reference if needed)
val darkPrimaryColor = Color(0xFFD7BBFF)
val darkPrimaryContainerColor = Color(0xFF4D3865)
val darkSecondaryColor = Color(0xFFE8B7D0)
val darkTertiaryColor = Color(0xFFC9C1FF)
val darkBackgroundColor = Color(0xFF111015)
val darkSurfaceColor = Color(0xFF19161F)
val darkErrorColor = Color(0xFFFFB4AB)
val darkOnPrimaryColor = Color(0xFF37204E)
val darkOnPrimaryContainerColor = Color(0xFFF2E8FF)
val darkOnSecondaryColor = Color(0xFF482638)
val darkOnTertiaryColor = Color(0xFF302A55)
val darkOnBackgroundColor = Color(0xFFEDE7EF)
val darkOnSurfaceColor = Color(0xFFEDE7EF)
val darkOnErrorColor = Color(0xFF690005)

View File

@ -63,7 +63,7 @@ fun CategoryPickerScreen(
if (item.isLocked) onNavigate(AppRoute.PAYWALL)
else onNavigate(AppRoute.spinWheel(item.category.id))
},
onHistory = { onNavigate(AppRoute.WHEEL_HISTORY) },
onHistory = { onNavigate(AppRoute.GAME_HISTORY) },
onRetry = viewModel::load
)
}

View File

@ -215,7 +215,7 @@ class SpinWheelViewModel @Inject constructor(
}
fun onHistory() {
_uiState.update { it.copy(navigateTo = AppRoute.WHEEL_HISTORY) }
_uiState.update { it.copy(navigateTo = AppRoute.GAME_HISTORY) }
}
fun onNavigated() {