mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2916 App | Tech | Prepare staging release (#1666)
Co-authored-by: Konstantin Ivanov <54908981+konstantiniiv@users.noreply.github.com>
This commit is contained in:
parent
14af7b40c1
commit
b78e3e4d0d
203 changed files with 2606 additions and 1726 deletions
|
@ -15,12 +15,13 @@ import com.anytypeio.anytype.core_models.ext.DateParser
|
|||
import com.anytypeio.anytype.core_models.primitives.RelationKey
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction
|
||||
import com.anytypeio.anytype.domain.all_content.RestoreAllContentState
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.feature_allcontent.presentation.AllContentViewModel.Companion.DEFAULT_INITIAL_SORT
|
||||
import com.anytypeio.anytype.feature_allcontent.presentation.AllContentViewModel.Companion.DEFAULT_INITIAL_TAB
|
||||
import com.anytypeio.anytype.presentation.library.DependentData
|
||||
import com.anytypeio.anytype.presentation.mapper.objectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.getDescriptionOrSnippet
|
||||
import com.anytypeio.anytype.presentation.objects.getProperName
|
||||
import com.anytypeio.anytype.presentation.objects.getProperType
|
||||
|
||||
|
@ -104,6 +105,11 @@ sealed class UiContentState {
|
|||
) : UiContentState()
|
||||
}
|
||||
|
||||
sealed class UiItemsState{
|
||||
data object Empty : UiItemsState()
|
||||
data class Content(val items: List<UiContentItem>) : UiItemsState()
|
||||
}
|
||||
|
||||
// ITEMS
|
||||
sealed class UiContentItem {
|
||||
abstract val id: String
|
||||
|
@ -151,6 +157,18 @@ sealed class UiContentItem {
|
|||
val editable: Boolean = true,
|
||||
) : UiContentItem()
|
||||
|
||||
data object NewRelation : UiContentItem() {
|
||||
override val id: String = "NewRelation"
|
||||
}
|
||||
|
||||
data object NewType : UiContentItem() {
|
||||
override val id: String = "NewType"
|
||||
}
|
||||
|
||||
data object UnlinkedDescription : UiContentItem() {
|
||||
override val id: String = "UnlinkedDescription"
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TODAY_ID = "TodayId"
|
||||
const val YESTERDAY_ID = "YesterdayId"
|
||||
|
@ -188,13 +206,27 @@ sealed class MenuSortsItem {
|
|||
}
|
||||
//endregion
|
||||
|
||||
//region BOTTOM_MENU
|
||||
data class AllContentBottomMenu(val isOwnerOrEditor: Boolean = true)
|
||||
//endregion
|
||||
|
||||
//region SNACKBAR
|
||||
sealed class UiSnackbarState {
|
||||
data object Hidden : UiSnackbarState()
|
||||
data class Visible(val message: String, val objId: Id) : UiSnackbarState()
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region MAPPING
|
||||
fun Key?.mapRelationKeyToSort(): AllContentSort {
|
||||
return when (this) {
|
||||
Relations.CREATED_DATE -> AllContentSort.ByDateCreated()
|
||||
Relations.LAST_MODIFIED_DATE -> AllContentSort.ByDateUpdated()
|
||||
Relations.NAME -> AllContentSort.ByName()
|
||||
else -> DEFAULT_INITIAL_SORT
|
||||
|
||||
fun RestoreAllContentState.Response.Success.mapToSort(): AllContentSort {
|
||||
val sortType = if (isAsc) DVSortType.ASC else DVSortType.DESC
|
||||
return when (activeSort) {
|
||||
Relations.CREATED_DATE -> AllContentSort.ByDateCreated(sortType = sortType)
|
||||
Relations.LAST_MODIFIED_DATE -> AllContentSort.ByDateUpdated(sortType = sortType)
|
||||
Relations.NAME -> AllContentSort.ByName(sortType = sortType)
|
||||
Relations.LAST_USED_DATE -> AllContentSort.ByDateUsed(sortType = sortType)
|
||||
else -> AllContentSort.ByName(sortType = DVSortType.ASC)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,12 +248,12 @@ fun ObjectWrapper.Basic.toAllContentItem(
|
|||
val obj = this
|
||||
val typeUrl = obj.getProperType()
|
||||
val isProfile = typeUrl == MarketplaceObjectTypeIds.PROFILE
|
||||
val layout = layout ?: ObjectType.Layout.BASIC
|
||||
val layout = obj.layout ?: ObjectType.Layout.BASIC
|
||||
return UiContentItem.Item(
|
||||
id = obj.id,
|
||||
space = space,
|
||||
name = obj.getProperName(),
|
||||
description = obj.description,
|
||||
description = getDescriptionOrSnippet(),
|
||||
type = typeUrl,
|
||||
typeName = objectTypes.firstOrNull { type ->
|
||||
if (isProfile) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.anytypeio.anytype.core_models.ObjectTypeIds
|
|||
import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys
|
||||
import com.anytypeio.anytype.core_models.RelationFormat
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.domain.library.StoreSearchParams
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.defaultKeys
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.defaultKeysObjectType
|
||||
|
@ -61,6 +62,7 @@ fun createSubscriptionParams(
|
|||
activeMode = activeMode
|
||||
)
|
||||
return StoreSearchParams(
|
||||
space = SpaceId(spaceId),
|
||||
filters = filters,
|
||||
sorts = sorts,
|
||||
keys = keys,
|
||||
|
|
|
@ -27,18 +27,21 @@ import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
|||
import com.anytypeio.anytype.domain.page.CreateObject
|
||||
import com.anytypeio.anytype.domain.search.SearchObjects
|
||||
import com.anytypeio.anytype.domain.workspace.RemoveObjectsFromWorkspace
|
||||
import com.anytypeio.anytype.feature_allcontent.models.AllContentBottomMenu
|
||||
import com.anytypeio.anytype.feature_allcontent.models.AllContentMenuMode
|
||||
import com.anytypeio.anytype.feature_allcontent.models.AllContentSort
|
||||
import com.anytypeio.anytype.feature_allcontent.models.AllContentTab
|
||||
import com.anytypeio.anytype.feature_allcontent.models.MenuSortsItem
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiContentItem
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiContentState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiItemsState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiMenuState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiSnackbarState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiTabsState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiTitleState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.createSubscriptionParams
|
||||
import com.anytypeio.anytype.feature_allcontent.models.filtersForSearch
|
||||
import com.anytypeio.anytype.feature_allcontent.models.mapRelationKeyToSort
|
||||
import com.anytypeio.anytype.feature_allcontent.models.mapToSort
|
||||
import com.anytypeio.anytype.feature_allcontent.models.toAnalyticsModeType
|
||||
import com.anytypeio.anytype.feature_allcontent.models.toAnalyticsSortType
|
||||
import com.anytypeio.anytype.feature_allcontent.models.toAnalyticsTabType
|
||||
|
@ -109,12 +112,14 @@ class AllContentViewModel(
|
|||
) : ViewModel(), AnalyticSpaceHelperDelegate by analyticSpaceHelperDelegate {
|
||||
|
||||
private val searchResultIds = MutableStateFlow<List<Id>>(emptyList())
|
||||
private val sortState = MutableStateFlow<AllContentSort>(DEFAULT_INITIAL_SORT)
|
||||
private val sortState = MutableStateFlow<AllContentSort>(AllContentSort.ByName())
|
||||
val uiTitleState = MutableStateFlow<UiTitleState>(DEFAULT_INITIAL_MODE)
|
||||
val uiTabsState = MutableStateFlow<UiTabsState>(UiTabsState())
|
||||
val uiMenuState = MutableStateFlow<UiMenuState>(UiMenuState.Hidden)
|
||||
val uiItemsState = MutableStateFlow<List<UiContentItem>>(emptyList())
|
||||
val uiItemsState = MutableStateFlow<UiItemsState>(UiItemsState.Empty)
|
||||
val uiContentState = MutableStateFlow<UiContentState>(UiContentState.Idle())
|
||||
val uiBottomMenu = MutableStateFlow<AllContentBottomMenu>(AllContentBottomMenu())
|
||||
val uiSnackbarState = MutableStateFlow<UiSnackbarState>(UiSnackbarState.Hidden)
|
||||
|
||||
val commands = MutableSharedFlow<Command>()
|
||||
|
||||
|
@ -155,6 +160,8 @@ class AllContentViewModel(
|
|||
userPermissionProvider
|
||||
.observe(space = vmParams.spaceId)
|
||||
.collect {
|
||||
uiBottomMenu.value =
|
||||
AllContentBottomMenu(isOwnerOrEditor = it?.isOwnerOrEditor() == true)
|
||||
permission.value = it
|
||||
}
|
||||
}
|
||||
|
@ -167,9 +174,14 @@ class AllContentViewModel(
|
|||
val initialParams = restoreAllContentState.run(
|
||||
RestoreAllContentState.Params(vmParams.spaceId)
|
||||
)
|
||||
if (!initialParams.activeSort.isNullOrEmpty()) {
|
||||
sortState.value = initialParams.activeSort.mapRelationKeyToSort()
|
||||
restartSubscription.value++
|
||||
when (initialParams) {
|
||||
RestoreAllContentState.Response.Empty -> {
|
||||
//do nothing
|
||||
}
|
||||
is RestoreAllContentState.Response.Success -> {
|
||||
sortState.value = initialParams.mapToSort()
|
||||
restartSubscription.value++
|
||||
}
|
||||
}
|
||||
}.onFailure { e ->
|
||||
Timber.e(e, "Error restoring state")
|
||||
|
@ -196,7 +208,7 @@ class AllContentViewModel(
|
|||
success = { searchResults ->
|
||||
Timber.d("Search objects by query:[$query], size: : ${searchResults.size}")
|
||||
if (searchResults.isEmpty()) {
|
||||
uiItemsState.value = emptyList()
|
||||
uiItemsState.value = UiItemsState.Empty
|
||||
uiContentState.value = UiContentState.Empty
|
||||
} else {
|
||||
searchResultIds.value = searchResults.map { it.id }
|
||||
|
@ -218,7 +230,12 @@ class AllContentViewModel(
|
|||
restartSubscription.flatMapLatest {
|
||||
loadData()
|
||||
}.collectLatest { items ->
|
||||
uiItemsState.value = items
|
||||
if (items.isEmpty()) {
|
||||
uiItemsState.value = UiItemsState.Empty
|
||||
uiContentState.value = UiContentState.Empty
|
||||
} else {
|
||||
uiItemsState.value = UiItemsState.Content(items)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -290,20 +307,25 @@ class AllContentViewModel(
|
|||
activeSort: AllContentSort,
|
||||
activeTab: AllContentTab
|
||||
): List<UiContentItem> {
|
||||
val isOwnerOrEditor = permission.value?.isOwnerOrEditor() == true
|
||||
return when (activeTab) {
|
||||
AllContentTab.TYPES -> {
|
||||
val items = objectWrappers.toUiContentTypes(
|
||||
urlBuilder = urlBuilder,
|
||||
isOwnerOrEditor = permission.value?.isOwnerOrEditor() == true
|
||||
isOwnerOrEditor = isOwnerOrEditor
|
||||
)
|
||||
items
|
||||
buildList {
|
||||
if (isOwnerOrEditor) add(UiContentItem.NewType)
|
||||
addAll(items)
|
||||
}
|
||||
}
|
||||
|
||||
AllContentTab.RELATIONS -> {
|
||||
val items = objectWrappers.toUiContentRelations(
|
||||
isOwnerOrEditor = permission.value?.isOwnerOrEditor() == true
|
||||
)
|
||||
items
|
||||
val items = objectWrappers.toUiContentRelations(isOwnerOrEditor = isOwnerOrEditor)
|
||||
buildList {
|
||||
if (isOwnerOrEditor) add(UiContentItem.NewRelation)
|
||||
addAll(items)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
@ -311,7 +333,7 @@ class AllContentViewModel(
|
|||
space = vmParams.spaceId,
|
||||
urlBuilder = urlBuilder,
|
||||
objectTypes = storeOfObjectTypes.getAll(),
|
||||
isOwnerOrEditor = permission.value?.isOwnerOrEditor() == true
|
||||
isOwnerOrEditor = isOwnerOrEditor
|
||||
)
|
||||
val result = when (activeSort) {
|
||||
is AllContentSort.ByDateCreated -> {
|
||||
|
@ -330,7 +352,14 @@ class AllContentViewModel(
|
|||
items
|
||||
}
|
||||
}
|
||||
result
|
||||
if (uiTitleState.value == UiTitleState.OnlyUnlinked) {
|
||||
buildList {
|
||||
add(UiContentItem.UnlinkedDescription)
|
||||
addAll(result)
|
||||
}
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -422,6 +451,7 @@ class AllContentViewModel(
|
|||
spaces = listOf(vmParams.spaceId.id)
|
||||
)
|
||||
return SearchObjects.Params(
|
||||
space = vmParams.spaceId,
|
||||
filters = filters,
|
||||
keys = listOf(Relations.ID),
|
||||
fulltext = activeQuery
|
||||
|
@ -484,14 +514,14 @@ class AllContentViewModel(
|
|||
}
|
||||
else -> {
|
||||
listOf(
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByName(isSelected = activeSort is AllContentSort.ByName)
|
||||
),
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByDateUpdated(isSelected = activeSort is AllContentSort.ByDateUpdated)
|
||||
),
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByDateCreated(isSelected = activeSort is AllContentSort.ByDateCreated)
|
||||
),
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByName(isSelected = activeSort is AllContentSort.ByName)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -531,7 +561,7 @@ class AllContentViewModel(
|
|||
tab.updateInitialState()
|
||||
shouldScrollToTopItems = true
|
||||
resetLimit()
|
||||
uiItemsState.value = emptyList()
|
||||
uiItemsState.value = UiItemsState.Empty
|
||||
uiTabsState.value = uiTabsState.value.copy(selectedTab = tab)
|
||||
restartSubscription.value++
|
||||
viewModelScope.launch {
|
||||
|
@ -545,7 +575,7 @@ class AllContentViewModel(
|
|||
fun onAllContentModeClicked(mode: AllContentMenuMode) {
|
||||
Timber.d("onAllContentModeClicked: $mode")
|
||||
shouldScrollToTopItems = true
|
||||
uiItemsState.value = emptyList()
|
||||
uiItemsState.value = UiItemsState.Empty
|
||||
uiTitleState.value = when (mode) {
|
||||
is AllContentMenuMode.AllContent -> UiTitleState.AllContent
|
||||
is AllContentMenuMode.Unlinked -> UiTitleState.OnlyUnlinked
|
||||
|
@ -576,7 +606,7 @@ class AllContentViewModel(
|
|||
}
|
||||
}
|
||||
shouldScrollToTopItems = true
|
||||
uiItemsState.value = emptyList()
|
||||
uiItemsState.value = UiItemsState.Empty
|
||||
sortState.value = newSort
|
||||
proceedWithSortSaving(uiTabsState.value, newSort)
|
||||
restartSubscription.value++
|
||||
|
@ -712,7 +742,10 @@ class AllContentViewModel(
|
|||
objType: ObjectWrapper.Type? = null
|
||||
) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
val params = objType?.uniqueKey.getCreateObjectParams(objType?.defaultTemplateId)
|
||||
val params = objType?.uniqueKey.getCreateObjectParams(
|
||||
space = vmParams.spaceId,
|
||||
objType?.defaultTemplateId
|
||||
)
|
||||
viewModelScope.launch {
|
||||
createObject.async(params).fold(
|
||||
onSuccess = { result ->
|
||||
|
@ -733,10 +766,22 @@ class AllContentViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onTypeClicked(item: UiContentItem.Type) {
|
||||
fun onTypeClicked(item: UiContentItem) {
|
||||
Timber.d("onTypeClicked: $item")
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.OpenTypeEditing(item))
|
||||
when (item) {
|
||||
UiContentItem.NewType -> {
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.OpenTypeCreation)
|
||||
}
|
||||
}
|
||||
is UiContentItem.Type -> {
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.OpenTypeEditing(item))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
viewModelScope.sendEvent(
|
||||
analytics = analytics,
|
||||
|
@ -744,24 +789,38 @@ class AllContentViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
fun onRelationClicked(item: UiContentItem.Relation) {
|
||||
fun onRelationClicked(item: UiContentItem) {
|
||||
Timber.d("onRelationClicked: $item")
|
||||
viewModelScope.launch {
|
||||
commands.emit(
|
||||
Command.OpenRelationEditing(
|
||||
typeName = item.name,
|
||||
id = item.id,
|
||||
iconUnicode = item.format.simpleIcon() ?: 0,
|
||||
readOnly = item.readOnly
|
||||
)
|
||||
)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
viewModelScope.sendEvent(
|
||||
analytics = analytics,
|
||||
eventName = libraryScreenRelation
|
||||
)
|
||||
when (item) {
|
||||
UiContentItem.NewRelation -> {
|
||||
viewModelScope.launch {
|
||||
commands.emit(
|
||||
Command.OpenRelationCreation(
|
||||
space = vmParams.spaceId.id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
is UiContentItem.Relation -> {
|
||||
viewModelScope.launch {
|
||||
commands.emit(
|
||||
Command.OpenRelationEditing(
|
||||
typeName = item.name,
|
||||
id = item.id,
|
||||
iconUnicode = item.format.simpleIcon() ?: 0,
|
||||
readOnly = item.readOnly
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
viewModelScope.sendEvent(
|
||||
analytics = analytics,
|
||||
eventName = libraryScreenRelation
|
||||
)
|
||||
}
|
||||
|
||||
fun onStart() {
|
||||
|
@ -782,7 +841,7 @@ class AllContentViewModel(
|
|||
viewModelScope.launch {
|
||||
userInput.value = DEFAULT_QUERY
|
||||
searchResultIds.value = emptyList()
|
||||
uiItemsState.value = emptyList()
|
||||
uiItemsState.value = UiItemsState.Empty
|
||||
uiContentState.value = UiContentState.Empty
|
||||
}
|
||||
}
|
||||
|
@ -796,7 +855,11 @@ class AllContentViewModel(
|
|||
setObjectListIsArchived.async(params).fold(
|
||||
onSuccess = { ids ->
|
||||
Timber.d("Successfully archived object: $ids")
|
||||
commands.emit(Command.SendToast.ObjectArchived(item.name))
|
||||
val name = item.name
|
||||
uiSnackbarState.value = UiSnackbarState.Visible(
|
||||
message = name.take(10),
|
||||
objId = item.id
|
||||
)
|
||||
},
|
||||
onFailure = { e ->
|
||||
Timber.e(e, "Error while archiving object")
|
||||
|
@ -806,6 +869,29 @@ class AllContentViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun proceedWithUndoMoveToBin(objectId: Id) {
|
||||
val params = SetObjectListIsArchived.Params(
|
||||
targets = listOf(objectId),
|
||||
isArchived = false
|
||||
)
|
||||
viewModelScope.launch {
|
||||
setObjectListIsArchived.async(params).fold(
|
||||
onSuccess = { ids ->
|
||||
Timber.d("Successfully archived object: $ids")
|
||||
uiSnackbarState.value = UiSnackbarState.Hidden
|
||||
},
|
||||
onFailure = { e ->
|
||||
Timber.e(e, "Error while un-archiving object")
|
||||
commands.emit(Command.SendToast.Error("Error while un-archiving object"))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun proceedWithDismissSnackbar() {
|
||||
uiSnackbarState.value = UiSnackbarState.Hidden
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the limit for the number of items fetched and triggers data reload.
|
||||
*/
|
||||
|
@ -819,7 +905,7 @@ class AllContentViewModel(
|
|||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
uiItemsState.value = emptyList()
|
||||
uiItemsState.value = UiItemsState.Empty
|
||||
resetLimit()
|
||||
}
|
||||
|
||||
|
@ -893,14 +979,14 @@ class AllContentViewModel(
|
|||
data class ObjectArchived(val name: String) : SendToast()
|
||||
}
|
||||
data class OpenTypeEditing(val item: UiContentItem.Type) : Command()
|
||||
data class OpenTypeCreation(val name: String): Command()
|
||||
data object OpenTypeCreation: Command()
|
||||
data class OpenRelationEditing(
|
||||
val typeName: String,
|
||||
val id: Id,
|
||||
val iconUnicode: Int,
|
||||
val readOnly: Boolean
|
||||
) : Command()
|
||||
data class OpenRelationCreation(val id: Id, val name: String, val space: Id): Command()
|
||||
data class OpenRelationCreation(val space: Id): Command()
|
||||
data object OpenGlobalSearch : Command()
|
||||
data object ExitToVault : Command()
|
||||
data object Back : Command()
|
||||
|
@ -913,7 +999,6 @@ class AllContentViewModel(
|
|||
const val DEFAULT_SEARCH_LIMIT = 100
|
||||
val DEFAULT_INITIAL_MODE = UiTitleState.AllContent
|
||||
val DEFAULT_INITIAL_TAB = AllContentTab.PAGES
|
||||
val DEFAULT_INITIAL_SORT = AllContentSort.ByName()
|
||||
val DEFAULT_QUERY = ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,9 +132,10 @@ private fun SortingBox(modifier: Modifier, subtitle: String, isExpanded: Boolean
|
|||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.padding(start = 10.dp)
|
||||
.size(18.dp)
|
||||
.rotate(rotationAngle),
|
||||
painter = painterResource(R.drawable.ic_menu_arrow_right),
|
||||
painter = painterResource(R.drawable.ic_arrow_disclosure_18),
|
||||
contentDescription = "",
|
||||
colorFilter = tint(colorResource(id = R.color.glyph_selected))
|
||||
)
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.compose.animation.fadeOut
|
|||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
@ -26,11 +27,15 @@ import androidx.compose.foundation.layout.statusBars
|
|||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.LazyItemScope
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarDuration
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.compose.material3.SwipeToDismissBox
|
||||
import androidx.compose.material3.SwipeToDismissBoxValue
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -39,6 +44,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
|
@ -59,14 +65,17 @@ import androidx.compose.ui.text.style.TextAlign
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
|
||||
import com.anytypeio.anytype.core_ui.extensions.simpleIcon
|
||||
import com.anytypeio.anytype.core_ui.extensions.swapList
|
||||
import com.anytypeio.anytype.core_ui.foundation.DismissBackground
|
||||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationMenu
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Regular
|
||||
import com.anytypeio.anytype.core_ui.views.PreviewTitle1Medium
|
||||
|
@ -79,15 +88,19 @@ import com.anytypeio.anytype.core_ui.widgets.ListWidgetObjectIcon
|
|||
import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK
|
||||
import com.anytypeio.anytype.feature_allcontent.BuildConfig
|
||||
import com.anytypeio.anytype.feature_allcontent.R
|
||||
import com.anytypeio.anytype.feature_allcontent.models.AllContentBottomMenu
|
||||
import com.anytypeio.anytype.feature_allcontent.models.AllContentMenuMode
|
||||
import com.anytypeio.anytype.feature_allcontent.models.AllContentSort
|
||||
import com.anytypeio.anytype.feature_allcontent.models.AllContentTab
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiContentItem
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiContentState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiItemsState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiMenuState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiSnackbarState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiTabsState
|
||||
import com.anytypeio.anytype.feature_allcontent.models.UiTitleState
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
@ -97,49 +110,34 @@ fun AllContentWrapperScreen(
|
|||
uiTitleState: UiTitleState,
|
||||
uiTabsState: UiTabsState,
|
||||
uiMenuState: UiMenuState,
|
||||
uiItemsState: List<UiContentItem>,
|
||||
uiSnackbarState: UiSnackbarState,
|
||||
uiItemsState: UiItemsState,
|
||||
uiBottomMenu: AllContentBottomMenu,
|
||||
onTabClick: (AllContentTab) -> Unit,
|
||||
onQueryChanged: (String) -> Unit,
|
||||
onModeClick: (AllContentMenuMode) -> Unit,
|
||||
onSortClick: (AllContentSort) -> Unit,
|
||||
onItemClicked: (UiContentItem.Item) -> Unit,
|
||||
onTypeClicked: (UiContentItem.Type) -> Unit,
|
||||
onRelationClicked: (UiContentItem.Relation) -> Unit,
|
||||
onTypeClicked: (UiContentItem) -> Unit,
|
||||
onRelationClicked: (UiContentItem) -> Unit,
|
||||
onBinClick: () -> Unit,
|
||||
canPaginate: Boolean,
|
||||
onUpdateLimitSearch: () -> Unit,
|
||||
uiContentState: UiContentState,
|
||||
onHomeClicked: () -> Unit,
|
||||
onGlobalSearchClicked: () -> Unit,
|
||||
onAddDocClicked: () -> Unit,
|
||||
onCreateObjectLongClicked: () -> Unit,
|
||||
onBackClicked: () -> Unit,
|
||||
onBackLongClicked: () -> Unit,
|
||||
moveToBin: (UiContentItem.Item) -> Unit
|
||||
moveToBin: (UiContentItem.Item) -> Unit,
|
||||
undoMoveToBin: (Id) -> Unit,
|
||||
onDismissSnackbar: () -> Unit
|
||||
) {
|
||||
val lazyListState = rememberLazyListState()
|
||||
|
||||
val canPaginateState = remember { mutableStateOf(false) }
|
||||
LaunchedEffect(key1 = canPaginate) {
|
||||
canPaginateState.value = canPaginate
|
||||
}
|
||||
|
||||
val shouldStartPaging = remember {
|
||||
derivedStateOf {
|
||||
canPaginateState.value && (lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
|
||||
?: -9) >= (lazyListState.layoutInfo.totalItemsCount - 2)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = shouldStartPaging.value) {
|
||||
if (shouldStartPaging.value && uiContentState is UiContentState.Idle) {
|
||||
onUpdateLimitSearch()
|
||||
}
|
||||
}
|
||||
|
||||
AllContentMainScreen(
|
||||
uiTitleState = uiTitleState,
|
||||
uiTabsState = uiTabsState,
|
||||
uiSnackbarState = uiSnackbarState,
|
||||
onTabClick = onTabClick,
|
||||
onQueryChanged = onQueryChanged,
|
||||
uiMenuState = uiMenuState,
|
||||
|
@ -148,46 +146,71 @@ fun AllContentWrapperScreen(
|
|||
onItemClicked = onItemClicked,
|
||||
onBinClick = onBinClick,
|
||||
uiItemsState = uiItemsState,
|
||||
lazyListState = lazyListState,
|
||||
uiContentState = uiContentState,
|
||||
onTypeClicked = onTypeClicked,
|
||||
onHomeClicked = onHomeClicked,
|
||||
onGlobalSearchClicked = onGlobalSearchClicked,
|
||||
onAddDocClicked = onAddDocClicked,
|
||||
onCreateObjectLongClicked = onCreateObjectLongClicked,
|
||||
onBackClicked = onBackClicked,
|
||||
onBackLongClicked = onBackLongClicked,
|
||||
moveToBin = moveToBin,
|
||||
onRelationClicked = onRelationClicked
|
||||
onRelationClicked = onRelationClicked,
|
||||
uiBottomMenu = uiBottomMenu,
|
||||
undoMoveToBin = undoMoveToBin,
|
||||
onDismissSnackbar = onDismissSnackbar,
|
||||
canPaginate = canPaginate,
|
||||
onUpdateLimitSearch = onUpdateLimitSearch
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun AllContentMainScreen(
|
||||
uiItemsState: List<UiContentItem>,
|
||||
uiItemsState: UiItemsState,
|
||||
uiTitleState: UiTitleState,
|
||||
uiTabsState: UiTabsState,
|
||||
uiMenuState: UiMenuState,
|
||||
uiSnackbarState: UiSnackbarState,
|
||||
uiBottomMenu: AllContentBottomMenu,
|
||||
onTabClick: (AllContentTab) -> Unit,
|
||||
onQueryChanged: (String) -> Unit,
|
||||
onModeClick: (AllContentMenuMode) -> Unit,
|
||||
onSortClick: (AllContentSort) -> Unit,
|
||||
onItemClicked: (UiContentItem.Item) -> Unit,
|
||||
onTypeClicked: (UiContentItem.Type) -> Unit,
|
||||
onRelationClicked: (UiContentItem.Relation) -> Unit,
|
||||
onTypeClicked: (UiContentItem) -> Unit,
|
||||
onRelationClicked: (UiContentItem) -> Unit,
|
||||
onBinClick: () -> Unit,
|
||||
lazyListState: LazyListState,
|
||||
uiContentState: UiContentState,
|
||||
onHomeClicked: () -> Unit,
|
||||
onGlobalSearchClicked: () -> Unit,
|
||||
onAddDocClicked: () -> Unit,
|
||||
onCreateObjectLongClicked: () -> Unit,
|
||||
onBackClicked: () -> Unit,
|
||||
onBackLongClicked: () -> Unit,
|
||||
moveToBin: (UiContentItem.Item) -> Unit
|
||||
moveToBin: (UiContentItem.Item) -> Unit,
|
||||
undoMoveToBin: (Id) -> Unit,
|
||||
onDismissSnackbar: () -> Unit,
|
||||
canPaginate: Boolean,
|
||||
onUpdateLimitSearch: () -> Unit,
|
||||
) {
|
||||
var isSearchEmpty by remember { mutableStateOf(true) }
|
||||
val snackBarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val snackBarText = stringResource(R.string.all_content_snackbar_title)
|
||||
val undoText = stringResource(R.string.undo)
|
||||
|
||||
LaunchedEffect(key1 = uiSnackbarState) {
|
||||
if (uiSnackbarState is UiSnackbarState.Visible) {
|
||||
ShowMoveToBinSnackbar(
|
||||
message = "'${uiSnackbarState.message}' $snackBarText",
|
||||
undo = undoText,
|
||||
scope = this,
|
||||
snackBarHostState = snackBarHostState,
|
||||
objectId = uiSnackbarState.objId,
|
||||
undoMoveToBin = undoMoveToBin,
|
||||
onDismissSnackbar = onDismissSnackbar
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier
|
||||
|
@ -207,12 +230,12 @@ fun AllContentMainScreen(
|
|||
) {
|
||||
BottomMenu(
|
||||
modifier = Modifier.align(Alignment.BottomCenter),
|
||||
onHomeClicked = onHomeClicked,
|
||||
onGlobalSearchClicked = onGlobalSearchClicked,
|
||||
onAddDocClicked = onAddDocClicked,
|
||||
onCreateObjectLongClicked = onCreateObjectLongClicked,
|
||||
onBackClicked = onBackClicked,
|
||||
onBackLongClicked = onBackLongClicked
|
||||
onBackLongClicked = onBackLongClicked,
|
||||
uiBottomMenu = uiBottomMenu
|
||||
)
|
||||
}
|
||||
},
|
||||
|
@ -262,8 +285,8 @@ fun AllContentMainScreen(
|
|||
modifier = contentModifier,
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
when {
|
||||
uiItemsState.isEmpty() -> {
|
||||
when (uiItemsState) {
|
||||
UiItemsState.Empty -> {
|
||||
when (uiContentState) {
|
||||
is UiContentState.Error -> {
|
||||
ErrorState(uiContentState.message)
|
||||
|
@ -284,27 +307,31 @@ fun AllContentMainScreen(
|
|||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
is UiItemsState.Content -> {
|
||||
ContentItems(
|
||||
uiItemsState = uiItemsState,
|
||||
onItemClicked = onItemClicked,
|
||||
onTypeClicked = onTypeClicked,
|
||||
uiContentState = uiContentState,
|
||||
lazyListState = lazyListState,
|
||||
moveToBin = moveToBin,
|
||||
onRelationClicked = onRelationClicked
|
||||
onRelationClicked = onRelationClicked,
|
||||
canPaginate = canPaginate,
|
||||
onUpdateLimitSearch = onUpdateLimitSearch
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackBarHostState)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BottomMenu(
|
||||
uiBottomMenu: AllContentBottomMenu,
|
||||
modifier: Modifier = Modifier,
|
||||
onHomeClicked: () -> Unit,
|
||||
onGlobalSearchClicked: () -> Unit,
|
||||
onAddDocClicked: () -> Unit,
|
||||
onCreateObjectLongClicked: () -> Unit,
|
||||
|
@ -317,42 +344,69 @@ fun BottomMenu(
|
|||
modifier = modifier,
|
||||
backClick = onBackClicked,
|
||||
backLongClick = onBackLongClicked,
|
||||
onProfileClicked = onHomeClicked,
|
||||
searchClick = onGlobalSearchClicked,
|
||||
addDocClick = onAddDocClicked,
|
||||
onCreateObjectLongClicked = onCreateObjectLongClicked
|
||||
addDocLongClick = onCreateObjectLongClicked,
|
||||
isOwnerOrEditor = uiBottomMenu.isOwnerOrEditor
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentItems(
|
||||
uiItemsState: List<UiContentItem>,
|
||||
uiItemsState: UiItemsState.Content,
|
||||
onItemClicked: (UiContentItem.Item) -> Unit,
|
||||
onTypeClicked: (UiContentItem.Type) -> Unit,
|
||||
onRelationClicked: (UiContentItem.Relation) -> Unit,
|
||||
onTypeClicked: (UiContentItem) -> Unit,
|
||||
onRelationClicked: (UiContentItem) -> Unit,
|
||||
uiContentState: UiContentState,
|
||||
lazyListState: LazyListState,
|
||||
moveToBin: (UiContentItem.Item) -> Unit
|
||||
canPaginate: Boolean,
|
||||
moveToBin: (UiContentItem.Item) -> Unit,
|
||||
onUpdateLimitSearch: () -> Unit
|
||||
) {
|
||||
val items = remember { mutableStateListOf<UiContentItem>() }
|
||||
items.swapList(uiItemsState.items)
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val lazyListState = rememberLazyListState()
|
||||
|
||||
val canPaginateState = remember { mutableStateOf(false) }
|
||||
LaunchedEffect(key1 = canPaginate) {
|
||||
canPaginateState.value = canPaginate
|
||||
}
|
||||
|
||||
val shouldStartPaging = remember {
|
||||
derivedStateOf {
|
||||
canPaginateState.value && (lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
|
||||
?: -9) >= (lazyListState.layoutInfo.totalItemsCount - 2)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = shouldStartPaging.value) {
|
||||
if (shouldStartPaging.value && uiContentState is UiContentState.Idle) {
|
||||
onUpdateLimitSearch()
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = lazyListState
|
||||
) {
|
||||
items(
|
||||
count = uiItemsState.size,
|
||||
key = { index -> uiItemsState[index].id },
|
||||
count = items.size,
|
||||
key = { index -> items[index].id },
|
||||
contentType = { index ->
|
||||
when (uiItemsState[index]) {
|
||||
when (items[index]) {
|
||||
is UiContentItem.Group -> "group"
|
||||
is UiContentItem.Item -> "item"
|
||||
is UiContentItem.Type -> "type"
|
||||
is UiContentItem.Relation -> "relation"
|
||||
UiContentItem.NewRelation -> "new_relation"
|
||||
UiContentItem.NewType -> "new_type"
|
||||
UiContentItem.UnlinkedDescription -> "unlinked_description"
|
||||
}
|
||||
}
|
||||
) { index ->
|
||||
when (val item = uiItemsState[index]) {
|
||||
when (val item = items[index]) {
|
||||
is UiContentItem.Group -> {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
@ -412,6 +466,29 @@ private fun ContentItems(
|
|||
item = item
|
||||
)
|
||||
}
|
||||
|
||||
UiContentItem.NewRelation -> {
|
||||
AddItem(
|
||||
modifier = Modifier
|
||||
.clickable { onRelationClicked(item) },
|
||||
text = stringResource(id = R.string.all_content_new_relation)
|
||||
)
|
||||
Divider(paddingStart = 16.dp, paddingEnd = 16.dp)
|
||||
}
|
||||
|
||||
UiContentItem.NewType -> {
|
||||
AddItem(
|
||||
modifier = Modifier
|
||||
.clickable { onTypeClicked(item) },
|
||||
text = stringResource(id = R.string.all_content_new_type)
|
||||
)
|
||||
Divider(paddingStart = 16.dp, paddingEnd = 16.dp)
|
||||
}
|
||||
|
||||
UiContentItem.UnlinkedDescription -> {
|
||||
UnlinkedDescription()
|
||||
Divider(paddingStart = 16.dp, paddingEnd = 16.dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uiContentState is UiContentState.Paging) {
|
||||
|
@ -442,6 +519,48 @@ private fun ContentItems(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LazyItemScope.UnlinkedDescription() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.height(64.dp)
|
||||
.animateItem(),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.all_content_unlinked_description),
|
||||
style = Caption1Regular,
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LazyItemScope.AddItem(modifier: Modifier, text: String) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(52.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
.animateItem(),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_default_plus),
|
||||
contentDescription = text,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 34.dp),
|
||||
text = text,
|
||||
style = BodyRegular,
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.LoadingState() {
|
||||
val loadingAlpha by animateFloatAsState(targetValue = 1f, label = "")
|
||||
|
@ -468,7 +587,7 @@ fun PreviewLoadingState() {
|
|||
@Composable
|
||||
fun PreviewMainScreen() {
|
||||
AllContentMainScreen(
|
||||
uiItemsState = emptyList(),
|
||||
uiItemsState = UiItemsState.Empty,
|
||||
uiTitleState = UiTitleState.AllContent,
|
||||
uiTabsState = UiTabsState(
|
||||
tabs = listOf(
|
||||
|
@ -484,17 +603,21 @@ fun PreviewMainScreen() {
|
|||
onSortClick = {},
|
||||
onItemClicked = {},
|
||||
onBinClick = {},
|
||||
lazyListState = rememberLazyListState(),
|
||||
uiContentState = UiContentState.Error("Error message"),
|
||||
onTypeClicked = {},
|
||||
onHomeClicked = {},
|
||||
onGlobalSearchClicked = {},
|
||||
onAddDocClicked = {},
|
||||
onCreateObjectLongClicked = {},
|
||||
onBackClicked = {},
|
||||
moveToBin = {},
|
||||
onBackLongClicked = {},
|
||||
onRelationClicked = {}
|
||||
onRelationClicked = {},
|
||||
uiBottomMenu = AllContentBottomMenu(isOwnerOrEditor = false),
|
||||
uiSnackbarState = UiSnackbarState.Hidden,
|
||||
undoMoveToBin = {},
|
||||
onDismissSnackbar = {},
|
||||
canPaginate = true,
|
||||
onUpdateLimitSearch = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -614,7 +737,10 @@ private fun Relation(
|
|||
|
||||
@Composable
|
||||
private fun ErrorState(message: String) {
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.windowInsetsPadding(WindowInsets.ime)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
@ -644,7 +770,10 @@ private fun EmptyState(isSearchEmpty: Boolean) {
|
|||
} else {
|
||||
stringResource(R.string.allContent_empty_state_title) to stringResource(R.string.allContent_empty_state_description)
|
||||
}
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.windowInsetsPadding(WindowInsets.ime)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
|
@ -712,6 +841,7 @@ fun SwipeToDismissListItems(
|
|||
) {
|
||||
var isRemoved by remember { mutableStateOf(false) }
|
||||
val dismissState = rememberSwipeToDismissBoxState(
|
||||
initialValue = SwipeToDismissBoxValue.Settled,
|
||||
confirmValueChange = { value ->
|
||||
if (value == SwipeToDismissBoxValue.EndToStart) {
|
||||
isRemoved = true
|
||||
|
@ -723,6 +853,12 @@ fun SwipeToDismissListItems(
|
|||
positionalThreshold = { it * .5f }
|
||||
)
|
||||
|
||||
if (dismissState.currentValue != SwipeToDismissBoxValue.Settled) {
|
||||
LaunchedEffect(Unit) {
|
||||
dismissState.snapTo(SwipeToDismissBoxValue.Settled)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = isRemoved) {
|
||||
if (isRemoved) {
|
||||
delay(animationDuration.toLong())
|
||||
|
@ -752,6 +888,35 @@ fun SwipeToDismissListItems(
|
|||
}
|
||||
}
|
||||
|
||||
private fun ShowMoveToBinSnackbar(
|
||||
objectId: Id,
|
||||
message: String,
|
||||
undo: String,
|
||||
scope: CoroutineScope,
|
||||
snackBarHostState: SnackbarHostState,
|
||||
undoMoveToBin: (Id) -> Unit,
|
||||
onDismissSnackbar: () -> Unit
|
||||
) {
|
||||
scope.launch {
|
||||
val result = snackBarHostState
|
||||
.showSnackbar(
|
||||
message = message,
|
||||
actionLabel = undo,
|
||||
duration = SnackbarDuration.Short,
|
||||
withDismissAction = true
|
||||
)
|
||||
when (result) {
|
||||
SnackbarResult.ActionPerformed -> {
|
||||
undoMoveToBin(objectId)
|
||||
}
|
||||
|
||||
SnackbarResult.Dismissed -> {
|
||||
onDismissSnackbar()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DefaultPreviews
|
||||
@Composable
|
||||
fun MtSwipeToDismissListItems() {
|
||||
|
|
|
@ -101,14 +101,8 @@ fun AllContentTopBarContainer(
|
|||
) {
|
||||
AllContentMenu(
|
||||
uiMenuState = uiMenuState,
|
||||
onModeClick = {
|
||||
onModeClick(it)
|
||||
isMenuExpanded = false
|
||||
},
|
||||
onSortClick = {
|
||||
onSortClick(it)
|
||||
isMenuExpanded = false
|
||||
},
|
||||
onModeClick = onModeClick,
|
||||
onSortClick = onSortClick,
|
||||
onBinClick = onBinClick
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue