Skip to content

Commit

Permalink
When article shortcut is clicked, then fetch the article source
Browse files Browse the repository at this point in the history
  • Loading branch information
msasikanth committed Jan 26, 2024
1 parent a247b16 commit b8ada9d
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ sealed interface ReaderEvent {
data object BackClicked : ReaderEvent

data object TogglePostBookmark : ReaderEvent

data object ArticleShortcutClicked : ReaderEvent
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.arkivanov.essenty.instancekeeper.InstanceKeeper
import com.arkivanov.essenty.instancekeeper.getOrCreate
import com.arkivanov.essenty.lifecycle.doOnCreate
import dev.sasikanth.readability.Readability
import dev.sasikanth.rss.reader.core.network.post.PostSourceFetcher
import dev.sasikanth.rss.reader.repository.RssRepository
import dev.sasikanth.rss.reader.util.DispatchersProvider
import dev.sasikanth.rss.reader.util.relativeDurationString
Expand All @@ -40,6 +41,7 @@ import me.tatarka.inject.annotations.Inject
class ReaderPresenter(
dispatchersProvider: DispatchersProvider,
private val rssRepository: RssRepository,
private val postSourceFetcher: PostSourceFetcher,
@Assisted private val postLink: String,
@Assisted componentContext: ComponentContext,
@Assisted private val goBack: () -> Unit
Expand All @@ -50,7 +52,8 @@ class ReaderPresenter(
PresenterInstance(
dispatchersProvider = dispatchersProvider,
rssRepository = rssRepository,
postLink = postLink
postLink = postLink,
postSourceFetcher = postSourceFetcher
)
}

Expand All @@ -75,6 +78,7 @@ class ReaderPresenter(
private val dispatchersProvider: DispatchersProvider,
private val rssRepository: RssRepository,
private val postLink: String,
private val postSourceFetcher: PostSourceFetcher,
) : InstanceKeeper.Instance {

private val coroutineScope = CoroutineScope(SupervisorJob() + dispatchersProvider.main)
Expand All @@ -94,6 +98,7 @@ class ReaderPresenter(
/* no-op */
}
ReaderEvent.TogglePostBookmark -> togglePostBookmark(postLink)
ReaderEvent.ArticleShortcutClicked -> articleShortcutClicked()
}
}

Expand Down Expand Up @@ -139,7 +144,18 @@ class ReaderPresenter(
}
}

private suspend fun extractArticleHtmlContent(feedLink: String, content: String) =
withContext(dispatchersProvider.io) { Readability(feedLink, content) }.parse().content
private suspend fun extractArticleHtmlContent(postLink: String, content: String) =
withContext(dispatchersProvider.io) { Readability(postLink, content) }.parse().content

