diff --git a/app/src/main/java/dev/msfjarvis/lobsters/ui/main/MainActivity.kt b/app/src/main/java/dev/msfjarvis/lobsters/ui/main/MainActivity.kt index 99c4371c..8db25a43 100644 --- a/app/src/main/java/dev/msfjarvis/lobsters/ui/main/MainActivity.kt +++ b/app/src/main/java/dev/msfjarvis/lobsters/ui/main/MainActivity.kt @@ -85,8 +85,8 @@ fun LobstersApp() { HottestPosts( posts = hottestPosts, listState = hottestPostsListState, - saveAction = viewModel::savePost, overscrollAction = viewModel::getMorePosts, + saveAction = viewModel::savePost, ) } composable(Destination.Saved.route) { diff --git a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/HottestPosts.kt b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/HottestPosts.kt index 6b040842..071b62c6 100644 --- a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/HottestPosts.kt +++ b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/HottestPosts.kt @@ -14,8 +14,8 @@ fun HottestPosts( posts: List, listState: LazyListState, modifier: Modifier = Modifier, - saveAction: (LobstersPost) -> Unit, overscrollAction: () -> Unit, + saveAction: (LobstersPost) -> Unit, ) { val urlLauncher = UrlLauncherAmbient.current @@ -32,9 +32,9 @@ fun HottestPosts( } LobstersItem( post = item, - linkOpenAction = { post -> urlLauncher.launch(post.url.ifEmpty { post.commentsUrl }) }, - commentOpenAction = { post -> urlLauncher.launch(post.commentsUrl) }, - saveAction = saveAction, + onClick = { urlLauncher.launch(item.url.ifEmpty { item.commentsUrl }) }, + onLongClick = { urlLauncher.launch(item.commentsUrl) }, + onSaveButtonClick = { saveAction.invoke(item) }, ) } } diff --git a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/LobstersItem.kt b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/LobstersItem.kt index 818e9d5b..626ed04d 100644 --- a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/LobstersItem.kt +++ b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/LobstersItem.kt @@ -4,107 +4,143 @@ import androidx.compose.foundation.Text import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ConstraintLayout import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.offsetPx +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumnFor -import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.FractionalThreshold -import androidx.compose.material.rememberSwipeableState -import androidx.compose.material.swipeable +import androidx.compose.material.Surface +import androidx.compose.material.ripple.RippleIndication import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.gesture.scrollorientationlocking.Orientation 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.unit.dp import androidx.ui.tooling.preview.Preview import coil.transform.CircleCropTransformation import dev.chrisbanes.accompanist.coil.CoilImage +import dev.msfjarvis.lobsters.R import dev.msfjarvis.lobsters.model.LobstersPost import dev.msfjarvis.lobsters.model.Submitter import dev.msfjarvis.lobsters.ui.theme.LobstersTheme import dev.msfjarvis.lobsters.ui.theme.titleColor +import dev.msfjarvis.lobsters.util.IconResource -private enum class SwipeState { - NotSwiped, - FullySwiped, -} +val TEST_POST = LobstersPost( + "zqyydb", + "https://lobste.rs/s/zqyydb", + "2020-09-21T07:11:14.000-05:00", + "k2k20 hackathon report: Bob Beck on LibreSSL progress", + "https://undeadly.org/cgi?action=article;sid=20200921105847", + 4, + 0, + 0, + "", + "https://lobste.rs/s/zqyydb/k2k20_hackathon_report_bob_beck_on", + Submitter( + "Vigdis", + "2017-02-27T21:08:14.000-06:00", + false, + "Alleycat for the fun, sys/net admin for a living and OpenBSD contributions for the pleasure. (Not so) French dude in Montreal\r\n\r\nhttps://chown.me", + false, + 76, + "/avatars/Vigdis-100.png", + "sevan", + null, + null, + emptyList(), + ), + listOf("openbsd", "linux", "containers", "hack the planet", "no thanks"), +) @Composable -fun LazyItemScope.LobstersItem( +fun LobstersItem( post: LobstersPost, - modifier: Modifier = Modifier, - linkOpenAction: (LobstersPost) -> Unit, - commentOpenAction: (LobstersPost) -> Unit, - saveAction: (LobstersPost) -> Unit, + onClick: () -> Unit, + onLongClick: () -> Unit, + onSaveButtonClick: () -> Unit, ) { - val width = with(DensityAmbient.current) { - 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( - modifier = modifier - .fillParentMaxWidth() - .swipeable( - state = swipeableState, - anchors = anchors, - thresholds = { _, _ -> FractionalThreshold(0.5f) }, - orientation = Orientation.Horizontal - ) - .offsetPx(swipeableState.offset) + Surface( + modifier = Modifier.fillMaxWidth() .clickable( - onClick = { linkOpenAction.invoke(post) }, - onLongClick = { commentOpenAction.invoke(post) }, + onClick = onClick, + onLongClick = onLongClick, ), ) { - Text( - text = post.title, - color = titleColor, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(top = 4.dp) - ) - Row( - modifier = Modifier.padding(vertical = 8.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp), - ) { - post.tags.take(4).forEach { tag -> - Text( - text = tag, - modifier = Modifier - .background(Color(0xFFFFFCD7), RoundedCornerShape(8.dp)) - .padding(vertical = 2.dp, horizontal = 6.dp), - color = Color.DarkGray, - ) - } - } - Row( - modifier = Modifier.wrapContentHeight(), + ConstraintLayout( + modifier = Modifier.padding(start = 4.dp, end = 4.dp), ) { + val (title, tags, avatar, submitter, saveButton) = createRefs() + Text( + text = post.title, + color = titleColor, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(top = 4.dp) + .constrainAs(title) { + top.linkTo(parent.top) + start.linkTo(parent.start) + }, + ) + TagRow( + tags = post.tags, + modifier = Modifier.constrainAs(tags) { + top.linkTo(title.bottom) + }.padding(vertical = 8.dp), + ) CoilImage( data = "https://lobste.rs/${post.submitterUser.avatarUrl}", fadeIn = true, requestBuilder = { transformations(CircleCropTransformation()) }, - modifier = Modifier.width(30.dp).padding(4.dp).align(Alignment.CenterVertically), + modifier = Modifier.width(30.dp).padding(4.dp) + .constrainAs(avatar) { + top.linkTo(tags.bottom) + start.linkTo(parent.start) + }, ) Text( text = "submitted by ${post.submitterUser.username}", - modifier = Modifier.padding(bottom = 4.dp).align(Alignment.CenterVertically), + modifier = Modifier.padding(bottom = 4.dp).constrainAs(submitter) { + top.linkTo(tags.bottom) + start.linkTo(avatar.end) + }, + ) + IconResource( + resourceId = R.drawable.ic_favorite_border_24px, + modifier = Modifier.padding(8.dp) + .clickable( + onClick = onSaveButtonClick, + indication = RippleIndication(), + ) + .constrainAs(saveButton) { + end.linkTo(parent.end) + centerVerticallyTo(parent) + }, + tint = Color(0xFFD97373), + ) + } + } +} + +@Composable +fun TagRow( + tags: List, + modifier: Modifier = Modifier, +) { + Row( + modifier = Modifier.then(modifier), + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + tags.take(3).forEach { tag -> + Text( + text = tag, + modifier = Modifier + .background(Color(0xFFFFFCD7), RoundedCornerShape(8.dp)) + .padding(vertical = 2.dp, horizontal = 6.dp), + color = Color.DarkGray, ) } } @@ -112,40 +148,14 @@ fun LazyItemScope.LobstersItem( @Composable @Preview -fun PreviewLobstersItem() { - val post = LobstersPost( - "zqyydb", - "https://lobste.rs/s/zqyydb", - "2020-09-21T07:11:14.000-05:00", - "k2k20 hackathon report: Bob Beck on LibreSSL progress", - "https://undeadly.org/cgi?action=article;sid=20200921105847", - 4, - 0, - 0, - "", - "https://lobste.rs/s/zqyydb/k2k20_hackathon_report_bob_beck_on", - Submitter( - "Vigdis", - "2017-02-27T21:08:14.000-06:00", - false, - "Alleycat for the fun, sys/net admin for a living and OpenBSD contributions for the pleasure. (Not so) French dude in Montreal\r\n\r\nhttps://chown.me", - false, - 76, - "/avatars/Vigdis-100.png", - "sevan", - null, - null, - emptyList(), - ), - listOf("openbsd"), - ) +fun Preview() { LobstersTheme { - LazyColumnFor(items = listOf(post)) { item -> + LazyColumnFor(items = listOf(TEST_POST, TEST_POST, TEST_POST, TEST_POST, TEST_POST)) { item -> LobstersItem( post = item, - linkOpenAction = {}, - commentOpenAction = {}, - saveAction = {}, + onClick = {}, + onLongClick = {}, + onSaveButtonClick = {}, ) } } diff --git a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/SavedPosts.kt b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/SavedPosts.kt index 4765aed5..1bf4537f 100644 --- a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/SavedPosts.kt +++ b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/SavedPosts.kt @@ -13,7 +13,7 @@ import dev.msfjarvis.lobsters.ui.urllauncher.UrlLauncherAmbient fun SavedPosts( posts: List, modifier: Modifier = Modifier, - saveAction: (LobstersPost) -> Unit + saveAction: (LobstersPost) -> Unit, ) { val listState = rememberLazyListState() val urlLauncher = UrlLauncherAmbient.current @@ -28,9 +28,9 @@ fun SavedPosts( ) { item -> LobstersItem( post = item, - linkOpenAction = { post -> urlLauncher.launch(post.url.ifEmpty { post.commentsUrl }) }, - commentOpenAction = { post -> urlLauncher.launch(post.commentsUrl) }, - saveAction = saveAction, + onClick = { urlLauncher.launch(item.url.ifEmpty { item.commentsUrl }) }, + onLongClick = { urlLauncher.launch(item.commentsUrl) }, + onSaveButtonClick = { saveAction.invoke(item) }, ) } }