Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8772fc4
Start reader improvements feature branch
nbradbury Mar 25, 2026
0fe604f
Remove content-scanning fallbacks for Reader featured image
nbradbury Mar 25, 2026
ff77238
Move featured image above title and excerpt in Reader post cards
nbradbury Mar 25, 2026
5265ae1
Fix grammar in code comments
nbradbury Mar 26, 2026
89c4227
Merge remote-tracking branch 'origin/trunk' into issue/reader-feature…
nbradbury Mar 26, 2026
1269c94
Fit portrait featured images in Reader instead of cropping
nbradbury Mar 26, 2026
e15f7a2
Fix import ordering in ReaderPostNewViewHolder
nbradbury Mar 26, 2026
8bcb7ba
Merge remote-tracking branch 'origin/trunk' into issue/reader-portrai…
nbradbury Mar 27, 2026
63fc925
Fix import ordering and remove unnecessary @JvmOverloads in ImageManager
nbradbury Mar 27, 2026
22cedba
Merge remote-tracking branch 'origin/trunk' into issue/reader-portrai…
nbradbury Mar 27, 2026
bdd5c62
Redesign Reader post detail header for adaptive layout
nbradbury Mar 27, 2026
e709ea7
Simplify Reader post detail header and image transformation code
nbradbury Mar 27, 2026
db6cd2c
Fix crash in Reader post detail caused by unresolvable Material3 attr…
nbradbury Mar 27, 2026
a1eeb7f
Simplify Reader post detail: remove dead code and redundant scroll li…
nbradbury Mar 27, 2026
17a6afc
Use fastStripHtml for reading time and fix code quality issues
nbradbury Mar 27, 2026
7914ed7
Fix blog section spacing between avatar and text
nbradbury Mar 27, 2026
ebc1c46
Merge remote-tracking branch 'origin/trunk' into feature/CMM-2002-ada…
nbradbury Mar 27, 2026
80c7aa0
Hide author name when blank or same as blog name
nbradbury Mar 27, 2026
b334c3c
Show blog description instead of post excerpt in detail header
nbradbury Mar 27, 2026
4a2692a
Reorder Reader post detail header layout
nbradbury Mar 27, 2026
6892a72
Fix blog section layout spacing and alignment
nbradbury Mar 27, 2026
07aa8f8
Make subscribe button smaller and place it after blog name
nbradbury Mar 28, 2026
4691444
Fix featured image duplication after returning from comments
nbradbury Mar 28, 2026
94841fc
Simplify Reader post detail header code
nbradbury Mar 28, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import android.view.ViewGroup
import android.view.ViewStub
import android.webkit.CookieManager
import android.webkit.WebView
import android.widget.ImageView.ScaleType.CENTER_CROP
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
Expand All @@ -37,6 +36,7 @@ import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
Expand All @@ -48,7 +48,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.CollapsingToolbarLayout
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
Expand Down Expand Up @@ -118,7 +117,6 @@ import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiSt
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.LoadingUiState
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.ReaderPostDetailsUiState
import org.wordpress.android.ui.reader.views.ReaderIconCountView
import org.wordpress.android.ui.reader.views.ReaderPostDetailsHeaderViewUiStateBuilder
import org.wordpress.android.ui.reader.views.ReaderSimplePostContainerView
import org.wordpress.android.ui.reader.views.ReaderWebView
import org.wordpress.android.ui.reader.views.ReaderWebView.ReaderCustomViewListener
Expand Down Expand Up @@ -146,7 +144,6 @@ import org.wordpress.android.util.extensions.getSerializableCompat
import org.wordpress.android.util.extensions.setVisible
import org.wordpress.android.util.helpers.SwipeToRefreshHelper
import org.wordpress.android.util.image.ImageManager
import org.wordpress.android.util.image.ImageType.PHOTO
import org.wordpress.android.util.widgets.CustomSwipeRefreshLayout
import org.wordpress.android.viewmodel.ContextProvider
import org.wordpress.android.viewmodel.observeEvent
Expand All @@ -158,7 +155,6 @@ import java.net.HttpURLConnection
import java.util.EnumSet
import javax.inject.Inject
import com.google.android.material.R as MaterialR
import androidx.core.view.isGone
import androidx.core.net.toUri
import androidx.core.view.forEach

