Fix profile avatar emoji fallback and bump TV/mobile app versions.

This commit is contained in:
Jos Vooges | STH 2026-09-13 16:29:49 +02:00
parent 91e7502d3b
commit 9efcfff484
9 changed files with 113 additions and 73 deletions

View file

@ -20,8 +20,8 @@ android {
applicationId = "nl.vonas.mediacluster"
minSdk = 24
targetSdk = 36
versionCode = 20
versionName = "1.0.19"
versionCode = 21
versionName = "1.0.20"
buildConfigField("String", "DEFAULT_API_BASE", "\"https://master.vonas.nl\"")
ndk {
abiFilters += listOf("arm64-v8a", "armeabi-v7a")

View file

@ -885,14 +885,21 @@ private fun JSONArray?.toProfiles(): List<ViewerProfile> {
}
}
private fun JSONObject.toProfile(): ViewerProfile = ViewerProfile(
id = getString("id"),
name = optString("name"),
avatarId = optString("avatarId").ifBlank { "fox" },
isOwner = optBoolean("isOwner"),
isKids = optBoolean("isKids"),
hasPin = optBoolean("hasPin"),
showAvatar = if (has("showAvatar")) optBoolean("showAvatar") else true,
hasCustomAvatar = optBoolean("hasCustomAvatar"),
avatarUrl = optString("avatarUrl").ifBlank { null },
)
private fun JSONObject.toProfile(): ViewerProfile {
val hasCustom = optBoolean("hasCustomAvatar")
val rawUrl = optString("avatarUrl").takeIf { it.isNotBlank() }
return ViewerProfile(
id = getString("id"),
name = optString("name"),
avatarId = optString("avatarId").ifBlank { "fox" },
isOwner = optBoolean("isOwner"),
isKids = optBoolean("isKids"),
hasPin = optBoolean("hasPin"),
showAvatar = when {
!has("showAvatar") || isNull("showAvatar") -> true
else -> optBoolean("showAvatar", true)
},
hasCustomAvatar = hasCustom,
avatarUrl = if (hasCustom) rawUrl else null,
)
}

View file

@ -86,10 +86,9 @@ class SessionStore(private val context: Context) {
if (showAvatar != null) {
prefs[profileShowAvatarKey] = if (showAvatar) "1" else "0"
}
if (avatarUrl != null) {
if (avatarUrl.isBlank()) prefs.remove(profileAvatarUrlKey)
else prefs[profileAvatarUrlKey] = avatarUrl
}
// Altijd syncen: null/blank = geen custom foto (emoji tonen)
if (avatarUrl.isNullOrBlank()) prefs.remove(profileAvatarUrlKey)
else prefs[profileAvatarUrlKey] = avatarUrl
}
}
}

View file

@ -1350,22 +1350,32 @@ private fun SettingsScreen(
.background(Color(0xFF2E2E3A)),
contentAlignment = Alignment.Center,
) {
if (profileShowAvatar && !profileAvatarUrl.isNullOrBlank()) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(profileAvatarUrl)
.apply {
if (!profileAuthHeader.isNullOrBlank()) {
addHeader("Authorization", profileAuthHeader)
}
}
.build(),
contentDescription = null,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
if (profileShowAvatar) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(avatarEmoji(profileAvatarId ?: "fox"), fontSize = 22.sp)
if (!profileAvatarUrl.isNullOrBlank()) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(profileAvatarUrl)
.apply {
if (!profileAuthHeader.isNullOrBlank()) {
addHeader("Authorization", profileAuthHeader)
}
}
.build(),
contentDescription = null,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
}
}
} else {
Text(avatarEmoji(profileAvatarId ?: "fox"), fontSize = 22.sp)
Text(
(profileName?.firstOrNull()?.uppercaseChar() ?: '?').toString(),
color = Color.White,
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
)
}
}
Column(Modifier.weight(1f)) {

View file

@ -20,8 +20,8 @@ android {
applicationId = "nl.vonas.mediacluster.tv"
minSdk = 24
targetSdk = 36
versionCode = 106
versionName = "0.14.43"
versionCode = 107
versionName = "0.14.44"
buildConfigField("String", "DEFAULT_API_BASE", "\"https://master.vonas.nl\"")
ndk {
abiFilters += listOf("arm64-v8a", "armeabi-v7a")

View file

@ -875,14 +875,21 @@ private fun JSONArray?.toProfiles(): List<ViewerProfile> {
}
}
private fun JSONObject.toProfile(): ViewerProfile = ViewerProfile(
id = getString("id"),
name = optString("name"),
avatarId = optString("avatarId").ifBlank { "fox" },
isOwner = optBoolean("isOwner"),
isKids = optBoolean("isKids"),
hasPin = optBoolean("hasPin"),
showAvatar = if (has("showAvatar")) optBoolean("showAvatar") else true,
hasCustomAvatar = optBoolean("hasCustomAvatar"),
avatarUrl = optString("avatarUrl").ifBlank { null },
)
private fun JSONObject.toProfile(): ViewerProfile {
val hasCustom = optBoolean("hasCustomAvatar")
val rawUrl = optString("avatarUrl").takeIf { it.isNotBlank() }
return ViewerProfile(
id = getString("id"),
name = optString("name"),
avatarId = optString("avatarId").ifBlank { "fox" },
isOwner = optBoolean("isOwner"),
isKids = optBoolean("isKids"),
hasPin = optBoolean("hasPin"),
showAvatar = when {
!has("showAvatar") || isNull("showAvatar") -> true
else -> optBoolean("showAvatar", true)
},
hasCustomAvatar = hasCustom,
avatarUrl = if (hasCustom) rawUrl else null,
)
}

View file

@ -105,10 +105,9 @@ class SessionStore(private val context: Context) {
if (showAvatar != null) {
prefs[profileShowAvatarKey] = if (showAvatar) "1" else "0"
}
if (avatarUrl != null) {
if (avatarUrl.isBlank()) prefs.remove(profileAvatarUrlKey)
else prefs[profileAvatarUrlKey] = avatarUrl
}
// Altijd syncen: null/blank = geen custom foto (emoji tonen)
if (avatarUrl.isNullOrBlank()) prefs.remove(profileAvatarUrlKey)
else prefs[profileAvatarUrlKey] = avatarUrl
}
}
}

