mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-08 23:54:39 +00:00
Merge branch 'vitorpamplona:main' into labeled-bookmarks
This commit is contained in:
@@ -286,8 +286,8 @@ class Account(
|
||||
|
||||
val peopleListDecryptionCache = PeopleListDecryptionCache(signer)
|
||||
val blockPeopleList = BlockPeopleListState(signer, cache, peopleListDecryptionCache, scope)
|
||||
val peopleListsState = PeopleListsState(signer, cache, peopleListDecryptionCache, scope)
|
||||
val followListsState = FollowListsState(signer, cache, scope)
|
||||
val peopleLists = PeopleListsState(signer, cache, peopleListDecryptionCache, scope)
|
||||
val followLists = FollowListsState(signer, cache, scope)
|
||||
|
||||
val hiddenUsers = HiddenUsersState(muteList.flow, blockPeopleList.flow, scope, settings)
|
||||
|
||||
@@ -325,7 +325,7 @@ class Account(
|
||||
val followsPerRelay = FollowsPerOutboxRelay(kind3FollowList, blockedRelayList, proxyRelayList, cache, scope).flow
|
||||
|
||||
// Merges all follow lists to create a single All Follows feed.
|
||||
val allFollows = MergedFollowListsState(kind3FollowList, peopleListsState, hashtagList, geohashList, communityList, scope)
|
||||
val allFollows = MergedFollowListsState(kind3FollowList, peopleLists, followLists, hashtagList, geohashList, communityList, scope)
|
||||
|
||||
val privateDMDecryptionCache = PrivateDMCache(signer)
|
||||
val privateZapsDecryptionCache = PrivateZapCache(signer)
|
||||
@@ -1780,8 +1780,8 @@ class Account(
|
||||
logTime("Account ${userProfile().toBestDisplayName()} newEventBundle Update with ${newNotes.size} new notes") {
|
||||
upgradeAttestations()
|
||||
newNotesPreProcessor.runNew(newNotes)
|
||||
peopleListsState.newNotes(newNotes)
|
||||
followListsState.newNotes(newNotes)
|
||||
peopleLists.newNotes(newNotes)
|
||||
followLists.newNotes(newNotes)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1790,8 +1790,8 @@ class Account(
|
||||
cache.live.deletedEventBundles.collect { deletedNotes ->
|
||||
logTime("Account ${userProfile().toBestDisplayName()} deletedEventBundle Update with ${deletedNotes.size} new notes") {
|
||||
newNotesPreProcessor.runDeleted(deletedNotes)
|
||||
peopleListsState.deletedNotes(deletedNotes)
|
||||
followListsState.deletedNotes(deletedNotes)
|
||||
peopleLists.deletedNotes(deletedNotes)
|
||||
followLists.deletedNotes(deletedNotes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-5
@@ -94,10 +94,20 @@ class PeopleListsState(
|
||||
|
||||
suspend fun List<PeopleListEvent>.mapToUserIdSet() = this.map { it.userIdSet() }.flattenToSet()
|
||||
|
||||
val allPeopleListProfiles: StateFlow<Set<HexKey>> =
|
||||
suspend fun List<PeopleListEvent>.mapGoodUsersToIdSet() =
|
||||
this
|
||||
.mapNotNull {
|
||||
if (it.dTag() != PeopleListEvent.BLOCK_LIST_D_TAG) {
|
||||
it.userIdSet()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.flattenToSet()
|
||||
|
||||
val allGoodPeopleListProfiles: StateFlow<Set<HexKey>> =
|
||||
latestLists
|
||||
.map { it.mapToUserIdSet() }
|
||||
.onStart { emit(latestLists.value.mapToUserIdSet()) }
|
||||
.map { it.mapGoodUsersToIdSet() }
|
||||
.onStart { emit(latestLists.value.mapGoodUsersToIdSet()) }
|
||||
.flowOn(Dispatchers.IO)
|
||||
.stateIn(scope, SharingStarted.Eagerly, emptySet())
|
||||
|
||||
@@ -131,8 +141,6 @@ class PeopleListsState(
|
||||
)
|
||||
}
|
||||
|
||||
fun isUserInFollowSets(user: User): Boolean = allPeopleListProfiles.value.contains(user.pubkeyHex)
|
||||
|
||||
fun DeletionEvent.hasDeletedAnyPeopleList() = deleteAddressesWithKind(PeopleListEvent.KIND) || deletesAnyEventIn(peopleListsEventIds.value)
|
||||
|
||||
fun hasItemInNoteList(notes: Set<Note>): Boolean =
|
||||
|
||||
+29
-12
@@ -24,8 +24,10 @@ import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.amethyst.model.nip02FollowLists.Kind3FollowListState
|
||||
import com.vitorpamplona.amethyst.model.nip51Lists.geohashLists.GeohashListState
|
||||
import com.vitorpamplona.amethyst.model.nip51Lists.hashtagLists.HashtagListState
|
||||
import com.vitorpamplona.amethyst.model.nip51Lists.peopleList.FollowListsState
|
||||
import com.vitorpamplona.amethyst.model.nip51Lists.peopleList.PeopleListsState
|
||||
import com.vitorpamplona.amethyst.model.nip72Communities.CommunityListState
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag
|
||||
import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId
|
||||
import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId
|
||||
@@ -41,7 +43,8 @@ import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
class MergedFollowListsState(
|
||||
val kind3List: Kind3FollowListState,
|
||||
val followSetList: PeopleListsState,
|
||||
val peopleList: PeopleListsState,
|
||||
val followList: FollowListsState,
|
||||
val hashtagList: HashtagListState,
|
||||
val geohashList: GeohashListState,
|
||||
val communityList: CommunityListState,
|
||||
@@ -63,13 +66,14 @@ class MergedFollowListsState(
|
||||
|
||||
fun mergeLists(
|
||||
kind3: Kind3FollowListState.Kind3Follows,
|
||||
followSetProfiles: Set<String>,
|
||||
peopleListProfiles: Set<String>,
|
||||
followListProfiles: Set<String>,
|
||||
hashtags: Set<String>,
|
||||
geohashes: Set<String>,
|
||||
community: Set<CommunityTag>,
|
||||
): AllFollows =
|
||||
AllFollows(
|
||||
authors = kind3.authors + followSetProfiles,
|
||||
authors = kind3.authors + peopleListProfiles + followListProfiles,
|
||||
hashtags = hashtags,
|
||||
geotags = geohashes,
|
||||
communities = community.mapTo(mutableSetOf()) { it.address.toValue() },
|
||||
@@ -77,17 +81,29 @@ class MergedFollowListsState(
|
||||
|
||||
val flow: StateFlow<AllFollows> =
|
||||
combine(
|
||||
kind3List.flow,
|
||||
followSetList.allPeopleListProfiles,
|
||||
hashtagList.flow,
|
||||
geohashList.flow,
|
||||
communityList.flow,
|
||||
::mergeLists,
|
||||
).onStart {
|
||||
listOf(
|
||||
kind3List.flow,
|
||||
peopleList.allGoodPeopleListProfiles,
|
||||
followList.allPeopleListProfiles,
|
||||
hashtagList.flow,
|
||||
geohashList.flow,
|
||||
communityList.flow,
|
||||
),
|
||||
) { args ->
|
||||
mergeLists(
|
||||
args[0] as Kind3FollowListState.Kind3Follows,
|
||||
args[1] as Set<HexKey>,
|
||||
args[2] as Set<HexKey>,
|
||||
args[3] as Set<String>,
|
||||
args[4] as Set<String>,
|
||||
args[5] as Set<CommunityTag>,
|
||||
)
|
||||
}.onStart {
|
||||
emit(
|
||||
mergeLists(
|
||||
kind3List.flow.value,
|
||||
followSetList.allPeopleListProfiles.value,
|
||||
peopleList.allGoodPeopleListProfiles.value,
|
||||
followList.allPeopleListProfiles.value,
|
||||
hashtagList.flow.value,
|
||||
geohashList.flow.value,
|
||||
communityList.flow.value,
|
||||
@@ -100,7 +116,8 @@ class MergedFollowListsState(
|
||||
SharingStarted.Eagerly,
|
||||
mergeLists(
|
||||
kind3List.flow.value,
|
||||
followSetList.allPeopleListProfiles.value,
|
||||
peopleList.allGoodPeopleListProfiles.value,
|
||||
followList.allPeopleListProfiles.value,
|
||||
hashtagList.flow.value,
|
||||
geohashList.flow.value,
|
||||
communityList.flow.value,
|
||||
|
||||
@@ -148,14 +148,14 @@ class TopNavFilterState(
|
||||
|
||||
val livePeopleListsFlow: Flow<List<FeedDefinition>> =
|
||||
combine(
|
||||
account.peopleListsState.peopleListNotes,
|
||||
account.followListsState.followListNotes,
|
||||
account.peopleLists.peopleListNotes,
|
||||
account.followLists.followListNotes,
|
||||
::mergePeopleLists,
|
||||
).onStart {
|
||||
emit(
|
||||
mergePeopleLists(
|
||||
account.peopleListsState.peopleListNotes.value,
|
||||
account.followListsState.followListNotes.value,
|
||||
account.peopleLists.peopleListNotes.value,
|
||||
account.followLists.followListNotes.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
+5
-5
@@ -55,7 +55,7 @@ class PeopleListViewModel : ViewModel() {
|
||||
selectedDTag
|
||||
.transformLatest {
|
||||
emitAll(
|
||||
account.peopleListsState.selectListFlow(it).flowOn(Dispatchers.IO),
|
||||
account.peopleLists.selectListFlow(it).flowOn(Dispatchers.IO),
|
||||
)
|
||||
}.flowOn(Dispatchers.IO)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)
|
||||
@@ -73,23 +73,23 @@ class PeopleListViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
suspend fun deleteFollowSet() {
|
||||
account.peopleListsState.deleteFollowSet(selectedDTag.value, account)
|
||||
account.peopleLists.deleteFollowSet(selectedDTag.value, account)
|
||||
}
|
||||
|
||||
fun loadNote(): AddressableNote? = account.peopleListsState.getPeopleListNote(selectedDTag.value)
|
||||
fun loadNote(): AddressableNote? = account.peopleLists.getPeopleListNote(selectedDTag.value)
|
||||
|
||||
suspend fun removeUserFromSet(
|
||||
user: User,
|
||||
isPrivate: Boolean,
|
||||
) {
|
||||
account.peopleListsState.removeUserFromSet(user, isPrivate, selectedDTag.value, account)
|
||||
account.peopleLists.removeUserFromSet(user, isPrivate, selectedDTag.value, account)
|
||||
}
|
||||
|
||||
suspend fun addUserToSet(
|
||||
user: User,
|
||||
isPrivate: Boolean,
|
||||
) {
|
||||
account.peopleListsState.addUserToSet(user, selectedDTag.value, isPrivate, account)
|
||||
account.peopleLists.addUserToSet(user, selectedDTag.value, isPrivate, account)
|
||||
}
|
||||
|
||||
fun hasUserFlow(
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ import com.vitorpamplona.amethyst.model.nip51Lists.peopleList.PeopleList
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size30dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size40dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -83,7 +83,7 @@ fun AllPeopleListFeedView(
|
||||
@Composable
|
||||
fun AllPeopleListFeedEmpty(message: String = stringRes(R.string.feed_is_empty)) {
|
||||
Column(
|
||||
Modifier.fillMaxSize().padding(horizontal = Size30dp),
|
||||
Modifier.fillMaxSize().padding(horizontal = Size40dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
|
||||
+7
-47
@@ -42,7 +42,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.nip51Lists.peopleList.PeopleList
|
||||
@@ -52,7 +51,6 @@ import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Composable
|
||||
@@ -61,10 +59,10 @@ fun ListOfPeopleListsScreen(
|
||||
nav: INav,
|
||||
) {
|
||||
ListOfPeopleListsScreen(
|
||||
listFlow = accountViewModel.account.peopleListsState.uiListFlow,
|
||||
listFlow = accountViewModel.account.peopleLists.uiListFlow,
|
||||
addItem = { title: String, description: String? ->
|
||||
accountViewModel.runIOCatching {
|
||||
accountViewModel.account.peopleListsState.addFollowList(
|
||||
accountViewModel.account.peopleLists.addFollowList(
|
||||
listName = title,
|
||||
listDescription = description,
|
||||
account = accountViewModel.account,
|
||||
@@ -76,7 +74,7 @@ fun ListOfPeopleListsScreen(
|
||||
},
|
||||
renameItem = { followSet, newValue ->
|
||||
accountViewModel.runIOCatching {
|
||||
accountViewModel.account.peopleListsState.renameFollowList(
|
||||
accountViewModel.account.peopleLists.renameFollowList(
|
||||
newName = newValue,
|
||||
peopleList = followSet,
|
||||
account = accountViewModel.account,
|
||||
@@ -85,7 +83,7 @@ fun ListOfPeopleListsScreen(
|
||||
},
|
||||
changeItemDescription = { followSet, newDescription ->
|
||||
accountViewModel.runIOCatching {
|
||||
accountViewModel.account.peopleListsState.modifyFollowSetDescription(
|
||||
accountViewModel.account.peopleLists.modifyFollowSetDescription(
|
||||
newDescription = newDescription,
|
||||
peopleList = followSet,
|
||||
account = accountViewModel.account,
|
||||
@@ -94,7 +92,7 @@ fun ListOfPeopleListsScreen(
|
||||
},
|
||||
cloneItem = { followSet, customName, customDescription ->
|
||||
accountViewModel.runIOCatching {
|
||||
accountViewModel.account.peopleListsState.cloneFollowSet(
|
||||
accountViewModel.account.peopleLists.cloneFollowSet(
|
||||
currentPeopleList = followSet,
|
||||
customCloneName = customName,
|
||||
customCloneDescription = customDescription,
|
||||
@@ -104,7 +102,7 @@ fun ListOfPeopleListsScreen(
|
||||
},
|
||||
deleteItem = { followSet ->
|
||||
accountViewModel.runIOCatching {
|
||||
accountViewModel.account.peopleListsState.deleteFollowSet(
|
||||
accountViewModel.account.peopleLists.deleteFollowSet(
|
||||
identifierTag = followSet.identifierTag,
|
||||
account = accountViewModel.account,
|
||||
)
|
||||
@@ -131,9 +129,7 @@ fun ListOfPeopleListsScreen(
|
||||
},
|
||||
floatingActionButton = {
|
||||
PeopleListFabsAndMenu(
|
||||
onAddSet = { name: String, description: String? ->
|
||||
addItem(name, description)
|
||||
},
|
||||
onAddSet = addItem,
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
@@ -142,8 +138,6 @@ fun ListOfPeopleListsScreen(
|
||||
.padding(
|
||||
top = paddingValues.calculateTopPadding(),
|
||||
bottom = paddingValues.calculateBottomPadding(),
|
||||
start = 10.dp,
|
||||
end = 10.dp,
|
||||
).fillMaxHeight(),
|
||||
) {
|
||||
AllPeopleListFeedView(
|
||||
@@ -257,37 +251,3 @@ fun NewPeopleListCreationDialog(
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showSystemUi = true)
|
||||
@Composable
|
||||
private fun PeopleListItemPreview() {
|
||||
val samplePeopleList =
|
||||
PeopleList(
|
||||
identifierTag = "00001-2222",
|
||||
title = "Sample List Title",
|
||||
description = "Sample List Description",
|
||||
emptySet(),
|
||||
emptySet(),
|
||||
)
|
||||
ThemeComparisonColumn {
|
||||
PeopleListItem(
|
||||
modifier = Modifier,
|
||||
samplePeopleList,
|
||||
onClick = {
|
||||
println("follow set: ${samplePeopleList.identifierTag}")
|
||||
},
|
||||
onRename = {
|
||||
println("Follow set new name: $it")
|
||||
},
|
||||
onDescriptionChange = { description ->
|
||||
println("The follow set's description has been changed to $description")
|
||||
},
|
||||
onClone = { newName, newDesc ->
|
||||
println("The follow set has been cloned, and has custom name: $newName, Desc: $newDesc")
|
||||
},
|
||||
onDelete = {
|
||||
println(" The follow set ${samplePeopleList.title} has been deleted.")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+173
-99
@@ -22,18 +22,21 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.People
|
||||
import androidx.compose.material.icons.outlined.Groups
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -41,7 +44,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
@@ -49,19 +51,110 @@ import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.model.nip51Lists.peopleList.PeopleList
|
||||
import com.vitorpamplona.amethyst.ui.components.ClickableBox
|
||||
import com.vitorpamplona.amethyst.ui.note.VerticalDotsIcon
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font10SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.NoSoTinyBorders
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size50ModifierOffset10
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size5dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.SpacedBy2dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.SpacedBy5dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||
|
||||
@Preview()
|
||||
@Composable
|
||||
private fun PeopleListItemPreview() {
|
||||
val user1: User = LocalCache.getOrCreateUser("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c")
|
||||
val user2: User = LocalCache.getOrCreateUser("ca89cb11f1c75d5b6622268ff43d2288ea8b2cb5b9aa996ff9ff704fc904b78b")
|
||||
val user3: User = LocalCache.getOrCreateUser("7eb29c126b3628077e2e3d863b917a56b74293aa9d8a9abc26a40ba3f2866baf")
|
||||
|
||||
val samplePeopleList1 =
|
||||
PeopleList(
|
||||
identifierTag = "00001-2222",
|
||||
title = "Sample List Title",
|
||||
description = "Sample List Description",
|
||||
emptySet(),
|
||||
emptySet(),
|
||||
)
|
||||
|
||||
val samplePeopleList2 =
|
||||
PeopleList(
|
||||
identifierTag = "00001-2222",
|
||||
title = "Sample List Title",
|
||||
description = "Sample List Description",
|
||||
setOf(user1, user3),
|
||||
emptySet(),
|
||||
)
|
||||
|
||||
val samplePeopleList3 =
|
||||
PeopleList(
|
||||
identifierTag = "00001-2222",
|
||||
title = "Sample List Title",
|
||||
description = "Sample List Description",
|
||||
emptySet(),
|
||||
setOf(user1, user3),
|
||||
)
|
||||
|
||||
val samplePeopleList4 =
|
||||
PeopleList(
|
||||
identifierTag = "00001-2222",
|
||||
title = "Sample List Title",
|
||||
description = "Sample List Description",
|
||||
setOf(user3),
|
||||
setOf(user1, user2, user3),
|
||||
)
|
||||
|
||||
ThemeComparisonColumn {
|
||||
Column {
|
||||
PeopleListItem(
|
||||
modifier = Modifier,
|
||||
peopleList = samplePeopleList1,
|
||||
onClick = {},
|
||||
onRename = {},
|
||||
onDescriptionChange = { },
|
||||
onClone = { newName, newDesc -> },
|
||||
onDelete = {},
|
||||
)
|
||||
PeopleListItem(
|
||||
modifier = Modifier,
|
||||
peopleList = samplePeopleList2,
|
||||
onClick = {},
|
||||
onRename = {},
|
||||
onDescriptionChange = { },
|
||||
onClone = { newName, newDesc -> },
|
||||
onDelete = {},
|
||||
)
|
||||
PeopleListItem(
|
||||
modifier = Modifier,
|
||||
peopleList = samplePeopleList3,
|
||||
onClick = {},
|
||||
onRename = {},
|
||||
onDescriptionChange = { },
|
||||
onClone = { newName, newDesc -> },
|
||||
onDelete = {},
|
||||
)
|
||||
PeopleListItem(
|
||||
modifier = Modifier,
|
||||
peopleList = samplePeopleList4,
|
||||
onClick = {},
|
||||
onRename = {},
|
||||
onDescriptionChange = { },
|
||||
onClone = { newName, newDesc -> },
|
||||
onDelete = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PeopleListItem(
|
||||
@@ -73,112 +166,93 @@ fun PeopleListItem(
|
||||
onClone: (customName: String?, customDescription: String?) -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Row(
|
||||
modifier =
|
||||
modifier
|
||||
.clickable(onClick = onClick),
|
||||
) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(bottom = 12.dp)
|
||||
.weight(1f),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
ListItem(
|
||||
modifier = modifier.clickable(onClick = onClick),
|
||||
headlineContent = {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(peopleList.title)
|
||||
|
||||
Column(
|
||||
modifier = NoSoTinyBorders,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.End,
|
||||
) {
|
||||
PeopleListOptionsButton(
|
||||
peopleListName = peopleList.title,
|
||||
peopleListDescription = peopleList.description,
|
||||
onListRename = onRename,
|
||||
onListDescriptionChange = onDescriptionChange,
|
||||
onListCloneCreate = onClone,
|
||||
onListDelete = onDelete,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
supportingContent = {
|
||||
Text(
|
||||
peopleList.description ?: "",
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 2,
|
||||
)
|
||||
},
|
||||
leadingContent = {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Groups,
|
||||
contentDescription = stringRes(R.string.follow_set_icon_description),
|
||||
modifier = Size50ModifierOffset10,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.align(Alignment.BottomCenter).offset(y = (-5).dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = SpacedBy5dp,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.format_list_bulleted_type),
|
||||
contentDescription = stringRes(R.string.follow_set_icon_description),
|
||||
)
|
||||
Text(peopleList.title, fontWeight = FontWeight.Bold)
|
||||
if (peopleList.publicMembers.isEmpty() && peopleList.privateMembers.isEmpty()) {
|
||||
FilterChip(
|
||||
selected = true,
|
||||
onClick = {},
|
||||
label = {
|
||||
Text(text = stringRes(R.string.follow_set_empty_label))
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.People,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
shape = ButtonBorder,
|
||||
Text(
|
||||
text = stringRes(R.string.follow_set_empty_label2),
|
||||
fontSize = Font10SP,
|
||||
)
|
||||
}
|
||||
if (peopleList.publicMembers.isNotEmpty()) {
|
||||
val publicMemberSize = peopleList.publicMembers.size
|
||||
FilterChip(
|
||||
selected = true,
|
||||
onClick = {},
|
||||
label = {
|
||||
Text(text = "$publicMemberSize")
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_public),
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
shape = ButtonBorder,
|
||||
)
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
}
|
||||
if (peopleList.privateMembers.isNotEmpty()) {
|
||||
val privateMemberSize = peopleList.privateMembers.size
|
||||
FilterChip(
|
||||
selected = true,
|
||||
onClick = {},
|
||||
label = {
|
||||
Text(text = "$privateMemberSize")
|
||||
},
|
||||
leadingIcon = {
|
||||
} else {
|
||||
if (peopleList.privateMembers.isNotEmpty()) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = SpacedBy2dp,
|
||||
) {
|
||||
Icon(
|
||||
painterResource(R.drawable.lock),
|
||||
modifier = Size10Modifier,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
shape = ButtonBorder,
|
||||
)
|
||||
Text(
|
||||
text = peopleList.privateMembers.size.toString(),
|
||||
fontSize = Font10SP,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (peopleList.publicMembers.isNotEmpty()) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = SpacedBy2dp,
|
||||
) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_public),
|
||||
modifier = Size10Modifier,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
text = peopleList.publicMembers.size.toString(),
|
||||
fontSize = Font10SP,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = StdVertSpacer)
|
||||
Text(
|
||||
peopleList.description ?: "",
|
||||
fontWeight = FontWeight.Light,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(start = 5.dp)
|
||||
.padding(vertical = 7.dp),
|
||||
verticalArrangement = Arrangement.Top,
|
||||
horizontalAlignment = Alignment.End,
|
||||
) {
|
||||
PeopleListOptionsButton(
|
||||
peopleListName = peopleList.title,
|
||||
peopleListDescription = peopleList.description,
|
||||
onListRename = onRename,
|
||||
onListDescriptionChange = onDescriptionChange,
|
||||
onListCloneCreate = onClone,
|
||||
onListDelete = onDelete,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
+4
-4
@@ -150,7 +150,7 @@ private fun FollowSetManagementScreenBody(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val followSetsState by accountViewModel.account.peopleListsState.uiListFlow
|
||||
val followSetsState by accountViewModel.account.peopleLists.uiListFlow
|
||||
.collectAsStateWithLifecycle()
|
||||
|
||||
if (followSetsState.isEmpty()) {
|
||||
@@ -168,7 +168,7 @@ private fun FollowSetManagementScreenBody(
|
||||
userIsPublicMember = list.publicMembers.contains(userToAddOrRemove),
|
||||
onRemoveUser = {
|
||||
accountViewModel.runIOCatching {
|
||||
accountViewModel.account.peopleListsState.removeUserFromSet(
|
||||
accountViewModel.account.peopleLists.removeUserFromSet(
|
||||
userToAddOrRemove,
|
||||
isPrivate = list.privateMembers.contains(userToAddOrRemove),
|
||||
list.identifierTag,
|
||||
@@ -178,7 +178,7 @@ private fun FollowSetManagementScreenBody(
|
||||
},
|
||||
onAddUserToList = { userShouldBePrivate ->
|
||||
accountViewModel.runIOCatching {
|
||||
accountViewModel.account.peopleListsState.addUserToSet(
|
||||
accountViewModel.account.peopleLists.addUserToSet(
|
||||
userToAddOrRemove,
|
||||
list.identifierTag,
|
||||
userShouldBePrivate,
|
||||
@@ -196,7 +196,7 @@ private fun FollowSetManagementScreenBody(
|
||||
userName = userToAddOrRemove.toBestDisplayName(),
|
||||
onSetCreate = { setName, memberShouldBePrivate, description ->
|
||||
accountViewModel.runIOCatching {
|
||||
accountViewModel.account.peopleListsState.addFollowList(
|
||||
accountViewModel.account.peopleLists.addFollowList(
|
||||
listName = setName,
|
||||
listDescription = description,
|
||||
isPrivate = memberShouldBePrivate,
|
||||
|
||||
@@ -30,6 +30,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
@@ -371,3 +372,5 @@ val SpacedBy5dp = Arrangement.spacedBy(Size5dp)
|
||||
val SpacedBy10dp = Arrangement.spacedBy(Size10dp)
|
||||
|
||||
val PopupUpEffect = RoundedCornerShape(0.dp, 0.dp, 15.dp, 15.dp)
|
||||
|
||||
val Size50ModifierOffset10 = Modifier.size(50.dp).offset(y = (-10).dp)
|
||||
|
||||
@@ -536,6 +536,7 @@
|
||||
<string name="follow_set_single_member_label">member</string>
|
||||
<string name="follow_set_multiple_member_label">members</string>
|
||||
<string name="follow_set_empty_label">No members</string>
|
||||
<string name="follow_set_empty_label2">Empty</string>
|
||||
<string name="follow_set_absence_indicator">%1$s is not in this list</string>
|
||||
<string name="follow_set_man_dialog_title">Your Lists</string>
|
||||
<string name="follow_set_empty_dialog_msg">No follow lists were found, or you don\'t have any follow lists. Tap below to refresh, or use the menu to create one.</string>
|
||||
|
||||
Reference in New Issue
Block a user