Skip to content

Commit ea8da23

Browse files
authored
Merge pull request #8983 from wordpress-mobile/issue/8955-page-item-redesign
Page list layout update
2 parents 5525ffd + 8e3ae3b commit ea8da23

File tree

16 files changed

+268
-118
lines changed

16 files changed

+268
-118
lines changed

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
* Refreshed page list layout that includes a timestamp and a featured image thumbnail
12
* Fixed a bug causing disappearance of old saved posts
23
* Add Importing from Giphy in Editor and Media Library
34
* Add support for .blog subdomains on new sites.

WordPress/src/main/java/org/wordpress/android/ui/pages/PageItem.kt

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,90 @@ import org.wordpress.android.ui.pages.PageItem.Action.VIEW_PAGE
1212
import org.wordpress.android.ui.pages.PageItem.Type.DIVIDER
1313
import org.wordpress.android.ui.pages.PageItem.Type.EMPTY
1414
import org.wordpress.android.ui.pages.PageItem.Type.PAGE
15+
import java.util.Date
1516

1617
sealed class PageItem(open val type: Type) {
1718
abstract class Page(
1819
open val id: Long,
1920
open val title: String,
21+
open val date: Date,
2022
open val labels: List<Int>,
2123
open var indent: Int,
24+
open var imageUrl: String?,
2225
open val actions: Set<Action>,
2326
open var actionsEnabled: Boolean
2427
) : PageItem(PAGE)
2528

2629
data class PublishedPage(
2730
override val id: Long,
2831
override val title: String,
32+
override val date: Date,
2933
override val labels: List<Int> = emptyList(),
3034
override var indent: Int = 0,
35+
override var imageUrl: String? = null,
3136
override var actionsEnabled: Boolean = true
32-
) : Page(id, title, labels, indent, setOf(VIEW_PAGE, SET_PARENT, MOVE_TO_DRAFT, MOVE_TO_TRASH), actionsEnabled)
37+
) : Page(
38+
id = id,
39+
title = title,
40+
date = date,
41+
labels = labels,
42+
indent = indent,
43+
imageUrl = imageUrl,
44+
actions = setOf(VIEW_PAGE, SET_PARENT, MOVE_TO_DRAFT, MOVE_TO_TRASH),
45+
actionsEnabled = actionsEnabled
46+
)
3347

3448
data class DraftPage(
3549
override val id: Long,
3650
override val title: String,
51+
override val date: Date,
3752
override val labels: List<Int> = emptyList(),
53+
override var imageUrl: String? = null,
3854
override var actionsEnabled: Boolean = true
39-
) : Page(id, title, labels, 0, setOf(VIEW_PAGE, SET_PARENT, PUBLISH_NOW, MOVE_TO_TRASH), actionsEnabled)
55+
) : Page(
56+
id = id,
57+
title = title,
58+
date = date,
59+
labels = labels,
60+
indent = 0,
61+
imageUrl = imageUrl,
62+
actions = setOf(VIEW_PAGE, SET_PARENT, PUBLISH_NOW, MOVE_TO_TRASH),
63+
actionsEnabled = actionsEnabled
64+
)
4065

4166
data class ScheduledPage(
4267
override val id: Long,
4368
override val title: String,
69+
override val date: Date,
70+
override var imageUrl: String? = null,
4471
override var actionsEnabled: Boolean = true
45-
) : Page(id, title, emptyList(), 0, setOf(VIEW_PAGE, SET_PARENT, MOVE_TO_DRAFT, MOVE_TO_TRASH), actionsEnabled)
72+
) : Page(
73+
id = id,
74+
title = title,
75+
date = date,
76+
labels = emptyList(),
77+
indent = 0,
78+
imageUrl = imageUrl,
79+
actions = setOf(VIEW_PAGE, SET_PARENT, MOVE_TO_DRAFT, MOVE_TO_TRASH),
80+
actionsEnabled = actionsEnabled
81+
)
4682

4783
data class TrashedPage(
4884
override val id: Long,
4985
override val title: String,
86+
override val date: Date,
87+
override var imageUrl: String? = null,
5088
override var actionsEnabled: Boolean = true
51-
) : Page(id, title, emptyList(), 0, setOf(VIEW_PAGE, MOVE_TO_DRAFT, DELETE_PERMANENTLY), actionsEnabled)
89+
) : Page(
90+
id = id,
91+
title = title,
92+
date = date,
93+
labels = emptyList(),
94+
indent = 0,
95+
imageUrl = imageUrl,
96+
actions = setOf(VIEW_PAGE, MOVE_TO_DRAFT, DELETE_PERMANENTLY),
97+
actionsEnabled = actionsEnabled
98+
)
5299

