From bac50668e86a6a8ac94f0c3229491814ca0a8499 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Sat, 30 Sep 2023 17:23:27 -0400 Subject: [PATCH] Speeds the composition of the Topbar --- .../amethyst/ui/navigation/AppBottomBar.kt | 6 - .../amethyst/ui/navigation/AppTopBar.kt | 152 +++++++++--------- app/src/main/res/values/strings.xml | 2 + 3 files changed, 80 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt index 1290bb749..68c448da3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.CircleShape @@ -24,7 +23,6 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -60,8 +58,6 @@ fun keyboardAsState(): State { val keyboardState = remember { mutableStateOf(Keyboard.Closed) } val view = LocalView.current - println("AAA - KeyboardState") - DisposableEffect(view) { val onGlobalListener = ViewTreeObserver.OnGlobalLayoutListener { val rect = Rect() @@ -128,8 +124,6 @@ private fun RowScope.HasNewItemsIcon( } } - println("AAA HasNewItemsIcon") - val size = remember { if ("Home" == route.base) 25.dp else 23.dp } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt index 0659d6a0b..618e2e0a6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt @@ -108,6 +108,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.RoomNameOnlyDisplay import com.vitorpamplona.amethyst.ui.screen.loggedIn.ShortChannelHeader import com.vitorpamplona.amethyst.ui.screen.loggedIn.SpinnerSelectionDialog import com.vitorpamplona.amethyst.ui.theme.BottomTopHeight +import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.HalfVertSpacer import com.vitorpamplona.amethyst.ui.theme.HeaderPictureModifier @@ -376,11 +377,9 @@ fun StoriesTopBar(followLists: FollowListViewModel, drawerState: DrawerState, ac GenericMainTopBar(drawerState, accountViewModel, nav) { accountViewModel -> val list by accountViewModel.storiesListLiveData.observeAsState(GLOBAL_FOLLOWS) - FollowList( + FollowListWithRoutes( followListsModel = followLists, - listName = list, - withGlobal = true, - withRoutes = false + listName = list ) { listName -> accountViewModel.account.changeDefaultStoriesFollowList(listName.code) } @@ -392,11 +391,9 @@ fun HomeTopBar(followLists: FollowListViewModel, drawerState: DrawerState, accou GenericMainTopBar(drawerState, accountViewModel, nav) { accountViewModel -> val list by accountViewModel.homeListLiveData.observeAsState(KIND3_FOLLOWS) - FollowList( + FollowListWithRoutes( followListsModel = followLists, - listName = list, - withGlobal = true, - withRoutes = true + listName = list ) { listName -> if (listName.type == CodeNameType.ROUTE) { nav(listName.code) @@ -412,11 +409,9 @@ fun NotificationTopBar(followLists: FollowListViewModel, drawerState: DrawerStat GenericMainTopBar(drawerState, accountViewModel, nav) { accountViewModel -> val list by accountViewModel.notificationListLiveData.observeAsState(GLOBAL_FOLLOWS) - FollowList( + FollowListWithoutRoutes( followListsModel = followLists, - listName = list, - withGlobal = true, - withRoutes = false + listName = list ) { listName -> accountViewModel.account.changeDefaultNotificationFollowList(listName.code) } @@ -428,11 +423,9 @@ fun DiscoveryTopBar(followLists: FollowListViewModel, drawerState: DrawerState, GenericMainTopBar(drawerState, accountViewModel, nav) { accountViewModel -> val list by accountViewModel.discoveryListLiveData.observeAsState(GLOBAL_FOLLOWS) - FollowList( + FollowListWithoutRoutes( followListsModel = followLists, - listName = list, - withGlobal = true, - withRoutes = false + listName = list ) { listName -> accountViewModel.account.changeDefaultDiscoveryFollowList(listName.code) } @@ -491,7 +484,7 @@ fun GenericMainTopBar( } } ) - Divider(thickness = 0.25.dp) + Divider(thickness = DividerThickness) } } @@ -510,7 +503,6 @@ private fun LoggedInUserPictureDrawer( onClick: () -> Unit ) { val profilePicture by accountViewModel.account.userProfile().live().profilePictureChanges.observeAsState() - val pubkeyHex = remember { accountViewModel.userProfile().pubkeyHex } val automaticallyShowProfilePicture = remember { @@ -536,42 +528,35 @@ private fun LoggedInUserPictureDrawer( } @Composable -fun FollowList( +fun FollowListWithRoutes( followListsModel: FollowListViewModel, listName: String, - withGlobal: Boolean, - withRoutes: Boolean, onChange: (CodeName) -> Unit ) { - val context = LocalContext.current - - val kind3Follow = CodeName(KIND3_FOLLOWS, ResourceName(R.string.follow_list_kind3follows, context), CodeNameType.HARDCODED) - val globalFollow = CodeName(GLOBAL_FOLLOWS, ResourceName(R.string.follow_list_global, context), CodeNameType.HARDCODED) - - val defaultOptions = if (withGlobal) listOf(kind3Follow, globalFollow) else listOf(kind3Follow) - - val followLists by followListsModel.peopleLists.collectAsState() - val routeList by followListsModel.routes.collectAsState() - - val allLists = remember(followLists) { - if (withRoutes) { - (defaultOptions + followLists + routeList) - } else { - (defaultOptions + followLists) - } - } - - val followNames by remember(followLists) { - derivedStateOf { - allLists.map { it.name }.toImmutableList() - } - } + val allLists by followListsModel.kind3GlobalPeopleRoutes.collectAsState() SimpleTextSpinner( - placeholder = allLists.firstOrNull { it.code == listName }?.name?.name() ?: "Select an Option", - options = followNames, + placeholderCode = listName, + options = allLists, onSelect = { - onChange(allLists.getOrNull(it) ?: kind3Follow) + onChange(allLists.getOrNull(it) ?: followListsModel.kind3Follow) + } + ) +} + +@Composable +fun FollowListWithoutRoutes( + followListsModel: FollowListViewModel, + listName: String, + onChange: (CodeName) -> Unit +) { + val allLists by followListsModel.kind3GlobalPeople.collectAsState() + + SimpleTextSpinner( + placeholderCode = listName, + options = allLists, + onSelect = { + onChange(allLists.getOrNull(it) ?: followListsModel.kind3Follow) } ) } @@ -582,6 +567,7 @@ enum class CodeNameType { abstract class Name { abstract fun name(): String + open fun name(context: Context) = name() } class GeoHashName(val geoHashTag: String) : Name() { @@ -590,8 +576,9 @@ class GeoHashName(val geoHashTag: String) : Name() { class HashtagName(val hashTag: String) : Name() { override fun name() = "#$hashTag" } -class ResourceName(val resourceId: Int, val context: Context) : Name() { - override fun name() = context.getString(resourceId) +class ResourceName(val resourceId: Int) : Name() { + override fun name() = " $resourceId " // Space to make sure it goes first + override fun name(context: Context) = context.getString(resourceId) } class PeopleListName(val note: AddressableNote) : Name() { @@ -606,11 +593,14 @@ data class CodeName(val code: String, val name: Name, val type: CodeNameType) @Stable class FollowListViewModel(val account: Account) : ViewModel() { - private var _peopleLists = MutableStateFlow>(emptyList().toPersistentList()) - val peopleLists = _peopleLists.asStateFlow() + val kind3Follow = CodeName(KIND3_FOLLOWS, ResourceName(R.string.follow_list_kind3follows), CodeNameType.HARDCODED) + val globalFollow = CodeName(GLOBAL_FOLLOWS, ResourceName(R.string.follow_list_global), CodeNameType.HARDCODED) - private var _routes = MutableStateFlow>(emptyList().toPersistentList()) - val routes = _routes.asStateFlow() + private var _kind3GlobalPeopleRoutes = MutableStateFlow>(emptyList().toPersistentList()) + val kind3GlobalPeopleRoutes = _kind3GlobalPeopleRoutes.asStateFlow() + + private var _kind3GlobalPeople = MutableStateFlow>(emptyList().toPersistentList()) + val kind3GlobalPeople = _kind3GlobalPeople.asStateFlow() fun refresh() { viewModelScope.launch(Dispatchers.Default) { @@ -632,11 +622,7 @@ class FollowListViewModel(val account: Account) : ViewModel() { } else { null } - }.sortedBy { it.name.name() }.toImmutableList() - - if (!equalImmutableLists(_peopleLists.value, newFollowLists)) { - _peopleLists.emit(newFollowLists) - } + }.sortedBy { it.name.name() } val communities = account.userProfile().cachedFollowingCommunitiesSet().mapNotNull { LocalCache.checkGetOrCreateAddressableNote(it)?.let { communityNote -> @@ -652,10 +638,18 @@ class FollowListViewModel(val account: Account) : ViewModel() { CodeName("Geohash/$it", GeoHashName(it), CodeNameType.ROUTE) } - val routeList = (communities + hashtags + geotags).sortedBy { it.name.name() }.toImmutableList() + val routeList = (communities + hashtags + geotags).sortedBy { it.name.name() } - if (!equalImmutableLists(_routes.value, routeList)) { - _routes.emit(routeList) + val kind3GlobalPeopleRouteList = listOf(listOf(kind3Follow, globalFollow), newFollowLists, routeList).flatten().toImmutableList() + + if (!equalImmutableLists(_kind3GlobalPeopleRoutes.value, kind3GlobalPeopleRouteList)) { + _kind3GlobalPeopleRoutes.emit(kind3GlobalPeopleRouteList) + } + + val kind3GlobalPeopleList = listOf(listOf(kind3Follow, globalFollow), newFollowLists).flatten().toImmutableList() + + if (!equalImmutableLists(_kind3GlobalPeople.value, kind3GlobalPeopleList)) { + _kind3GlobalPeople.emit(kind3GlobalPeopleList) } } @@ -691,14 +685,24 @@ class FollowListViewModel(val account: Account) : ViewModel() { @Composable fun SimpleTextSpinner( - placeholder: String, - options: ImmutableList, + placeholderCode: String, + options: ImmutableList, onSelect: (Int) -> Unit, modifier: Modifier = Modifier ) { val interactionSource = remember { MutableInteractionSource() } var optionsShowing by remember { mutableStateOf(false) } - var currentText by remember(placeholder) { mutableStateOf(placeholder) } + + val context = LocalContext.current + val selectAnOption = stringResource( + id = R.string.select_an_option + ) + + var currentText by remember { + mutableStateOf( + options.firstOrNull { it.code == placeholderCode }?.name?.name(context) ?: selectAnOption + ) + } Box( modifier = modifier, @@ -706,7 +710,7 @@ fun SimpleTextSpinner( ) { Row(verticalAlignment = Alignment.CenterVertically) { Spacer(modifier = Modifier.size(20.dp)) - Text(placeholder) + Text(currentText) Icon( imageVector = Icons.Default.ExpandMore, null, @@ -732,22 +736,22 @@ fun SimpleTextSpinner( options = options, onDismiss = { optionsShowing = false }, onSelect = { - currentText = options[it].name() + currentText = options[it].name.name(context) optionsShowing = false onSelect(it) } ) { - RenderOption(it) + RenderOption(it.name) } } } } @Composable -fun RenderOption(it: Name) { - when (it) { +fun RenderOption(option: Name) { + when (option) { is GeoHashName -> { - LoadCityName(it.geoHashTag) { + LoadCityName(option.geoHashTag) { Row( horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth() @@ -761,7 +765,7 @@ fun RenderOption(it: Name) { horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth() ) { - Text(text = it.name(), color = MaterialTheme.colorScheme.onSurface) + Text(text = option.name(), color = MaterialTheme.colorScheme.onSurface) } } is ResourceName -> { @@ -769,7 +773,7 @@ fun RenderOption(it: Name) { horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth() ) { - Text(text = stringResource(id = it.resourceId), color = MaterialTheme.colorScheme.onSurface) + Text(text = stringResource(id = option.resourceId), color = MaterialTheme.colorScheme.onSurface) } } is PeopleListName -> { @@ -777,7 +781,7 @@ fun RenderOption(it: Name) { horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth() ) { - Text(text = it.name(), color = MaterialTheme.colorScheme.onSurface) + Text(text = option.name(), color = MaterialTheme.colorScheme.onSurface) } } is CommunityName -> { @@ -785,7 +789,7 @@ fun RenderOption(it: Name) { horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth() ) { - val name by it.note.live().metadata.map { + val name by option.note.live().metadata.map { "/n/" + (it.note as? AddressableNote)?.dTag() }.observeAsState() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b4bb722ac..3d1a8397e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -600,4 +600,6 @@ Hide new word or sentence Profile Picture Show Profile pictures + + Select an Option