mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2856 All content | Object types, part 1 (#1624)
This commit is contained in:
parent
dd91489638
commit
f71f86a054
16 changed files with 335 additions and 165 deletions
|
@ -2,17 +2,22 @@ package com.anytypeio.anytype.feature_allcontent.models
|
|||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.anytypeio.anytype.core_models.DVSortType
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Key
|
||||
import com.anytypeio.anytype.core_models.MarketplaceObjectTypeIds
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.Relations.SOURCE_OBJECT
|
||||
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.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.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.getProperName
|
||||
import com.anytypeio.anytype.presentation.objects.getProperType
|
||||
|
@ -68,22 +73,16 @@ sealed class AllContentSort {
|
|||
|
||||
//TITLE
|
||||
sealed class UiTitleState {
|
||||
data object Hidden : UiTitleState()
|
||||
data object AllContent : UiTitleState()
|
||||
data object OnlyUnlinked : UiTitleState()
|
||||
}
|
||||
|
||||
// TABS
|
||||
@Immutable
|
||||
sealed class UiTabsState {
|
||||
data object Hidden : UiTabsState()
|
||||
|
||||
@Immutable
|
||||
data class Default(
|
||||
val tabs: List<AllContentTab>,
|
||||
val selectedTab: AllContentTab
|
||||
) : UiTabsState()
|
||||
}
|
||||
data class UiTabsState(
|
||||
val tabs: List<AllContentTab> = AllContentTab.entries,
|
||||
val selectedTab: AllContentTab = DEFAULT_INITIAL_TAB
|
||||
)
|
||||
|
||||
// CONTENT
|
||||
sealed class UiContentState {
|
||||
|
@ -122,6 +121,17 @@ sealed class UiContentItem {
|
|||
val createdDate: Long = 0L,
|
||||
) : UiContentItem()
|
||||
|
||||
data class Type(
|
||||
override val id: Id,
|
||||
val name: String,
|
||||
val icon: ObjectIcon? = null,
|
||||
val sourceObject: Id? = null,
|
||||
val uniqueKey: Key? = null,
|
||||
val readOnly: Boolean = true,
|
||||
val editable: Boolean = true,
|
||||
val dependentData: DependentData = DependentData.None
|
||||
) : UiContentItem()
|
||||
|
||||
companion object {
|
||||
const val TODAY_ID = "TodayId"
|
||||
const val YESTERDAY_ID = "YesterdayId"
|
||||
|
@ -209,4 +219,30 @@ fun ObjectWrapper.Basic.toAllContentItem(
|
|||
createdDate = DateParser.parse(obj.getValue(Relations.CREATED_DATE)) ?: 0L
|
||||
)
|
||||
}
|
||||
|
||||
fun List<ObjectWrapper.Basic>.toUiContentTypes(
|
||||
urlBuilder: UrlBuilder
|
||||
): List<UiContentItem.Type> {
|
||||
return map { it.toAllContentType(urlBuilder) }
|
||||
}
|
||||
|
||||
fun ObjectWrapper.Basic.toAllContentType(
|
||||
urlBuilder: UrlBuilder,
|
||||
): UiContentItem.Type {
|
||||
val obj = this
|
||||
val layout = layout ?: ObjectType.Layout.BASIC
|
||||
return UiContentItem.Type(
|
||||
id = obj.id,
|
||||
name = obj.name.orEmpty(),
|
||||
icon = ObjectIcon.from(
|
||||
obj = obj,
|
||||
layout = layout,
|
||||
builder = urlBuilder
|
||||
),
|
||||
sourceObject = obj.map[SOURCE_OBJECT]?.toString(),
|
||||
uniqueKey = obj.uniqueKey,
|
||||
readOnly = obj.restrictions.contains(ObjectRestriction.DELETE),
|
||||
editable = !obj.restrictions.contains(ObjectRestriction.DETAILS)
|
||||
)
|
||||
}
|
||||
//endregion
|
|
@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.DVFilterCondition
|
|||
import com.anytypeio.anytype.core_models.DVSort
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
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
|
||||
|
@ -116,8 +117,38 @@ fun AllContentTab.filtersForSubscribe(
|
|||
val sorts = listOf(activeSort.toDVSort())
|
||||
return filters to sorts
|
||||
}
|
||||
|
||||
AllContentTab.TYPES -> TODO()
|
||||
AllContentTab.TYPES -> {
|
||||
val filters = buildList {
|
||||
addAll(buildDeletedFilter())
|
||||
add(buildSpaceIdFilter(spaces))
|
||||
if (limitedObjectIds.isNotEmpty()) {
|
||||
add(buildLimitedObjectIdsFilter(limitedObjectIds = limitedObjectIds))
|
||||
}
|
||||
add(
|
||||
DVFilter(
|
||||
relation = Relations.LAYOUT,
|
||||
condition = DVFilterCondition.NOT_EQUAL,
|
||||
value = ObjectType.Layout.PARTICIPANT.code.toDouble()
|
||||
)
|
||||
)
|
||||
add(
|
||||
DVFilter(
|
||||
relation = Relations.LAYOUT,
|
||||
condition = DVFilterCondition.EQUAL,
|
||||
value = ObjectType.Layout.OBJECT_TYPE.code.toDouble()
|
||||
)
|
||||
)
|
||||
add(
|
||||
DVFilter(
|
||||
relation = Relations.UNIQUE_KEY,
|
||||
condition = DVFilterCondition.NOT_EQUAL,
|
||||
value = ObjectTypeIds.CHAT_DERIVED
|
||||
)
|
||||
)
|
||||
}
|
||||
val sorts = listOf(activeSort.toDVSort())
|
||||
return filters to sorts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,24 +156,14 @@ fun AllContentTab.filtersForSearch(
|
|||
spaces: List<Id>
|
||||
): List<DVFilter> {
|
||||
val tab = this
|
||||
when (this) {
|
||||
AllContentTab.PAGES,
|
||||
AllContentTab.LISTS,
|
||||
AllContentTab.FILES,
|
||||
AllContentTab.MEDIA,
|
||||
AllContentTab.BOOKMARKS -> {
|
||||
val filters = buildList {
|
||||
addAll(buildDeletedFilter())
|
||||
add(buildSpaceIdFilter(spaces))
|
||||
if (tab == AllContentTab.PAGES) {
|
||||
add(buildTemplateFilter())
|
||||
}
|
||||
}
|
||||
return filters
|
||||
val filters = buildList {
|
||||
addAll(buildDeletedFilter())
|
||||
add(buildSpaceIdFilter(spaces))
|
||||
if (tab == AllContentTab.PAGES) {
|
||||
add(buildTemplateFilter())
|
||||
}
|
||||
|
||||
AllContentTab.TYPES -> TODO()
|
||||
}
|
||||
return filters
|
||||
}
|
||||
|
||||
private fun buildLayoutFilter(layouts: List<ObjectType.Layout>): DVFilter = DVFilter(
|
||||
|
@ -196,6 +217,11 @@ private fun buildDeletedFilter(): List<DVFilter> {
|
|||
relation = Relations.IS_DELETED,
|
||||
condition = DVFilterCondition.NOT_EQUAL,
|
||||
value = true
|
||||
),
|
||||
DVFilter(
|
||||
relation = Relations.IS_HIDDEN_DISCOVERY,
|
||||
condition = DVFilterCondition.NOT_EQUAL,
|
||||
value = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ 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.toUiContentItems
|
||||
import com.anytypeio.anytype.feature_allcontent.models.toUiContentTypes
|
||||
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
|
||||
import com.anytypeio.anytype.presentation.home.OpenObjectNavigation
|
||||
import com.anytypeio.anytype.presentation.home.navigation
|
||||
|
@ -49,7 +50,6 @@ import kotlinx.coroutines.flow.debounce
|
|||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
@ -79,9 +79,8 @@ class AllContentViewModel(
|
|||
|
||||
private val searchResultIds = MutableStateFlow<List<Id>>(emptyList())
|
||||
private val sortState = MutableStateFlow<AllContentSort>(DEFAULT_INITIAL_SORT)
|
||||
|
||||
val uiTitleState = MutableStateFlow<UiTitleState>(UiTitleState.Hidden)
|
||||
val uiTabsState = MutableStateFlow<UiTabsState>(UiTabsState.Hidden)
|
||||
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 uiContentState = MutableStateFlow<UiContentState>(UiContentState.Idle())
|
||||
|
@ -106,7 +105,7 @@ class AllContentViewModel(
|
|||
*/
|
||||
val canPaginate = MutableStateFlow(false)
|
||||
private var itemsLimit = DEFAULT_SEARCH_LIMIT
|
||||
private val limitUpdateTrigger = MutableStateFlow(0)
|
||||
private val restartSubscription = MutableStateFlow(0L)
|
||||
|
||||
private var shouldScrollToTopItems = false
|
||||
|
||||
|
@ -119,11 +118,6 @@ class AllContentViewModel(
|
|||
}
|
||||
|
||||
private fun setupInitialStateParams() {
|
||||
uiTitleState.value = UiTitleState.AllContent
|
||||
uiTabsState.value = UiTabsState.Default(
|
||||
tabs = AllContentTab.entries,
|
||||
selectedTab = DEFAULT_INITIAL_TAB
|
||||
)
|
||||
viewModelScope.launch {
|
||||
if (vmParams.useHistory) {
|
||||
runCatching {
|
||||
|
@ -132,6 +126,7 @@ class AllContentViewModel(
|
|||
)
|
||||
if (!initialParams.activeSort.isNullOrEmpty()) {
|
||||
sortState.value = initialParams.activeSort.mapRelationKeyToSort()
|
||||
restartSubscription.value++
|
||||
}
|
||||
}.onFailure { e ->
|
||||
Timber.e(e, "Error restoring state")
|
||||
|
@ -146,26 +141,24 @@ class AllContentViewModel(
|
|||
Timber.d("New query: [$query]")
|
||||
if (query.isBlank()) {
|
||||
searchResultIds.value = emptyList()
|
||||
restartSubscription.value++
|
||||
} else {
|
||||
val activeTab = uiTabsState.value
|
||||
if (activeTab is UiTabsState.Default) {
|
||||
resetLimit()
|
||||
val searchParams = createSearchParams(
|
||||
activeTab = activeTab.selectedTab,
|
||||
activeQuery = query
|
||||
)
|
||||
searchObjects(searchParams).process(
|
||||
success = { searchResults ->
|
||||
Timber.d("Search objects by query:[$query], size: : ${searchResults.size}")
|
||||
searchResultIds.value = searchResults.map { it.id }
|
||||
},
|
||||
failure = {
|
||||
Timber.e(it, "Error searching objects by query")
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Timber.w("Unexpected tabs state: $activeTab")
|
||||
}
|
||||
resetLimit()
|
||||
val searchParams = createSearchParams(
|
||||
activeTab = activeTab.selectedTab,
|
||||
activeQuery = query
|
||||
)
|
||||
searchObjects(searchParams).process(
|
||||
success = { searchResults ->
|
||||
Timber.d("Search objects by query:[$query], size: : ${searchResults.size}")
|
||||
searchResultIds.value = searchResults.map { it.id }
|
||||
restartSubscription.value++
|
||||
},
|
||||
failure = {
|
||||
Timber.e(it, "Error searching objects by query")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,53 +167,46 @@ class AllContentViewModel(
|
|||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun setupUiStateFlow() {
|
||||
viewModelScope.launch {
|
||||
combine(
|
||||
uiTitleState,
|
||||
uiTabsState.filterIsInstance<UiTabsState.Default>(),
|
||||
sortState,
|
||||
searchResultIds,
|
||||
limitUpdateTrigger
|
||||
) { mode, tab, sort, limitedObjectIds, _ ->
|
||||
Result(mode, tab, sort, limitedObjectIds)
|
||||
restartSubscription.flatMapLatest {
|
||||
loadData()
|
||||
}.collect { items ->
|
||||
uiItemsState.value = items
|
||||
}
|
||||
.flatMapLatest { currentState ->
|
||||
Timber.d("New params:$currentState, restart subscription")
|
||||
loadData(currentState)
|
||||
}.collect {
|
||||
uiItemsState.value = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscriptionId() = "all_content_subscription_${vmParams.spaceId.id}"
|
||||
//todo discuss with someone
|
||||
private fun loadData(): Flow<List<UiContentItem>> = flow {
|
||||
|
||||
private fun loadData(
|
||||
result: Result
|
||||
): Flow<List<UiContentItem>> = flow {
|
||||
|
||||
if (itemsLimit == DEFAULT_SEARCH_LIMIT) {
|
||||
uiContentState.value = UiContentState.InitLoading
|
||||
uiContentState.value = if (itemsLimit == DEFAULT_SEARCH_LIMIT) {
|
||||
UiContentState.InitLoading
|
||||
} else {
|
||||
uiContentState.value = UiContentState.Paging
|
||||
UiContentState.Paging
|
||||
}
|
||||
|
||||
val activeTab = uiTabsState.value.selectedTab
|
||||
val activeSort = sortState.value
|
||||
|
||||
val searchParams = createSubscriptionParams(
|
||||
activeTab = result.tab.selectedTab,
|
||||
activeSort = result.sort,
|
||||
limitedObjectIds = result.limitedObjectIds,
|
||||
activeTab = activeTab,
|
||||
activeSort = activeSort,
|
||||
limitedObjectIds = searchResultIds.value,
|
||||
limit = itemsLimit,
|
||||
subscriptionId = subscriptionId(),
|
||||
spaceId = vmParams.spaceId.id,
|
||||
activeMode = result.mode
|
||||
activeMode = uiTitleState.value
|
||||
)
|
||||
|
||||
Timber.d("Restart subscription: with params: $searchParams")
|
||||
|
||||
val dataFlow = storelessSubscriptionContainer.subscribe(searchParams)
|
||||
emitAll(
|
||||
dataFlow.map { objWrappers ->
|
||||
canPaginate.value = objWrappers.size == itemsLimit
|
||||
val items = mapToUiContentItems(
|
||||
objectWrappers = objWrappers,
|
||||
activeSort = result.sort
|
||||
activeSort = activeSort,
|
||||
activeTab = activeTab
|
||||
)
|
||||
uiContentState.value = if (items.isEmpty()) {
|
||||
UiContentState.Empty
|
||||
|
@ -241,22 +227,32 @@ class AllContentViewModel(
|
|||
|
||||
private suspend fun mapToUiContentItems(
|
||||
objectWrappers: List<ObjectWrapper.Basic>,
|
||||
activeSort: AllContentSort
|
||||
activeSort: AllContentSort,
|
||||
activeTab: AllContentTab
|
||||
): List<UiContentItem> {
|
||||
val items = objectWrappers.toUiContentItems(
|
||||
space = vmParams.spaceId,
|
||||
urlBuilder = urlBuilder,
|
||||
objectTypes = storeOfObjectTypes.getAll()
|
||||
)
|
||||
return when (activeSort) {
|
||||
is AllContentSort.ByDateCreated -> {
|
||||
groupItemsByDate(items = items, isSortByDateCreated = true)
|
||||
}
|
||||
is AllContentSort.ByDateUpdated -> {
|
||||
groupItemsByDate(items = items, isSortByDateCreated = false)
|
||||
}
|
||||
is AllContentSort.ByName -> {
|
||||
items
|
||||
if (activeTab == AllContentTab.TYPES) {
|
||||
val items = objectWrappers.toUiContentTypes(
|
||||
urlBuilder = urlBuilder
|
||||
)
|
||||
return items
|
||||
} else {
|
||||
val items = objectWrappers.toUiContentItems(
|
||||
space = vmParams.spaceId,
|
||||
urlBuilder = urlBuilder,
|
||||
objectTypes = storeOfObjectTypes.getAll()
|
||||
)
|
||||
return when (activeSort) {
|
||||
is AllContentSort.ByDateCreated -> {
|
||||
groupItemsByDate(items = items, isSortByDateCreated = true)
|
||||
}
|
||||
|
||||
is AllContentSort.ByDateUpdated -> {
|
||||
groupItemsByDate(items = items, isSortByDateCreated = false)
|
||||
}
|
||||
|
||||
is AllContentSort.ByName -> {
|
||||
items
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -342,26 +338,39 @@ class AllContentViewModel(
|
|||
viewModelScope.launch {
|
||||
combine(
|
||||
uiTitleState,
|
||||
sortState
|
||||
) { mode, sort ->
|
||||
mode to sort
|
||||
}.collectLatest { (mode, sort) ->
|
||||
val uiMode = listOf(
|
||||
AllContentMenuMode.AllContent(isSelected = mode == UiTitleState.AllContent),
|
||||
AllContentMenuMode.Unlinked(isSelected = mode == UiTitleState.OnlyUnlinked)
|
||||
)
|
||||
val container = MenuSortsItem.Container(sort = sort)
|
||||
val uiSorts = listOf(
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByName(isSelected = sort is AllContentSort.ByName)
|
||||
),
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByDateUpdated(isSelected = sort is AllContentSort.ByDateUpdated)
|
||||
),
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByDateCreated(isSelected = sort is AllContentSort.ByDateCreated)
|
||||
sortState,
|
||||
uiTabsState
|
||||
) { mode, sort, tabs ->
|
||||
Triple(mode, sort, tabs)
|
||||
}.collectLatest { (mode, sort, tabs) ->
|
||||
val uiMode = if (tabs.selectedTab == AllContentTab.TYPES) {
|
||||
listOf()
|
||||
} else {
|
||||
listOf(
|
||||
AllContentMenuMode.AllContent(isSelected = mode == UiTitleState.AllContent),
|
||||
AllContentMenuMode.Unlinked(isSelected = mode == UiTitleState.OnlyUnlinked)
|
||||
)
|
||||
)
|
||||
}
|
||||
val container = MenuSortsItem.Container(sort = sort)
|
||||
val uiSorts = if (tabs.selectedTab == AllContentTab.TYPES) {
|
||||
listOf(
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByName(isSelected = sort is AllContentSort.ByName)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
listOf(
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByName(isSelected = sort is AllContentSort.ByName)
|
||||
),
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByDateUpdated(isSelected = sort is AllContentSort.ByDateUpdated)
|
||||
),
|
||||
MenuSortsItem.Sort(
|
||||
sort = AllContentSort.ByDateCreated(isSelected = sort is AllContentSort.ByDateCreated)
|
||||
)
|
||||
)
|
||||
}
|
||||
val uiSortTypes = listOf(
|
||||
MenuSortsItem.SortType(
|
||||
sort = sort,
|
||||
|
@ -387,18 +396,15 @@ class AllContentViewModel(
|
|||
fun onTabClicked(tab: AllContentTab) {
|
||||
Timber.d("onTabClicked: $tab")
|
||||
if (tab == AllContentTab.TYPES) {
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.SendToast("Not implemented yet"))
|
||||
}
|
||||
return
|
||||
sortState.value = AllContentSort.ByName()
|
||||
userInput.value = DEFAULT_QUERY
|
||||
uiTitleState.value = UiTitleState.AllContent
|
||||
}
|
||||
shouldScrollToTopItems = true
|
||||
resetLimit()
|
||||
uiItemsState.value = emptyList()
|
||||
uiTabsState.value = UiTabsState.Default(
|
||||
tabs = AllContentTab.entries,
|
||||
selectedTab = tab
|
||||
)
|
||||
uiTabsState.value = uiTabsState.value.copy(selectedTab = tab)
|
||||
restartSubscription.value++
|
||||
}
|
||||
|
||||
fun onAllContentModeClicked(mode: AllContentMenuMode) {
|
||||
|
@ -409,14 +415,27 @@ class AllContentViewModel(
|
|||
is AllContentMenuMode.AllContent -> UiTitleState.AllContent
|
||||
is AllContentMenuMode.Unlinked -> UiTitleState.OnlyUnlinked
|
||||
}
|
||||
restartSubscription.value++
|
||||
}
|
||||
|
||||
fun onSortClicked(sort: AllContentSort) {
|
||||
Timber.d("onSortClicked: $sort")
|
||||
val newSort = when (sort) {
|
||||
is AllContentSort.ByDateCreated -> {
|
||||
sort.copy(isSelected = true)
|
||||
}
|
||||
is AllContentSort.ByDateUpdated -> {
|
||||
sort.copy(isSelected = true)
|
||||
}
|
||||
is AllContentSort.ByName -> {
|
||||
sort.copy(isSelected = true)
|
||||
}
|
||||
}
|
||||
shouldScrollToTopItems = true
|
||||
uiItemsState.value = emptyList()
|
||||
sortState.value = sort
|
||||
proceedWithSortSaving(sort)
|
||||
sortState.value = newSort
|
||||
proceedWithSortSaving(newSort)
|
||||
restartSubscription.value++
|
||||
}
|
||||
|
||||
private fun proceedWithSortSaving(sort: AllContentSort) {
|
||||
|
@ -480,6 +499,13 @@ class AllContentViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onTypeClicked(item: UiContentItem.Type) {
|
||||
Timber.d("onTypeClicked: ${item.id}")
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.OpenTypeEditing(item))
|
||||
}
|
||||
}
|
||||
|
||||
fun onStop() {
|
||||
Timber.d("onStop")
|
||||
viewModelScope.launch {
|
||||
|
@ -494,7 +520,7 @@ class AllContentViewModel(
|
|||
Timber.d("Update limit, canPaginate: ${canPaginate.value} uiContentState: ${uiContentState.value}")
|
||||
if (canPaginate.value && uiContentState.value is UiContentState.Idle) {
|
||||
itemsLimit += DEFAULT_SEARCH_LIMIT
|
||||
limitUpdateTrigger.value++
|
||||
restartSubscription.value++
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -509,23 +535,19 @@ class AllContentViewModel(
|
|||
itemsLimit = DEFAULT_SEARCH_LIMIT
|
||||
}
|
||||
|
||||
private fun subscriptionId() = "all_content_subscription_${vmParams.spaceId.id}"
|
||||
|
||||
data class VmParams(
|
||||
val spaceId: SpaceId,
|
||||
val useHistory: Boolean = true
|
||||
)
|
||||
|
||||
internal data class Result(
|
||||
val mode: UiTitleState,
|
||||
val tab: UiTabsState.Default,
|
||||
val sort: AllContentSort,
|
||||
val limitedObjectIds: List<String>
|
||||
)
|
||||
|
||||
sealed class Command {
|
||||
data class NavigateToEditor(val id: Id, val space: Id) : Command()
|
||||
data class NavigateToSetOrCollection(val id: Id, val space: Id) : Command()
|
||||
data class NavigateToBin(val space: Id) : Command()
|
||||
data class SendToast(val message: String) : Command()
|
||||
data class OpenTypeEditing(val item: UiContentItem.Type) : Command()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -533,6 +555,7 @@ class AllContentViewModel(
|
|||
|
||||
//INITIAL STATE
|
||||
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 = ""
|
||||
|
|
|
@ -56,7 +56,9 @@ fun AllContentMenu(
|
|||
)
|
||||
Divider(0.5.dp)
|
||||
}
|
||||
Divider(7.5.dp)
|
||||
if (uiMenuState.mode.isNotEmpty()) {
|
||||
Divider(7.5.dp)
|
||||
}
|
||||
SortingBox(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
|
|
|
@ -55,6 +55,7 @@ import com.anytypeio.anytype.core_ui.common.DefaultPreviews
|
|||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Regular
|
||||
import com.anytypeio.anytype.core_ui.views.PreviewTitle1Medium
|
||||
import com.anytypeio.anytype.core_ui.views.PreviewTitle2Medium
|
||||
import com.anytypeio.anytype.core_ui.views.Relations3
|
||||
import com.anytypeio.anytype.core_ui.views.UXBody
|
||||
|
@ -94,6 +95,7 @@ fun AllContentWrapperScreen(
|
|||
onModeClick: (AllContentMenuMode) -> Unit,
|
||||
onSortClick: (AllContentSort) -> Unit,
|
||||
onItemClicked: (UiContentItem.Item) -> Unit,
|
||||
onTypeClicked: (UiContentItem.Type) -> Unit,
|
||||
onBinClick: () -> Unit,
|
||||
canPaginate: Boolean,
|
||||
onUpdateLimitSearch: () -> Unit,
|
||||
|
@ -131,7 +133,8 @@ fun AllContentWrapperScreen(
|
|||
onBinClick = onBinClick,
|
||||
uiItemsState = uiItemsState,
|
||||
lazyListState = lazyListState,
|
||||
uiContentState = uiContentState
|
||||
uiContentState = uiContentState,
|
||||
onTypeClicked = onTypeClicked
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -147,6 +150,7 @@ fun AllContentMainScreen(
|
|||
onModeClick: (AllContentMenuMode) -> Unit,
|
||||
onSortClick: (AllContentSort) -> Unit,
|
||||
onItemClicked: (UiContentItem.Item) -> Unit,
|
||||
onTypeClicked: (UiContentItem.Type) -> Unit,
|
||||
onBinClick: () -> Unit,
|
||||
lazyListState: LazyListState,
|
||||
uiContentState: UiContentState
|
||||
|
@ -169,20 +173,15 @@ fun AllContentMainScreen(
|
|||
else
|
||||
Modifier.fillMaxWidth()
|
||||
) {
|
||||
if (uiTitleState !is UiTitleState.Hidden) {
|
||||
AllContentTopBarContainer(
|
||||
titleState = uiTitleState,
|
||||
uiMenuState = uiMenuState,
|
||||
onSortClick = onSortClick,
|
||||
onModeClick = onModeClick,
|
||||
onBinClick = onBinClick
|
||||
)
|
||||
}
|
||||
|
||||
if (uiTabsState is UiTabsState.Default) {
|
||||
AllContentTabs(tabsViewState = uiTabsState) { tab ->
|
||||
onTabClick(tab)
|
||||
}
|
||||
AllContentTopBarContainer(
|
||||
titleState = uiTitleState,
|
||||
uiMenuState = uiMenuState,
|
||||
onSortClick = onSortClick,
|
||||
onModeClick = onModeClick,
|
||||
onBinClick = onBinClick
|
||||
)
|
||||
AllContentTabs(tabsViewState = uiTabsState) { tab ->
|
||||
onTabClick(tab)
|
||||
}
|
||||
Spacer(modifier = Modifier.size(10.dp))
|
||||
AllContentSearchBar(onQueryChanged = {
|
||||
|
@ -231,6 +230,7 @@ fun AllContentMainScreen(
|
|||
ContentItems(
|
||||
uiItemsState = uiItemsState,
|
||||
onItemClicked = onItemClicked,
|
||||
onTypeClicked = onTypeClicked,
|
||||
uiContentState = uiContentState,
|
||||
lazyListState = lazyListState
|
||||
)
|
||||
|
@ -245,6 +245,7 @@ fun AllContentMainScreen(
|
|||
private fun ContentItems(
|
||||
uiItemsState: List<UiContentItem>,
|
||||
onItemClicked: (UiContentItem.Item) -> Unit,
|
||||
onTypeClicked: (UiContentItem.Type) -> Unit,
|
||||
uiContentState: UiContentState,
|
||||
lazyListState: LazyListState
|
||||
) {
|
||||
|
@ -261,6 +262,7 @@ private fun ContentItems(
|
|||
when (uiItemsState[index]) {
|
||||
is UiContentItem.Group -> "group"
|
||||
is UiContentItem.Item -> "item"
|
||||
is UiContentItem.Type -> "type"
|
||||
}
|
||||
}
|
||||
) { index ->
|
||||
|
@ -296,6 +298,19 @@ private fun ContentItems(
|
|||
item = item
|
||||
)
|
||||
}
|
||||
|
||||
is UiContentItem.Type -> {
|
||||
Type(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.bottomBorder()
|
||||
.animateItem()
|
||||
.clickable {
|
||||
onTypeClicked(item)
|
||||
},
|
||||
item = item
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uiContentState is UiContentState.Paging) {
|
||||
|
@ -351,7 +366,7 @@ fun PreviewMainScreen() {
|
|||
AllContentMainScreen(
|
||||
uiItemsState = emptyList(),
|
||||
uiTitleState = UiTitleState.AllContent,
|
||||
uiTabsState = UiTabsState.Default(tabs = listOf(AllContentTab.PAGES, AllContentTab.TYPES, AllContentTab.LISTS), selectedTab = AllContentTab.LISTS),
|
||||
uiTabsState = UiTabsState(tabs = listOf(AllContentTab.PAGES, AllContentTab.TYPES, AllContentTab.LISTS), selectedTab = AllContentTab.LISTS),
|
||||
uiMenuState = UiMenuState.Hidden,
|
||||
onTabClick = {},
|
||||
onQueryChanged = {},
|
||||
|
@ -360,7 +375,8 @@ fun PreviewMainScreen() {
|
|||
onItemClicked = {},
|
||||
onBinClick = {},
|
||||
lazyListState = rememberLazyListState(),
|
||||
uiContentState = UiContentState.Error("Error message")
|
||||
uiContentState = UiContentState.Error("Error message"),
|
||||
onTypeClicked = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -421,9 +437,37 @@ private fun Item(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Type(
|
||||
modifier: Modifier,
|
||||
item: UiContentItem.Type
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
verticalAlignment = CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(start = 0.dp, top = 14.dp, end = 14.dp, bottom = 14.dp)
|
||||
.wrapContentSize()
|
||||
) {
|
||||
AllContentItemIcon(icon = item.icon, modifier = Modifier, iconSize = 24.dp)
|
||||
}
|
||||
val name = item.name.trim().ifBlank { stringResource(R.string.untitled) }
|
||||
|
||||
Text(
|
||||
text = name,
|
||||
style = PreviewTitle1Medium,
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AllContentItemIcon(
|
||||
icon: ObjectIcon,
|
||||
icon: ObjectIcon?,
|
||||
modifier: Modifier,
|
||||
iconSize: Dp = 48.dp,
|
||||
onTaskIconClicked: (Boolean) -> Unit = {},
|
||||
|
|
|
@ -160,7 +160,6 @@ private fun AllContentTopBarContainerPreview() {
|
|||
@Composable
|
||||
fun AllContentTitle(state: UiTitleState) {
|
||||
when (state) {
|
||||
UiTitleState.Hidden -> return
|
||||
UiTitleState.AllContent -> {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
|
@ -202,7 +201,7 @@ fun AllContentMenuButton(onClick: () -> Unit) {
|
|||
//region AllContentTabs
|
||||
@Composable
|
||||
fun AllContentTabs(
|
||||
tabsViewState: UiTabsState.Default,
|
||||
tabsViewState: UiTabsState,
|
||||
onClick: (AllContentTab) -> Unit
|
||||
) {
|
||||
val scrollState = rememberLazyListState()
|
||||
|
@ -270,7 +269,7 @@ private fun getTabText(tab: AllContentTab): String {
|
|||
@Composable
|
||||
private fun AllContentTabsPreview() {
|
||||
AllContentTabs(
|
||||
tabsViewState = UiTabsState.Default(
|
||||
tabsViewState = UiTabsState(
|
||||
tabs = listOf(
|
||||
AllContentTab.PAGES,
|
||||
AllContentTab.FILES,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue