diff --git a/app/src/main/assets/badges/administrator.png b/app/src/main/assets/badges/administrator.png
new file mode 100644
index 00000000..ab4cf796
Binary files /dev/null and b/app/src/main/assets/badges/administrator.png differ
diff --git a/app/src/main/assets/badges/clown.png b/app/src/main/assets/badges/clown.png
new file mode 100644
index 00000000..5d800687
Binary files /dev/null and b/app/src/main/assets/badges/clown.png differ
diff --git a/app/src/main/assets/badges/developer.png b/app/src/main/assets/badges/developer.png
new file mode 100644
index 00000000..590f74cd
Binary files /dev/null and b/app/src/main/assets/badges/developer.png differ
diff --git a/app/src/main/assets/badges/first_100_members.png b/app/src/main/assets/badges/first_100_members.png
new file mode 100644
index 00000000..61b6b1ae
Binary files /dev/null and b/app/src/main/assets/badges/first_100_members.png differ
diff --git a/app/src/main/assets/badges/founder.png b/app/src/main/assets/badges/founder.png
new file mode 100644
index 00000000..1f7e6666
Binary files /dev/null and b/app/src/main/assets/badges/founder.png differ
diff --git a/app/src/main/assets/badges/gump.png b/app/src/main/assets/badges/gump.png
new file mode 100644
index 00000000..18daf3b1
Binary files /dev/null and b/app/src/main/assets/badges/gump.png differ
diff --git a/app/src/main/assets/badges/karen.png b/app/src/main/assets/badges/karen.png
new file mode 100644
index 00000000..edae58ae
Binary files /dev/null and b/app/src/main/assets/badges/karen.png differ
diff --git a/app/src/main/assets/badges/supporter.png b/app/src/main/assets/badges/supporter.png
new file mode 100644
index 00000000..90c9c9e7
Binary files /dev/null and b/app/src/main/assets/badges/supporter.png differ
diff --git a/app/src/main/assets/badges/top-contributor.png b/app/src/main/assets/badges/top-contributor.png
new file mode 100644
index 00000000..2e267a20
Binary files /dev/null and b/app/src/main/assets/badges/top-contributor.png differ
diff --git a/app/src/main/assets/badges/trusted-seller.png b/app/src/main/assets/badges/trusted-seller.png
new file mode 100644
index 00000000..f92e0fce
Binary files /dev/null and b/app/src/main/assets/badges/trusted-seller.png differ
diff --git a/app/src/main/assets/badges/verifiedvendor.svg b/app/src/main/assets/badges/verifiedvendor.svg
new file mode 100644
index 00000000..d8024f5c
--- /dev/null
+++ b/app/src/main/assets/badges/verifiedvendor.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/java/chat/zekochat/composables/chat/MemberListItem.kt b/app/src/main/java/chat/zekochat/composables/chat/MemberListItem.kt
index 19017820..3ef82b8c 100644
--- a/app/src/main/java/chat/zekochat/composables/chat/MemberListItem.kt
+++ b/app/src/main/java/chat/zekochat/composables/chat/MemberListItem.kt
@@ -5,9 +5,15 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.width
import androidx.compose.ui.Modifier
+import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
import chat.zekochat.api.PeptideAPI
import chat.zekochat.api.internals.BrushCompat
import chat.zekochat.api.internals.Roles
@@ -44,16 +50,30 @@ fun MemberListItem(
colors = TransparentListItemColours,
modifier = modifier,
headlineContent = {
- Text(
- text = member?.nickname
- ?: user?.displayName
- ?: user?.username
- ?: user?.id
- ?: userId,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- style = LocalTextStyle.current.copy(brush = colour),
- )
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(
+ text = member?.nickname
+ ?: user?.displayName
+ ?: user?.username
+ ?: user?.id
+ ?: userId,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ style = LocalTextStyle.current.copy(brush = colour),
+ modifier = Modifier.weight(1f)
+ )
+
+ if (hasVerifiedVendor(user?.badges)) {
+ Spacer(modifier = Modifier.width(4.dp))
+ UserVendorBadge(
+ badges = user?.badges,
+ size = 16.dp
+ )
+ }
+ }
},
supportingContent = {
user?.status?.text?.let {
diff --git a/app/src/main/java/chat/zekochat/composables/chat/Message.kt b/app/src/main/java/chat/zekochat/composables/chat/Message.kt
index 4bc89300..572cccf8 100644
--- a/app/src/main/java/chat/zekochat/composables/chat/Message.kt
+++ b/app/src/main/java/chat/zekochat/composables/chat/Message.kt
@@ -417,6 +417,14 @@ fun Message(
)
)
+ if (hasVerifiedVendor(author.badges)) {
+ Spacer(modifier = Modifier.width(5.dp))
+ UserVendorBadge(
+ badges = author.badges,
+ size = 16.dp
+ )
+ }
+
InlineBadges(
bot = author.bot != null && message.masquerade == null,
bridge = message.masquerade != null && author.bot != null,
diff --git a/app/src/main/java/chat/zekochat/composables/chat/UserBadgeList.kt b/app/src/main/java/chat/zekochat/composables/chat/UserBadgeList.kt
index d1b09347..d8d5d78f 100644
--- a/app/src/main/java/chat/zekochat/composables/chat/UserBadgeList.kt
+++ b/app/src/main/java/chat/zekochat/composables/chat/UserBadgeList.kt
@@ -50,77 +50,70 @@ fun BadgeListEntry(badge: UserBadges) {
UserBadges.Developer.value -> {
BadgeListEntryTemplate(
label = stringResource(R.string.user_badge_developer),
- icon = painterResource(R.drawable.user_badge_developer)
+ icon = painterResource(R.drawable.badge_developer)
)
}
UserBadges.Translator.value -> {
BadgeListEntryTemplate(
- label = stringResource(R.string.user_badge_translator),
- icon = painterResource(R.drawable.user_badge_translator)
+ label = stringResource(R.string.user_badge_first_100_members),
+ icon = painterResource(R.drawable.badge_first_100_members)
)
}
UserBadges.Supporter.value -> {
BadgeListEntryTemplate(
label = stringResource(R.string.user_badge_supporter),
- icon = painterResource(R.drawable.user_badge_supporter)
+ icon = painterResource(R.drawable.badge_supporter)
)
}
UserBadges.ResponsibleDisclosure.value -> {
BadgeListEntryTemplate(
- label = stringResource(R.string.user_badge_responsible_disclosure),
- icon = painterResource(R.drawable.user_badge_disclosure)
+ label = stringResource(R.string.user_badge_trusted_seller),
+ icon = painterResource(R.drawable.badge_trusted_seller)
)
}
UserBadges.Founder.value -> {
BadgeListEntryTemplate(
label = stringResource(R.string.user_badge_founder),
- icon = painterResource(R.drawable.user_badge_founder)
+ icon = painterResource(R.drawable.badge_founder)
)
}
UserBadges.PlatformModeration.value -> {
BadgeListEntryTemplate(
- label = stringResource(R.string.user_badge_platform_moderation),
- icon = painterResource(R.drawable.user_badge_moderation)
- )
- }
-
- UserBadges.ActiveSupporter.value -> {
- BadgeListEntryTemplate(
- label = stringResource(R.string.user_badge_active_supporter),
- icon = painterResource(R.drawable.icn_emoji_people_24dp)
+ label = stringResource(R.string.user_badge_administrator),
+ icon = painterResource(R.drawable.badge_administrator)
)
}
UserBadges.Paw.value -> {
BadgeListEntryTemplate(
- label = stringResource(R.string.user_badge_paw),
- icon = painterResource(R.drawable.user_badge_paw)
+ label = stringResource(R.string.user_badge_clown),
+ icon = painterResource(R.drawable.badge_clown)
)
}
UserBadges.EarlyAdopter.value -> {
BadgeListEntryTemplate(
- label = stringResource(R.string.user_badge_early_adopter),
- icon = painterResource(R.drawable.user_badge_early_adopter)
+ label = stringResource(R.string.user_badge_top_contributor),
+ icon = painterResource(R.drawable.badge_top_contributor)
)
}
UserBadges.ReservedRelevantJokeBadge1.value -> {
BadgeListEntryTemplate(
- label = stringResource(R.string.user_badge_reserved_relevant_joke_badge_1),
- icon = painterResource(R.drawable.user_badge_reserved_relevant_one)
+ label = stringResource(R.string.user_badge_karen),
+ icon = painterResource(R.drawable.badge_karen)
)
}
UserBadges.ReservedRelevantJokeBadge2.value -> {
BadgeListEntryTemplate(
- label = stringResource(R.string.user_badge_reserved_relevant_joke_badge_2),
- icon = painterResource(R.drawable.user_badge_reserved_relevant_two)
+ label = stringResource(R.string.user_badge_gump),
+ icon = painterResource(R.drawable.badge_gump)
)
}
}
@@ -132,7 +125,7 @@ fun UserBadgeList(badges: Long) {
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
UserBadges.entries
- .filter { badges has it }
+ .filter { it != UserBadges.ActiveSupporter && (badges has it) }
.forEach { badge ->
BadgeListEntry(badge)
}
@@ -147,34 +140,34 @@ fun UserBadgeRow(badges: Long) {
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
UserBadges.entries
- .filter { badges has it }
+ .filter { it != UserBadges.ActiveSupporter && (badges has it) }
.forEach { badge ->
Image(
painter = when (badge) {
- UserBadges.Developer -> painterResource(R.drawable.user_badge_developer)
- UserBadges.Translator -> painterResource(R.drawable.user_badge_translator)
- UserBadges.Supporter -> painterResource(R.drawable.user_badge_supporter)
- UserBadges.ResponsibleDisclosure -> painterResource(R.drawable.user_badge_disclosure)
- UserBadges.Founder -> painterResource(R.drawable.user_badge_founder)
- UserBadges.PlatformModeration -> painterResource(R.drawable.user_badge_moderation)
+ UserBadges.Developer -> painterResource(R.drawable.badge_developer)
+ UserBadges.Translator -> painterResource(R.drawable.badge_first_100_members)
+ UserBadges.Supporter -> painterResource(R.drawable.badge_supporter)
+ UserBadges.ResponsibleDisclosure -> painterResource(R.drawable.badge_trusted_seller)
+ UserBadges.Founder -> painterResource(R.drawable.badge_founder)
+ UserBadges.PlatformModeration -> painterResource(R.drawable.badge_administrator)
UserBadges.ActiveSupporter -> painterResource(R.drawable.icn_emoji_people_24dp)
- UserBadges.Paw -> painterResource(R.drawable.user_badge_paw)
- UserBadges.EarlyAdopter -> painterResource(R.drawable.user_badge_early_adopter)
- UserBadges.ReservedRelevantJokeBadge1 -> painterResource(R.drawable.user_badge_reserved_relevant_one)
- UserBadges.ReservedRelevantJokeBadge2 -> painterResource(R.drawable.user_badge_reserved_relevant_two)
+ UserBadges.Paw -> painterResource(R.drawable.badge_clown)
+ UserBadges.EarlyAdopter -> painterResource(R.drawable.badge_top_contributor)
+ UserBadges.ReservedRelevantJokeBadge1 -> painterResource(R.drawable.badge_karen)
+ UserBadges.ReservedRelevantJokeBadge2 -> painterResource(R.drawable.badge_gump)
},
contentDescription = when (badge) {
UserBadges.Developer -> stringResource(R.string.user_badge_developer)
- UserBadges.Translator -> stringResource(R.string.user_badge_translator)
+ UserBadges.Translator -> stringResource(R.string.user_badge_first_100_members)
UserBadges.Supporter -> stringResource(R.string.user_badge_supporter)
- UserBadges.ResponsibleDisclosure -> stringResource(R.string.user_badge_responsible_disclosure)
+ UserBadges.ResponsibleDisclosure -> stringResource(R.string.user_badge_trusted_seller)
UserBadges.Founder -> stringResource(R.string.user_badge_founder)
- UserBadges.PlatformModeration -> stringResource(R.string.user_badge_platform_moderation)
+ UserBadges.PlatformModeration -> stringResource(R.string.user_badge_administrator)
UserBadges.ActiveSupporter -> stringResource(R.string.user_badge_active_supporter)
- UserBadges.Paw -> stringResource(R.string.user_badge_paw)
- UserBadges.EarlyAdopter -> stringResource(R.string.user_badge_early_adopter)
- UserBadges.ReservedRelevantJokeBadge1 -> stringResource(R.string.user_badge_reserved_relevant_joke_badge_1)
- UserBadges.ReservedRelevantJokeBadge2 -> stringResource(R.string.user_badge_reserved_relevant_joke_badge_2)
+ UserBadges.Paw -> stringResource(R.string.user_badge_clown)
+ UserBadges.EarlyAdopter -> stringResource(R.string.user_badge_top_contributor)
+ UserBadges.ReservedRelevantJokeBadge1 -> stringResource(R.string.user_badge_karen)
+ UserBadges.ReservedRelevantJokeBadge2 -> stringResource(R.string.user_badge_gump)
},
modifier = Modifier
.size(32.dp)
diff --git a/app/src/main/java/chat/zekochat/composables/chat/UserVendorBadge.kt b/app/src/main/java/chat/zekochat/composables/chat/UserVendorBadge.kt
new file mode 100644
index 00000000..a0592498
--- /dev/null
+++ b/app/src/main/java/chat/zekochat/composables/chat/UserVendorBadge.kt
@@ -0,0 +1,40 @@
+package chat.zekochat.composables.chat
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import chat.zekochat.R
+import chat.zekochat.api.schemas.UserBadges
+
+/**
+ * Compact "Verified Vendor" indicator shown next to usernames.
+ *
+ * Web mapping notes:
+ * - ResponsibleDisclosure (8) and ReservedRelevantJokeBadge1 (512) both trigger the vendor badge.
+ */
+fun hasVerifiedVendor(badges: Long?): Boolean {
+ val b = badges ?: 0L
+ return (b and UserBadges.ResponsibleDisclosure.value) != 0L ||
+ (b and UserBadges.ReservedRelevantJokeBadge1.value) != 0L
+}
+
+@Composable
+fun UserVendorBadge(
+ badges: Long?,
+ modifier: Modifier = Modifier,
+ size: Dp = 16.dp,
+) {
+ if (!hasVerifiedVendor(badges)) return
+
+ Image(
+ painter = painterResource(R.drawable.badge_verified_vendor),
+ contentDescription = stringResource(R.string.user_badge_verified_vendor),
+ modifier = modifier.then(Modifier.size(size)),
+ )
+}
+
diff --git a/app/src/main/java/chat/zekochat/sheets/UserInfoSheet.kt b/app/src/main/java/chat/zekochat/sheets/UserInfoSheet.kt
index 48c8ad00..ec1181d7 100644
--- a/app/src/main/java/chat/zekochat/sheets/UserInfoSheet.kt
+++ b/app/src/main/java/chat/zekochat/sheets/UserInfoSheet.kt
@@ -63,6 +63,8 @@ import chat.zekochat.api.settings.NotificationType
import chat.zekochat.api.settings.SyncedSettings
import chat.zekochat.callbacks.Action
import chat.zekochat.callbacks.ActionChannel
+import chat.zekochat.composables.chat.UserBadgeRow
+import chat.zekochat.composables.chat.UserVendorBadge
import chat.zekochat.composables.generic.NonIdealState
import chat.zekochat.composables.generic.SheetButton
import chat.zekochat.composables.generic.UserAvatar
@@ -193,13 +195,29 @@ fun UserInfoSheet(
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
+
resolvedUser!!.username?.let { uname ->
- Text(
- text = "@$uname",
- style = MaterialTheme.typography.bodySmall,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis
- )
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(6.dp)
+ ) {
+ Text(
+ text = "@$uname",
+ style = MaterialTheme.typography.bodySmall,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ UserVendorBadge(
+ badges = resolvedUser!!.badges,
+ size = 16.dp
+ )
+ }
+ }
+
+ val badgesValue = resolvedUser!!.badges ?: 0L
+ if (badgesValue > 0L) {
+ Spacer(Modifier.height(8.dp))
+ UserBadgeRow(badges = badgesValue)
}
}
if (Experiments.enableServerIdentityOptions.isEnabled) {
diff --git a/app/src/main/res/drawable/badge_administrator.png b/app/src/main/res/drawable/badge_administrator.png
new file mode 100644
index 00000000..ab4cf796
Binary files /dev/null and b/app/src/main/res/drawable/badge_administrator.png differ
diff --git a/app/src/main/res/drawable/badge_clown.png b/app/src/main/res/drawable/badge_clown.png
new file mode 100644
index 00000000..5d800687
Binary files /dev/null and b/app/src/main/res/drawable/badge_clown.png differ
diff --git a/app/src/main/res/drawable/badge_developer.png b/app/src/main/res/drawable/badge_developer.png
new file mode 100644
index 00000000..590f74cd
Binary files /dev/null and b/app/src/main/res/drawable/badge_developer.png differ
diff --git a/app/src/main/res/drawable/badge_first_100_members.png b/app/src/main/res/drawable/badge_first_100_members.png
new file mode 100644
index 00000000..61b6b1ae
Binary files /dev/null and b/app/src/main/res/drawable/badge_first_100_members.png differ
diff --git a/app/src/main/res/drawable/badge_founder.png b/app/src/main/res/drawable/badge_founder.png
new file mode 100644
index 00000000..1f7e6666
Binary files /dev/null and b/app/src/main/res/drawable/badge_founder.png differ
diff --git a/app/src/main/res/drawable/badge_gump.png b/app/src/main/res/drawable/badge_gump.png
new file mode 100644
index 00000000..18daf3b1
Binary files /dev/null and b/app/src/main/res/drawable/badge_gump.png differ
diff --git a/app/src/main/res/drawable/badge_karen.png b/app/src/main/res/drawable/badge_karen.png
new file mode 100644
index 00000000..edae58ae
Binary files /dev/null and b/app/src/main/res/drawable/badge_karen.png differ
diff --git a/app/src/main/res/drawable/badge_supporter.png b/app/src/main/res/drawable/badge_supporter.png
new file mode 100644
index 00000000..90c9c9e7
Binary files /dev/null and b/app/src/main/res/drawable/badge_supporter.png differ
diff --git a/app/src/main/res/drawable/badge_top_contributor.png b/app/src/main/res/drawable/badge_top_contributor.png
new file mode 100644
index 00000000..2e267a20
Binary files /dev/null and b/app/src/main/res/drawable/badge_top_contributor.png differ
diff --git a/app/src/main/res/drawable/badge_trusted_seller.png b/app/src/main/res/drawable/badge_trusted_seller.png
new file mode 100644
index 00000000..f92e0fce
Binary files /dev/null and b/app/src/main/res/drawable/badge_trusted_seller.png differ
diff --git a/app/src/main/res/drawable/badge_verified_vendor.xml b/app/src/main/res/drawable/badge_verified_vendor.xml
new file mode 100644
index 00000000..fe230dd5
--- /dev/null
+++ b/app/src/main/res/drawable/badge_verified_vendor.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0892fa01..92a05ce6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -465,6 +465,16 @@
sus
It\'s Morbin Time
+
+ First 100 Members
+ Top Contributor
+ Administrator
+ Trusted Seller
+ Karen
+ Gump
+ Clown
+ Verified Vendor
+
Add Server
A server is where the magic happens. Chat with your friends, share memes, build communities, and more.
Join by invite code or link