View file

@ -784,6 +784,7 @@ private fun MainHub(
MainTab.Settings -> SettingsScreen(
api = api,
profileAvatarId = profileAvatarId,
profileShowAvatar = profileShowAvatar,
profileName = profileName,
isOwner = isOwner,
onBack = {
@ -1644,6 +1645,7 @@ private fun ShelfBlock(
private fun SettingsScreen(
api: ApiClient,
profileAvatarId: String? = null,
profileShowAvatar: Boolean = true,
profileName: String? = null,
isOwner: Boolean = false,
onBack: () -> Unit,
@ -1737,12 +1739,21 @@ private fun SettingsScreen(
.background(Color(0xFF2E2E3A)),
contentAlignment = Alignment.Center,
) {
Text(
avatarEmoji(profileAvatarId ?: "fox"),
fontSize = 30.sp,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
)
if (profileShowAvatar) {
Text(
avatarEmoji(profileAvatarId ?: "fox"),
fontSize = 30.sp,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
)
} else {
Text(
(profileName?.firstOrNull()?.uppercaseChar() ?: '?').toString(),
color = Color.White,
fontSize = 26.sp,
fontWeight = FontWeight.Bold,
)
}
}
Column(Modifier.weight(1f)) {
Text(

View file

@ -321,25 +321,32 @@ fun TopNavBar(
horizontalArrangement = Arrangement.spacedBy(6.dp),
) {
if (profileShowAvatar) {
if (!profileAvatarUrl.isNullOrBlank()) {
val ctx = LocalContext.current
AsyncImage(
model = ImageRequest.Builder(ctx)
.data(profileAvatarUrl)
.apply {
if (!profileAuthHeader.isNullOrBlank()) {
addHeader("Authorization", profileAuthHeader)
Box(
Modifier.size(22.dp),
contentAlignment = Alignment.Center,
) {
// Emoji altijd als basis; custom foto eroverheen indien beschikbaar
if (profileAvatarEmoji != null) {
Text(profileAvatarEmoji, fontSize = 15.sp)
}
if (!profileAvatarUrl.isNullOrBlank()) {
val ctx = LocalContext.current
AsyncImage(
model = ImageRequest.Builder(ctx)
.data(profileAvatarUrl)
.apply {
if (!profileAuthHeader.isNullOrBlank()) {
addHeader("Authorization", profileAuthHeader)
}
}
}
.build(),
contentDescription = null,
modifier = Modifier
.size(22.dp)
.clip(RoundedCornerShape(50)),
contentScale = ContentScale.Crop,
)
} else if (profileAvatarEmoji != null) {
Text(profileAvatarEmoji, fontSize = 15.sp)
.build(),
contentDescription = null,
modifier = Modifier
.size(22.dp)
.clip(RoundedCornerShape(50)),
contentScale = ContentScale.Crop,
)
}
}
}
if (!profileLabel.isNullOrBlank()) {