mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-08-15 06:56:30 +00:00
Group geohash people as People and Anon
Replaces the "on location" / "teleported in" / "anonymous" split with two sections: peers who announced a nickname, then the anons. Teleport state was never worth a section of its own -- every row already carries it as a distinct glyph -- and splitting on it fragmented the short list people actually read, in a channel where most participants are anonymous anyway. Self stays in the People section even when unnamed.
This commit is contained in:
parent
9703ebfcaf
commit
bcfc33f35c
@ -3,6 +3,7 @@ package com.bitchat.android.ui
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Email
|
||||
import androidx.compose.material.icons.outlined.Explore
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.Person
|
||||
import androidx.compose.material.icons.outlined.LocationOn
|
||||
import android.util.Log
|
||||
@ -59,8 +60,8 @@ fun GeohashPeopleList(
|
||||
Column(modifier = modifier) {
|
||||
if (geohashPeople.isEmpty()) {
|
||||
SheetIconSectionHeader(
|
||||
icon = Icons.Outlined.LocationOn,
|
||||
title = stringResource(R.string.section_on_location)
|
||||
icon = Icons.Outlined.Person,
|
||||
title = stringResource(R.string.section_people)
|
||||
)
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
@ -126,15 +127,18 @@ fun GeohashPeopleList(
|
||||
viewModel.isPersonTeleported(person.id)
|
||||
}
|
||||
|
||||
// Anonymous participants form their own trailing section rather than a tail on each
|
||||
// of the others. A busy geohash is mostly anons, and splitting them across "on
|
||||
// location" and "teleported in" pushed the few recognisable names out of view twice
|
||||
// over. Self is never grouped as an anon even when unnamed — you always want to find
|
||||
// yourself where you actually are.
|
||||
// Two groups: peers who announced a nickname, then the anons.
|
||||
//
|
||||
// A busy geohash is mostly anonymous drive-by participants, and mixing them in pushed
|
||||
// the few recognisable names out of view. Teleport state is not a grouping any more —
|
||||
// it is already on every row as its own glyph, so splitting "on location" from
|
||||
// "teleported in" only fragmented the short list that people actually read.
|
||||
//
|
||||
// Self is never grouped as an anon even when unnamed: you always want to find yourself
|
||||
// among the people, not buried at the bottom.
|
||||
val isSelf: (GeoPerson) -> Boolean = { myHex != null && it.id == myHex }
|
||||
val namedPeople = orderedPeople.filter { isSelf(it) || !it.isAnonymous() }
|
||||
val anonPeople = orderedPeople.filter { !isSelf(it) && it.isAnonymous() }
|
||||
val (teleportedPeople, localPeople) = namedPeople.partition { personTeleported(it) }
|
||||
|
||||
@Composable
|
||||
fun personRow(person: GeoPerson) {
|
||||
@ -157,30 +161,19 @@ fun GeohashPeopleList(
|
||||
)
|
||||
}
|
||||
|
||||
if (localPeople.isNotEmpty()) {
|
||||
if (namedPeople.isNotEmpty()) {
|
||||
SheetIconSectionHeader(
|
||||
icon = Icons.Outlined.LocationOn,
|
||||
title = stringResource(R.string.section_on_location)
|
||||
icon = Icons.Outlined.Person,
|
||||
title = stringResource(R.string.section_people)
|
||||
)
|
||||
PeopleCard(people = localPeople, row = { personRow(it) })
|
||||
}
|
||||
|
||||
if (teleportedPeople.isNotEmpty()) {
|
||||
SheetIconSectionHeader(
|
||||
icon = Icons.Outlined.Explore,
|
||||
title = stringResource(R.string.section_teleported_in),
|
||||
modifier = Modifier.padding(top = if (localPeople.isNotEmpty()) 20.dp else 0.dp)
|
||||
)
|
||||
PeopleCard(people = teleportedPeople, row = { personRow(it) })
|
||||
PeopleCard(people = namedPeople, row = { personRow(it) })
|
||||
}
|
||||
|
||||
if (anonPeople.isNotEmpty()) {
|
||||
SheetIconSectionHeader(
|
||||
icon = Icons.Outlined.Person,
|
||||
title = stringResource(R.string.section_anonymous),
|
||||
modifier = Modifier.padding(
|
||||
top = if (localPeople.isNotEmpty() || teleportedPeople.isNotEmpty()) 20.dp else 0.dp
|
||||
)
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
title = stringResource(R.string.section_anon),
|
||||
modifier = Modifier.padding(top = if (namedPeople.isNotEmpty()) 20.dp else 0.dp)
|
||||
)
|
||||
PeopleCard(people = anonPeople, capped = true, row = { personRow(it) })
|
||||
}
|
||||
|
||||
@ -314,9 +314,8 @@
|
||||
|
||||
<!-- People sheet -->
|
||||
<string name="people_count_title">People (%1$d)</string>
|
||||
<string name="section_on_location">On location</string>
|
||||
<string name="section_teleported_in">Teleported in</string>
|
||||
<string name="section_anonymous">Anonymous</string>
|
||||
<string name="section_people">People</string>
|
||||
<string name="section_anon">Anon</string>
|
||||
<string name="people_n_more">%1$d more\u2026</string>
|
||||
|
||||
<string name="grant_location_permission">Grant location permission</string>
|
||||
|
||||
@ -104,7 +104,10 @@ class GeohashAnonOrderingTest {
|
||||
|
||||
// MARK: - Sectioning
|
||||
|
||||
/** Mirrors the grouping in GeohashPeopleList: self is never treated as an anon. */
|
||||
/**
|
||||
* Mirrors the two-group split in GeohashPeopleList: peers who announced a nickname, then the
|
||||
* anons. Self is never treated as an anon.
|
||||
*/
|
||||
private fun sections(people: List<GeoPerson>, myId: String?): Triple<List<String>, List<String>, List<String>> {
|
||||
val isSelf: (GeoPerson) -> Boolean = { myId != null && it.id == myId }
|
||||
val named = people.filter { isSelf(it) || !it.isAnonymous() }
|
||||
@ -117,7 +120,7 @@ class GeohashAnonOrderingTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `anons are grouped out of the named sections entirely`() {
|
||||
fun `anons are grouped out of the people section entirely`() {
|
||||
val people = listOf(person("alice"), person("anon1"), person("bob"), person("anon2"))
|
||||
val (named, anons, _) = sections(people, myId = null)
|
||||
|
||||
@ -126,7 +129,7 @@ class GeohashAnonOrderingTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `self stays in the named sections even when unnamed`() {
|
||||
fun `self stays in the people section even when unnamed`() {
|
||||
// You always want to find yourself where you actually are, not buried in the anon section.
|
||||
val me = person("anon")
|
||||
val people = listOf(me, person("alice"), person("anon2"))
|
||||
@ -138,7 +141,7 @@ class GeohashAnonOrderingTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a list of only anons yields no named section`() {
|
||||
fun `a list of only anons yields no people section`() {
|
||||
val people = (1..4).map { person("anon$it") }
|
||||
val (named, anons, _) = sections(people, myId = null)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user