Skip to content

Commit 3f3f282

Browse files
nbradburyclaude
andauthored
Redesign Reader post detail header for adaptive layout (#22754)
* Start reader improvements feature branch Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove content-scanning fallbacks for Reader featured image Only use editorial.image, featured_image, or featured_media.uri as featured image sources instead of scanning post content for suitable images or videos. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Move featured image above title and excerpt in Reader post cards Reorder ConstraintLayout constraints so the visual hierarchy is: blog header → featured image → title → excerpt → interactions → footer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix grammar in code comments Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fit portrait featured images in Reader instead of cropping When a Reader post has a portrait featured image, the image is now scaled to fit the container height and centered horizontally with a gray background fill, instead of being center-cropped which often cuts off heads and other important content. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix import ordering in ReaderPostNewViewHolder Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix import ordering and remove unnecessary @jvmoverloads in ImageManager Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Redesign Reader post detail header for adaptive layout Move featured image from collapsing AppBar to inline in the header view with adaptive aspect ratio. Restructure blog section so site name, author, and date each appear on their own line with absolute date+time format. Add reading time indicator and excerpt display to the header. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Simplify Reader post detail header and image transformation code - Extract Regex and date format constants in header UI state builder - Replace verbose null-check patterns with setTextOrHide helper - Hoist Paint allocation to class property in PortraitAwareCropTransformation - Remove unnecessary list allocation in applyInteractionSectionTheme Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix crash in Reader post detail caused by unresolvable Material3 attribute Replace ?attr/colorOnSurfaceVariant (Material3-only) with compatible alternatives since the reading preferences ContextThemeWrapper uses Theme.MaterialComponents.DayNight which lacks this attribute. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Simplify Reader post detail: remove dead code and redundant scroll listener - Remove unused postDetailsHeaderViewUiStateBuilder injection from fragment - Replace per-scroll toolbar coloring with one-time setup in initAppBar - Inline trivial buildPostDetailsHeaderUiState delegation - Remove unnecessary default values in ReaderFeaturedImageUiState Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Use fastStripHtml for reading time and fix code quality issues Replace HtmlCompat.fromHtml() with lighter HtmlUtils.fastStripHtml() for word counting, fix detekt ReturnCount and checkstyle empty-line violations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix blog section spacing between avatar and text Chain blog name and author vertically against the avatar, add marginStart with goneMarginStart so text aligns flush when there is no avatar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Hide author name when blank or same as blog name Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Show blog description instead of post excerpt in detail header Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Reorder Reader post detail header layout Move blog name to top, post title second, avatar with author and date below title, then featured image, blog description (up to 3 lines), and reading time. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix blog section layout spacing and alignment Anchor dateline start directly to avatar so it stays positioned when author name is hidden. Add barrier below blog name and follow button so the post title clears both. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Make subscribe button smaller and place it after blog name Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix featured image duplication after returning from comments findPost() excludes the text column for performance, so shouldAddFeaturedImage() couldn't detect the image was already in the post body HTML. Fetch with text column included when returning from comments to preserve deduplication. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Simplify Reader post detail header code - Flatten ReaderPostDetailsHeaderViewUiState sealed class into top-level data classes (only had one subclass) - Inline trivial wrapper methods in the header UI state builder - Inline single-line delegation methods in the header view Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix detekt LongMethod violation in mapPostToUiState Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix review issues: cache date formatter, move DB query off main thread, rename excerpt to blogDescription - Cache SimpleDateFormat as a class property instead of allocating per call - Wrap ReaderBlogTableWrapper.getBlogInfo() in withContext(Dispatchers.IO) and propagate suspend through the call chain - Rename excerpt/text_excerpt to blogDescription/text_blog_description since the field shows blog description, not post excerpt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove unused bg_rectangle_black_translucent_40 drawable This drawable was only referenced by the collapsing toolbar featured image FrameLayout which was removed in the header redesign. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Simplify Reader post detail header code - Remove redundant likeCount/commentCount local variables - Simplify featured image null handling with if/else - Make ReaderFeaturedImageUiState.url and onFeaturedImageClicked non-null since the state object is only created with valid values - Rewrite buildReadingTime with early returns for readability Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix detekt ReturnCount violation in buildReadingTime Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Minor vm tweaks * Fix review issues: threading, thread safety, and data class cleanup - Move DB query off main thread in onUserNavigateFromComments - Replace SimpleDateFormat with thread-safe DateTimeFormatter - Reapply toolbar icon colors after menu visibility changes - Hide blog name in blog section layout XML instead of at runtime - Move featured image click lambda out of data class for proper equality - Guard reading time word count against empty split results - Revert formatting-only test changes to reduce diff noise Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix detekt ReturnCount violation in buildReadingTime Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add "View original" button to Reader post detail header Adds a flat text button with a circled arrow icon on the right side of the reading time row. Tapping it opens the post's original URL in the browser. The button is only shown when the post has a URL. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Move tags from post detail header to below post content Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Move likes/comments counts from header to below tags Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove comment count from interaction section below post content The comment count is already shown above the comment list, so it's redundant in the likes area. Simplified to a single like count TextView. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix featured image flickering in Reader post detail Preserve the featured image state across UI re-renders so it doesn't disappear when fresh post text causes the URL deduplication heuristic to produce a different result. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove time from publication date in Reader post detail Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Change "Visit site" to "View site" and open site in Reader Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Show liker avatars inline before like count in Reader post detail Display up to 5 small circular liker avatars before the like count text below post content. Ungates the liker data pipeline so avatar URLs are fetched regardless of the likes enhancements feature flag. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fetch liker data on initial post load for inline avatars onRefreshLikersData() was not called from updatePostDetailsUi(), so the liker data pipeline was never triggered during the initial post load. This meant the likesUiState observer never received data and the avatar ImageViews stayed hidden. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove inline avatar ImageViews, keep existing faces train Remove the 5 small inline avatar ImageViews from the like count row and revert the layout to the original MaterialTextView. The existing liker faces train (32dp RecyclerView avatars) is now always shown since the data pipeline was ungated. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove duplicate like count text, use faces train only The like count was shown twice: once as a standalone TextView below the tags and again as a trailing label in the liker faces train. Remove the standalone header_like_count TextView and let the faces train be the sole display of like count and liker avatars. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Restyle Subscribe button as unfilled pill in post detail header Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove unused ReaderImageScanner.getLargestImage() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix Subscribe pill clipping and soften border color Use medium-emphasis color for pill stroke and text instead of black. Adjust layout constraints so the pill drives row height and the blog name centers vertically against it, preventing top clipping. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove redundant tagItemsVisibility and showViewOriginal fields Derive tag visibility from tagItems.isNotEmpty() and view-original visibility from onViewOriginalClicked != null. Also remove unused lambda binding in onFeaturedImageClicked. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix detekt and lint issues: unused imports, long method, unused drawable Extract buildInteractionSection and buildViewOriginalClicked helpers to shorten mapPostToUiState. Remove unused OpenPost imports and delete unused ic_arrow_circle_right_16dp drawable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Show post excerpt instead of blog description in post detail header Replace the blog description with the post excerpt in the reader post detail header. Auto-generated excerpts (where WordPress truncates content and appends […] or …) are detected and suppressed so only author-written excerpts are displayed. The excerpt is capped at 5 lines with a "View more" link to expand. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add thin divider below the post excerpt in detail header Show a divider under the excerpt section (hidden when no excerpt is present). Uses ?android:attr/listDivider for theme-consistent styling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove dead code and simplify Reader post detail branch Remove unused interactionSectionUiState and its class, deduplicate dateLine (read from blogSectionUiState instead), drop unnecessary suspend modifiers, and simplify modifyMoreMenu and buildExcerpt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove dead LikesClicked/CommentsClicked header actions and redundant visibility attr Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix detekt and lint issues: ReturnCount, TrimLambda, missing null annotations Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Always show header divider and darken excerpt text and divider color Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Simplify title builder and move divider visibility to XML Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Improve auto-generated excerpt detection with suffix check and whitespace normalization Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add KDoc comments to mapPostToUiState and buildExcerpt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix detekt ReturnCount in isAutoGeneratedExcerpt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix flaky likers test by skipping onShowPost during init The test sets viewModel.post manually and only needs to verify the liking action path, so pass showPost=false to avoid triggering handleGetLikesForPost from updatePostDetailsUi. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Address PR review feedback for post detail header - Link site title to blog preview with ripple feedback - Reduce site title line height (lineSpacingMultiplier + no font padding) - Link author name to user profile bottom sheet - Soften excerpt divider using wpColorOnSurfaceMedium - Fix icon theming and add drawableTint for visual centering Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix review feedback: tighter title, softer divider, simpler author card - Use android:lineHeight instead of lineSpacingMultiplier to actually reduce the site title leading (overrides Material3 LabelLarge default) - Use ?android:attr/listDivider for the excerpt separator (theme-aware and visibly softer than the previous color) - Replace UserProfileBottomSheetFragment with a simple BottomSheetDialog that shows the avatar centered above the name, no site icon, and opens the blog URL in an external browser Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix divider color to match iOS and restore title lineHeight - Add reader_separator color matching iOS UIColor.separator (light: rgba(60,60,67,0.29), dark: rgba(84,84,88,0.6)) - Restore lineHeight=16sp on blog section title style since the title can wrap to multiple lines Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Reduce post title line spacing and fix icon vertical alignment - Reduce lineSpacingMultiplier from 1.2 to 1.1 on the post title style (ReaderTextView.PostDetail.Header.Title) — the correct style for the multi-line post title (not BlogSection.Title) - Revert ineffective lineHeight on BlogSection.Title (single-line blog name view) - Fix icon centering by adding includeFontPadding=false and replacing baseline alignment with top/bottom constraints so the icons and text center as a unit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix detekt ReturnCount in buildAuthorClicked Chain takeIf/takeUnless to reduce return statements from 3 to 2. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Removed lineSpacingMultiplier * Extract author profile bottom sheet to Fragment with XML layout Replace the programmatic BottomSheetDialog in ReaderPostDetailFragment with a proper BottomSheetDialogFragment backed by an XML layout, consistent with existing patterns (e.g. ReaderLoginRequiredBottomSheetFragment). Also remove unused siteId field from ShowAuthorProfile nav event. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Cancel pending excerpt truncation check before posting new one Stores the Runnable reference and calls removeCallbacks() to prevent stale truncation checks from accumulating during rapid updatePost() calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix Visit/View site string resources for correct scoping Revert reader_label_visit back to "Visit site" (used by post card more-menu) and introduce reader_label_view ("View site") for the post detail header, replacing the now-unused reader_view_original. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix review issues: Paint thread safety, data class lambdas, View Binding - Allocate Paint per transform() call in PortraitAwareCropTransformation to avoid thread-safety issues from concurrent Glide calls - Move onFeaturedImageClicked, onViewOriginalClicked, onAuthorClicked lambdas out of ReaderPostDetailsHeaderUiState data class so equals()/hashCode() work correctly for LiveData diffing. The view now dispatches actions via an onHeaderAction callback parameter. - Replace findViewById with View Binding in ReaderAuthorProfileBottomSheetFragment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Simplify bottom sheet R import and ViewModel null handling - Add R import and remove fully-qualified reference in ReaderAuthorProfileBottomSheetFragment - Use takeIf/let in onViewOriginalClicked - Inline cast and rename lambda param in onUserNavigateFromComments Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix tiny text in author profile bottom sheet Use MaterialComponents-compatible text appearances with explicit sizes instead of Material3 attributes that don't resolve in the MaterialComponents bottom sheet theme. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Migrate ReaderAuthorProfileBottomSheet to Compose Replace XML layout + View Binding with ComposeView + AppThemeM3, eliminating theme attribute resolution issues. Uses Coil AsyncImage for the avatar and removes the ImageManager dependency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Revert Compose migration for author profile bottom sheet ComposeView inside BottomSheetDialogFragment causes the content to briefly appear at the top of the screen before jumping to the bottom. This is a known interop issue with no reliable fix, so revert to the original XML layout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix review issues: consistent feature gating, divider, crash safety - Restore likesEnhancementsFeatureConfig gates that were inconsistently removed in Fragment and ViewModel (6 locations) - Change excerpt divider from 0.5dp to 1px for visibility on low-dpi - Use context null-check instead of requireContext() in click listener - Align showViewOriginal check with click handler null/blank logic Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Simplify author row linking and fix View original alignment Make the entire blog section row link to the author profile (like iOS) instead of having separate tap targets for the site and author name. Fix View original vertical misalignment by removing extra top margin. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Changed "View site" to "View original" * Make sure author profile shows a url when blog name is missing * Use filled Subscribe button * Fixed image resize * Fall back to "featured_image" for FP posts * Reverted adjustViewBounds change * Align Reader post list horizontal margins with post detail Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5c1393c commit 3f3f282

37 files changed

Lines changed: 855 additions & 591 deletions

WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ public static ReaderPost fromJson(JSONObject json) {
136136
post.blogId = jsonEditorial.optLong("blog_id");
137137
post.mBlogName = JSONUtils.getStringDecoded(jsonEditorial, "blog_name");
138138
post.mFeaturedImage = getEditorialImage(JSONUtils.getString(jsonEditorial, "image"));
139+
if (post.mFeaturedImage == null) {
140+
post.mFeaturedImage = JSONUtils.getString(json, "featured_image");
141+
}
139142
post.setPrimaryTag(JSONUtils.getString(jsonEditorial, "highlight_topic_title"));
140143
// freshly-pressed posts show the date they were chosen rather than the day published
141144
post.mDatePublished = JSONUtils.getString(jsonEditorial, "displayed_on");
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package org.wordpress.android.ui.reader
2+
3+
import android.os.Bundle
4+
import android.view.LayoutInflater
5+
import android.view.View
6+
import android.view.ViewGroup
7+
import androidx.core.os.bundleOf
8+
import androidx.core.view.isVisible
9+
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
10+
import dagger.hilt.android.AndroidEntryPoint
11+
import org.wordpress.android.R
12+
import org.wordpress.android.databinding.ReaderAuthorProfileBottomSheetBinding
13+
import org.wordpress.android.util.UrlUtils
14+
import org.wordpress.android.util.WPAvatarUtils
15+
import org.wordpress.android.util.image.ImageManager
16+
import org.wordpress.android.util.image.ImageType
17+
import javax.inject.Inject
18+
19+
@AndroidEntryPoint
20+
class ReaderAuthorProfileBottomSheetFragment : BottomSheetDialogFragment() {
21+
@Inject
22+
lateinit var imageManager: ImageManager
23+
24+
private var _binding: ReaderAuthorProfileBottomSheetBinding? = null
25+
private val binding get() = _binding!!
26+
27+
override fun onCreateView(
28+
inflater: LayoutInflater,
29+
container: ViewGroup?,
30+
savedInstanceState: Bundle?
31+
): View {
32+
_binding = ReaderAuthorProfileBottomSheetBinding.inflate(
33+
inflater, container, false
34+
)
35+
return binding.root
36+
}
37+
38+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
39+
super.onViewCreated(view, savedInstanceState)
40+
val args = requireArguments()
41+
42+
val authorName = args.getString(ARG_AUTHOR_NAME).orEmpty()
43+
val authorAvatar = args.getString(ARG_AUTHOR_AVATAR).orEmpty()
44+
val blogName = args.getString(ARG_BLOG_NAME).orEmpty()
45+
val blogUrl = args.getString(ARG_BLOG_URL).orEmpty()
46+
47+
val avatarSz = resources.getDimensionPixelSize(
48+
R.dimen.user_profile_bottom_sheet_avatar_sz
49+
)
50+
imageManager.loadIntoCircle(
51+
binding.authorAvatar,
52+
ImageType.AVATAR_WITH_BACKGROUND,
53+
WPAvatarUtils.rewriteAvatarUrl(authorAvatar, avatarSz)
54+
)
55+
56+
binding.authorName.text = authorName
57+
58+
if (blogUrl.isNotBlank()) {
59+
binding.authorBlogName.isVisible = true
60+
binding.authorBlogName.text =
61+
blogName.ifBlank { UrlUtils.getHost(blogUrl) }
62+
binding.authorBlogName.setOnClickListener {
63+
val ctx = context ?: return@setOnClickListener
64+
ReaderActivityLauncher.openUrl(ctx, blogUrl)
65+
dismiss()
66+
}
67+
}
68+
}
69+
70+
override fun onDestroyView() {
71+
super.onDestroyView()
72+
_binding = null
73+
}
74+
75+
companion object {
76+
const val TAG = "ReaderAuthorProfileBottomSheetFragment"
77+
private const val ARG_AUTHOR_NAME = "author_name"
78+
private const val ARG_AUTHOR_AVATAR = "author_avatar"
79+
private const val ARG_BLOG_NAME = "blog_name"
80+
private const val ARG_BLOG_URL = "blog_url"
81+
82+
fun newInstance(
83+
authorName: String,
84+
authorAvatar: String,
85+
blogName: String,
86+
blogUrl: String,
87+
) = ReaderAuthorProfileBottomSheetFragment().apply {
88+
arguments = bundleOf(
89+
ARG_AUTHOR_NAME to authorName,
90+
ARG_AUTHOR_AVATAR to authorAvatar,
91+
ARG_BLOG_NAME to blogName,
92+
ARG_BLOG_URL to blogUrl,
93+
)
94+
}
95+
}
96+
}

WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.kt

Lines changed: 66 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import android.view.ViewGroup
2424
import android.view.ViewStub
2525
import android.webkit.CookieManager
2626
import android.webkit.WebView
27-
import android.widget.ImageView.ScaleType.CENTER_CROP
2827
import android.widget.ProgressBar
2928
import android.widget.TextView
3029
import androidx.appcompat.app.AlertDialog
@@ -37,6 +36,7 @@ import androidx.core.graphics.BlendModeColorFilterCompat
3736
import androidx.core.graphics.BlendModeCompat
3837
import androidx.core.view.ViewCompat
3938
import androidx.core.view.WindowInsetsCompat
39+
import androidx.core.view.isGone
4040
import androidx.core.view.isInvisible
4141
import androidx.core.view.isVisible
4242
import androidx.fragment.app.FragmentManager
@@ -48,7 +48,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
4848
import androidx.recyclerview.widget.RecyclerView
4949
import com.facebook.shimmer.ShimmerFrameLayout
5050
import com.google.android.material.appbar.AppBarLayout
51-
import com.google.android.material.appbar.CollapsingToolbarLayout
5251
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior
5352
import com.google.android.material.dialog.MaterialAlertDialogBuilder
5453
import com.google.android.material.snackbar.Snackbar
@@ -118,7 +117,6 @@ import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiSt
118117
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.LoadingUiState
119118
import org.wordpress.android.ui.reader.viewmodels.ReaderPostDetailViewModel.UiState.ReaderPostDetailsUiState
120119
import org.wordpress.android.ui.reader.views.ReaderIconCountView
121-
import org.wordpress.android.ui.reader.views.ReaderPostDetailsHeaderViewUiStateBuilder
122120
import org.wordpress.android.ui.reader.views.ReaderSimplePostContainerView
123121
import org.wordpress.android.ui.reader.views.ReaderWebView
124122
import org.wordpress.android.ui.reader.views.ReaderWebView.ReaderCustomViewListener
@@ -146,7 +144,6 @@ import org.wordpress.android.util.extensions.getSerializableCompat
146144
import org.wordpress.android.util.extensions.setVisible
147145
import org.wordpress.android.util.helpers.SwipeToRefreshHelper
148146
import org.wordpress.android.util.image.ImageManager
149-
import org.wordpress.android.util.image.ImageType.PHOTO
150147
import org.wordpress.android.util.widgets.CustomSwipeRefreshLayout
151148
import org.wordpress.android.viewmodel.ContextProvider
152149
import org.wordpress.android.viewmodel.observeEvent
@@ -158,7 +155,6 @@ import java.net.HttpURLConnection
158155
import java.util.EnumSet
159156
import javax.inject.Inject
160157
import com.google.android.material.R as MaterialR
161-
import androidx.core.view.isGone
162158
import androidx.core.net.toUri
163159
import androidx.core.view.forEach
164160

@@ -251,9 +247,6 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
251247
@Inject
252248
internal lateinit var imageManager: ImageManager
253249

254-
@Inject
255-
lateinit var postDetailsHeaderViewUiStateBuilder: ReaderPostDetailsHeaderViewUiStateBuilder
256-
257250
@Inject
258251
lateinit var readerUtilsWrapper: ReaderUtilsWrapper
259252

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

295-
private val appBarLayoutOffsetChangedListener =
296-
AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
297-
val collapsingToolbarLayout = appBarLayout
298-
.findViewById<CollapsingToolbarLayout>(R.id.collapsing_toolbar)
299-
val toolbar = appBarLayout.findViewById<Toolbar>(R.id.toolbar_main)
300-
301-
view?.context?.let { context ->
302-
val menu: Menu = toolbar.menu
303-
304-
val collapsingToolbarHeight = collapsingToolbarLayout.height
305-
val isCollapsed = (collapsingToolbarHeight + verticalOffset) <=
306-
collapsingToolbarLayout.scrimVisibleHeightTrigger
307-
308-
val color = if (isCollapsed) {
309-
context.getColorFromAttribute(MaterialR.attr.colorOnSurface)
310-
} else {
311-
ContextCompat.getColor(context, R.color.white)
312-
}
313-
val colorFilter = BlendModeColorFilterCompat
314-
.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP)
315-
316-
toolbar.setTitleTextColor(color)
317-
toolbar.navigationIcon?.colorFilter = colorFilter
318-
319-
menu.forEach {
320-
it.icon?.colorFilter = colorFilter
321-
}
322-
}
323-
}
324-
325288
override fun onCreate(savedInstanceState: Bundle?) {
326289
super.onCreate(savedInstanceState)
327290
(requireActivity().application as WordPress).component().inject(this)
@@ -404,8 +367,6 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
404367
appBar = view.findViewById(R.id.appbar_with_collapsing_toolbar_layout)
405368
toolBar = appBar.findViewById(R.id.toolbar_main)
406369

407-
appBar.addOnOffsetChangedListener(appBarLayoutOffsetChangedListener)
408-
409370
// Fixes collapsing toolbar layout being obscured by the status bar when drawn behind it
410371
ViewCompat.setOnApplyWindowInsetsListener(appBar) { _: View, insets: WindowInsetsCompat ->
411372
val insetTop = insets.getInsets(WindowInsetsCompat. Type. systemBars()).top
@@ -430,6 +391,21 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
430391
toolBar.setNavigationIcon(R.drawable.ic_arrow_left_white_24dp)
431392
toolBar.setNavigationOnClickListener { requireActivity().onBackPressedDispatcher.onBackPressed() }
432393
}
394+
395+
applyToolbarIconColors(view.context)
396+
}
397+
398+
private fun applyToolbarIconColors(context: Context) {
399+
val color = context.getColorFromAttribute(
400+
MaterialR.attr.colorOnSurface
401+
)
402+
val colorFilter = BlendModeColorFilterCompat
403+
.createBlendModeColorFilterCompat(
404+
color, BlendModeCompat.SRC_ATOP
405+
)
406+
toolBar.setTitleTextColor(color)
407+
toolBar.navigationIcon?.colorFilter = colorFilter
408+
toolBar.menu.forEach { it.icon?.colorFilter = colorFilter }
433409
}
434410

