Implement androidx Paging and unify TimeLineViewModel state
This commit is contained in:
parent
16ed0ef05e
commit
36f768044a
@ -3,10 +3,10 @@ package com.readrops.app.compose.timelime
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
@ -31,6 +31,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import cafe.adriel.voyager.navigator.tab.Tab
|
||||
@ -48,27 +49,22 @@ object TimelineTab : Tab {
|
||||
|
||||
override val options: TabOptions
|
||||
@Composable
|
||||
get() {
|
||||
return TabOptions(
|
||||
index = 1u,
|
||||
title = "Timeline",
|
||||
)
|
||||
}
|
||||
get() = TabOptions(
|
||||
index = 1u,
|
||||
title = "Timeline",
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val viewModel = getViewModel<TimelineViewModel>()
|
||||
|
||||
val state by viewModel.timelineState.collectAsStateWithLifecycle()
|
||||
val drawerState by viewModel.drawerState.collectAsStateWithLifecycle()
|
||||
val isRefreshing by viewModel.isRefreshing.collectAsStateWithLifecycle()
|
||||
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
val scrollState = rememberLazyListState()
|
||||
val swipeState = rememberSwipeRefreshState(isRefreshing)
|
||||
val drawerUIState = rememberDrawerState(
|
||||
val swipeState = rememberSwipeRefreshState(state.isRefreshing)
|
||||
val drawerState = rememberDrawerState(
|
||||
initialValue = DrawerValue.Closed,
|
||||
confirmStateChange = {
|
||||
if (it == DrawerValue.Closed) {
|
||||
@ -82,23 +78,23 @@ object TimelineTab : Tab {
|
||||
)
|
||||
|
||||
BackHandler(
|
||||
enabled = drawerState.isOpen,
|
||||
enabled = state.isDrawerOpen,
|
||||
onBack = { viewModel.closeDrawer() }
|
||||
)
|
||||
|
||||
LaunchedEffect(drawerState.isOpen) {
|
||||
if (drawerState.isOpen) {
|
||||
drawerUIState.open()
|
||||
LaunchedEffect(state.isDrawerOpen) {
|
||||
if (state.isDrawerOpen) {
|
||||
drawerState.open()
|
||||
} else {
|
||||
drawerUIState.close()
|
||||
drawerState.close()
|
||||
}
|
||||
}
|
||||
|
||||
ModalNavigationDrawer(
|
||||
drawerState = drawerUIState,
|
||||
drawerState = drawerState,
|
||||
drawerContent = {
|
||||
TimelineDrawer(
|
||||
state = drawerState,
|
||||
state = state,
|
||||
onClickDefaultItem = {
|
||||
viewModel.updateDrawerDefaultItem(it)
|
||||
},
|
||||
@ -156,8 +152,8 @@ object TimelineTab : Tab {
|
||||
onRefresh = { viewModel.refreshTimeline() },
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
) {
|
||||
when (state) {
|
||||
is TimelineState.Loading -> {
|
||||
when (val itemState = state.items) {
|
||||
is ItemState.Loading -> {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
@ -167,34 +163,28 @@ object TimelineTab : Tab {
|
||||
}
|
||||
}
|
||||
|
||||
is TimelineState.Error -> {
|
||||
is ItemState.Error -> TODO()
|
||||
is ItemState.Loaded -> {
|
||||
val items = itemState.items.collectAsLazyPagingItems()
|
||||
|
||||
}
|
||||
|
||||
is TimelineState.Loaded -> {
|
||||
val items = (state as TimelineState.Loaded).items
|
||||
|
||||
if (items.isNotEmpty()) {
|
||||
LazyColumn(
|
||||
state = scrollState,
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.shortSpacing)
|
||||
) {
|
||||
items(
|
||||
items = items,
|
||||
key = { it.item.id },
|
||||
contentType = { "item_with_feed" }
|
||||
) { itemWithFeed ->
|
||||
TimelineItem(
|
||||
itemWithFeed = itemWithFeed,
|
||||
onClick = { navigator.push(ItemScreen()) },
|
||||
onFavorite = {},
|
||||
onReadLater = {},
|
||||
onShare = {},
|
||||
)
|
||||
}
|
||||
LazyColumn(
|
||||
state = scrollState,
|
||||
contentPadding = PaddingValues(vertical = MaterialTheme.spacing.shortSpacing),
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.shortSpacing)
|
||||
) {
|
||||
items(
|
||||
count = items.itemCount,
|
||||
key = { items[it]!!.item.id },
|
||||
contentType = { "item_with_feed" }
|
||||
) { itemCount ->
|
||||
TimelineItem(
|
||||
itemWithFeed = items[itemCount]!!,
|
||||
onClick = { navigator.push(ItemScreen()) },
|
||||
onFavorite = {},
|
||||
onReadLater = {},
|
||||
onShare = {},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
NoItemPlaceholder()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,23 +2,26 @@ package com.readrops.app.compose.timelime
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import com.readrops.app.compose.base.TabViewModel
|
||||
import com.readrops.app.compose.repositories.GetFoldersWithFeeds
|
||||
import com.readrops.app.compose.timelime.drawer.DrawerDefaultItemsSelection
|
||||
import com.readrops.db.Database
|
||||
import com.readrops.db.entities.Feed
|
||||
import com.readrops.db.entities.Folder
|
||||
import com.readrops.db.filters.FilterType
|
||||
import com.readrops.db.pojo.ItemWithFeed
|
||||
import com.readrops.db.queries.ItemsQueryBuilder
|
||||
import com.readrops.db.queries.QueryFilters
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.consumeAsFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
@ -29,108 +32,128 @@ class TimelineViewModel(
|
||||
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
) : TabViewModel(database) {
|
||||
|
||||
private val _timelineState = MutableStateFlow<TimelineState>(TimelineState.Loading)
|
||||
private val _timelineState = MutableStateFlow(TimelineState())
|
||||
val timelineState = _timelineState.asStateFlow()
|
||||
|
||||
private var _isRefreshing = MutableStateFlow(false)
|
||||
val isRefreshing = _isRefreshing.asStateFlow()
|
||||
|
||||
private val _drawerState = MutableStateFlow(DrawerState())
|
||||
val drawerState = _drawerState.asStateFlow()
|
||||
private val filters = MutableStateFlow(_timelineState.value.filters)
|
||||
|
||||
init {
|
||||
viewModelScope.launch(dispatcher) {
|
||||
accountEvent.consumeAsFlow().collectLatest { account ->
|
||||
val query = ItemsQueryBuilder.buildItemsQuery(QueryFilters(accountId = account.id))
|
||||
combine(
|
||||
accountEvent.consumeAsFlow(),
|
||||
filters
|
||||
) { account, filters ->
|
||||
Pair(account, filters)
|
||||
}.collectLatest { (account, filters) ->
|
||||
val query = ItemsQueryBuilder.buildItemsQuery(filters.copy(accountId = account.id))
|
||||
|
||||
val items = async {
|
||||
database.newItemDao().selectAll(query)
|
||||
.catch { _timelineState.value = TimelineState.Error(Exception(it)) }
|
||||
.collect {
|
||||
_timelineState.value = TimelineState.Loaded(it)
|
||||
}
|
||||
}
|
||||
|
||||
val drawer = async {
|
||||
_drawerState.update {
|
||||
it.copy(
|
||||
foldersAndFeeds = getFoldersWithFeeds.get(account.id)
|
||||
_timelineState.update {
|
||||
it.copy(
|
||||
foldersAndFeeds = getFoldersWithFeeds.get(account.id),
|
||||
items = ItemState.Loaded(
|
||||
items = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = 100,
|
||||
prefetchDistance = 150
|
||||
),
|
||||
pagingSourceFactory = {
|
||||
database.newItemDao().selectAll(query)
|
||||
},
|
||||
).flow
|
||||
.cachedIn(viewModelScope)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
awaitAll(items, drawer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshTimeline() {
|
||||
_isRefreshing.value = true
|
||||
_timelineState.update { it.copy(isRefreshing = true) }
|
||||
viewModelScope.launch(dispatcher) {
|
||||
repository?.synchronize(null) {
|
||||
|
||||
}
|
||||
|
||||
_isRefreshing.value = false
|
||||
_timelineState.update { it.copy(isRefreshing = false) }
|
||||
}
|
||||
}
|
||||
|
||||
fun openDrawer() {
|
||||
_drawerState.update { it.copy(isOpen = true) }
|
||||
_timelineState.update { it.copy(isDrawerOpen = true) }
|
||||
}
|
||||
|
||||
fun closeDrawer() {
|
||||
_drawerState.update { it.copy(isOpen = false) }
|
||||
_timelineState.update { it.copy(isDrawerOpen = false) }
|
||||
}
|
||||
|
||||
fun updateDrawerDefaultItem(selection: DrawerDefaultItemsSelection) {
|
||||
_drawerState.update {
|
||||
fun updateDrawerDefaultItem(selection: FilterType) {
|
||||
_timelineState.update {
|
||||
it.copy(
|
||||
isOpen = false,
|
||||
selection = selection,
|
||||
selectedFolderId = 0,
|
||||
selectedFeedId = 0,
|
||||
filters = updateFilters {
|
||||
it.filters.copy(
|
||||
filterType = selection
|
||||
)
|
||||
},
|
||||
isDrawerOpen = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateDrawerFolderSelection(folderId: Int) {
|
||||
_drawerState.update {
|
||||
_timelineState.update {
|
||||
it.copy(
|
||||
isOpen = false,
|
||||
selectedFolderId = folderId,
|
||||
selectedFeedId = 0
|
||||
filters = updateFilters {
|
||||
it.filters.copy(
|
||||
filterType = FilterType.FOLDER_FILER,
|
||||
filterFolderId = folderId,
|
||||
filterFeedId = 0
|
||||
)
|
||||
},
|
||||
isDrawerOpen = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateDrawerFeedSelection(feedId: Int) {
|
||||
_drawerState.update {
|
||||
_timelineState.update {
|
||||
it.copy(
|
||||
isOpen = false,
|
||||
selectedFeedId = feedId,
|
||||
selectedFolderId = 0
|
||||
filters = updateFilters {
|
||||
it.filters.copy(
|
||||
filterType = FilterType.FEED_FILTER,
|
||||
filterFeedId = feedId,
|
||||
filterFolderId = 0
|
||||
)
|
||||
},
|
||||
isDrawerOpen = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class TimelineState {
|
||||
object Loading : TimelineState()
|
||||
private fun updateFilters(block: () -> QueryFilters): QueryFilters {
|
||||
val filter = block()
|
||||
filters.update { filter }
|
||||
|
||||
@Immutable
|
||||
data class Error(val exception: Exception) : TimelineState()
|
||||
|
||||
@Immutable
|
||||
data class Loaded(val items: List<ItemWithFeed>) : TimelineState()
|
||||
return filter
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class DrawerState(
|
||||
val isOpen: Boolean = false,
|
||||
val selection: DrawerDefaultItemsSelection = DrawerDefaultItemsSelection.ARTICLES,
|
||||
val selectedFolderId: Int = 0,
|
||||
val selectedFeedId: Int = 0,
|
||||
val foldersAndFeeds: Map<Folder?, List<Feed>> = emptyMap()
|
||||
data class TimelineState(
|
||||
val isRefreshing: Boolean = false,
|
||||
val isDrawerOpen: Boolean = false,
|
||||
val filters: QueryFilters = QueryFilters(),
|
||||
val foldersAndFeeds: Map<Folder?, List<Feed>> = emptyMap(),
|
||||
val items: ItemState = ItemState.Loading
|
||||
)
|
||||
|
||||
sealed class ItemState {
|
||||
@Immutable
|
||||
object Loading : ItemState()
|
||||
|
||||
@Immutable
|
||||
data class Error(val exception: Exception) : ItemState()
|
||||
|
||||
@Immutable
|
||||
data class Loaded(val items: Flow<PagingData<ItemWithFeed>>) : ItemState()
|
||||
}
|
||||
|
@ -23,20 +23,14 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.AsyncImage
|
||||
import com.readrops.app.compose.R
|
||||
import com.readrops.app.compose.timelime.DrawerState
|
||||
import com.readrops.app.compose.timelime.TimelineState
|
||||
import com.readrops.app.compose.util.theme.spacing
|
||||
|
||||
enum class DrawerDefaultItemsSelection {
|
||||
ARTICLES,
|
||||
NEW,
|
||||
FAVORITES,
|
||||
READ_LATER
|
||||
}
|
||||
import com.readrops.db.filters.FilterType
|
||||
|
||||
@Composable
|
||||
fun TimelineDrawer(
|
||||
state: DrawerState,
|
||||
onClickDefaultItem: (DrawerDefaultItemsSelection) -> Unit,
|
||||
state: TimelineState,
|
||||
onClickDefaultItem: (FilterType) -> Unit,
|
||||
onFolderClick: (Int) -> Unit,
|
||||
onFeedClick: (Int) -> Unit,
|
||||
) {
|
||||
@ -50,7 +44,7 @@ fun TimelineDrawer(
|
||||
Spacer(modifier = Modifier.size(MaterialTheme.spacing.drawerSpacing))
|
||||
|
||||
DrawerDefaultItems(
|
||||
selectedItem = state.selection,
|
||||
selectedItem = state.filters.filterType,
|
||||
onClick = { onClickDefaultItem(it) }
|
||||
)
|
||||
|
||||
@ -78,10 +72,10 @@ fun TimelineDrawer(
|
||||
badge = {
|
||||
Text(folderEntry.value.sumOf { it.unreadCount }.toString())
|
||||
},
|
||||
selected = state.selectedFolderId == folder.id,
|
||||
selected = state.filters.filterFolderId == folder.id,
|
||||
onClick = { onFolderClick(folder.id) },
|
||||
feeds = folderEntry.value,
|
||||
selectedFeed = state.selectedFeedId,
|
||||
selectedFeed = state.filters.filterFeedId,
|
||||
onFeedClick = { onFeedClick(it) },
|
||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
||||
)
|
||||
@ -106,7 +100,7 @@ fun TimelineDrawer(
|
||||
)
|
||||
},
|
||||
badge = { Text(feed.unreadCount.toString()) },
|
||||
selected = feed.id == state.selectedFeedId,
|
||||
selected = feed.id == state.filters.filterFeedId,
|
||||
onClick = { onFeedClick(feed.id) },
|
||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
||||
)
|
||||
@ -119,8 +113,8 @@ fun TimelineDrawer(
|
||||
|
||||
@Composable
|
||||
fun DrawerDefaultItems(
|
||||
selectedItem: DrawerDefaultItemsSelection,
|
||||
onClick: (DrawerDefaultItemsSelection) -> Unit,
|
||||
selectedItem: FilterType,
|
||||
onClick: (FilterType) -> Unit,
|
||||
) {
|
||||
NavigationDrawerItem(
|
||||
label = { Text("Articles") },
|
||||
@ -130,8 +124,8 @@ fun DrawerDefaultItems(
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
selected = selectedItem == DrawerDefaultItemsSelection.ARTICLES,
|
||||
onClick = { onClick(DrawerDefaultItemsSelection.ARTICLES) },
|
||||
selected = selectedItem == FilterType.NO_FILTER,
|
||||
onClick = { onClick(FilterType.NO_FILTER) },
|
||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
||||
)
|
||||
|
||||
@ -143,8 +137,8 @@ fun DrawerDefaultItems(
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
selected = selectedItem == DrawerDefaultItemsSelection.NEW,
|
||||
onClick = { onClick(DrawerDefaultItemsSelection.NEW) },
|
||||
selected = selectedItem == FilterType.NEW,
|
||||
onClick = { onClick(FilterType.NEW) },
|
||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
||||
)
|
||||
|
||||
@ -156,8 +150,8 @@ fun DrawerDefaultItems(
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
selected = selectedItem == DrawerDefaultItemsSelection.FAVORITES,
|
||||
onClick = { onClick(DrawerDefaultItemsSelection.FAVORITES) },
|
||||
selected = selectedItem == FilterType.STARS_FILTER,
|
||||
onClick = { onClick(FilterType.STARS_FILTER) },
|
||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
||||
)
|
||||
|
||||
@ -169,8 +163,8 @@ fun DrawerDefaultItems(
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
selected = selectedItem == DrawerDefaultItemsSelection.READ_LATER,
|
||||
onClick = { onClick(DrawerDefaultItemsSelection.READ_LATER) },
|
||||
selected = selectedItem == FilterType.READ_IT_LATER_FILTER,
|
||||
onClick = { onClick(FilterType.READ_IT_LATER_FILTER) },
|
||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
||||
)
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ dependencies {
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
implementation "androidx.room:room-rxjava2:$room_version"
|
||||
androidTestImplementation "androidx.room:room-testing:$room_version"
|
||||
implementation "androidx.room:room-paging:$room_version"
|
||||
|
||||
implementation 'com.github.MatrixDev.Roomigrant:RoomigrantLib:0.3.4'
|
||||
kapt 'com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4'
|
||||
@ -98,4 +99,7 @@ dependencies {
|
||||
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
|
||||
|
||||
api "androidx.paging:paging-runtime:3.1.1"
|
||||
api "androidx.paging:paging-compose:1.0.0-alpha18"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import io.reactivex.Completable
|
||||
interface ItemDao : BaseDao<Item> {
|
||||
|
||||
@RawQuery(observedEntities = [Item::class, Folder::class, Feed::class, ItemState::class])
|
||||
fun selectAll(query: SupportSQLiteQuery): DataSource.Factory<Int?, ItemWithFeed>
|
||||
fun selectAll(query: SupportSQLiteQuery): DataSource.Factory<Int, ItemWithFeed>
|
||||
|
||||
@Query("Select * From Item Where id = :itemId")
|
||||
fun select(itemId: Int): Item
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.readrops.db.dao.newdao
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.RawQuery
|
||||
@ -9,13 +10,12 @@ import com.readrops.db.entities.Folder
|
||||
import com.readrops.db.entities.Item
|
||||
import com.readrops.db.entities.ItemState
|
||||
import com.readrops.db.pojo.ItemWithFeed
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class NewItemDao : NewBaseDao<Item> {
|
||||
|
||||
@RawQuery(observedEntities = [Item::class, Feed::class, Folder::class, ItemState::class])
|
||||
abstract fun selectAll(query: SupportSQLiteQuery): Flow<List<ItemWithFeed>>
|
||||
abstract fun selectAll(query: SupportSQLiteQuery): PagingSource<Int, ItemWithFeed>
|
||||
|
||||
@Query("Select count(*) From Item Where feed_id = :feedId And read = 0")
|
||||
abstract fun selectUnreadCount(feedId: Int): Int
|
||||
|
@ -5,5 +5,6 @@ enum class FilterType {
|
||||
FOLDER_FILER,
|
||||
READ_IT_LATER_FILTER,
|
||||
STARS_FILTER,
|
||||
NO_FILTER
|
||||
NO_FILTER,
|
||||
NEW
|
||||
}
|
@ -81,11 +81,11 @@ object ItemsQueryBuilder {
|
||||
|
||||
}
|
||||
|
||||
class QueryFilters(
|
||||
var showReadItems: Boolean = true,
|
||||
var filterFeedId: Int = 0,
|
||||
var filterFolderId: Int = 0,
|
||||
var accountId: Int = 0,
|
||||
var filterType: FilterType = FilterType.NO_FILTER,
|
||||
var sortType: ListSortType = ListSortType.NEWEST_TO_OLDEST,
|
||||
data class QueryFilters(
|
||||
var showReadItems: Boolean = true,
|
||||
var filterFeedId: Int = 0,
|
||||
var filterFolderId: Int = 0,
|
||||
var accountId: Int = 0,
|
||||
var filterType: FilterType = FilterType.NO_FILTER,
|
||||
var sortType: ListSortType = ListSortType.NEWEST_TO_OLDEST,
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user