Skip to content
This repository was archived by the owner on Sep 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions Pocket/src/main/java/com/pocket/app/list/notes/Notes.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.pocket.app.list.notes

import android.text.Spanned
import android.text.format.DateFormat
import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateContentSize
Expand Down Expand Up @@ -45,7 +46,7 @@ import com.pocket.app.App
import com.pocket.app.list.MyListViewModel
import com.pocket.data.models.Note
import com.pocket.sdk.api.value.MarkdownString
import com.pocket.sdk.util.MarkdownHandler
import com.pocket.sdk.util.MarkdownFormatter
import com.pocket.ui.view.button.BoxButton
import com.pocket.ui.view.button.OverflowMenuIcon
import com.pocket.ui.view.button.PocketIconButton
Expand Down Expand Up @@ -107,8 +108,8 @@ private fun NotesList(
) {
val context = LocalContext.current
val dateFormat = remember(context) { DateFormat.getMediumDateFormat(context) }
val markdownHandler = remember(context) {
MarkdownHandler(context) { App.viewUrl(context, it) }
val markdownFormatter = remember(context) {
MarkdownFormatter(context, App::viewUrl)
}

PullToRefreshBox(
Expand All @@ -125,9 +126,10 @@ private fun NotesList(
if (note != null) {
NoteRow(
note.title,
note.content,
note.date.formatWith(dateFormat),
markdownHandler,
remember(note.content) {
markdownFormatter.format(note.content.value)
},
remember(note.date) { note.date.formatWith(dateFormat) },
Modifier
.padding(20.dp)
.animateItem(),
Expand All @@ -147,9 +149,8 @@ private fun Instant.formatWith(dateFormat: java.text.DateFormat): String {
@Composable
private fun NoteRow(
title: String?,
content: MarkdownString,
content: Spanned,
date: String,
markdownHandler: MarkdownHandler,
modifier: Modifier = Modifier,
) = Row(
modifier,
Expand All @@ -171,9 +172,7 @@ private fun NoteRow(
Modifier.animateContentSize(),
onReset = { /* Nothing to do, but needed to opt into view reuse. */ },
) {
root.apply {
with(markdownHandler) { setMarkdownString(it) }
}
root.text = it
}
}
Spacer(Modifier.height(PocketTheme.dimensions.spaceSmall))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ import com.pocket.app.auth.AuthenticationActivity
import com.pocket.app.home.slates.overflow.RecommendationOverflowBottomSheetFragment
import com.pocket.app.reader.Reader
import com.pocket.app.reader.ReaderFragment
import com.pocket.sdk.api.value.MarkdownString
import com.pocket.sdk.tts.Listen
import com.pocket.sdk.util.AbsPocketFragment
import com.pocket.sdk.util.MarkdownHandler
import com.pocket.sdk.util.MarkdownFormatter
import com.pocket.util.android.FormFactor
import com.pocket.util.android.navigateSafely
import com.pocket.util.android.view.InstantChangeItemAnimator
Expand Down Expand Up @@ -50,7 +49,7 @@ class CollectionFragment : AbsPocketFragment(), Reader.NavigationEventHandler {
private val binding: FragmentCollectionBinding
get() = _binding!!

private lateinit var markdownHandler: MarkdownHandler
private lateinit var markdown: MarkdownFormatter

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -72,7 +71,7 @@ class CollectionFragment : AbsPocketFragment(), Reader.NavigationEventHandler {
super.onViewCreated(view, savedInstanceState)
Log.d("Navigation", "CollectionFragment")
tracker.track(CollectionEvents.screenView())
markdownHandler = MarkdownHandler(requireContext()) { readerFragment?.openUrl(it) }
markdown = MarkdownFormatter(requireContext()) { _, url -> readerFragment?.openUrl(url) }
setupUiStateListener()
setupToolbar()
setupRecyclerView()
Expand Down Expand Up @@ -122,8 +121,9 @@ class CollectionFragment : AbsPocketFragment(), Reader.NavigationEventHandler {

private fun setupUiStateListener() {
viewModel.uiState.collectWhenResumed(viewLifecycleOwner) { uiState ->
with(markdownHandler) {
uiState.intro?.let { binding.intro.setMarkdownString(MarkdownString(uiState.intro)) }
uiState.intro?.let {
binding.intro.setMovementMethodForLinks(true)
binding.intro.text = markdown.format(it)
}
}
}
Expand All @@ -132,7 +132,7 @@ class CollectionFragment : AbsPocketFragment(), Reader.NavigationEventHandler {
binding.storyList.adapter = CollectionStoryAdapter(
viewLifecycleOwner = viewLifecycleOwner,
viewModel = viewModel,
markdown = markdownHandler,
markdown = markdown,
corpusRecommendationId = args.url,
)
binding.storyList.itemAnimator = InstantChangeItemAnimator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.ideashower.readitlater.databinding.ViewHomeHeroCardBinding
import com.pocket.sdk.api.value.MarkdownString
import com.pocket.sdk.util.MarkdownHandler
import com.pocket.sdk.util.MarkdownFormatter
import com.pocket.sdk2.view.LazyAssetBitmap
import com.pocket.ui.util.LazyBitmapDrawable
import com.pocket.util.android.repeatOnCreated

class CollectionStoryAdapter(
viewLifecycleOwner: LifecycleOwner,
private val viewModel: CollectionViewModel,
private val markdown: MarkdownHandler,
private val markdown: MarkdownFormatter,
private val corpusRecommendationId: String?,
): ListAdapter<CollectionViewModel.StoryUiState,
CollectionStoryAdapter.ViewHolder>(DIFF_CALLBACK) {
Expand Down Expand Up @@ -51,9 +50,8 @@ class CollectionStoryAdapter(
title.text = state.title

excerpt.visibility = View.VISIBLE
with(markdown) {
excerpt.setMarkdownString(MarkdownString(state.excerpt))
}
excerpt.setMovementMethodForLinks(true)
excerpt.text = markdown.format(state.excerpt)

collectionLabel.visibility = if (state.collectionLabelVisible) {
View.VISIBLE
Expand Down Expand Up @@ -85,7 +83,6 @@ class CollectionStoryAdapter(
corpusRecommendationId = corpusRecommendationId,
)
}
excerpt.setOnClickListener { viewModel.onCardClicked(state.url) }
root.setOnClickListener { viewModel.onCardClicked(state.url) }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ class DeleteAccountFragment : AbsPocketFragment() {

with(cancelPremiumLabel) {
applyAnnotations()
setMovementMethodForLinks()
setMovementMethodForLinks(true)
}

cancelPremiumCheckbox.setOnCheckedChangeListener { _, isChecked ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.pocket.sdk.util

import android.content.Context
import android.widget.TextView
import com.pocket.sdk.api.value.MarkdownString
import com.pocket.ui.text.CustomTypefaceSpan
import com.pocket.ui.text.Fonts
import io.noties.markwon.AbstractMarkwonPlugin
Expand All @@ -12,37 +10,30 @@ import io.noties.markwon.MarkwonSpansFactory
import org.commonmark.node.Emphasis
import org.commonmark.node.StrongEmphasis

class MarkdownHandler(
class MarkdownFormatter(
context: Context,
onLinkClicked: (link: String) -> Unit,
onLinkClicked: (context: Context, link: String) -> Unit,
) {

private val markwon = Markwon.builder(context)
.usePlugin(object : AbstractMarkwonPlugin() {
override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
builder
.setFactory(Emphasis::class.java) {_, _ ->
.setFactory(Emphasis::class.java) { _, _ ->
CustomTypefaceSpan(Fonts.get(context, Fonts.Font.GRAPHIK_LCG_REGULAR_ITALIC))
}
.setFactory(StrongEmphasis::class.java) {_, _ ->
.setFactory(StrongEmphasis::class.java) { _, _ ->
CustomTypefaceSpan(Fonts.get(context, Fonts.Font.GRAPHIK_LCG_MEDIUM))
}
}

override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
builder.linkResolver { _, link ->
onLinkClicked(link)
builder.linkResolver { view, link ->
onLinkClicked(view.context, link)
}
}
})
.build()

private val parser = MarkdownString.Parser { mdString ->
val node = markwon.parse(mdString.value)
markwon.render(node)
}

fun TextView.setMarkdownString(markdownString: MarkdownString) {
markwon.setParsedMarkdown(this, markdownString.parsed(parser))
}
}
fun format(markdown: String) = markwon.toMarkdown(markdown)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import androidx.core.content.ContextCompat
import androidx.core.widget.ImageViewCompat
import androidx.databinding.BindingAdapter
import com.pocket.app.App
import com.pocket.sdk.api.value.MarkdownString
import com.pocket.sdk.util.MarkdownHandler
import com.pocket.sdk.util.MarkdownFormatter
import com.pocket.ui.view.themed.ThemedTextView

@BindingAdapter("visibility")
Expand Down Expand Up @@ -37,10 +36,7 @@ fun setTextUnderline(view: TextView, enabled: Boolean) {

@BindingAdapter("textMarkdown")
fun setTextMarkdown(view: ThemedTextView, markdown: String) {
with(MarkdownHandler(view.context) { App.viewUrl(view.context, it) }) {
view.setMarkdownString(MarkdownString(markdown))
}

view.text = MarkdownFormatter(view.context, App::viewUrl).format(markdown)
}

@BindingAdapter("drawableId")
Expand Down
1 change: 1 addition & 0 deletions Pocket/src/main/res/layout/fragment_authentication.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/continueSignedOutButton"
app:movementMethodForLinks="@{true}"
app:textMarkdown="@{@string/authentication_legal_disclaimer}"
/>
<FrameLayout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,12 @@ public void setBold(boolean bold) {
}
}

public void setMovementMethodForLinks() {
setMovementMethod(new FixedLinkMethod());
public void setMovementMethodForLinks(boolean enabled) {
if (enabled) {
setMovementMethod(new FixedLinkMethod());
} else {
setMovementMethod(getDefaultMovementMethod());
}
}

@SuppressLint("ClickableViewAccessibility") // Super is always called, so this lint warning is too paranoid.
Expand Down