435411
private fun initScrollView(view: View) {
@@ -695,30 +671,44 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
695671
with(requireActivity()) {
696672
if (this.isFinishing) return@with
697673

698-
val shouldSkipAnimation = likeFacesTrain.isGone && state.goingToShowFaces
674+
val shouldSkipAnimation =
675+
likeFacesTrain.isGone && state.goingToShowFaces
699676

700677
setupLikeFacesTrain(
701678
state.engageItemsList,
702679
state.showLoading,
703680
shouldSkipAnimation
704681
)
705682

706-
likeProgressBar.visibility = if (state.showLoading) View.VISIBLE else View.GONE
707-
likeFacesTrain.visibility = if (state.showLikeFacesTrainContainer) View.VISIBLE else View.GONE
683+
likeProgressBar.visibility =
684+
if (state.showLoading) View.VISIBLE else View.GONE
685+
likeFacesTrain.visibility =
686+
if (state.showLikeFacesTrainContainer) {
687+
View.VISIBLE
688+
} else {
689+
View.GONE
690+
}
708691

709692
if (state.showEmptyState) {
710-
uiHelpers.setTextOrHide(likeEmptyStateText, state.emptyStateTitle?.let {
711-
getString(R.string.like_faces_error_loading_message, uiHelpers.getTextOfUiString(this, it))
712-
})
693+
uiHelpers.setTextOrHide(
694+
likeEmptyStateText,
695+
state.emptyStateTitle?.let {
696+
getString(
697+
R.string.like_faces_error_loading_message,
698+
uiHelpers.getTextOfUiString(this, it)
699+
)
700+
}
701+
)
713702
likeEmptyStateText.visibility = View.VISIBLE
714703
} else {
715704
likeEmptyStateText.visibility = View.GONE
716705
}
717706

718-
likeFacesTrain.contentDescription = uiHelpers.getTextOfUiString(
719-
contextProvider.getContext(),
720-
state.contentDescription
721-
)
707+
likeFacesTrain.contentDescription =
708+
uiHelpers.getTextOfUiString(
709+
contextProvider.getContext(),
710+
state.contentDescription
711+
)
722712

723713
likeFacesTrain.setOnClickListener {
724714
if (!isAdded) return@setOnClickListener
@@ -798,10 +788,19 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
798788
}
799789
}
800790

801-
binding.headerView.updatePost(state.headerUiState, getReadingPreferences())
791+
binding.headerView.updatePost(
792+
state.headerUiState,
793+
getReadingPreferences(),
794+
viewModel::handleHeaderAction
795+
)
796+
797+
binding.expandableTagsView.setVisible(state.headerUiState.tagItems.isNotEmpty())
798+
binding.expandableTagsView.updateUi(
799+
state.headerUiState.tagItems, getReadingPreferences()
800+
)
801+
802802
showOrHideMoreMenu(state)
803803

804-
updateFeaturedImage(state.featuredImageUiState, binding)
805804
updateExcerptFooter(state.excerptFooterUiState)
806805

807806
with(layoutFooterBinding) {
@@ -921,35 +920,29 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
921920
ReaderReadingPreferencesTracker.Source.POST_DETAIL_MORE_MENU,
922921
)
923922

923+
is ReaderNavigationEvents.ShowAuthorProfile -> showAuthorProfile(this)
924+
924925
is ReaderNavigationEvents.ShowPostDetail,
925926
is ReaderNavigationEvents.ShowVideoViewer,
926927
is ReaderNavigationEvents.ShowReaderSubs -> Unit // Do Nothing
927928
is ReaderNavigationEvents.ShowLoginRequiredBottomSheet -> showLoginRequiredBottomSheet()
928929
}
929930
}
930931