private fun articleShortcutClicked() {
coroutineScope.launch {
val content = postSourceFetcher.fetch(postLink)
if (content != null) {
_state.update { it.copy(isFetchingFullArticle = true) }
val htmlContent = extractArticleHtmlContent(postLink, content)
_state.update { it.copy(content = htmlContent, isFetchingFullArticle = false) }
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ internal data class ReaderState(
val content: String?,
val publishedAt: String?,
val isBookmarked: Boolean?,
val feed: Feed? = null
val feed: Feed?,
val isFetchingFullArticle: Boolean?
) {

val hasContent: Boolean
Expand All @@ -42,7 +43,8 @@ internal data class ReaderState(
content = null,
publishedAt = null,
isBookmarked = null,
feed = null
feed = null,
isFetchingFullArticle = null
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ package dev.sasikanth.rss.reader.reader.ui

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Close
Expand Down Expand Up @@ -55,6 +55,7 @@ import dev.sasikanth.material.color.utilities.utils.StringUtils
import dev.sasikanth.rss.reader.platform.LocalLinkHandler
import dev.sasikanth.rss.reader.reader.ReaderEvent
import dev.sasikanth.rss.reader.reader.ReaderPresenter
import dev.sasikanth.rss.reader.resources.icons.ArticleShortcut
import dev.sasikanth.rss.reader.resources.icons.Bookmark
import dev.sasikanth.rss.reader.resources.icons.Bookmarked
import dev.sasikanth.rss.reader.resources.icons.Share
Expand Down Expand Up @@ -107,27 +108,49 @@ internal fun ReaderScreen(presenter: ReaderPresenter, modifier: Modifier = Modif
modifier =
Modifier.fillMaxWidth()
.windowInsetsPadding(WindowInsets.navigationBars)
.padding(vertical = 8.dp)
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(Modifier.weight(1f))
val bookmarkIcon =
if (state.isBookmarked == true) {
TwineIcons.Bookmarked
Box(Modifier.weight(1f), contentAlignment = Alignment.Center) {
val bookmarkIcon =
if (state.isBookmarked == true) {
TwineIcons.Bookmarked
} else {
TwineIcons.Bookmark
}
IconButton(onClick = { presenter.dispatch(ReaderEvent.TogglePostBookmark) }) {
Icon(bookmarkIcon, contentDescription = null)
}
}

Box(Modifier.weight(1f), contentAlignment = Alignment.Center) {
if (state.isFetchingFullArticle == true) {
CircularProgressIndicator(
color = AppTheme.colorScheme.tintedForeground,
modifier = Modifier.requiredSize(24.dp)
)
} else {
TwineIcons.Bookmark
IconButton(
onClick = {
coroutineScope.launch { presenter.dispatch(ReaderEvent.ArticleShortcutClicked) }
}
) {
Icon(TwineIcons.ArticleShortcut, contentDescription = null)
}
}
IconButton(onClick = { presenter.dispatch(ReaderEvent.TogglePostBookmark) }) {
Icon(bookmarkIcon, contentDescription = null)
}
Spacer(Modifier.weight(1f))
IconButton(onClick = { coroutineScope.launch { linkHandler.openLink(state.link) } }) {
Icon(TwineIcons.Website, contentDescription = null)

Box(Modifier.weight(1f), contentAlignment = Alignment.Center) {
IconButton(onClick = { coroutineScope.launch { linkHandler.openLink(state.link) } }) {
Icon(TwineIcons.Website, contentDescription = null)
}
}
Spacer(Modifier.weight(1f))
IconButton(onClick = { coroutineScope.launch { sharedHandler.share(state.link) } }) {
Icon(TwineIcons.Share, contentDescription = null)

Box(Modifier.weight(1f), contentAlignment = Alignment.Center) {
IconButton(onClick = { coroutineScope.launch { sharedHandler.share(state.link) } }) {
Icon(TwineIcons.Share, contentDescription = null)
}
}
Spacer(Modifier.weight(1f))
}
}
},
Expand Down Expand Up @@ -163,11 +186,12 @@ internal fun ReaderScreen(presenter: ReaderPresenter, modifier: Modifier = Modif
val dividerColor =
StringUtils.hexFromArgb(AppTheme.colorScheme.surfaceContainerHigh.toArgb())

val htmlTemplate = remember {
// TODO: Extract out the HTML rendering and customisation to separate class
// with actual templating
// language=HTML
"""
val htmlTemplate =
remember(state.content) {
// TODO: Extract out the HTML rendering and customisation to separate class
// with actual templating
// language=HTML
"""
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
Expand Down Expand Up @@ -299,16 +323,17 @@ internal fun ReaderScreen(presenter: ReaderPresenter, modifier: Modifier = Modif
</body>
</html>
"""
.trimIndent()
}
.trimIndent()
}
val webViewState = rememberWebViewStateWithHTMLData(htmlTemplate)

Box(Modifier.fillMaxSize().padding(paddingValues).padding(horizontal = 16.dp)) {
WebView(
modifier = Modifier.fillMaxSize(),
state = webViewState,
navigator = navigator,
webViewJsBridge = jsBridge
webViewJsBridge = jsBridge,
captureBackPresses = false
)
}
}
Expand Down

0 comments on commit b8ada9d

Please sign in to comment.