Add TimelineItem large layout base
This commit is contained in:
parent
8a04fad0d7
commit
b15eb9fa91
@ -103,5 +103,6 @@ dependencies {
|
|||||||
|
|
||||||
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:4.9.0'
|
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:4.9.0'
|
||||||
|
|
||||||
implementation "com.github.skydoves:landscapist-coil:2.2.2"
|
implementation "io.coil-kt:coil:2.4.0"
|
||||||
|
implementation "io.coil-kt:coil-compose:2.4.0"
|
||||||
}
|
}
|
@ -9,9 +9,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil.request.ImageRequest
|
|
||||||
import com.readrops.db.entities.Feed
|
import com.readrops.db.entities.Feed
|
||||||
import com.skydoves.landscapist.coil.CoilImage
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FeedItem(feed: Feed) {
|
fun FeedItem(feed: Feed) {
|
||||||
@ -22,11 +20,11 @@ fun FeedItem(feed: Feed) {
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
) {
|
) {
|
||||||
CoilImage(imageRequest = {
|
/*CoilImage(imageRequest = {
|
||||||
ImageRequest.Builder(context)
|
ImageRequest.Builder(context)
|
||||||
.data(feed.url)
|
.data(feed.url)
|
||||||
.build()
|
.build()
|
||||||
})
|
})*/
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = feed.name!!,
|
text = feed.name!!,
|
||||||
|
@ -1,73 +1,152 @@
|
|||||||
package com.readrops.app.compose.timelime
|
package com.readrops.app.compose.timelime
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Add
|
||||||
|
import androidx.compose.material.icons.outlined.FavoriteBorder
|
||||||
|
import androidx.compose.material.icons.outlined.Share
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import coil.compose.AsyncImage
|
||||||
|
import com.readrops.api.utils.DateUtils
|
||||||
|
import com.readrops.app.compose.R
|
||||||
|
import com.readrops.app.compose.utils.theme.ShortSpacer
|
||||||
|
import com.readrops.app.compose.utils.theme.VeryShortSpacer
|
||||||
|
import com.readrops.app.compose.utils.theme.spacing
|
||||||
|
import com.readrops.db.pojo.ItemWithFeed
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItem(
|
fun TimelineItem(
|
||||||
|
itemWithFeed: ItemWithFeed,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
|
onFavorite: () -> Unit,
|
||||||
|
onReadLater: () -> Unit,
|
||||||
|
onShare: () -> Unit
|
||||||
) {
|
) {
|
||||||
Card(
|
Card(
|
||||||
// elevation = 4.card,
|
modifier = Modifier
|
||||||
modifier = Modifier.background(Color.White)
|
.padding(
|
||||||
.padding(8.dp)
|
PaddingValues(
|
||||||
|
horizontal = MaterialTheme.spacing.shortSpacing,
|
||||||
|
vertical = MaterialTheme.spacing.veryShortSpacing
|
||||||
|
)
|
||||||
|
)
|
||||||
.clickable { onClick() }
|
.clickable { onClick() }
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(8.dp)
|
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(
|
||||||
|
start = MaterialTheme.spacing.shortSpacing,
|
||||||
|
end = MaterialTheme.spacing.shortSpacing,
|
||||||
|
top = MaterialTheme.spacing.shortSpacing,
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
/* Icon(
|
Icon(
|
||||||
painter = painterResource(id = com.readrops.app.R.drawable.ic_rss_feed_grey),
|
painter = painterResource(id = R.drawable.ic_rss_feed_grey),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
// modifier = Modifier.size((MaterialTheme.typography.subtitle2.fontSize.value * 1.5).dp)
|
modifier = Modifier.size(MaterialTheme.typography.labelLarge.fontSize.value.dp)
|
||||||
)*/
|
|
||||||
|
|
||||||
// Spacer(Modifier.padding(4.dp))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = "feed name",
|
|
||||||
//style = MaterialTheme.typography.
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
VeryShortSpacer()
|
||||||
|
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = itemWithFeed.feedName,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
|
||||||
|
VeryShortSpacer()
|
||||||
|
|
||||||
|
if (itemWithFeed.folder != null) {
|
||||||
|
Text(
|
||||||
|
text = itemWithFeed.folder!!.name!!,
|
||||||
|
style = MaterialTheme.typography.labelMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "Item date",
|
text = DateUtils.formattedDateByLocal(itemWithFeed.item.pubDate!!),
|
||||||
// style = MaterialTheme.typography.subtitle2
|
style = MaterialTheme.typography.labelMedium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(Modifier.size(8.dp))
|
ShortSpacer()
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "title example",
|
text = itemWithFeed.item.title!!,
|
||||||
//style = MaterialTheme.typography.h5,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
maxLines = 2,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.padding(horizontal = MaterialTheme.spacing.shortSpacing)
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(Modifier.size(8.dp))
|
ShortSpacer()
|
||||||
|
|
||||||
/* Image(
|
if (itemWithFeed.item.imageLink != null) {
|
||||||
painter = painterResource(id = com.readrops.app.R.drawable.header_background),
|
AsyncImage(
|
||||||
contentDescription = null
|
model = itemWithFeed.item.imageLink,
|
||||||
)*/
|
contentDescription = itemWithFeed.item.title!!,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = Modifier
|
||||||
|
.aspectRatio(3f / 2f)
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(MaterialTheme.spacing.shortSpacing)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.FavoriteBorder,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.clickable { onFavorite() }
|
||||||
|
)
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Add, // placeholder icon
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.clickable { onReadLater() }
|
||||||
|
)
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Share,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.clickable { onShare() }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -65,16 +65,21 @@ object TimelineTab : Tab {
|
|||||||
modifier = Modifier.padding(paddingValues)
|
modifier = Modifier.padding(paddingValues)
|
||||||
) {
|
) {
|
||||||
when (state) {
|
when (state) {
|
||||||
is TimelineState.LoadedState -> {
|
is TimelineState.Loaded -> {
|
||||||
val items = (state as TimelineState.LoadedState).items
|
val items = (state as TimelineState.Loaded).items
|
||||||
|
|
||||||
if (items.isNotEmpty()) {
|
if (items.isNotEmpty()) {
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
items(
|
items(
|
||||||
items = items
|
items = items,
|
||||||
) {
|
key = { it.item.id },
|
||||||
|
) { itemWithFeed ->
|
||||||
TimelineItem(
|
TimelineItem(
|
||||||
onClick = { navigator.push(ItemScreen()) }
|
itemWithFeed = itemWithFeed,
|
||||||
|
onClick = { navigator.push(ItemScreen()) },
|
||||||
|
onFavorite = {},
|
||||||
|
onReadLater = {},
|
||||||
|
onShare = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ package com.readrops.app.compose.timelime
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.readrops.app.compose.base.TabViewModel
|
import com.readrops.app.compose.base.TabViewModel
|
||||||
import com.readrops.db.Database
|
import com.readrops.db.Database
|
||||||
import com.readrops.db.entities.Item
|
import com.readrops.db.pojo.ItemWithFeed
|
||||||
|
import com.readrops.db.queries.ItemsQueryBuilder
|
||||||
|
import com.readrops.db.queries.QueryFilters
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@ -14,7 +16,7 @@ class TimelineViewModel(
|
|||||||
private val database: Database,
|
private val database: Database,
|
||||||
) : TabViewModel(database) {
|
) : TabViewModel(database) {
|
||||||
|
|
||||||
private val _timelineState = MutableStateFlow<TimelineState>(TimelineState.InitialState)
|
private val _timelineState = MutableStateFlow<TimelineState>(TimelineState.Loading)
|
||||||
val timelineState = _timelineState.asStateFlow()
|
val timelineState = _timelineState.asStateFlow()
|
||||||
|
|
||||||
private var _isRefreshing = MutableStateFlow(false)
|
private var _isRefreshing = MutableStateFlow(false)
|
||||||
@ -22,10 +24,12 @@ class TimelineViewModel(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch(context = Dispatchers.IO) {
|
viewModelScope.launch(context = Dispatchers.IO) {
|
||||||
database.newItemDao().selectAll()
|
val query = ItemsQueryBuilder.buildItemsQuery(QueryFilters(accountId = 1))
|
||||||
.catch { _timelineState.value = TimelineState.ErrorState(Exception(it)) }
|
|
||||||
|
database.newItemDao().selectAll(query)
|
||||||
|
.catch { _timelineState.value = TimelineState.Error(Exception(it)) }
|
||||||
.collect {
|
.collect {
|
||||||
_timelineState.value = TimelineState.LoadedState(it)
|
_timelineState.value = TimelineState.Loaded(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,13 +46,13 @@ class TimelineViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() {
|
override fun invalidate() {
|
||||||
refreshTimeline()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class TimelineState {
|
sealed class TimelineState {
|
||||||
object InitialState : TimelineState()
|
object Loading : TimelineState()
|
||||||
data class ErrorState(val exception: Exception) : TimelineState()
|
data class Error(val exception: Exception) : TimelineState()
|
||||||
data class LoadedState(val items: List<Item>) : TimelineState()
|
data class Loaded(val items: List<ItemWithFeed>) : TimelineState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
package com.readrops.db.dao.newdao
|
package com.readrops.db.dao.newdao
|
||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.RawQuery
|
||||||
|
import androidx.sqlite.db.SupportSQLiteQuery
|
||||||
|
import com.readrops.db.entities.Feed
|
||||||
|
import com.readrops.db.entities.Folder
|
||||||
import com.readrops.db.entities.Item
|
import com.readrops.db.entities.Item
|
||||||
|
import com.readrops.db.entities.ItemState
|
||||||
|
import com.readrops.db.pojo.ItemWithFeed
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
abstract class NewItemDao : NewBaseDao<Item> {
|
abstract class NewItemDao : NewBaseDao<Item> {
|
||||||
|
|
||||||
@Query("Select * From Item")
|
@RawQuery(observedEntities = [Item::class, Feed::class, Folder::class, ItemState::class])
|
||||||
abstract fun selectAll(): Flow<List<Item>>
|
abstract fun selectAll(query: SupportSQLiteQuery): Flow<List<ItemWithFeed>>
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user