932+
private fun showAuthorProfile(event: ReaderNavigationEvents.ShowAuthorProfile) {
933+
ReaderAuthorProfileBottomSheetFragment.newInstance(
934+
authorName = event.authorName,
935+
authorAvatar = event.authorAvatar,
936+
blogName = event.blogName,
937+
blogUrl = event.blogUrl,
938+
).show(childFragmentManager, ReaderAuthorProfileBottomSheetFragment.TAG)
939+
}
940+
931941
private fun showLoginRequiredBottomSheet() {
932942
ReaderLoginRequiredBottomSheetFragment.newInstance()
933943
.show(childFragmentManager, ReaderLoginRequiredBottomSheetFragment.TAG)
934944
}
935945

936-
private fun updateFeaturedImage(
937-
state: ReaderPostDetailsUiState.ReaderPostFeaturedImageUiState?,
938-
binding: ReaderFragmentPostDetailBinding
939-
) {
940-
val featuredImageView = binding.appbarWithCollapsingToolbarLayout.featuredImage
941-
featuredImageView.setVisible(state != null)
942-
state?.let {
943-
featuredImageView.layoutParams.height = it.height
944-
it.url?.let { url ->
945-
imageManager.load(featuredImageView, PHOTO, url, CENTER_CROP)
946-
featuredImageView.setOnClickListener {
947-
viewModel.onFeaturedImageClicked(blogId = state.blogId, featuredImageUrl = url)
948-
}
949-
}
950-
}
951-
}
952-
953946
private fun updateExcerptFooter(state: ReaderPostDetailsUiState.ExcerptFooterUiState?) {
954947
// if we're showing just the excerpt, show a footer which links to the full post
955948
excerptFooter.setVisible(state != null)
@@ -993,16 +986,8 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
993986
}
994987
}
995988

996-
private fun modifyMoreMenu(
997-
postBlocked: Boolean
998-
){
999-
val moreMenu:MenuItem? = toolBar.menu.findItem(R.id.menu_more)
1000-
if (postBlocked){
1001-
moreMenu?.setVisible(false)
1002-
}
1003-
else{
1004-
moreMenu?.setVisible(true)
1005-
}
989+
private fun modifyMoreMenu(postBlocked: Boolean) {
990+
toolBar.menu.findItem(R.id.menu_more)?.isVisible = !postBlocked
1006991
}
1007992

1008993
private fun showOrHideMoreMenu(
@@ -1080,6 +1065,8 @@ class ReaderPostDetailFragment : ViewPagerFragment(),
10801065
// show more menu
10811066
val menuMore = menu.findItem(R.id.menu_more)
10821067
menuMore?.isVisible = true
1068+
1069+
applyToolbarIconColors(toolBar.context)
10831070
}
10841071

10851072
private fun hideMenu(menu: Menu) {

0 commit comments

Comments
 (0)