60: Make saving a swipe action r=msfjarvis a=msfjarvis

~~This isn't ready yet, because when done we want to make this use just `Modifier.swipeable` and not actually dismiss the view.~~ Good to go now 


Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
bors[bot] 2020-11-01 20:05:40 +00:00 committed by GitHub
commit 713706caff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 27 deletions

View file

@ -53,6 +53,7 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
"-Xskip-prerelease-check", "-Xskip-prerelease-check",
"-Xopt-in=kotlin.RequiresOptIn", "-Xopt-in=kotlin.RequiresOptIn",
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-Xopt-in=androidx.compose.material.ExperimentalMaterialApi",
] ]
} }
} }

View file

@ -8,11 +8,11 @@ import androidx.compose.foundation.layout.padding
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.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import dev.msfjarvis.lobsters.R import dev.msfjarvis.lobsters.R
import dev.msfjarvis.lobsters.util.IconResource import dev.msfjarvis.lobsters.util.IconResource
import dev.msfjarvis.lobsters.ui.theme.savedTitleColor
@Composable @Composable
fun EmptyList(saved: Boolean) { fun EmptyList(saved: Boolean) {
@ -24,7 +24,7 @@ fun EmptyList(saved: Boolean) {
if (saved) { if (saved) {
IconResource( IconResource(
R.drawable.ic_favorite_border_24px, R.drawable.ic_favorite_border_24px,
tint = savedTitleColor, tint = Color(0xFFD97373),
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
) )
Text(stringResource(R.string.no_saved_posts)) Text(stringResource(R.string.no_saved_posts))

View file

@ -6,18 +6,23 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.offsetPx
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumnFor import androidx.compose.foundation.lazy.LazyColumnFor
import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.FractionalThreshold
import androidx.compose.material.rememberSwipeableState
import androidx.compose.material.swipeable
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.gesture.scrollorientationlocking.Orientation
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ConfigurationAmbient
import androidx.compose.ui.platform.DensityAmbient
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.ui.tooling.preview.Preview import androidx.ui.tooling.preview.Preview
@ -27,9 +32,13 @@ import dev.msfjarvis.lobsters.injection.ApiModule
import dev.msfjarvis.lobsters.model.LobstersPost import dev.msfjarvis.lobsters.model.LobstersPost
import dev.msfjarvis.lobsters.model.Submitter import dev.msfjarvis.lobsters.model.Submitter
import dev.msfjarvis.lobsters.ui.theme.LobstersTheme import dev.msfjarvis.lobsters.ui.theme.LobstersTheme
import dev.msfjarvis.lobsters.ui.theme.savedTitleColor
import dev.msfjarvis.lobsters.ui.theme.titleColor import dev.msfjarvis.lobsters.ui.theme.titleColor
private enum class SwipeState {
NotSwiped,
FullySwiped,
}
@Composable @Composable
fun LazyItemScope.LobstersItem( fun LazyItemScope.LobstersItem(
post: LobstersPost, post: LobstersPost,
@ -38,20 +47,29 @@ fun LazyItemScope.LobstersItem(
commentOpenAction: (LobstersPost) -> Unit, commentOpenAction: (LobstersPost) -> Unit,
saveAction: (LobstersPost) -> Unit, saveAction: (LobstersPost) -> Unit,
) { ) {
val liked = remember { mutableStateOf(false) } val width = with(DensityAmbient.current) {
val titleColor = if (post.isLiked || liked.value) savedTitleColor else titleColor ConfigurationAmbient.current.screenWidthDp.toDp().toPx()
}
val swipeableState = rememberSwipeableState(SwipeState.NotSwiped)
val anchors = mapOf(0f to SwipeState.NotSwiped, width to SwipeState.FullySwiped)
if (swipeableState.offset.value >= (width / 2)) {
saveAction.invoke(post)
swipeableState.animateTo(SwipeState.NotSwiped)
}
Column( Column(
modifier = modifier modifier = modifier
.fillParentMaxWidth() .fillParentMaxWidth()
.swipeable(
state = swipeableState,
anchors = anchors,
thresholds = { _, _ -> FractionalThreshold(0.5f) },
orientation = Orientation.Horizontal
)
.offsetPx(swipeableState.offset)
.clickable( .clickable(
onClick = { linkOpenAction.invoke(post) }, onClick = { linkOpenAction.invoke(post) },
onLongClick = { commentOpenAction.invoke(post) }, onLongClick = { commentOpenAction.invoke(post) },
onDoubleClick = {
post.isLiked = true
liked.value = true
saveAction.invoke(post)
},
), ),
) { ) {
Text( Text(
@ -128,7 +146,8 @@ fun PreviewLobstersItem() {
post = item, post = item,
linkOpenAction = {}, linkOpenAction = {},
commentOpenAction = {}, commentOpenAction = {},
saveAction = {}) saveAction = {},
)
} }
} }
} }

View file

@ -6,7 +6,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
val titleColor = Color(0xFF7395D9) val titleColor = Color(0xFF7395D9)
val savedTitleColor = Color(0xFFD97373)
val darkColors = darkColors( val darkColors = darkColors(
primary = Color.White, primary = Color.White,

View file

@ -54,15 +54,9 @@ class LobstersViewModel @ViewModelInject constructor(
getMorePostsInternal(false) getMorePostsInternal(false)
} }
fun refreshPosts() {
apiPage = 1
getMorePostsInternal(true)
}
private fun getMorePostsInternal(firstLoad: Boolean) { private fun getMorePostsInternal(firstLoad: Boolean) {
viewModelScope.launch(coroutineExceptionHandler) { viewModelScope.launch(coroutineExceptionHandler) {
val newPosts = lobstersApi.getHottestPosts(apiPage) val newPosts = lobstersApi.getHottestPosts(apiPage)
.transformLikedFlag()
.toList() .toList()
if (firstLoad) { if (firstLoad) {
_posts.value = newPosts _posts.value = newPosts
@ -79,7 +73,6 @@ class LobstersViewModel @ViewModelInject constructor(
viewModelScope.launch { viewModelScope.launch {
savedPostsDao.insertPosts(post) savedPostsDao.insertPosts(post)
getSavedPosts() getSavedPosts()
_posts.value = _posts.value.transformLikedFlag().toList()
} }
} }
@ -87,11 +80,6 @@ class LobstersViewModel @ViewModelInject constructor(
viewModelScope.launch { viewModelScope.launch {
savedPostsDao.deletePostById(post.shortId) savedPostsDao.deletePostById(post.shortId)
getSavedPosts() getSavedPosts()
_posts.value = _posts.value.transformLikedFlag().toList()
} }
} }
private suspend fun List<LobstersPost>.transformLikedFlag() = map {
it.apply { isLiked = savedPostsDao.isLiked(shortId) }
}
} }

View file

@ -23,5 +23,6 @@ class LobstersPost(
@Json(name = "submitter_user") @Json(name = "submitter_user")
val submitterUser: Submitter, val submitterUser: Submitter,
val tags: List<String>, val tags: List<String>,
var isLiked: Boolean = false, @Deprecated("Retained for database compatibility as I am too lazy to write migrations")
val isLiked: Boolean = false,
) )