From f2fdfac4ad2ee0d7ed245140846accdef852a93f Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Sun, 4 Apr 2021 17:23:27 +0530 Subject: [PATCH 01/14] android: add Comments UI composables (cherry picked from commit 65c6f8ff52c8ecde84c7b5a505ba5a401da3a22a) --- .../claw/android/comments/CommentEntry.kt | 22 +++++++++++++++++++ .../claw/android/comments/Comments.kt | 19 ++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 android/src/main/kotlin/dev/msfjarvis/claw/android/comments/CommentEntry.kt create mode 100644 android/src/main/kotlin/dev/msfjarvis/claw/android/comments/Comments.kt diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/CommentEntry.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/CommentEntry.kt new file mode 100644 index 00000000..2d376dce --- /dev/null +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/CommentEntry.kt @@ -0,0 +1,22 @@ +package dev.msfjarvis.claw.android.comments + +import android.text.Html +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.unit.dp +import dev.msfjarvis.claw.model.Comment + +@Composable +fun CommentEntry( + comment: Comment, +) { + Row(modifier = Modifier.padding(start = (10 * (comment.indentLevel.toFloat() - 1)).dp)) { + Text( + text = buildAnnotatedString { @Suppress("DEPRECATION") Html.fromHtml(comment.comment) }, + ) + } +} diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/Comments.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/Comments.kt new file mode 100644 index 00000000..3fe0ffc4 --- /dev/null +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/Comments.kt @@ -0,0 +1,19 @@ +package dev.msfjarvis.claw.android.comments + +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.runtime.Composable +import dev.msfjarvis.claw.model.LobstersPostDetails + +@Composable +private fun CommentsPageInternal( + details: LobstersPostDetails, +) { + LazyColumn { items(details.comments) { CommentEntry(it) } } +} + +@Composable +fun CommentsPage( + postId: String, + getDetails: suspend (String) -> LobstersPostDetails, +) {} From 7c306acfa9136bbe8f91e347c92e99763b7c710e Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 4 Oct 2021 14:43:24 +0530 Subject: [PATCH 02/14] android: add post details methods to VM --- .../msfjarvis/claw/android/viewmodel/ClawViewModel.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt index d24b16d9..01c646e6 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt @@ -7,19 +7,22 @@ import dagger.hilt.android.lifecycle.HiltViewModel import dev.msfjarvis.claw.android.paging.LobstersPagingSource import dev.msfjarvis.claw.api.LobstersApi import dev.msfjarvis.claw.database.local.SavedPost +import dev.msfjarvis.claw.model.LobstersPostDetails import javax.inject.Inject +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.last import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.withContext @OptIn(ExperimentalCoroutinesApi::class) @HiltViewModel class ClawViewModel @Inject constructor( - api: LobstersApi, + private val api: LobstersApi, private val repository: SavedPostsRepository, ) : ViewModel() { var lastPagingSource: LobstersPagingSource? = null @@ -46,6 +49,11 @@ constructor( } } + suspend fun getPostComments(postId: String): LobstersPostDetails = + withContext(Dispatchers.IO) { + return@withContext api.getPostDetails(postId) + } + fun reloadPosts() { lastPagingSource?.invalidate() } From e053ca20281d429d8fe6f12c68cc97d2860278df Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 4 Oct 2021 15:12:54 +0530 Subject: [PATCH 03/14] android: extract HottestPosts composable --- .../msfjarvis/claw/android/ui/HottestPosts.kt | 48 +++++++++++++++++++ .../msfjarvis/claw/android/ui/LobstersApp.kt | 38 ++++----------- 2 files changed, 58 insertions(+), 28 deletions(-) create mode 100644 android/src/main/kotlin/dev/msfjarvis/claw/android/ui/HottestPosts.kt diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/HottestPosts.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/HottestPosts.kt new file mode 100644 index 00000000..0c79c13d --- /dev/null +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/HottestPosts.kt @@ -0,0 +1,48 @@ +package dev.msfjarvis.claw.android.ui + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.paging.LoadState +import androidx.paging.compose.LazyPagingItems +import com.google.accompanist.swiperefresh.SwipeRefresh +import com.google.accompanist.swiperefresh.rememberSwipeRefreshState +import dev.msfjarvis.claw.database.local.SavedPost +import dev.msfjarvis.claw.model.LobstersPost +import kotlinx.coroutines.launch + +@Composable +fun HottestPosts( + items: LazyPagingItems, + listState: LazyListState, + isPostSaved: suspend (SavedPost) -> Boolean, + toggleSave: suspend (SavedPost) -> Unit, + reloadPosts: () -> Unit, + launchUrl: (String) -> Unit, + modifier: Modifier, +) { + val coroutineScope = rememberCoroutineScope() + val isRefreshing = items.loadState.refresh == LoadState.Loading + SwipeRefresh( + state = rememberSwipeRefreshState(isRefreshing), + onRefresh = reloadPosts, + ) { + if (items.itemCount == 0) { + Box(modifier = Modifier.fillMaxSize()) + } else { + NetworkPosts( + items = items, + launchUrl = launchUrl, + listState = listState, + isSaved = isPostSaved, + toggleSave = { coroutineScope.launch { toggleSave(it) } }, + modifier = Modifier.padding(top = 16.dp).then(modifier), + ) + } + } +} diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt index 8e9c452f..763f0656 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt @@ -2,9 +2,6 @@ package dev.msfjarvis.claw.android.ui import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold @@ -15,7 +12,6 @@ import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset @@ -23,20 +19,15 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel -import androidx.paging.LoadState import androidx.paging.compose.collectAsLazyPagingItems import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsPadding import com.google.accompanist.insets.statusBarsPadding -import com.google.accompanist.swiperefresh.SwipeRefresh -import com.google.accompanist.swiperefresh.rememberSwipeRefreshState import com.google.accompanist.systemuicontroller.rememberSystemUiController import dev.msfjarvis.claw.android.viewmodel.ClawViewModel import dev.msfjarvis.claw.common.theme.LobstersTheme import dev.msfjarvis.claw.common.urllauncher.UrlLauncher -import kotlinx.coroutines.launch private const val ScrollDelta = 50 @@ -49,7 +40,6 @@ fun LobstersApp( val systemUiController = rememberSystemUiController() val scaffoldState = rememberScaffoldState() val listState = rememberLazyListState() - val coroutineScope = rememberCoroutineScope() var isFabVisible by remember { mutableStateOf(true) } val nestedScrollConnection = remember { object : NestedScrollConnection { @@ -77,6 +67,7 @@ fun LobstersApp( systemUiController.setNavigationBarColor(color = Color.Transparent) } val items = viewModel.pagerFlow.collectAsLazyPagingItems() + Scaffold( scaffoldState = scaffoldState, topBar = { ClawAppBar(modifier = Modifier.statusBarsPadding()) }, @@ -88,24 +79,15 @@ fun LobstersApp( ) }, ) { - val isRefreshing = items.loadState.refresh == LoadState.Loading - SwipeRefresh( - state = rememberSwipeRefreshState(isRefreshing), - onRefresh = viewModel::reloadPosts, - ) { - if (items.itemCount == 0) { - Box(modifier = Modifier.fillMaxSize()) - } else { - NetworkPosts( - items = items, - launchUrl = urlLauncher::launch, - listState = listState, - isSaved = viewModel::isPostSaved, - toggleSave = { coroutineScope.launch { viewModel.toggleSave(it) } }, - modifier = Modifier.padding(top = 16.dp).nestedScroll(nestedScrollConnection), - ) - } - } + HottestPosts( + items, + listState, + viewModel::isPostSaved, + viewModel::toggleSave, + viewModel::reloadPosts, + urlLauncher::launch, + Modifier.nestedScroll(nestedScrollConnection), + ) } } } From e85e25aa504c71193761ef6276dbc83d5b2f745f Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 4 Oct 2021 15:12:13 +0530 Subject: [PATCH 04/14] android: integrate AndroidX Navigation --- android/build.gradle.kts | 1 + .../msfjarvis/claw/android/ui/LobstersApp.kt | 26 ++++++++++++------- gradle/libs.versions.toml | 1 + 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 2526dd68..1c558ec8 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { implementation(libs.androidx.appcompat) implementation(libs.androidx.coreKtx) implementation(libs.androidx.lifecycle.compose) + implementation(libs.androidx.navigation.compose) implementation(libs.androidx.paging.compose) implementation(libs.dagger.hilt.android) implementation(libs.sqldelight.extensions.coroutines) diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt index 763f0656..a18a440d 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt @@ -20,6 +20,9 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import androidx.paging.compose.collectAsLazyPagingItems import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsPadding @@ -40,6 +43,7 @@ fun LobstersApp( val systemUiController = rememberSystemUiController() val scaffoldState = rememberScaffoldState() val listState = rememberLazyListState() + val navController = rememberNavController() var isFabVisible by remember { mutableStateOf(true) } val nestedScrollConnection = remember { object : NestedScrollConnection { @@ -79,15 +83,19 @@ fun LobstersApp( ) }, ) { - HottestPosts( - items, - listState, - viewModel::isPostSaved, - viewModel::toggleSave, - viewModel::reloadPosts, - urlLauncher::launch, - Modifier.nestedScroll(nestedScrollConnection), - ) + NavHost(navController, startDestination = "hottest") { + composable("hottest") { + HottestPosts( + items, + listState, + viewModel::isPostSaved, + viewModel::toggleSave, + viewModel::reloadPosts, + urlLauncher::launch, + Modifier.nestedScroll(nestedScrollConnection), + ) + } + } } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 07e135b0..b8c9ffc0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,6 +23,7 @@ androidx-appcompat = "androidx.appcompat:appcompat:1.4.0-beta01" androidx-browser = "androidx.browser:browser:1.4.0-beta01" androidx-coreKtx = "androidx.core:core-ktx:1.7.0-beta02" androidx-lifecycle-compose = "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0-rc01" +androidx-navigation-compose = "androidx.navigation:navigation-compose:2.4.0-alpha10" androidx-paging-compose = "androidx.paging:paging-compose:1.0.0-alpha13" aurora-component = { module = "org.pushing-pixels:aurora-component", version.ref = "aurora" } From 7f54e6ff1bd36a2cc0ee0820e3e1e347c7dbdf1d Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 4 Oct 2021 16:56:21 +0530 Subject: [PATCH 05/14] android: add comments destination --- .../kotlin/dev/msfjarvis/claw/android/ui/HottestPosts.kt | 2 ++ .../kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt | 8 ++++++++ .../kotlin/dev/msfjarvis/claw/android/ui/NetworkPosts.kt | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/HottestPosts.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/HottestPosts.kt index 0c79c13d..3cb07f20 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/HottestPosts.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/HottestPosts.kt @@ -24,6 +24,7 @@ fun HottestPosts( toggleSave: suspend (SavedPost) -> Unit, reloadPosts: () -> Unit, launchUrl: (String) -> Unit, + viewComments: (String) -> Unit, modifier: Modifier, ) { val coroutineScope = rememberCoroutineScope() @@ -40,6 +41,7 @@ fun HottestPosts( launchUrl = launchUrl, listState = listState, isSaved = isPostSaved, + viewComments = viewComments, toggleSave = { coroutineScope.launch { toggleSave(it) } }, modifier = Modifier.padding(top = 16.dp).then(modifier), ) diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt index a18a440d..bcbca4cf 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt @@ -28,6 +28,7 @@ import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsPadding import com.google.accompanist.insets.statusBarsPadding import com.google.accompanist.systemuicontroller.rememberSystemUiController +import dev.msfjarvis.claw.android.comments.CommentsPage import dev.msfjarvis.claw.android.viewmodel.ClawViewModel import dev.msfjarvis.claw.common.theme.LobstersTheme import dev.msfjarvis.claw.common.urllauncher.UrlLauncher @@ -92,9 +93,16 @@ fun LobstersApp( viewModel::toggleSave, viewModel::reloadPosts, urlLauncher::launch, + { navController.navigate("comments/$it") }, Modifier.nestedScroll(nestedScrollConnection), ) } + composable("comments/{postId}") { backStackEntry -> + CommentsPage( + postId = requireNotNull(backStackEntry.arguments?.getString("postId")), + getDetails = viewModel::getPostComments, + ) + } } } } diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/NetworkPosts.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/NetworkPosts.kt index 8c3e7143..31d58df7 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/NetworkPosts.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/NetworkPosts.kt @@ -26,6 +26,7 @@ fun NetworkPosts( launchUrl: (String) -> Unit, isSaved: suspend (SavedPost) -> Boolean, toggleSave: (SavedPost) -> Unit, + viewComments: (String) -> Unit, modifier: Modifier = Modifier, ) { val coroutineScope = rememberCoroutineScope() @@ -42,7 +43,7 @@ fun NetworkPosts( post = dbModel, isSaved = saved, viewPost = { launchUrl(item.url.ifEmpty { item.commentsUrl }) }, - viewComments = { launchUrl(item.commentsUrl) }, + viewComments = { viewComments(item.shortId) }, toggleSave = { toggleSave(dbModel) }, modifier = Modifier.padding(bottom = 16.dp, start = 16.dp, end = 16.dp), ) From b7ca16ebe3905e95bf01c6f1fb9bb9deb8b00bf4 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 4 Oct 2021 17:25:49 +0530 Subject: [PATCH 06/14] common: import toDbModel and implement for LobstersPostDetails --- .../msfjarvis/claw/android/ext/database.kt | 18 ----------- .../msfjarvis/claw/android/ui/NetworkPosts.kt | 2 +- common/build.gradle.kts | 1 + .../dev/msfjarvis/claw/common/posts/ext.kt | 31 +++++++++++++++++++ desktop/src/jvmMain/kotlin/main.kt | 16 +--------- 5 files changed, 34 insertions(+), 34 deletions(-) delete mode 100644 android/src/main/kotlin/dev/msfjarvis/claw/android/ext/database.kt create mode 100644 common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/ext.kt diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ext/database.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ext/database.kt deleted file mode 100644 index 9835f896..00000000 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ext/database.kt +++ /dev/null @@ -1,18 +0,0 @@ -package dev.msfjarvis.claw.android.ext - -import dev.msfjarvis.claw.database.local.SavedPost -import dev.msfjarvis.claw.model.LobstersPost - -/** Convert a [LobstersPost] object returned by the API into a [SavedPost] for persistence. */ -fun LobstersPost.toDbModel(): SavedPost { - return SavedPost( - shortId = shortId, - title = title, - url = url, - createdAt = createdAt, - commentsUrl = commentsUrl, - submitterName = submitter.username, - submitterAvatarUrl = submitter.avatarUrl, - tags = tags, - ) -} diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/NetworkPosts.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/NetworkPosts.kt index 31d58df7..03f9189a 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/NetworkPosts.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/NetworkPosts.kt @@ -13,8 +13,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.items -import dev.msfjarvis.claw.android.ext.toDbModel import dev.msfjarvis.claw.common.posts.LobstersCard +import dev.msfjarvis.claw.common.posts.toDbModel import dev.msfjarvis.claw.database.local.SavedPost import dev.msfjarvis.claw.model.LobstersPost import kotlinx.coroutines.launch diff --git a/common/build.gradle.kts b/common/build.gradle.kts index f72eb54a..e15d2a6d 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -16,6 +16,7 @@ kotlin { api(compose.foundation) api(compose.material) api(projects.database) + api(projects.model) } } sourceSets["androidMain"].apply { diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/ext.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/ext.kt new file mode 100644 index 00000000..9c6b1398 --- /dev/null +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/ext.kt @@ -0,0 +1,31 @@ +package dev.msfjarvis.claw.common.posts + +import dev.msfjarvis.claw.database.local.SavedPost +import dev.msfjarvis.claw.model.LobstersPost +import dev.msfjarvis.claw.model.LobstersPostDetails + +fun LobstersPost.toDbModel(): SavedPost { + return SavedPost( + shortId = shortId, + title = title, + url = url, + createdAt = createdAt, + commentsUrl = commentsUrl, + submitterName = submitter.username, + submitterAvatarUrl = submitter.avatarUrl, + tags = tags, + ) +} + +fun LobstersPostDetails.toDbModel(): SavedPost { + return SavedPost( + shortId = shortId, + title = title, + url = url, + createdAt = createdAt, + commentsUrl = commentsUrl, + submitterName = submitter.username, + submitterAvatarUrl = submitter.avatarUrl, + tags = tags, + ) +} diff --git a/desktop/src/jvmMain/kotlin/main.kt b/desktop/src/jvmMain/kotlin/main.kt index e5ef9c0b..f510549d 100644 --- a/desktop/src/jvmMain/kotlin/main.kt +++ b/desktop/src/jvmMain/kotlin/main.kt @@ -14,27 +14,13 @@ import androidx.compose.ui.window.WindowPosition import androidx.compose.ui.window.application import androidx.compose.ui.window.rememberWindowState import dev.msfjarvis.claw.common.posts.LobstersCard +import dev.msfjarvis.claw.common.posts.toDbModel import dev.msfjarvis.claw.common.theme.LobstersTheme import dev.msfjarvis.claw.common.urllauncher.UrlLauncher -import dev.msfjarvis.claw.database.local.SavedPost -import dev.msfjarvis.claw.model.LobstersPost import org.pushingpixels.aurora.component.AuroraVerticalScrollbar import org.pushingpixels.aurora.skin.ceruleanSkin import org.pushingpixels.aurora.window.AuroraWindow -fun LobstersPost.toDbModel(): SavedPost { - return SavedPost( - shortId = shortId, - title = title, - url = url, - createdAt = createdAt, - commentsUrl = commentsUrl, - submitterName = submitter.username, - submitterAvatarUrl = submitter.avatarUrl, - tags = tags, - ) -} - fun main() = application { val paging = Paging(rememberCoroutineScope()) val items = paging.pagingData.collectAsLazyPagingItems() From 5b2b7de7d015f7eda6b4c2d741fce4f1d30bf2c4 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 4 Oct 2021 17:26:23 +0530 Subject: [PATCH 07/14] common: remove unused TEST_POST --- .../dev/msfjarvis/claw/common/posts/LobstersItem.kt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersItem.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersItem.kt index f9888fee..51ccfe40 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersItem.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersItem.kt @@ -37,18 +37,6 @@ import dev.msfjarvis.claw.common.theme.titleColor import dev.msfjarvis.claw.common.ui.NetworkImage import dev.msfjarvis.claw.database.local.SavedPost -val TEST_POST = - SavedPost( - shortId = "zqyydb", - title = "k2k20 hackathon report: Bob Beck on LibreSSL progress", - url = "https://undeadly.org/cgi?action=article;sid=20200921105847", - createdAt = "2020-09-21T07:11:14.000-05:00", - commentsUrl = "https://lobste.rs/s/zqyydb/k2k20_hackathon_report_bob_beck_on", - submitterName = "Vigdis", - submitterAvatarUrl = "https://avatars.githubusercontent.com/u/13348378?v=4", - tags = listOf("openbsd", "linux", "containers", "hack the planet", "no thanks"), - ) - @Composable @OptIn(ExperimentalMaterialApi::class) fun LobstersCard( From 84fd9a2c613c9c0a96764d214209d589d1533820 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 4 Oct 2021 17:26:54 +0530 Subject: [PATCH 08/14] common: extract PostDetails composable for comments --- .../claw/common/posts/LobstersItem.kt | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersItem.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersItem.kt index 51ccfe40..44751575 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersItem.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersItem.kt @@ -55,16 +55,8 @@ fun LobstersCard( modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp).fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(4.dp), ) { - PostTitle( - title = post.title, - ) - TagRow( - tags = post.tags, - ) - SubmitterName( - text = "Submitted by ${post.submitterName}", - avatarUrl = "https://lobste.rs/${post.submitterAvatarUrl}", - contentDescription = "Submitted by ${post.submitterName}", + PostDetails( + post = post, ) Row( modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp), @@ -86,6 +78,23 @@ fun LobstersCard( } } +@Composable +fun PostDetails( + post: SavedPost, +) { + PostTitle( + title = post.title, + ) + TagRow( + tags = post.tags, + ) + SubmitterName( + text = "Submitted by ${post.submitterName}", + avatarUrl = "https://lobste.rs/${post.submitterAvatarUrl}", + contentDescription = "Submitted by ${post.submitterName}", + ) +} + @Composable fun PostTitle( title: String, From d56b887a21b09bb5211761ff261ca18c8609a302 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 4 Oct 2021 17:34:04 +0530 Subject: [PATCH 09/14] all: flesh out comments UI and move to common --- .../claw/android/comments/CommentEntry.kt | 22 ------ .../claw/android/comments/Comments.kt | 19 ----- .../msfjarvis/claw/android/ui/LobstersApp.kt | 9 ++- .../dev/msfjarvis/claw/common/NetworkState.kt | 7 ++ .../claw/common/comments/CommentEntry.kt | 58 ++++++++++++++ .../claw/common/comments/Comments.kt | 76 +++++++++++++++++++ 6 files changed, 147 insertions(+), 44 deletions(-) delete mode 100644 android/src/main/kotlin/dev/msfjarvis/claw/android/comments/CommentEntry.kt delete mode 100644 android/src/main/kotlin/dev/msfjarvis/claw/android/comments/Comments.kt create mode 100644 common/src/commonMain/kotlin/dev/msfjarvis/claw/common/NetworkState.kt create mode 100644 common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt create mode 100644 common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/CommentEntry.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/CommentEntry.kt deleted file mode 100644 index 2d376dce..00000000 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/CommentEntry.kt +++ /dev/null @@ -1,22 +0,0 @@ -package dev.msfjarvis.claw.android.comments - -import android.text.Html -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.unit.dp -import dev.msfjarvis.claw.model.Comment - -@Composable -fun CommentEntry( - comment: Comment, -) { - Row(modifier = Modifier.padding(start = (10 * (comment.indentLevel.toFloat() - 1)).dp)) { - Text( - text = buildAnnotatedString { @Suppress("DEPRECATION") Html.fromHtml(comment.comment) }, - ) - } -} diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/Comments.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/Comments.kt deleted file mode 100644 index 3fe0ffc4..00000000 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/comments/Comments.kt +++ /dev/null @@ -1,19 +0,0 @@ -package dev.msfjarvis.claw.android.comments - -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.runtime.Composable -import dev.msfjarvis.claw.model.LobstersPostDetails - -@Composable -private fun CommentsPageInternal( - details: LobstersPostDetails, -) { - LazyColumn { items(details.comments) { CommentEntry(it) } } -} - -@Composable -fun CommentsPage( - postId: String, - getDetails: suspend (String) -> LobstersPostDetails, -) {} diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt index bcbca4cf..a32cfc4c 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt @@ -1,5 +1,6 @@ package dev.msfjarvis.claw.android.ui +import android.text.Html import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.lazy.rememberLazyListState @@ -28,8 +29,8 @@ import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsPadding import com.google.accompanist.insets.statusBarsPadding import com.google.accompanist.systemuicontroller.rememberSystemUiController -import dev.msfjarvis.claw.android.comments.CommentsPage import dev.msfjarvis.claw.android.viewmodel.ClawViewModel +import dev.msfjarvis.claw.common.comments.CommentsPage import dev.msfjarvis.claw.common.theme.LobstersTheme import dev.msfjarvis.claw.common.urllauncher.UrlLauncher @@ -78,12 +79,12 @@ fun LobstersApp( topBar = { ClawAppBar(modifier = Modifier.statusBarsPadding()) }, floatingActionButton = { ClawFab( - isFabVisible = isFabVisible, + isFabVisible = isFabVisible && navController.currentDestination?.route == "hottest", listState = listState, modifier = Modifier.navigationBarsPadding(), ) }, - ) { + ) { paddingValues -> NavHost(navController, startDestination = "hottest") { composable("hottest") { HottestPosts( @@ -101,6 +102,8 @@ fun LobstersApp( CommentsPage( postId = requireNotNull(backStackEntry.arguments?.getString("postId")), getDetails = viewModel::getPostComments, + parseHtml = { source -> Html.fromHtml(source).toString().trim() }, + paddingValues = paddingValues, ) } } diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/NetworkState.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/NetworkState.kt new file mode 100644 index 00000000..99666597 --- /dev/null +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/NetworkState.kt @@ -0,0 +1,7 @@ +package dev.msfjarvis.lobsters.ui.comments + +sealed class NetworkState { + class Success(val data: T) : NetworkState() + class Error(val message: String) : NetworkState() + object Loading : NetworkState() +} diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt new file mode 100644 index 00000000..fc0afc52 --- /dev/null +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt @@ -0,0 +1,58 @@ +package dev.msfjarvis.claw.common.comments + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Divider +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import dev.msfjarvis.claw.common.posts.PostDetails +import dev.msfjarvis.claw.common.posts.SubmitterName +import dev.msfjarvis.claw.common.posts.toDbModel +import dev.msfjarvis.claw.model.Comment +import dev.msfjarvis.claw.model.LobstersPostDetails + +@Composable +fun CommentsHeader( + postDetails: LobstersPostDetails, +) { + Surface { + Column( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp).fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + PostDetails( + post = postDetails.toDbModel(), + ) + } + } +} + +@Composable +fun CommentEntry( + comment: Comment, + parseHtml: (String) -> String, +) { + val indentLevel = comment.indentLevel.toInt() - 1 + val startPadding = ((10 * indentLevel) + 16).dp + + Divider(color = Color.Gray.copy(0.4f)) + + Row(modifier = Modifier.padding(start = startPadding, end = 8.dp, top = 4.dp, bottom = 4.dp)) { + val text = parseHtml(comment.comment) + Column { + SubmitterName( + text = "Submitted by ${comment.user.username}", + avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}", + contentDescription = "Submitted by ${comment.user.username}", + ) + Text(text = text, modifier = Modifier.padding(top = 8.dp)) + } + } +} diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt new file mode 100644 index 00000000..dd6ea428 --- /dev/null +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt @@ -0,0 +1,76 @@ +package dev.msfjarvis.claw.common.comments + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Divider +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import dev.msfjarvis.claw.model.LobstersPostDetails +import dev.msfjarvis.lobsters.ui.comments.NetworkState + +@Composable +private fun CommentsPageInternal( + details: LobstersPostDetails, + parseHtml: (String) -> String, + bottomPadding: Dp, +) { + LazyColumn(Modifier.padding(bottom = bottomPadding)) { + item { CommentsHeader(postDetails = details) } + + item { Spacer(modifier = Modifier.height(8.dp)) } + + items(details.comments) { item -> CommentEntry(item, parseHtml) } + + item { Divider(color = Color.Gray.copy(0.4f)) } + } +} + +@Suppress("UNCHECKED_CAST") +@Composable +fun CommentsPage( + postId: String, + getDetails: suspend (String) -> LobstersPostDetails, + parseHtml: (String) -> String, + paddingValues: PaddingValues, +) { + var postDetails: NetworkState by remember { mutableStateOf(NetworkState.Loading) } + + LaunchedEffect(postId) { postDetails = NetworkState.Success(getDetails(postId)) } + + when (postDetails) { + is NetworkState.Success<*> -> { + CommentsPageInternal( + (postDetails as NetworkState.Success).data, + parseHtml, + paddingValues.calculateBottomPadding(), + ) + } + is NetworkState.Error -> TODO("Handle no network scenario") + NetworkState.Loading -> ProgressBar(paddingValues.calculateBottomPadding()) + } +} + +@Composable +private fun ProgressBar(bottomPadding: Dp) { + Box( + modifier = Modifier.padding(bottom = bottomPadding).fillMaxSize(), + contentAlignment = Alignment.Center + ) { CircularProgressIndicator(color = MaterialTheme.colors.secondary) } +} From 79faf01c170b3ae0dc3098526c33c7a36d9689c8 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 4 Oct 2021 17:49:10 +0530 Subject: [PATCH 10/14] common: integrate CommentTreeColors into comments UI --- .../claw/common/comments/CommentEntry.kt | 34 ++++++++++++++++--- .../claw/common/comments/CommentTreeColors.kt | 2 +- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt index fc0afc52..197acecc 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt @@ -1,10 +1,16 @@ package dev.msfjarvis.claw.common.comments +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.material.Divider import androidx.compose.material.Surface import androidx.compose.material.Text @@ -41,12 +47,14 @@ fun CommentEntry( ) { val indentLevel = comment.indentLevel.toInt() - 1 val startPadding = ((10 * indentLevel) + 16).dp + val text = parseHtml(comment.comment) Divider(color = Color.Gray.copy(0.4f)) - - Row(modifier = Modifier.padding(start = startPadding, end = 8.dp, top = 4.dp, bottom = 4.dp)) { - val text = parseHtml(comment.comment) - Column { + Row(modifier = Modifier.height(IntrinsicSize.Min)) { + CommentTreeColors(indentLevel = indentLevel) + Column( + modifier = Modifier.padding(start = startPadding, end = 8.dp, top = 4.dp, bottom = 4.dp) + ) { SubmitterName( text = "Submitted by ${comment.user.username}", avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}", @@ -56,3 +64,21 @@ fun CommentEntry( } } } + +@Composable +private fun CommentTreeColors( + indentLevel: Int, + modifier: Modifier = Modifier, +) { + Box(modifier = modifier) { + for (level in 1..indentLevel) { + Box( + modifier = + Modifier.padding(start = (level * 12).dp) + .fillMaxHeight() + .width(1.dp) + .background(CommentTreeColor[level]) + ) + } + } +} diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentTreeColors.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentTreeColors.kt index 6fb6159b..11401ef9 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentTreeColors.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentTreeColors.kt @@ -24,7 +24,7 @@ object CommentTreeColor { Color(0xFFFF0097), Color(0xFF1E7145), ) - private val size = colors.size + val size = colors.size operator fun get(idx: Int): Color = colors[idx % size] } From b0c3af7883b8f0739fd49a590d089576c909cf55 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Tue, 5 Oct 2021 11:40:00 +0530 Subject: [PATCH 11/14] build: bump to AGP 7.1.0-alpha13 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8caa6771..7b0330bf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,7 @@ buildscript { classpath("com.android.tools:r8:3.1.17-dev") classpath(kotlin("gradle-plugin", version = kotlinVersion)) classpath(kotlin("serialization", version = kotlinVersion)) - classpath("com.android.tools.build:gradle:7.1.0-alpha12") + classpath("com.android.tools.build:gradle:7.1.0-alpha13") classpath("com.diffplug.spotless:spotless-plugin-gradle:5.15.0") classpath("com.google.dagger:hilt-android-gradle-plugin:2.39") } From 5749b98b233af7f93ec5b5f0c83ddd0d77499900 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Tue, 5 Oct 2021 14:34:19 +0530 Subject: [PATCH 12/14] common: delegate comment parsing to platforms --- android/build.gradle.kts | 4 ++++ .../dev/msfjarvis/claw/android/ui/LobstersApp.kt | 10 ++++++++-- .../msfjarvis/claw/common/comments/CommentEntry.kt | 14 ++++++-------- .../dev/msfjarvis/claw/common/comments/Comments.kt | 8 ++++---- gradle/libs.versions.toml | 6 ++++++ 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 1c558ec8..837f728f 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -22,6 +22,10 @@ dependencies { implementation(libs.androidx.lifecycle.compose) implementation(libs.androidx.navigation.compose) implementation(libs.androidx.paging.compose) + implementation(libs.compose.richtext.markdown) + implementation(libs.compose.richtext.material) + implementation(libs.compose.richtext.ui) + implementation(libs.copydown) implementation(libs.dagger.hilt.android) implementation(libs.sqldelight.extensions.coroutines) implementation(libs.kotlinx.serialization.json) diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt index a32cfc4c..e2bc2756 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt @@ -1,6 +1,5 @@ package dev.msfjarvis.claw.android.ui -import android.text.Html import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.lazy.rememberLazyListState @@ -29,10 +28,13 @@ import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsPadding import com.google.accompanist.insets.statusBarsPadding import com.google.accompanist.systemuicontroller.rememberSystemUiController +import com.halilibo.richtext.markdown.Markdown +import com.halilibo.richtext.ui.material.MaterialRichText import dev.msfjarvis.claw.android.viewmodel.ClawViewModel import dev.msfjarvis.claw.common.comments.CommentsPage import dev.msfjarvis.claw.common.theme.LobstersTheme import dev.msfjarvis.claw.common.urllauncher.UrlLauncher +import io.github.furstenheim.CopyDown private const val ScrollDelta = 50 @@ -42,6 +44,7 @@ fun LobstersApp( viewModel: ClawViewModel = viewModel(), urlLauncher: UrlLauncher, ) { + val copydown = remember { CopyDown() } val systemUiController = rememberSystemUiController() val scaffoldState = rememberScaffoldState() val listState = rememberLazyListState() @@ -102,7 +105,10 @@ fun LobstersApp( CommentsPage( postId = requireNotNull(backStackEntry.arguments?.getString("postId")), getDetails = viewModel::getPostComments, - parseHtml = { source -> Html.fromHtml(source).toString().trim() }, + renderMarkdown = { source, modifier -> + val markdown = copydown.convert(source) + MaterialRichText(modifier = modifier) { Markdown(markdown) } + }, paddingValues = paddingValues, ) } diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt index 197acecc..5d4f0999 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt @@ -4,16 +4,14 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material.Divider import androidx.compose.material.Surface -import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -43,15 +41,15 @@ fun CommentsHeader( @Composable fun CommentEntry( comment: Comment, - parseHtml: (String) -> String, + renderMarkdown: @Composable (comment: String, modifier: Modifier) -> Unit, ) { val indentLevel = comment.indentLevel.toInt() - 1 val startPadding = ((10 * indentLevel) + 16).dp - val text = parseHtml(comment.comment) Divider(color = Color.Gray.copy(0.4f)) - Row(modifier = Modifier.height(IntrinsicSize.Min)) { - CommentTreeColors(indentLevel = indentLevel) + Row(modifier = Modifier.wrapContentHeight()) { + // Don't work without IntrinsicSize, which we cannot use with the Android markdown implementation + // CommentTreeColors(indentLevel = indentLevel) Column( modifier = Modifier.padding(start = startPadding, end = 8.dp, top = 4.dp, bottom = 4.dp) ) { @@ -60,7 +58,7 @@ fun CommentEntry( avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}", contentDescription = "Submitted by ${comment.user.username}", ) - Text(text = text, modifier = Modifier.padding(top = 8.dp)) + renderMarkdown(comment.comment, Modifier.padding(top = 8.dp)) } } } diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt index dd6ea428..feb0da24 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt @@ -28,7 +28,7 @@ import dev.msfjarvis.lobsters.ui.comments.NetworkState @Composable private fun CommentsPageInternal( details: LobstersPostDetails, - parseHtml: (String) -> String, + renderMarkdown: @Composable (comment: String, modifier: Modifier) -> Unit, bottomPadding: Dp, ) { LazyColumn(Modifier.padding(bottom = bottomPadding)) { @@ -36,7 +36,7 @@ private fun CommentsPageInternal( item { Spacer(modifier = Modifier.height(8.dp)) } - items(details.comments) { item -> CommentEntry(item, parseHtml) } + items(details.comments) { item -> CommentEntry(item, renderMarkdown) } item { Divider(color = Color.Gray.copy(0.4f)) } } @@ -47,7 +47,7 @@ private fun CommentsPageInternal( fun CommentsPage( postId: String, getDetails: suspend (String) -> LobstersPostDetails, - parseHtml: (String) -> String, + renderMarkdown: @Composable (comment: String, modifier: Modifier) -> Unit, paddingValues: PaddingValues, ) { var postDetails: NetworkState by remember { mutableStateOf(NetworkState.Loading) } @@ -58,7 +58,7 @@ fun CommentsPage( is NetworkState.Success<*> -> { CommentsPageInternal( (postDetails as NetworkState.Success).data, - parseHtml, + renderMarkdown, paddingValues.calculateBottomPadding(), ) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b8c9ffc0..f4e6d5b4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,6 +3,7 @@ accompanist = "0.19.0" aurora = "0.0.54-SNAPSHOT" coroutines = "1.5.2" hilt = "2.39" +richtext = "0.8.1" serialization = "1.3.0" sqldelight = "1.5.1" @@ -37,6 +38,11 @@ dagger-hilt-android = { module = "com.google.dagger:hilt-android", version.ref = dagger-hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } dagger-hilt-core = { module = "com.google.dagger:hilt-core", version.ref = "hilt" } +compose-richtext-ui = { module = "com.halilibo.compose-richtext:richtext-ui", version.ref = "richtext" } +compose-richtext-material = { module = "com.halilibo.compose-richtext:richtext-ui-material", version.ref = "richtext" } +compose-richtext-markdown = { module = "com.halilibo.compose-richtext:richtext-commonmark", version.ref = "richtext" } +copydown = "io.github.furstenheim:copy_down:1.0" + multiplatform-paging = "dev.msfjarvis.paging:multiplatform-paging:0.4.5-SNAPSHOT" retrofit-lib = "com.squareup.retrofit2:retrofit:2.9.0" From 87e9c218a27d8cbb4fdaf68aac85c2962b5bdc33 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Wed, 6 Oct 2021 10:50:34 +0530 Subject: [PATCH 13/14] android: switch to MikePenz' Markdown renderer --- android/build.gradle.kts | 4 +--- .../kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt | 5 ++--- .../dev/msfjarvis/claw/common/comments/CommentEntry.kt | 8 ++++---- gradle/libs.versions.toml | 5 +---- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 837f728f..9ae04a46 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -22,9 +22,7 @@ dependencies { implementation(libs.androidx.lifecycle.compose) implementation(libs.androidx.navigation.compose) implementation(libs.androidx.paging.compose) - implementation(libs.compose.richtext.markdown) - implementation(libs.compose.richtext.material) - implementation(libs.compose.richtext.ui) + implementation(libs.multiplatform.markdown.android) implementation(libs.copydown) implementation(libs.dagger.hilt.android) implementation(libs.sqldelight.extensions.coroutines) diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt index e2bc2756..f4cf8455 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt @@ -28,8 +28,7 @@ import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsPadding import com.google.accompanist.insets.statusBarsPadding import com.google.accompanist.systemuicontroller.rememberSystemUiController -import com.halilibo.richtext.markdown.Markdown -import com.halilibo.richtext.ui.material.MaterialRichText +import com.mikepenz.markdown.Markdown import dev.msfjarvis.claw.android.viewmodel.ClawViewModel import dev.msfjarvis.claw.common.comments.CommentsPage import dev.msfjarvis.claw.common.theme.LobstersTheme @@ -107,7 +106,7 @@ fun LobstersApp( getDetails = viewModel::getPostComments, renderMarkdown = { source, modifier -> val markdown = copydown.convert(source) - MaterialRichText(modifier = modifier) { Markdown(markdown) } + Markdown(markdown, modifier = modifier) }, paddingValues = paddingValues, ) diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt index 5d4f0999..1fe73a5d 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt @@ -4,12 +4,13 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material.Divider import androidx.compose.material.Surface import androidx.compose.runtime.Composable @@ -47,9 +48,8 @@ fun CommentEntry( val startPadding = ((10 * indentLevel) + 16).dp Divider(color = Color.Gray.copy(0.4f)) - Row(modifier = Modifier.wrapContentHeight()) { - // Don't work without IntrinsicSize, which we cannot use with the Android markdown implementation - // CommentTreeColors(indentLevel = indentLevel) + Row(modifier = Modifier.height(IntrinsicSize.Min)) { + CommentTreeColors(indentLevel = indentLevel) Column( modifier = Modifier.padding(start = startPadding, end = 8.dp, top = 4.dp, bottom = 4.dp) ) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f4e6d5b4..280a0cfc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,6 @@ accompanist = "0.19.0" aurora = "0.0.54-SNAPSHOT" coroutines = "1.5.2" hilt = "2.39" -richtext = "0.8.1" serialization = "1.3.0" sqldelight = "1.5.1" @@ -38,9 +37,7 @@ dagger-hilt-android = { module = "com.google.dagger:hilt-android", version.ref = dagger-hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } dagger-hilt-core = { module = "com.google.dagger:hilt-core", version.ref = "hilt" } -compose-richtext-ui = { module = "com.halilibo.compose-richtext:richtext-ui", version.ref = "richtext" } -compose-richtext-material = { module = "com.halilibo.compose-richtext:richtext-ui-material", version.ref = "richtext" } -compose-richtext-markdown = { module = "com.halilibo.compose-richtext:richtext-commonmark", version.ref = "richtext" } +multiplatform-markdown-android = "com.mikepenz:multiplatform-markdown-renderer-android:0.0.1" copydown = "io.github.furstenheim:copy_down:1.0" multiplatform-paging = "dev.msfjarvis.paging:multiplatform-paging:0.4.5-SNAPSHOT" From 6272d67024de6635ed15ae94d6426bdad675a24f Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Wed, 6 Oct 2021 11:56:47 +0530 Subject: [PATCH 14/14] common: tweak comment tree spacing --- .../dev/msfjarvis/claw/common/comments/CommentEntry.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt index 1fe73a5d..3954cf4d 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt @@ -45,14 +45,11 @@ fun CommentEntry( renderMarkdown: @Composable (comment: String, modifier: Modifier) -> Unit, ) { val indentLevel = comment.indentLevel.toInt() - 1 - val startPadding = ((10 * indentLevel) + 16).dp Divider(color = Color.Gray.copy(0.4f)) Row(modifier = Modifier.height(IntrinsicSize.Min)) { CommentTreeColors(indentLevel = indentLevel) - Column( - modifier = Modifier.padding(start = startPadding, end = 8.dp, top = 4.dp, bottom = 4.dp) - ) { + Column(modifier = Modifier.padding(start = 12.dp, end = 8.dp, top = 4.dp, bottom = 4.dp)) { SubmitterName( text = "Submitted by ${comment.user.username}", avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}", @@ -72,7 +69,7 @@ private fun CommentTreeColors( for (level in 1..indentLevel) { Box( modifier = - Modifier.padding(start = (level * 12).dp) + Modifier.padding(start = (12 + ((level - 1) * 10)).dp) .fillMaxHeight() .width(1.dp) .background(CommentTreeColor[level])