53100
data class ParentPage(
54101
val id: Long,

WordPress/src/main/java/org/wordpress/android/ui/pages/PageItemViewHolder.kt

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,24 @@ import android.view.LayoutInflater
77
import android.view.View
88
import android.view.ViewGroup
99
import android.widget.ImageButton
10+
import android.widget.ImageView
11+
import android.widget.ImageView.ScaleType
1012
import android.widget.PopupMenu
1113
import android.widget.RadioButton
1214
import android.widget.TextView
1315
import org.wordpress.android.R
14-
import org.wordpress.android.R.id
15-
import org.wordpress.android.R.layout
1616
import org.wordpress.android.ui.ActionableEmptyView
1717
import org.wordpress.android.ui.pages.PageItem.Divider
1818
import org.wordpress.android.ui.pages.PageItem.Empty
1919
import org.wordpress.android.ui.pages.PageItem.Page
2020
import org.wordpress.android.ui.pages.PageItem.ParentPage
21+
import org.wordpress.android.ui.reader.utils.ReaderUtils
22+
import org.wordpress.android.util.DateTimeUtils
2123
import org.wordpress.android.util.DisplayUtils
24+
import org.wordpress.android.util.ImageUtils
25+
import org.wordpress.android.util.image.ImageManager
26+
import org.wordpress.android.util.image.ImageType
27+
import java.util.Date
2228

2329
sealed class PageItemViewHolder(internal val parent: ViewGroup, @LayoutRes layout: Int) :
2430
RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(layout, parent, false)) {
@@ -27,51 +33,45 @@ sealed class PageItemViewHolder(internal val parent: ViewGroup, @LayoutRes layou
2733
class PageViewHolder(
2834
parentView: ViewGroup,
2935
private val onMenuAction: (PageItem.Action, Page) -> Boolean,
30-
private val onItemTapped: (Page) -> Unit
31-
) : PageItemViewHolder(parentView, layout.page_list_item) {
32-
private val pageTitle = itemView.findViewById<TextView>(id.page_title)
33-
private val pageMore = itemView.findViewById<ImageButton>(id.page_more)
34-
private val firstLabel = itemView.findViewById<TextView>(id.first_label)
35-
private val secondLabel = itemView.findViewById<TextView>(id.second_label)
36-
private val pageItemContainer = itemView.findViewById<ViewGroup>(id.page_item)
37-
private val largeStretcher = itemView.findViewById<View>(id.large_stretcher)
38-
private val smallStretcher = itemView.findViewById<View>(id.small_stretcher)
36+
private val onItemTapped: (Page) -> Unit,
37+
private val imageManager: ImageManager,
38+
private val isSitePhotonCapable: Boolean
39+
) : PageItemViewHolder(parentView, R.layout.page_list_item) {
40+
private val pageTitle = itemView.findViewById<TextView>(R.id.page_title)
41+
private val pageMore = itemView.findViewById<ImageButton>(R.id.page_more)
42+
private val time = itemView.findViewById<TextView>(R.id.time_posted)
43+
private val labels = itemView.findViewById<TextView>(R.id.labels)
44+
private val featuredImage = itemView.findViewById<ImageView>(R.id.featured_image)
45+
private val pageItemContainer = itemView.findViewById<ViewGroup>(R.id.page_item)
46+
47+
companion object {
48+
const val FEATURED_IMAGE_THUMBNAIL_SIZE_DP = 40
49+
}
3950

4051
override fun onBind(pageItem: PageItem) {
41-
(pageItem as Page).apply {
42-
val indentWidth = DisplayUtils.dpToPx(parent.context, 16 * pageItem.indent)
52+
(pageItem as Page).let { page ->
53+
val indentWidth = DisplayUtils.dpToPx(parent.context, 16 * page.indent)
4354
val marginLayoutParams = pageItemContainer.layoutParams as ViewGroup.MarginLayoutParams
4455
marginLayoutParams.leftMargin = indentWidth
4556
pageItemContainer.layoutParams = marginLayoutParams
4657

47-
pageTitle.text = if (pageItem.title.isEmpty())
58+
pageTitle.text = if (page.title.isEmpty())
4859
parent.context.getString(R.string.untitled_in_parentheses)
4960
else
50-
pageItem.title
61+
page.title
5162

52-
if (pageItem.labels.isEmpty()) {
53-
firstLabel.visibility = View.GONE
54-
smallStretcher.visibility = View.VISIBLE
55-
largeStretcher.visibility = View.GONE
56-
} else {
57-
firstLabel.text = parent.context.getString(pageItem.labels.first())
58-
firstLabel.visibility = View.VISIBLE
59-
smallStretcher.visibility = View.GONE
60-
largeStretcher.visibility = View.VISIBLE
61-
}
63+
val date = if (page.date == Date(0)) Date() else page.date
64+
time.text = DateTimeUtils.javaDateToTimeSpan(date, parent.context).capitalize()
6265

63-
if (pageItem.labels.size <= 1) {
64-
secondLabel.visibility = View.GONE
65-
} else {
66-
secondLabel.text = parent.context.getString(pageItem.labels[1])
67-
secondLabel.visibility = View.VISIBLE
68-
}
66+
labels.text = page.labels.map { parent.context.getString(it) }.sorted().joinToString(" · ")
6967

70-
itemView.setOnClickListener { onItemTapped(pageItem) }
68+
itemView.setOnClickListener { onItemTapped(page) }
7169

72-
pageMore.setOnClickListener { moreClick(pageItem, it) }
70+
pageMore.setOnClickListener { view -> moreClick(page, view) }
7371
pageMore.visibility =
74-
if (pageItem.actions.isNotEmpty() && pageItem.actionsEnabled) View.VISIBLE else View.INVISIBLE
72+
if (page.actions.isNotEmpty() && page.actionsEnabled) View.VISIBLE else View.INVISIBLE
73+
74+
showFeaturedImage(page.imageUrl)
7575
}
7676
}
7777

@@ -87,10 +87,31 @@ sealed class PageItemViewHolder(internal val parent: ViewGroup, @LayoutRes layou
8787
}
8888
popup.show()
8989
}
90+
91+
private fun showFeaturedImage(imageUrl: String?) {
92+
val imageSize = DisplayUtils.dpToPx(parent.context, FEATURED_IMAGE_THUMBNAIL_SIZE_DP)
93+
if (imageUrl == null) {
94+
featuredImage.visibility = View.GONE
95+
imageManager.cancelRequestAndClearImageView(featuredImage)
96+
} else if (imageUrl.startsWith("http")) {
97+
featuredImage.visibility = View.VISIBLE
98+
val photonUrl = ReaderUtils.getResizedImageUrl(imageUrl, imageSize, imageSize, !isSitePhotonCapable)
99+
imageManager.load(featuredImage, ImageType.PHOTO, photonUrl, ScaleType.CENTER_CROP)
100+
} else {
101+
val bmp = ImageUtils.getWPImageSpanThumbnailFromFilePath(featuredImage.context, imageUrl, imageSize)
102+
if (bmp != null) {
103+
featuredImage.visibility = View.VISIBLE
104+
imageManager.load(featuredImage, bmp)
105+
} else {
106+
featuredImage.visibility = View.GONE
107+
imageManager.cancelRequestAndClearImageView(featuredImage)
108+
}
109+
}
110+
}
90111
}
91112

92-
class PageDividerViewHolder(parentView: ViewGroup) : PageItemViewHolder(parentView, layout.page_divider_item) {
93-
private val dividerTitle = itemView.findViewById<TextView>(id.divider_text)
113+
class PageDividerViewHolder(parentView: ViewGroup) : PageItemViewHolder(parentView, R.layout.page_divider_item) {
114+
private val dividerTitle = itemView.findViewById<TextView>(R.id.divider_text)
94115

95116
override fun onBind(pageItem: PageItem) {
96117
(pageItem as Divider).apply {
@@ -104,8 +125,8 @@ sealed class PageItemViewHolder(internal val parent: ViewGroup, @LayoutRes layou
104125
private val onParentSelected: (ParentPage) -> Unit,
105126
@LayoutRes layout: Int
106127
) : PageItemViewHolder(parentView, layout) {
107-
private val pageTitle = itemView.findViewById<TextView>(id.page_title)
108-
private val radioButton = itemView.findViewById<RadioButton>(id.radio_button)
128+
private val pageTitle = itemView.findViewById<TextView>(R.id.page_title)
129+
private val radioButton = itemView.findViewById<RadioButton>(R.id.radio_button)
109130

110131
override fun onBind(pageItem: PageItem) {
111132
(pageItem as ParentPage).apply {
@@ -131,12 +152,12 @@ sealed class PageItemViewHolder(internal val parent: ViewGroup, @LayoutRes layou
131152
class EmptyViewHolder(
132153
parentView: ViewGroup,
133154
private val onActionButtonClicked: () -> Unit
134-
) : PageItemViewHolder(parentView, layout.page_empty_item) {
135-
private val emptyView = itemView.findViewById<ActionableEmptyView>(id.actionable_empty_view)
155+
) : PageItemViewHolder(parentView, R.layout.page_empty_item) {
156+
private val emptyView = itemView.findViewById<ActionableEmptyView>(R.id.actionable_empty_view)
136157

137158
@Suppress("DEPRECATION")
138159
override fun onBind(pageItem: PageItem) {
139-
if (pageItem is Empty) {
160+
(pageItem as Empty).apply {
140161
emptyView.title.text = emptyView.resources.getString(pageItem.textResource)
141162

142163
if (pageItem.isButtonVisible) {

WordPress/src/main/java/org/wordpress/android/ui/pages/PageListFragment.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import org.wordpress.android.R
1717
import org.wordpress.android.WordPress
1818
import org.wordpress.android.modules.UI_SCOPE
1919
import org.wordpress.android.util.DisplayUtils
20+
import org.wordpress.android.util.image.ImageManager
2021
import org.wordpress.android.viewmodel.pages.PageListViewModel
2122
import org.wordpress.android.viewmodel.pages.PageListViewModel.PageListType
2223
import org.wordpress.android.viewmodel.pages.PagesViewModel
@@ -26,6 +27,7 @@ import javax.inject.Named
2627

2728
class PageListFragment : Fragment() {
2829
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
30+
@Inject internal lateinit var imageManager: ImageManager
2931
@field:[Inject Named(UI_SCOPE)] lateinit var uiScope: CoroutineScope
3032
private lateinit var viewModel: PageListViewModel
3133
private var linearLayoutManager: LinearLayoutManager? = null
@@ -90,7 +92,7 @@ class PageListFragment : Fragment() {
9092

9193
private fun setupObservers() {
9294
viewModel.pages.observe(this, Observer { data ->
93-
data?.let { setPages(data) }
95+
data?.let { setPages(data.first, data.second) }
9496
})
9597

9698
viewModel.scrollToPosition.observe(this, Observer { position ->
@@ -100,13 +102,15 @@ class PageListFragment : Fragment() {
100102
})
101103
}
102104

103-
private fun setPages(pages: List<PageItem>) {
105+
private fun setPages(pages: List<PageItem>, isSitePhotonCapable: Boolean) {
104106
val adapter: PagesAdapter
105107
if (recyclerView.adapter == null) {
106108
adapter = PagesAdapter(
107109
onMenuAction = { action, page -> viewModel.onMenuAction(action, page) },
108110
onItemTapped = { page -> viewModel.onItemTapped(page) },
109111
onEmptyActionButtonTapped = { viewModel.onEmptyListNewPageButtonTapped() },
112+
imageManager = imageManager,
113+
isSitePhotonCapable = isSitePhotonCapable,
110114
uiScope = uiScope
111115
)
112116
recyclerView.adapter = adapter

WordPress/src/main/java/org/wordpress/android/ui/pages/PagesAdapter.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,23 @@ import org.wordpress.android.ui.pages.PageItemViewHolder.EmptyViewHolder
1313
import org.wordpress.android.ui.pages.PageItemViewHolder.PageDividerViewHolder
1414
import org.wordpress.android.ui.pages.PageItemViewHolder.PageParentViewHolder
1515
import org.wordpress.android.ui.pages.PageItemViewHolder.PageViewHolder
16+
import org.wordpress.android.util.image.ImageManager
1617

1718
class PagesAdapter(
1819
private val onMenuAction: (PageItem.Action, Page) -> Boolean = { _, _ -> false },
1920
private val onItemTapped: (Page) -> Unit = { },
2021
private val onEmptyActionButtonTapped: () -> Unit = { },
2122
private val onParentSelected: (ParentPage) -> Unit = { },
23+
private val isSitePhotonCapable: Boolean = false,
24+
private val imageManager: ImageManager? = null,
2225
private val uiScope: CoroutineScope
2326
) : Adapter<PageItemViewHolder>() {
2427
private val items = mutableListOf<PageItem>()
2528

2629
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageItemViewHolder {
2730
return when (viewType) {
28-
PageItem.Type.PAGE.viewType -> PageViewHolder(parent, onMenuAction, onItemTapped)
31+
PageItem.Type.PAGE.viewType -> PageViewHolder(parent, onMenuAction, onItemTapped, imageManager!!,
32+
isSitePhotonCapable)
2933
PageItem.Type.DIVIDER.viewType -> PageDividerViewHolder(parent)
3034
PageItem.Type.EMPTY.viewType -> EmptyViewHolder(parent, onEmptyActionButtonTapped)
3135
PageItem.Type.PARENT.viewType -> PageParentViewHolder(parent,

0 commit comments

Comments
 (0)