Expand Down Expand Up @@ -251,9 +247,6 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
@Inject
internal lateinit var imageManager: ImageManager

@Inject
lateinit var postDetailsHeaderViewUiStateBuilder: ReaderPostDetailsHeaderViewUiStateBuilder

@Inject
lateinit var readerUtilsWrapper: ReaderUtilsWrapper

Expand Down Expand Up @@ -292,36 +285,6 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
val isCustomViewShowing: Boolean
get() = view != null && readerWebView.isCustomViewShowing

private val appBarLayoutOffsetChangedListener =
AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
val collapsingToolbarLayout = appBarLayout
.findViewById<CollapsingToolbarLayout>(R.id.collapsing_toolbar)
val toolbar = appBarLayout.findViewById<Toolbar>(R.id.toolbar_main)

view?.context?.let { context ->
val menu: Menu = toolbar.menu

val collapsingToolbarHeight = collapsingToolbarLayout.height
val isCollapsed = (collapsingToolbarHeight + verticalOffset) <=
collapsingToolbarLayout.scrimVisibleHeightTrigger

val color = if (isCollapsed) {
context.getColorFromAttribute(MaterialR.attr.colorOnSurface)
} else {
ContextCompat.getColor(context, R.color.white)
}
val colorFilter = BlendModeColorFilterCompat
.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP)

toolbar.setTitleTextColor(color)
toolbar.navigationIcon?.colorFilter = colorFilter

menu.forEach {
it.icon?.colorFilter = colorFilter
}
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
(requireActivity().application as WordPress).component().inject(this)
Expand Down Expand Up @@ -404,8 +367,6 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
appBar = view.findViewById(R.id.appbar_with_collapsing_toolbar_layout)
toolBar = appBar.findViewById(R.id.toolbar_main)

appBar.addOnOffsetChangedListener(appBarLayoutOffsetChangedListener)

// Fixes collapsing toolbar layout being obscured by the status bar when drawn behind it
ViewCompat.setOnApplyWindowInsetsListener(appBar) { _: View, insets: WindowInsetsCompat ->
val insetTop = insets.getInsets(WindowInsetsCompat. Type. systemBars()).top
Expand All @@ -430,6 +391,21 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
toolBar.setNavigationIcon(R.drawable.ic_arrow_left_white_24dp)
toolBar.setNavigationOnClickListener { requireActivity().onBackPressedDispatcher.onBackPressed() }
}

applyToolbarIconColors(view.context)
}

private fun applyToolbarIconColors(context: Context) {
val color = context.getColorFromAttribute(
MaterialR.attr.colorOnSurface
)
val colorFilter = BlendModeColorFilterCompat
.createBlendModeColorFilterCompat(
color, BlendModeCompat.SRC_ATOP
)
toolBar.setTitleTextColor(color)
toolBar.navigationIcon?.colorFilter = colorFilter
toolBar.menu.forEach { it.icon?.colorFilter = colorFilter }
}

private fun initScrollView(view: View) {
Expand Down Expand Up @@ -801,7 +777,6 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
binding.headerView.updatePost(state.headerUiState, getReadingPreferences())
showOrHideMoreMenu(state)

updateFeaturedImage(state.featuredImageUiState, binding)
updateExcerptFooter(state.excerptFooterUiState)

with(layoutFooterBinding) {
Expand Down Expand Up @@ -933,23 +908,6 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
.show(childFragmentManager, ReaderLoginRequiredBottomSheetFragment.TAG)
}

private fun updateFeaturedImage(
state: ReaderPostDetailsUiState.ReaderPostFeaturedImageUiState?,
binding: ReaderFragmentPostDetailBinding
) {
val featuredImageView = binding.appbarWithCollapsingToolbarLayout.featuredImage
featuredImageView.setVisible(state != null)
state?.let {
featuredImageView.layoutParams.height = it.height
it.url?.let { url ->
imageManager.load(featuredImageView, PHOTO, url, CENTER_CROP)
featuredImageView.setOnClickListener {
viewModel.onFeaturedImageClicked(blogId = state.blogId, featuredImageUrl = url)
}
}
}
}

private fun updateExcerptFooter(state: ReaderPostDetailsUiState.ExcerptFooterUiState?) {
// if we're showing just the excerpt, show a footer which links to the full post
excerptFooter.setVisible(state != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import org.wordpress.android.ui.reader.discover.ReaderPostCardActionType
import org.wordpress.android.ui.reader.discover.ReaderPostUiStateBuilder
import org.wordpress.android.ui.reader.models.ReaderSimplePost
import org.wordpress.android.ui.reader.models.ReaderSimplePostList
import org.wordpress.android.ui.reader.utils.FeaturedImageUtils
import org.wordpress.android.ui.reader.utils.ReaderUtilsWrapper
import org.wordpress.android.ui.reader.utils.ThreadedCommentsUtils
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.CommentSnippetState
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.CommentSnippetState.CommentSnippetData
Expand All @@ -19,7 +17,6 @@ import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.Comm
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.CommentSnippetUiState
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.ReaderPostDetailsUiState
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.ReaderPostDetailsUiState.ExcerptFooterUiState
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.ReaderPostDetailsUiState.ReaderPostFeaturedImageUiState
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.ReaderPostDetailsUiState.RelatedPostsUiState
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.ReaderPostDetailsUiState.RelatedPostsUiState.ReaderRelatedPostUiState
import org.wordpress.android.ui.reader.views.ReaderPostDetailsHeaderViewUiStateBuilder
Expand All @@ -39,22 +36,17 @@ import org.wordpress.android.ui.utils.UiString.UiStringText
import org.wordpress.android.util.AppLog
import org.wordpress.android.util.AppLog.T
import org.wordpress.android.util.DateTimeUtilsWrapper
import org.wordpress.android.util.DisplayUtilsWrapper
import org.wordpress.android.util.WPAvatarUtilsWrapper
import org.wordpress.android.viewmodel.ContextProvider
import org.wordpress.android.viewmodel.ResourceProvider
import javax.inject.Inject

const val READER_POST_FEATURED_IMAGE_HEIGHT_PERCENT = 0.4
const val RELATED_POST_IMAGE_HEIGHT_WIDTH_RATION = 0.56 // 9:16

@Reusable
class ReaderPostDetailUiStateBuilder @Inject constructor(
private val postDetailsHeaderViewUiStateBuilder: ReaderPostDetailsHeaderViewUiStateBuilder,
private val postUiStateBuilder: ReaderPostUiStateBuilder,
private val featuredImageUtils: FeaturedImageUtils,
private val readerUtilsWrapper: ReaderUtilsWrapper,
private val displayUtilsWrapper: DisplayUtilsWrapper,
private val contextProvider: ContextProvider,
private val htmlUtilsWrapper: HtmlUtilsWrapper,
private val htmlMessageUtils: HtmlMessageUtils,
Expand All @@ -76,8 +68,7 @@ class ReaderPostDetailUiStateBuilder @Inject constructor(
) = ReaderPostDetailsUiState(
postId = post.postId,
blogId = post.blogId,
featuredImageUiState = buildReaderPostFeaturedImageUiState(post),
headerUiState = buildPostDetailsHeaderUiState(
headerUiState = postDetailsHeaderViewUiStateBuilder.mapPostToUiState(
post,
onHeaderAction,
),
Expand Down Expand Up @@ -209,32 +200,6 @@ class ReaderPostDetailUiStateBuilder @Inject constructor(
onItemClicked = onItemClicked
)

private fun buildReaderPostFeaturedImageUiState(post: ReaderPost) =
post.takeIf { featuredImageUtils.shouldAddFeaturedImage(post) }?.let {
ReaderPostFeaturedImageUiState(
blogId = post.blogId,
url = buildReaderPostFeaturedImageUrl(post),
height = (displayUtilsWrapper.getWindowPixelHeight() *
READER_POST_FEATURED_IMAGE_HEIGHT_PERCENT).toInt()
)
}

private fun buildReaderPostFeaturedImageUrl(post: ReaderPost) = readerUtilsWrapper.getResizedImageUrl(
post.featuredImage,
displayUtilsWrapper.getDisplayPixelWidth(),
0,
post.isPrivate,
post.isPrivateAtomic
)

private fun buildPostDetailsHeaderUiState(
post: ReaderPost,
onHeaderAction: (ReaderPostDetailsHeaderAction) -> Unit,
) = postDetailsHeaderViewUiStateBuilder.mapPostToUiState(
post,
onHeaderAction,
)

private fun buildExcerptFooterUiState(post: ReaderPost): ExcerptFooterUiState? =
post.takeIf { post.shouldShowExcerpt() }?.let {
ExcerptFooterUiState(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiSt
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.ReaderPostDetailsUiState
import org.wordpress.android.ui.reader.views.uistates.CommentSnippetItemState
import org.wordpress.android.ui.reader.views.uistates.ReaderPostDetailsHeaderAction
import org.wordpress.android.ui.reader.views.uistates.ReaderPostDetailsHeaderViewUiState.ReaderPostDetailsHeaderUiState
import org.wordpress.android.ui.reader.views.uistates.ReaderPostDetailsHeaderUiState
import org.wordpress.android.ui.utils.HtmlMessageUtils
import org.wordpress.android.ui.utils.UiDimen
import org.wordpress.android.ui.utils.UiString
Expand Down Expand Up @@ -571,6 +571,8 @@ class ReaderPostDetailViewModel @Inject constructor(
is ReaderPostDetailsHeaderAction.LikesClicked -> onLikesClicked()
is ReaderPostDetailsHeaderAction.CommentsClicked -> onCommentsClicked()
is ReaderPostDetailsHeaderAction.TagItemClicked -> onTagItemClicked(action.tagSlug)
is ReaderPostDetailsHeaderAction.FeaturedImageClicked ->
onFeaturedImageClicked(action.blogId, action.featuredImageUrl)
}
}

Expand Down Expand Up @@ -922,16 +924,13 @@ class ReaderPostDetailViewModel @Inject constructor(
data class ReaderPostDetailsUiState(
val postId: Long,
val blogId: Long,
val featuredImageUiState: ReaderPostFeaturedImageUiState? = null,
val headerUiState: ReaderPostDetailsHeaderUiState,
val excerptFooterUiState: ExcerptFooterUiState?,
val moreMenuItems: List<ReaderPostCardAction>? = null,
val actions: ReaderPostActions,
val localRelatedPosts: RelatedPostsUiState? = null,
val globalRelatedPosts: RelatedPostsUiState? = null
) : UiState() {
data class ReaderPostFeaturedImageUiState(val blogId: Long, val url: String? = null, val height: Int)

data class ExcerptFooterUiState(val visitPostExcerptFooterLinkText: UiString? = null, val postLink: String?)

data class RelatedPostsUiState(
Expand Down Expand Up @@ -986,10 +985,15 @@ class ReaderPostDetailViewModel @Inject constructor(
}

fun onUserNavigateFromComments() {
// reload post from DB and update UI state
// reload post from DB (including text column for featured image
// deduplication) and update UI state
val currentUiState: ReaderPostDetailsUiState? = (_uiState.value as? ReaderPostDetailsUiState)
currentUiState?.let {
findPost(currentUiState.postId, currentUiState.blogId)?.let { post ->
readerPostTableWrapper.getBlogPost(
it.blogId,
it.postId,
false
)?.let { post ->
this.post = post
onUpdatePost(post)
}
Expand Down
Loading
Loading