Compare commits
2 Commits
dev
...
chen/20240
| Author | SHA1 | Date | |
|---|---|---|---|
| 2238aa220b | |||
| 569f2ed741 |
@ -575,7 +575,9 @@ andResGuard {
|
||||
"R.id.cardMask",
|
||||
"R.id.cardGradientMask",
|
||||
"R.id.gameIconIv",
|
||||
"R.id.titleContainer"
|
||||
"R.id.titleContainer",
|
||||
"R.id.v_bubble_background",
|
||||
"R.id.tv_bubble"
|
||||
]
|
||||
compressFilePattern = [
|
||||
"*.png",
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.widget.FrameLayout
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
||||
class InterceptTouchContainView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,14 @@
|
||||
package com.gh.gamecenter.adapter.viewholder
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.marginStart
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.databinding.*
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
|
||||
class SearchGameFooterViewHolder(val binding: SearchGameFooterBinding) : BaseRecyclerViewHolder<Any>(binding.root)
|
||||
class PersonalHomeRatingViewHolder(val binding: PersonalHomeRatingBinding) : BaseRecyclerViewHolder<Any>(binding.root)
|
||||
@ -22,4 +29,62 @@ class CommonCollectionImageTextItemViewHolder(val binding: CommonCollectionImage
|
||||
BaseRecyclerViewHolder<Any>(binding.root)
|
||||
|
||||
class CommonCollectionDetailTwoItemHorizontalViewHolder(val binding: CommonCollectionDetailTwoItemHorizontalCustomBinding) :
|
||||
BaseRecyclerViewHolder<Any>(binding.root)
|
||||
BaseRecyclerViewHolder<Any>(binding.root)
|
||||
|
||||
class CustomCollectionDetailRecommendCardViewHolder(
|
||||
val binding: RecyclerRecommendCardCommonContentCollectionDetailCustomBinding
|
||||
) : BaseRecyclerViewHolder<Any>(binding.root) {
|
||||
|
||||
fun bind(item: CustomPageData.RecommendCard) {
|
||||
ImageUtils.display(binding.ivCover, item.image)
|
||||
binding.tvTitle.text = item.title
|
||||
binding.tvLabel.text = item.tag
|
||||
binding.tvPrice.text = item.highlight.text
|
||||
binding.tvOriginalPrice.text = if (item.deletion.isShowCurrencySymbol) {
|
||||
itemView.context.getString(R.string.price_with_symbol, item.deletion.text)
|
||||
} else {
|
||||
item.deletion.text
|
||||
}
|
||||
binding.tvOriginalPrice.paint.flags = Paint.STRIKE_THRU_TEXT_FLAG
|
||||
binding.tvCopy.text = item.addedContent
|
||||
binding.tvPriceSymbol.goneIf(!item.highlight.isShowCurrencySymbol)
|
||||
|
||||
binding.root.post {
|
||||
val views = mutableListOf(
|
||||
binding.tvPrice,
|
||||
binding.tvOriginalPrice,
|
||||
binding.tvCopy,
|
||||
)
|
||||
if (item.highlight.isShowCurrencySymbol) {
|
||||
views.add(0, binding.tvPriceSymbol)
|
||||
}
|
||||
|
||||
binding.tvLabel.goneIf(item.tag.isBlank()) {
|
||||
views.add(binding.tvLabel)
|
||||
}
|
||||
views.forEach {
|
||||
it.goneIf(false)
|
||||
}
|
||||
|
||||
hideOutOfBoundViewsIfNeed(views)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算统一排的view能否完整显示在 itemView 内,如果显示不下,则根据优先级依次隐藏优先级较低的
|
||||
* 数据中的View优先级由高到低排列,最后一个优先级最低
|
||||
*/
|
||||
private fun hideOutOfBoundViewsIfNeed(views: MutableList<TextView>) {
|
||||
if (views.isEmpty()) {
|
||||
return
|
||||
}
|
||||
val totalWidth = views.sumOf {
|
||||
it.width + it.marginStart
|
||||
}
|
||||
if (totalWidth > itemView.width) {
|
||||
views.removeLast().goneIf(true)
|
||||
hideOutOfBoundViewsIfNeed(views)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@ -17,8 +18,14 @@ data class CommonCollectionEntity(
|
||||
@SerializedName("vertical_line")
|
||||
val verticalLine: String = "", // 竖排时才有数据,代表竖排行数控制
|
||||
@SerializedName("common_collection_content")
|
||||
val collectionList: MutableList<CommonCollectionContentEntity> = mutableListOf()
|
||||
val collectionList: MutableList<CommonCollectionContentEntity> = mutableListOf(),
|
||||
@SerializedName("common_collection_recommend_cards")
|
||||
private val _commonCollectionRecommendCards: List<CustomPageData.RecommendCard>? = null
|
||||
) {
|
||||
|
||||
val commonCollectionRecommendCards: List<CustomPageData.RecommendCard>
|
||||
get() = _commonCollectionRecommendCards ?: emptyList()
|
||||
|
||||
val layoutChinese: String
|
||||
get() = when (layout) {
|
||||
0 -> "轮播banner"
|
||||
@ -30,6 +37,10 @@ data class CommonCollectionEntity(
|
||||
6 -> "双列竖式卡片"
|
||||
7 -> "竖式图文列表"
|
||||
8 -> "横排图文列表"
|
||||
9 -> "内容标签泳道"
|
||||
10 -> "通知栏目"
|
||||
11 -> "公告横幅"
|
||||
12 -> "推荐卡片"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.graphics.Color
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.feature.entity.Time
|
||||
import com.google.gson.annotations.SerializedName
|
||||
@ -22,5 +23,87 @@ data class GameNavigationEntity(
|
||||
var hintStartTime: Long = 0,
|
||||
@SerializedName("hint_end_time")
|
||||
var hintEndTime: Long = 0,
|
||||
var time: Time? = null
|
||||
)
|
||||
var time: Time? = null,
|
||||
@SerializedName("entry_name_status")
|
||||
private val _entryNameStatus: String? = null,
|
||||
@SerializedName("guide")
|
||||
private val _guide: Guide? = null
|
||||
) {
|
||||
|
||||
val isShowEntryName: Boolean
|
||||
get() = ENTRY_NAME_STATUS_HIDE != _entryNameStatus
|
||||
|
||||
val isShowBubble: Boolean
|
||||
get() = _guide != null
|
||||
|
||||
val guide: Guide
|
||||
get() = _guide ?: Guide()
|
||||
|
||||
data class Guide(
|
||||
@SerializedName("text")
|
||||
private val _text: String? = null,
|
||||
@SerializedName("color")
|
||||
private val _color: String? = null
|
||||
) {
|
||||
|
||||
val text: String
|
||||
get() = _text ?: ""
|
||||
|
||||
val color: String
|
||||
get() = _color ?: ""
|
||||
|
||||
/**
|
||||
* 文字颜色 不透明度为 70%
|
||||
* 十六进制: B2
|
||||
* 十进制: 178
|
||||
*/
|
||||
val textColorInt: Int
|
||||
get() = parseColorWithAlpha(TEXT_ALPHA, color)
|
||||
|
||||
/**
|
||||
* 边框颜色 不透明度为 10%
|
||||
* 十六进制: 4D
|
||||
* 十进制: 77
|
||||
*/
|
||||
val borderColorInt: Int
|
||||
get() = parseColorWithAlpha(BORDER_ALPHA, color)
|
||||
|
||||
/**
|
||||
* 背景颜色 不透明度为 30%
|
||||
* 十六进制: 1A
|
||||
* 十进制: 26
|
||||
*/
|
||||
val backgroundColorInt: Int
|
||||
get() = parseColorWithAlpha(BACKGROUND_ALPHA, color)
|
||||
|
||||
|
||||
private fun parseColorWithAlpha(alpha: Int, color: String): Int {
|
||||
val colorInt = try {
|
||||
Color.parseColor(color)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// 解析失败,默认使用红色
|
||||
Color.RED
|
||||
}
|
||||
val hsv = FloatArray(3)
|
||||
Color.colorToHSV(colorInt, hsv)
|
||||
return Color.HSVToColor(alpha, hsv)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val COLOR_BLUE = "blue"
|
||||
private const val COLOR_PURPLE = "purple"
|
||||
private const val COLOR_RED = "red"
|
||||
private const val COLOR_ORANGE = "orange"
|
||||
private const val COLOR_YELLOW = "yellow"
|
||||
private const val COLOR_GREEN = "green"
|
||||
|
||||
private const val TEXT_ALPHA = 178
|
||||
private const val BORDER_ALPHA = 77
|
||||
private const val BACKGROUND_ALPHA = 26
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ENTRY_NAME_STATUS_HIDE = "hide"
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,8 @@ data class HomeRecommend(
|
||||
private val _image: String? = null,
|
||||
@SerializedName("link_community")
|
||||
private val community: CommunityEntity? = null,
|
||||
|
||||
@SerializedName("guide")
|
||||
private val _guide: Guide? = null,
|
||||
// 绑定的曝光实体
|
||||
var exposureEvent: ExposureEvent? = null,
|
||||
) {
|
||||
@ -28,6 +29,12 @@ data class HomeRecommend(
|
||||
val image: String
|
||||
get() = _image ?: ""
|
||||
|
||||
val isShowGuide: Boolean
|
||||
get() = _guide != null
|
||||
|
||||
val guide: Guide
|
||||
get() = _guide ?: Guide()
|
||||
|
||||
fun transformLinkEntity(): LinkEntity {
|
||||
return LinkEntity(
|
||||
name = name,
|
||||
@ -38,4 +45,12 @@ data class HomeRecommend(
|
||||
community = community
|
||||
)
|
||||
}
|
||||
|
||||
data class Guide(
|
||||
@SerializedName("text")
|
||||
private val _text: String? = null
|
||||
) {
|
||||
val text: String
|
||||
get() = _text ?: ""
|
||||
}
|
||||
}
|
||||
@ -44,9 +44,12 @@ data class HomeSubSlide(
|
||||
data class CardData(
|
||||
var games: List<GameEntity> = arrayListOf(),
|
||||
@SerializedName("game_total")
|
||||
val gameTotal: GameTotal = GameTotal(),
|
||||
private val _gameTotal: GameTotal? = null,
|
||||
val stamp: String = ""
|
||||
)
|
||||
) {
|
||||
val gameTotal: GameTotal
|
||||
get() = _gameTotal ?: GameTotal()
|
||||
}
|
||||
|
||||
data class GameTotal(
|
||||
val vote: Int = 0,
|
||||
|
||||
@ -9,10 +9,7 @@ import com.gh.common.exposure.IExposable
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.adapter.viewholder.CommonCollectionDetailOneItemViewHolder
|
||||
import com.gh.gamecenter.adapter.viewholder.CommonCollectionDetailTwoItemHorizontalViewHolder
|
||||
import com.gh.gamecenter.adapter.viewholder.CommonCollectionDetailTwoItemViewHolder
|
||||
import com.gh.gamecenter.adapter.viewholder.CommonCollectionImageTextItemViewHolder
|
||||
import com.gh.gamecenter.adapter.viewholder.*
|
||||
import com.gh.gamecenter.common.baselist.ListAdapter
|
||||
import com.gh.gamecenter.common.constant.ItemViewType
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
@ -21,11 +18,13 @@ import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.entity.CommonCollectionContentEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.game.data.CommonContentCollectionDetailItem
|
||||
import com.gh.gamecenter.game.data.CommonContentCollectionDetailRecommendCardItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_BANNER
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_SLIDE_BANNER
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_RECOMMEND_CARD
|
||||
|
||||
class CustomCommonCollectionDetailAdapter(
|
||||
context: Context,
|
||||
@ -35,13 +34,13 @@ class CustomCommonCollectionDetailAdapter(
|
||||
val mTabIndex: Int,
|
||||
val mEntrance: String,
|
||||
private val mBasicExposureSourceList: List<ExposureSource>?
|
||||
) : ListAdapter<CommonCollectionContentEntity>(context), IExposable {
|
||||
) : ListAdapter<CommonContentCollectionDetailItem>(context), IExposable {
|
||||
|
||||
private val mExposureEventSparseArray = SparseArray<ExposureEvent>()
|
||||
|
||||
override fun areItemsTheSame(
|
||||
oldItem: CommonCollectionContentEntity?,
|
||||
newItem: CommonCollectionContentEntity?
|
||||
oldItem: CommonContentCollectionDetailItem?,
|
||||
newItem: CommonContentCollectionDetailItem?
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
@ -50,12 +49,19 @@ class CustomCommonCollectionDetailAdapter(
|
||||
return if (viewType == ItemViewType.ITEM_BODY) {
|
||||
when (collectionStyle) {
|
||||
"1-1" -> CommonCollectionDetailOneItemViewHolder(parent.toBinding())
|
||||
"1-2" -> if (mViewModel.getLayout() == COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_SLIDE_BANNER
|
||||
|| mViewModel.getLayout() == COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_BANNER
|
||||
) {
|
||||
CommonCollectionDetailTwoItemHorizontalViewHolder(parent.toBinding())
|
||||
} else {
|
||||
CommonCollectionDetailTwoItemViewHolder(parent.toBinding())
|
||||
"1-2" -> when (mViewModel.getLayout()) {
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_SLIDE_BANNER,
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_BANNER -> {
|
||||
CommonCollectionDetailTwoItemHorizontalViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_RECOMMEND_CARD -> {
|
||||
CustomCollectionDetailRecommendCardViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
else -> {
|
||||
CommonCollectionDetailTwoItemViewHolder(parent.toBinding())
|
||||
}
|
||||
}
|
||||
|
||||
else -> CommonCollectionImageTextItemViewHolder(parent.toBinding())
|
||||
@ -79,7 +85,7 @@ class CustomCommonCollectionDetailAdapter(
|
||||
}
|
||||
|
||||
val contentEntity = mEntityList[position]
|
||||
val linkEntity = mEntityList[position].linkEntity
|
||||
val linkEntity = contentEntity.link
|
||||
|
||||
val listener: (v: View) -> Unit = {
|
||||
DirectUtils.directToLinkPage(
|
||||
@ -189,6 +195,15 @@ class CustomCommonCollectionDetailAdapter(
|
||||
root.setOnClickListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
is CustomCollectionDetailRecommendCardViewHolder-> {
|
||||
if (contentEntity is CommonContentCollectionDetailRecommendCardItem) {
|
||||
val recommendCard = contentEntity.data
|
||||
holder.bind(recommendCard)
|
||||
holder.itemView.setOnClickListener(listener)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,8 +5,11 @@ import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.gamecenter.common.baselist.ListViewModel
|
||||
import com.gh.gamecenter.entity.CommonCollectionContentEntity
|
||||
import com.gh.gamecenter.entity.CommonCollectionEntity
|
||||
import com.gh.gamecenter.game.data.CommonContentCollectionDetailItem
|
||||
import com.gh.gamecenter.game.data.CommonContentCollectionDetailOldItem
|
||||
import com.gh.gamecenter.game.data.CommonContentCollectionDetailRecommendCardItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.Observable
|
||||
@ -15,16 +18,16 @@ class CustomCommonCollectionDetailViewModel(
|
||||
application: Application,
|
||||
private val mCollectionId: String,
|
||||
cachedLayout: Int,
|
||||
) : ListViewModel<CommonCollectionContentEntity, CommonCollectionContentEntity>(application) {
|
||||
) : ListViewModel<CommonContentCollectionDetailItem, CommonContentCollectionDetailItem>(application) {
|
||||
|
||||
var finalLayout = cachedLayout
|
||||
val commonCollectionLiveData = MutableLiveData<CommonCollectionEntity>()
|
||||
|
||||
fun getLayout() : Int {
|
||||
fun getLayout(): Int {
|
||||
return finalLayout
|
||||
}
|
||||
|
||||
override fun provideDataObservable(page: Int): Observable<MutableList<CommonCollectionContentEntity>>? {
|
||||
override fun provideDataObservable(page: Int): Observable<List<CommonContentCollectionDetailItem>>? {
|
||||
return if (page == 1) {
|
||||
RetrofitManager.getInstance().api
|
||||
.getCommonCollectionDetail(mCollectionId)
|
||||
@ -33,11 +36,40 @@ class CustomCommonCollectionDetailViewModel(
|
||||
finalLayout = it.layout
|
||||
}
|
||||
commonCollectionLiveData.postValue(it)
|
||||
it.collectionList
|
||||
if (it.layout == CustomPageItem.COMMON_CONTENT_COLLECTION_LAYOUT_RECOMMEND_CARD) {
|
||||
it.commonCollectionRecommendCards
|
||||
.map {
|
||||
CommonContentCollectionDetailRecommendCardItem(it)
|
||||
}
|
||||
} else {
|
||||
it.collectionList.map {
|
||||
CommonContentCollectionDetailOldItem(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RetrofitManager.getInstance().api
|
||||
.getCommonCollectionDetail(mCollectionId, page)
|
||||
if (finalLayout == CustomPageItem.COMMON_CONTENT_COLLECTION_LAYOUT_RECOMMEND_CARD) {
|
||||
RetrofitManager.getInstance().api
|
||||
.getCommonCollectionDetailWithRecommenCards(mCollectionId, page)
|
||||
.map {
|
||||
it
|
||||
.map { entity ->
|
||||
CommonContentCollectionDetailRecommendCardItem(entity)
|
||||
}
|
||||
.toMutableList()
|
||||
}
|
||||
} else {
|
||||
RetrofitManager.getInstance().api
|
||||
.getCommonCollectionDetail(mCollectionId, page)
|
||||
.map {
|
||||
it
|
||||
.map { entity ->
|
||||
CommonContentCollectionDetailOldItem(entity)
|
||||
}
|
||||
.toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
package com.gh.gamecenter.game.data
|
||||
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.entity.CommonCollectionContentEntity
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
|
||||
abstract class CommonContentCollectionDetailItem {
|
||||
|
||||
abstract val title: String
|
||||
|
||||
abstract val image: String
|
||||
|
||||
abstract val addedContent1: String
|
||||
|
||||
abstract val addedContent2: String
|
||||
|
||||
abstract val link: LinkEntity
|
||||
}
|
||||
|
||||
data class CommonContentCollectionDetailOldItem(
|
||||
val data: CommonCollectionContentEntity
|
||||
) : CommonContentCollectionDetailItem() {
|
||||
override val title: String
|
||||
get() = data.title
|
||||
override val image: String
|
||||
get() = data.image
|
||||
override val addedContent1: String
|
||||
get() = data.addedContent1 ?: ""
|
||||
override val addedContent2: String
|
||||
get() = data.addedContent2 ?: ""
|
||||
override val link: LinkEntity
|
||||
get() = data.linkEntity
|
||||
}
|
||||
|
||||
data class CommonContentCollectionDetailRecommendCardItem(
|
||||
val data: CustomPageData.RecommendCard
|
||||
) : CommonContentCollectionDetailItem() {
|
||||
override val title: String
|
||||
get() = data.title
|
||||
override val image: String
|
||||
get() = data.image
|
||||
override val addedContent1: String
|
||||
get() = data.addedContent
|
||||
override val addedContent2: String
|
||||
get() = ""
|
||||
override val link: LinkEntity
|
||||
get() = LinkEntity(link = data.linkId, type = data.linkType, linkText = data.linkText)
|
||||
}
|
||||
|
||||
@ -23,6 +23,8 @@ class BannerInRecyclerController(
|
||||
|
||||
private var isParentScrolling = false
|
||||
|
||||
private var isDestroyed = false
|
||||
|
||||
private val onScrollListener = object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
isParentScrolling = newState != RecyclerView.SCROLL_STATE_IDLE
|
||||
@ -37,6 +39,7 @@ class BannerInRecyclerController(
|
||||
fun onViewAttachedToWindow(parent: RecyclerView?) {
|
||||
isAttachToWindow = true
|
||||
parent?.addOnScrollListener(onScrollListener)
|
||||
start()
|
||||
}
|
||||
|
||||
fun onViewDetachedFromWindow(parent: RecyclerView?) {
|
||||
@ -46,7 +49,7 @@ class BannerInRecyclerController(
|
||||
}
|
||||
|
||||
fun start() {
|
||||
if (isActive && !isParentScrolling) {
|
||||
if (isActive && !isParentScrolling && !isDestroyed) {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
nextToPage()
|
||||
}
|
||||
@ -56,7 +59,7 @@ class BannerInRecyclerController(
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
private fun destroy() {
|
||||
fun destroy() {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
@ -73,6 +76,7 @@ class BannerInRecyclerController(
|
||||
}
|
||||
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
isDestroyed = true
|
||||
destroy()
|
||||
}
|
||||
|
||||
|
||||
@ -483,6 +483,9 @@ class CustomPageViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
val shareHiddenNotifications: LiveData<HashMap<String, MutableSet<String>>>
|
||||
get() = repository.hiddenNotifications
|
||||
|
||||
private fun getPositionAndPackageMap(list: List<CustomPageItem>): HashMap<String, Int> {
|
||||
val hashMap = hashMapOf<String, Int>()
|
||||
list.forEach { custom ->
|
||||
@ -608,10 +611,8 @@ class CustomPageViewModel(
|
||||
private val _userDestination = MutableLiveData<Event<Triple<String, String, String>>>()
|
||||
val userDestination: LiveData<Event<Triple<String, String, String>>> = _userDestination
|
||||
override fun navigateUserHomePage(item: CustomPageItem, userId: String) {
|
||||
//todo 待定
|
||||
val entrance = ""
|
||||
val path = ""
|
||||
|
||||
when {
|
||||
item is CustomSubjectCollectionItem -> pageTracker.trackGameListCollectionClickWithUser(item, userId)
|
||||
}
|
||||
@ -634,7 +635,12 @@ class CustomPageViewModel(
|
||||
|
||||
private val _linkDestination = MutableLiveData<Event<Pair<LinkEntity, ExposureEvent?>>>()
|
||||
val linkDestination: LiveData<Event<Pair<LinkEntity, ExposureEvent?>>> = _linkDestination
|
||||
override fun navigateToLinkPage(item: CustomPageItem, link: LinkEntity, text: String, exposureEvent: ExposureEvent?) {
|
||||
override fun navigateToLinkPage(
|
||||
item: CustomPageItem,
|
||||
link: LinkEntity,
|
||||
text: String,
|
||||
exposureEvent: ExposureEvent?
|
||||
) {
|
||||
_linkDestination.value = Event(Pair(link, exposureEvent))
|
||||
}
|
||||
|
||||
@ -650,7 +656,8 @@ class CustomPageViewModel(
|
||||
_badgeWallDestination.value = Event(comment)
|
||||
}
|
||||
|
||||
private val _gameDetailDestinationOnAmway = MutableLiveData<Event<Triple<CustomPageTrackData, String, ExposureEvent?>>>()
|
||||
private val _gameDetailDestinationOnAmway =
|
||||
MutableLiveData<Event<Triple<CustomPageTrackData, String, ExposureEvent?>>>()
|
||||
val gameDetailDestinationOnAmway: LiveData<Event<Triple<CustomPageTrackData, String, ExposureEvent?>>> =
|
||||
_gameDetailDestinationOnAmway
|
||||
|
||||
@ -707,6 +714,10 @@ class CustomPageViewModel(
|
||||
_gameListSquareDestination.value = Event(item)
|
||||
}
|
||||
|
||||
fun hideNotificationItem(id: String, itemId: String) {
|
||||
repository.hideNotificationItem(id, itemId)
|
||||
}
|
||||
|
||||
private fun Disposable.addDisposable() {
|
||||
compositeDisposable.add(this)
|
||||
}
|
||||
|
||||
@ -0,0 +1,98 @@
|
||||
package com.gh.gamecenter.home.custom.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.databinding.GameCollectionBannerItemBinding
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
|
||||
class AnnouncementBannerAdapter(
|
||||
context: Context,
|
||||
private val listener: OnChildEventListener
|
||||
) :
|
||||
CustomBaseChildAdapter<CustomPageData.Announcement, AnnouncementBannerAdapter.AnnouncementBannerChildViewHolder>(
|
||||
context
|
||||
) {
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun checkResetData(updates: List<CustomPageData.Announcement>?) {
|
||||
if (updates.isNullOrEmpty()) {
|
||||
_countAndKey = null
|
||||
notifyDataSetChanged()
|
||||
return
|
||||
}
|
||||
|
||||
val countAndKey = _countAndKey ?: Pair(0, "")
|
||||
val (oldSize, oldKeys) = countAndKey
|
||||
|
||||
val newSize = updates.size
|
||||
var newKeys = ""
|
||||
updates.forEach {
|
||||
newKeys += it.id
|
||||
}
|
||||
|
||||
val needRefresh = !(oldSize == newSize && oldKeys == newKeys && !isDarkModeChange())
|
||||
if (needRefresh) {
|
||||
if (isBanner) {
|
||||
// 刷新 [前 中 后] 三个 itemView
|
||||
val currentPosition = listener.getCurrentPosition()
|
||||
val startPosition = if (currentPosition > 0) currentPosition - 1 else currentPosition
|
||||
notifyItemRangeChanged(startPosition, 3)
|
||||
} else {
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
val isBanner: Boolean
|
||||
get() = dataList.size > 1
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return if (isBanner) Int.MAX_VALUE else super.getItemCount()
|
||||
}
|
||||
|
||||
fun getDataPosition(position: Int) =
|
||||
if (isBanner) {
|
||||
position % dataList.size
|
||||
} else {
|
||||
position
|
||||
}
|
||||
|
||||
override fun getItem(position: Int): CustomPageData.Announcement {
|
||||
return super.getItem(getDataPosition(position))
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnnouncementBannerChildViewHolder {
|
||||
return AnnouncementBannerChildViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AnnouncementBannerChildViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
listener.exposure(position, item)
|
||||
holder.bind(item)
|
||||
holder.binding.bannerIv.setOnClickListener {
|
||||
listener.onItemClick(getDataPosition(position), item)
|
||||
}
|
||||
}
|
||||
|
||||
class AnnouncementBannerChildViewHolder(val binding: GameCollectionBannerItemBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: CustomPageData.Announcement) {
|
||||
ImageUtils.display(binding.bannerIv, item.image)
|
||||
}
|
||||
}
|
||||
|
||||
interface OnChildEventListener {
|
||||
|
||||
fun onItemClick(childPosition: Int, announcement: CustomPageData.Announcement)
|
||||
|
||||
fun getCurrentPosition(): Int
|
||||
|
||||
fun exposure(childPosition: Int, announcement: CustomPageData.Announcement)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package com.gh.gamecenter.home.custom.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.databinding.RecyclerContentLabelLaneItemBinding
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
|
||||
class ContentLabelLaneAdapter(
|
||||
context: Context,
|
||||
private val clickInvoke: (Int, CustomPageData.CommonContentCollection.ContentTag) -> Unit,
|
||||
private val exposureInvoke: (Int, CustomPageData.CommonContentCollection.ContentTag) -> Unit
|
||||
) : CustomBaseChildAdapter<CustomPageData.CommonContentCollection.ContentTag, ContentLabelLaneAdapter.ContentLabelChildViewHolder>(
|
||||
context
|
||||
) {
|
||||
|
||||
override fun getKey(t: CustomPageData.CommonContentCollection.ContentTag): String {
|
||||
return t.id
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContentLabelChildViewHolder {
|
||||
return ContentLabelChildViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ContentLabelChildViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
with(holder.binding) {
|
||||
ivIcon.displayGameIcon(item.image, null, null)
|
||||
tvTitle.text = item.title
|
||||
tvSubTitle.goneIf(item.addedContent.isBlank()) {
|
||||
tvSubTitle.text = context.getString(R.string.content_tag_added_content_with_prefix, item.addedContent)
|
||||
}
|
||||
gBubble.goneIf(!item.isShowGuide) {
|
||||
tvBubble.text = item.guide.text
|
||||
}
|
||||
}
|
||||
|
||||
exposureInvoke(position, item)
|
||||
holder.itemView.setOnClickListener {
|
||||
clickInvoke(position, item)
|
||||
}
|
||||
}
|
||||
|
||||
class ContentLabelChildViewHolder(
|
||||
val binding: RecyclerContentLabelLaneItemBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -20,7 +20,7 @@ abstract class CustomBaseChildAdapter<T, VH : RecyclerView.ViewHolder>(
|
||||
|
||||
private var darkMode = DarkModeUtils.isDarkModeOn(context)
|
||||
|
||||
private var _countAndKey: Pair<Int, String>? = null
|
||||
protected var _countAndKey: Pair<Int, String>? = null
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun submitList(data: List<T>?, forceRefresh: Boolean = false) {
|
||||
@ -85,7 +85,7 @@ abstract class CustomBaseChildAdapter<T, VH : RecyclerView.ViewHolder>(
|
||||
}
|
||||
|
||||
if (oldSize == newSize) {
|
||||
if (oldKeys != newKeys || darkMode != DarkModeUtils.isDarkModeOn(context)) { // 数量不变,内容发生变化 || 切换浅色模式
|
||||
if (oldKeys != newKeys || isDarkModeChange()) { // 数量不变,内容发生变化 || 切换浅色模式
|
||||
notifyItemRangeChanged(0, itemCount, "")
|
||||
}
|
||||
} else {// 数量发生变化
|
||||
@ -95,4 +95,6 @@ abstract class CustomBaseChildAdapter<T, VH : RecyclerView.ViewHolder>(
|
||||
}
|
||||
|
||||
protected open fun getKey(t: T) = ""
|
||||
|
||||
fun isDarkModeChange() = darkMode != DarkModeUtils.isDarkModeOn(context)
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.gamecenter.home.custom.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -10,10 +11,7 @@ import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.entity.ExposureEntity
|
||||
import com.gh.gamecenter.common.json.json
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.PageSwitchDataHelper
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.databinding.ItemGameNavigationCustomBinding
|
||||
@ -45,44 +43,62 @@ class CustomGameNavigationAdapter(
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: GameNavigationViewHolder, position: Int) {
|
||||
|
||||
// 是否显示小红点
|
||||
var isShowHint = false
|
||||
val entity = dataList[position]
|
||||
ImageUtils.display(holder.binding.navigationView, entity.image)
|
||||
holder.binding.navigationNameTv.text = entity.entryName
|
||||
|
||||
if (entity.hint) {
|
||||
val record = recordMap[entity.id]
|
||||
if (record == null) {
|
||||
holder.binding.redHintIv.visibility = View.VISIBLE
|
||||
} else {
|
||||
val split = record.split(divider)//时间戳|点击次数
|
||||
val updateTime = split[0].toLong()
|
||||
val count = split[1].toInt()
|
||||
//判断是否更新过
|
||||
if (updateTime == entity.time?.update) {
|
||||
holder.binding.redHintIv.visibility = View.GONE
|
||||
} else {
|
||||
val currentTime = System.currentTimeMillis() / 1000
|
||||
holder.binding.redHintIv.goneIf(currentTime !in entity.hintStartTime..entity.hintEndTime || count >= 2)
|
||||
}
|
||||
}
|
||||
holder.binding.navigationNameTv.text = if (entity.isShowEntryName) {
|
||||
entity.entryName
|
||||
} else {
|
||||
holder.binding.redHintIv.visibility = View.GONE
|
||||
""
|
||||
}
|
||||
val isFirstLine = position < 4
|
||||
if (entity.isShowBubble && isFirstLine) {
|
||||
isShowHint = false
|
||||
showGuide(entity, holder.binding)
|
||||
} else {
|
||||
holder.binding.flBubbleContainer.goneIf(true)
|
||||
if (entity.hint) {
|
||||
val record = recordMap[entity.id]
|
||||
if (record == null) {
|
||||
isShowHint = true
|
||||
holder.binding.redHintIv.visibility = View.VISIBLE
|
||||
} else {
|
||||
val split = record.split(divider)//时间戳|点击次数
|
||||
val updateTime = split[0].toLong()
|
||||
val count = split[1].toInt()
|
||||
//判断是否更新过
|
||||
if (updateTime == entity.time?.update) {
|
||||
isShowHint = false
|
||||
holder.binding.redHintIv.visibility = View.GONE
|
||||
} else {
|
||||
val currentTime = System.currentTimeMillis() / 1000
|
||||
val isGone = currentTime !in entity.hintStartTime..entity.hintEndTime || count >= 2
|
||||
holder.binding.redHintIv.goneIf(isGone)
|
||||
isShowHint = !isGone
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isShowHint = false
|
||||
holder.binding.redHintIv.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
holder.itemView.setOnClickListener {
|
||||
entity.linkEntity?.let {
|
||||
val record = recordMap[entity.id]
|
||||
if (record == null) {
|
||||
recordMap[entity.id] = "${entity.time?.update}${divider}1"
|
||||
} else {
|
||||
val split = record.split(divider)
|
||||
val updateTime = split[0].toLong()
|
||||
var count = split[1].toInt()
|
||||
recordMap[entity.id] = "${updateTime}${divider}${++count}"
|
||||
if (isShowHint) {
|
||||
val record = recordMap[entity.id]
|
||||
if (record == null) {
|
||||
recordMap[entity.id] = "${entity.time?.update}${divider}1"
|
||||
} else {
|
||||
val split = record.split(divider)
|
||||
val updateTime = split[0].toLong()
|
||||
var count = split[1].toInt()
|
||||
recordMap[entity.id] = "${updateTime}${divider}${++count}"
|
||||
}
|
||||
SPUtils.setMap(Constants.SP_GAME_NAVIGATION, recordMap)
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
SPUtils.setMap(Constants.SP_GAME_NAVIGATION, recordMap)
|
||||
notifyItemChanged(position)
|
||||
PageSwitchDataHelper.pushCurrentPageData(
|
||||
hashMapOf(
|
||||
Pair(PageSwitchDataHelper.PAGE_BUSINESS_TYPE, "板块-内容列表->导航栏"),
|
||||
@ -119,6 +135,30 @@ class CustomGameNavigationAdapter(
|
||||
|
||||
}
|
||||
|
||||
private fun showGuide(entity: GameNavigationEntity, binding: ItemGameNavigationCustomBinding) {
|
||||
binding.flBubbleContainer.goneIf(false)
|
||||
binding.tvBubble.text = entity.guide.text
|
||||
binding.tvBubble.setTextColor(entity.guide.textColorInt)
|
||||
|
||||
val gradientDrawable =
|
||||
(binding.tvBubble.background as? GradientDrawable) ?: GradientDrawable()
|
||||
gradientDrawable.cornerRadii =
|
||||
floatArrayOf(
|
||||
8F.dip2px().toFloat(),
|
||||
8F.dip2px().toFloat(),
|
||||
8F.dip2px().toFloat(),
|
||||
8F.dip2px().toFloat(),
|
||||
2F.dip2px().toFloat(),
|
||||
2F.dip2px().toFloat(),
|
||||
2F.dip2px().toFloat(),
|
||||
2F.dip2px().toFloat()
|
||||
)
|
||||
gradientDrawable.setStroke(1F.dip2px(), entity.guide.borderColorInt)
|
||||
gradientDrawable.setColor(entity.guide.backgroundColorInt)
|
||||
binding.tvBubble.background = gradientDrawable
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val divider = "|"
|
||||
}
|
||||
|
||||
@ -4,21 +4,20 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import androidx.core.view.ViewCompat
|
||||
import com.gh.common.exposure.ExposureManager
|
||||
import com.gh.common.exposure.ExposureTraceUtils
|
||||
import com.gh.common.util.LogUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.setDebouncedClickListener
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.PageSwitchDataHelper
|
||||
import com.gh.gamecenter.databinding.ItemHomeRecommendListItemCustomBinding
|
||||
import com.gh.gamecenter.entity.HomeRecommend
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.exposure.ExposureType
|
||||
import com.gh.gamecenter.home.custom.eventlistener.CommonContentCollectionEventHelper
|
||||
import com.gh.gamecenter.home.custom.viewholder.CustomHomeRecommendItemViewHolder.Companion.MAX_SPAN_COUNT
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
@ -33,9 +32,11 @@ class CustomHomeRecommendItemGridAdapter(
|
||||
|
||||
private val dataList = arrayListOf<HomeRecommend>()
|
||||
private var exposureEventList: List<ExposureEvent>? = null
|
||||
private var spanCount = MAX_SPAN_COUNT
|
||||
|
||||
fun submitList(data: List<HomeRecommend>, trackEventList: List<ExposureEvent>?) {
|
||||
fun submitList(data: List<HomeRecommend>, spanCount: Int, trackEventList: List<ExposureEvent>?) {
|
||||
exposureEventList = trackEventList
|
||||
this.spanCount = spanCount
|
||||
dataList.clear()
|
||||
dataList.addAll(data)
|
||||
notifyDataSetChanged()
|
||||
@ -63,7 +64,14 @@ class CustomHomeRecommendItemGridAdapter(
|
||||
ImageUtils.display(binding.iconIv, data.image)
|
||||
binding.nameTv.text = data.name
|
||||
binding.nameTv.setTextColor(R.color.text_primary.toColor(binding.root.context))
|
||||
// 当金刚区一排需要展示五个时,就算后台返回了引导文案,最右边 itemView 仍然会出现显示不全的情况,所以这里将此种情况的引导文案隐藏
|
||||
val isRightmost = spanCount == MAX_SPAN_COUNT && (position + 1) % MAX_SPAN_COUNT == 0
|
||||
binding.tvBubble.goneIf(!data.isShowGuide || isRightmost) {
|
||||
binding.tvBubble.text = data.guide.text
|
||||
}
|
||||
}
|
||||
|
||||
ViewCompat.setElevation(binding.root, 999F - position)
|
||||
initEvent(binding, position)
|
||||
return binding.root
|
||||
}
|
||||
@ -114,7 +122,11 @@ class CustomHomeRecommendItemGridAdapter(
|
||||
ExposureManager.log(clickEvent)
|
||||
}
|
||||
}
|
||||
eventHelper.navigateToLinkPage(recommend.transformLinkEntity(), "金刚区", exposureEventList?.getOrNull(position))
|
||||
eventHelper.navigateToLinkPage(
|
||||
recommend.transformLinkEntity(),
|
||||
"金刚区",
|
||||
exposureEventList?.getOrNull(position)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import androidx.recyclerview.widget.RecyclerView.OnScrollListener
|
||||
import com.gh.common.exposure.IExposable
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
@ -17,16 +18,18 @@ import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.game.GameAndPosition
|
||||
import com.gh.gamecenter.home.custom.CustomPageViewModel
|
||||
import com.gh.gamecenter.home.custom.IGameChangedNotifier
|
||||
import com.gh.gamecenter.home.custom.model.CustomFooterItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomGameTestV2Item
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem
|
||||
import com.gh.gamecenter.home.custom.model.*
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_AMWAY_WALL
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COLLECTION_REFRESH_ICON_LANE
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COLLECTION_REFRESH_ICON_MATRIX
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COLLECTION_REFRESH_SLIDE_LIST
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COMMON_ANNOUNCEMENT_BANNER
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COMMON_BANNER
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COMMON_BANNER_WITH_CARDS
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COMMON_CONTENT_LABEL_LANE
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COMMON_HORIZONTAL_SLIDE
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COMMON_NOTIFICATION_COLUMN
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COMMON_RECOMMEND_CARD
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_COMMON_VERTICAL_TWO_CARDS
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_CONTENT_CARD
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_DISCOVER
|
||||
@ -51,7 +54,6 @@ import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_SUBJECT_COLLECTION_BANNER
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_SUBJECT_COLLECTION_HORIZONTAL_SLIDE_LARGE_CARD
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_SUBJECT_COLLECTION_HORIZONTAL_SLIDE_SMALL_CARD
|
||||
import com.gh.gamecenter.home.custom.model.CustomRecentGamesItem
|
||||
import com.gh.gamecenter.home.custom.viewholder.*
|
||||
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
|
||||
import com.lightgame.download.DownloadEntity
|
||||
@ -190,8 +192,20 @@ class CustomPageAdapter(
|
||||
CUSTOM_PAGE_ITEM_TYPE_COLLECTION_REFRESH_SLIDE_LIST ->
|
||||
CustomGameCollectionRefreshVerticalSlideViewHolder(viewModel, parent.toBinding())
|
||||
|
||||
CUSTOM_PAGE_ITEM_TYPE_COMMON_CONTENT_LABEL_LANE ->
|
||||
ContentLabelLaneViewHolder(viewModel, parent.toBinding())
|
||||
|
||||
CUSTOM_PAGE_ITEM_TYPE_COMMON_NOTIFICATION_COLUMN ->
|
||||
NotificationColumnViewHolder(viewModel, lifecycleOwner, parent.toBinding())
|
||||
|
||||
CUSTOM_PAGE_ITEM_TYPE_FOOTER -> CustomFooterViewHolder(viewModel, parent.toBinding())
|
||||
|
||||
CUSTOM_PAGE_ITEM_TYPE_COMMON_ANNOUNCEMENT_BANNER ->
|
||||
CustomAnnouncementBannerViewHolder(viewModel, lifecycleOwner, parent.toBinding())
|
||||
|
||||
CUSTOM_PAGE_ITEM_TYPE_COMMON_RECOMMEND_CARD ->
|
||||
CustomRecommendCardViewHolder(viewModel, parent.toBinding())
|
||||
|
||||
else -> CustomDoubleCardViewHolder(viewModel, parent.toBinding())
|
||||
}
|
||||
|
||||
@ -258,6 +272,14 @@ class CustomPageAdapter(
|
||||
|
||||
is CustomGameCollectionRefreshVerticalSlideViewHolder -> holder.bindView(item)
|
||||
|
||||
is ContentLabelLaneViewHolder -> holder.bindView(item)
|
||||
|
||||
is NotificationColumnViewHolder -> holder.bindView(item)
|
||||
|
||||
is CustomAnnouncementBannerViewHolder -> holder.bindView(item)
|
||||
|
||||
is CustomRecommendCardViewHolder -> holder.bindView(item)
|
||||
|
||||
is CustomFooterViewHolder -> holder.initFooterViewHolder(
|
||||
loadStatus == LoadStatus.LIST_LOADING,
|
||||
loadStatus == LoadStatus.LIST_FAILED,
|
||||
@ -271,6 +293,8 @@ class CustomPageAdapter(
|
||||
notifyItemChanged(itemCount - 1)
|
||||
}
|
||||
}
|
||||
|
||||
else -> holder.bindView(item)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
package com.gh.gamecenter.home.custom.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.visibleIf
|
||||
import com.gh.gamecenter.databinding.RecyclerNotificationColumnItemBinding
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
|
||||
class NotificationColumnAdapter(
|
||||
context: Context,
|
||||
private val exposureInvoke: (Int, CustomPageData.Notify) -> Unit
|
||||
) :
|
||||
CustomBaseChildAdapter<CustomPageData.Notify, NotificationColumnAdapter.NotificationColumChildViewHolder>(context) {
|
||||
|
||||
private var toBeDeletedItemIds = arrayListOf<String>()
|
||||
|
||||
override fun getKey(t: CustomPageData.Notify): String {
|
||||
return "${t.id}-${t.title}"
|
||||
}
|
||||
|
||||
val dataCount: Int
|
||||
get() = dataList.size
|
||||
|
||||
private val dataCountWithoutToBeDeleted: Int
|
||||
get() = dataCount - toBeDeletedItemIds.size
|
||||
|
||||
val isBanner: Boolean
|
||||
get() = dataCount > 1
|
||||
|
||||
override fun getItem(position: Int): CustomPageData.Notify {
|
||||
return super.getItem(getDataPosition(position))
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return if (dataCount > 1) {
|
||||
Int.MAX_VALUE
|
||||
} else {
|
||||
dataCount
|
||||
}
|
||||
}
|
||||
|
||||
fun getDataPosition(position: Int): Int {
|
||||
return if (isBanner) position % dataCount else position
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationColumChildViewHolder {
|
||||
return NotificationColumChildViewHolder((parent.toBinding()))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: NotificationColumChildViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
with(holder.binding) {
|
||||
ivIcon.displayGameIcon(item.image, null, null)
|
||||
tvTitle.text = item.title
|
||||
tvDesc.text = item.addedContent
|
||||
ivClose.visibleIf(item.isClosable)
|
||||
}
|
||||
exposureInvoke(position, item)
|
||||
}
|
||||
|
||||
private fun getValidItem(position: Int): CustomPageData.Notify {
|
||||
val item = getItem(position)
|
||||
val hasRemoved = toBeDeletedItemIds.remove(item.id)
|
||||
return if (hasRemoved) {
|
||||
_dataList.remove(item)
|
||||
getValidItem(position)
|
||||
} else {
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为了不影响当前循环的数据位置,这里暂时将需要删除的数据标记为 待删除 状态,直接下一轮循环到需要删除的数据时,真正执行删除操作
|
||||
*/
|
||||
fun removeItem(itemId: String) {
|
||||
val hasContains = _dataList.any { it.id == itemId }
|
||||
if (hasContains) {
|
||||
toBeDeletedItemIds.add(itemId)
|
||||
if (dataCountWithoutToBeDeleted == 1) {
|
||||
// 退化为普通列表
|
||||
_dataList.removeAll {
|
||||
toBeDeletedItemIds.contains(it.id)
|
||||
}
|
||||
toBeDeletedItemIds.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationColumChildViewHolder(
|
||||
val binding: RecyclerNotificationColumnItemBinding
|
||||
) : RecyclerView.ViewHolder(binding.root)
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package com.gh.gamecenter.home.custom.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Paint
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.marginStart
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.databinding.RecyclerRecommendCardItemBinding
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
import com.gh.gamecenter.home.custom.viewholder.ui.RecommendCardUi
|
||||
|
||||
class RecommendCardAdapter(
|
||||
context: Context,
|
||||
private val listener: RecommendCardUi.OnRecommendCardEventListener
|
||||
) : CustomBaseChildAdapter<CustomPageData.RecommendCard, RecommendCardAdapter.RecommendCardChildViewHolder>(context) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecommendCardChildViewHolder {
|
||||
return RecommendCardChildViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecommendCardChildViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
listener.onItemExposure(position, item)
|
||||
holder.bind(item, position)
|
||||
holder.itemView.setOnClickListener {
|
||||
listener.onItemClick(position, item)
|
||||
}
|
||||
}
|
||||
|
||||
class RecommendCardChildViewHolder(val binding: RecyclerRecommendCardItemBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: CustomPageData.RecommendCard, position: Int) {
|
||||
ImageUtils.display(binding.ivCover, item.image)
|
||||
binding.tvTitle.text = item.title
|
||||
binding.tvLabel.text = item.tag
|
||||
binding.tvPrice.text = item.highlight.text
|
||||
binding.tvOriginalPrice.text = if (item.deletion.isShowCurrencySymbol) {
|
||||
itemView.context.getString(R.string.price_with_symbol, item.deletion.text)
|
||||
} else {
|
||||
item.deletion.text
|
||||
}
|
||||
binding.tvOriginalPrice.paint.flags = Paint.STRIKE_THRU_TEXT_FLAG
|
||||
binding.tvCopy.text = item.addedContent
|
||||
binding.tvPriceSymbol.goneIf(!item.highlight.isShowCurrencySymbol)
|
||||
|
||||
binding.root.post {
|
||||
val views = mutableListOf(
|
||||
binding.tvPrice,
|
||||
binding.tvOriginalPrice,
|
||||
binding.tvCopy,
|
||||
)
|
||||
if (item.highlight.isShowCurrencySymbol) {
|
||||
views.add(0, binding.tvPriceSymbol)
|
||||
}
|
||||
|
||||
binding.tvLabel.goneIf(item.tag.isBlank()) {
|
||||
views.add(binding.tvLabel)
|
||||
}
|
||||
views.forEach {
|
||||
it.goneIf(false)
|
||||
}
|
||||
|
||||
hideOutOfBoundViewsIfNeed(views)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算统一排的view能否完整显示在 itemView 内,如果显示不下,则根据优先级依次隐藏优先级较低的
|
||||
* 数据中的View优先级由高到低排列,最后一个优先级最低
|
||||
*/
|
||||
private fun hideOutOfBoundViewsIfNeed(views: MutableList<TextView>) {
|
||||
if (views.isEmpty()) {
|
||||
return
|
||||
}
|
||||
val totalWidth = views.sumOf {
|
||||
it.width + it.marginStart
|
||||
}
|
||||
if (totalWidth > itemView.width) {
|
||||
views.removeLast().goneIf(true)
|
||||
hideOutOfBoundViewsIfNeed(views)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.gh.gamecenter.home.custom.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
|
||||
/**
|
||||
* 宽度不受父布局限制的 TextView
|
||||
* 使用场景 :子布局超出父布局,并且宽度可能长于父布局
|
||||
* @see CustomHomeRecommendItemGridAdapter
|
||||
*/
|
||||
class WidthUnlimitedTextView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attr: AttributeSet? = null,
|
||||
def: Int = 0
|
||||
) : androidx.appcompat.widget.AppCompatTextView(context, attr, def) {
|
||||
|
||||
val MAX_WIDTH = 1000F.dip2px()
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(MAX_WIDTH, MeasureSpec.AT_MOST), heightMeasureSpec)
|
||||
}
|
||||
|
||||
}
|
||||
@ -352,6 +352,8 @@ class CustomPageData(
|
||||
private val _id: String? = null,
|
||||
@SerializedName("name")
|
||||
private val _name: String? = null,
|
||||
@SerializedName("subtitle")
|
||||
private val _subtitle: String? = null,
|
||||
@SerializedName("detail_style")
|
||||
private val _detailStyle: String? = null,
|
||||
@SerializedName("layout")
|
||||
@ -370,6 +372,14 @@ class CustomPageData(
|
||||
private val _navigations: List<GameNavigationEntity>? = null,
|
||||
@SerializedName("recommends")
|
||||
private val _recommends: List<HomeRecommend>? = null,
|
||||
@SerializedName("content_tags")
|
||||
private val _contentTags: List<ContentTag>? = null,
|
||||
@SerializedName("notifies")
|
||||
private var _notifies: MutableList<Notify>? = null,
|
||||
@SerializedName("announcements")
|
||||
private var _announcements: List<Announcement>? = null,
|
||||
@SerializedName("recommend_cards") // TODO 待定
|
||||
private var _recommendCards: List<RecommendCard>? = null
|
||||
) {
|
||||
|
||||
val id: String
|
||||
@ -378,6 +388,9 @@ class CustomPageData(
|
||||
val name: String
|
||||
get() = _name ?: ""
|
||||
|
||||
val subtitle: String
|
||||
get() = _subtitle ?: ""
|
||||
|
||||
val detailStyle: String
|
||||
get() = _detailStyle ?: ""
|
||||
|
||||
@ -395,6 +408,8 @@ class CustomPageData(
|
||||
6 -> "双列竖式卡片"
|
||||
7 -> "竖式图文列表"
|
||||
8 -> "横排图文列表"
|
||||
9 -> "内容标签泳道"
|
||||
10 -> "通知栏目"
|
||||
else -> ""
|
||||
}
|
||||
|
||||
@ -419,6 +434,21 @@ class CustomPageData(
|
||||
val recommends: List<HomeRecommend>
|
||||
get() = _recommends ?: emptyList()
|
||||
|
||||
val contentTags: List<ContentTag>
|
||||
get() = _contentTags ?: emptyList()
|
||||
|
||||
var notifies: MutableList<Notify>
|
||||
get() = _notifies ?: mutableListOf()
|
||||
set(value) {
|
||||
_notifies = value
|
||||
}
|
||||
|
||||
val announcements: List<Announcement>
|
||||
get() = _announcements ?: emptyList()
|
||||
|
||||
val recommendCards: List<RecommendCard>
|
||||
get() = _recommendCards ?: emptyList()
|
||||
|
||||
data class Slides(
|
||||
@SerializedName("slide")
|
||||
private val _slide: List<HomeSlide>? = null,
|
||||
@ -433,5 +463,259 @@ class CustomPageData(
|
||||
get() = _subSlide ?: emptyList()
|
||||
}
|
||||
|
||||
|
||||
data class ContentTag(
|
||||
@SerializedName("_id")
|
||||
private val _id: String? = null,
|
||||
@SerializedName("title")
|
||||
private val _title: String? = null,
|
||||
@SerializedName("image")
|
||||
private val _image: String? = null,
|
||||
@SerializedName("added_content")
|
||||
private val _addedContent: String? = null,
|
||||
@SerializedName("guide")
|
||||
private val _guide: Guide? = null,
|
||||
@SerializedName("link_id")
|
||||
private val _linkId: String? = null, // 链接地址
|
||||
@SerializedName("link_type")
|
||||
private val _linkType: String? = null,
|
||||
@SerializedName("link_text")
|
||||
private val _linkText: String? = null
|
||||
) {
|
||||
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
val title: String
|
||||
get() = _title ?: ""
|
||||
|
||||
val image: String
|
||||
get() = _image ?: ""
|
||||
|
||||
val addedContent: String
|
||||
get() = _addedContent ?: ""
|
||||
|
||||
val isShowGuide: Boolean
|
||||
get() = _guide != null
|
||||
|
||||
val guide: Guide
|
||||
get() = _guide ?: Guide()
|
||||
|
||||
val linkId: String
|
||||
get() = _linkId ?: ""
|
||||
|
||||
val linkType: String
|
||||
get() = _linkType ?: ""
|
||||
|
||||
val linkText: String
|
||||
get() = _linkText ?: ""
|
||||
|
||||
data class Guide(
|
||||
@SerializedName("text")
|
||||
private val _text: String? = null
|
||||
) {
|
||||
|
||||
val text: String
|
||||
get() = _text ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class Notify(
|
||||
@SerializedName("_id")
|
||||
private val _id: String? = null,
|
||||
@SerializedName("title")
|
||||
private val _title: String? = null,
|
||||
@SerializedName("image")
|
||||
private val _image: String? = null,
|
||||
@SerializedName("added_content")
|
||||
private val _addedContent: String? = null,
|
||||
@SerializedName("link_type")
|
||||
private val _linkType: String? = null,
|
||||
@SerializedName("link_id")
|
||||
private val _linkId: String? = null,
|
||||
@SerializedName("link_text")
|
||||
private val _linkText: String? = null,
|
||||
@SerializedName("link_community")
|
||||
private val _linkCommunity: LinkCommunity? = null,
|
||||
@SerializedName("display")
|
||||
private val _display: Display? = null,
|
||||
@SerializedName("display_status")
|
||||
private val _displayStatus: String? = null
|
||||
) {
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
val title: String
|
||||
get() = _title ?: ""
|
||||
|
||||
val image: String
|
||||
get() = _image ?: ""
|
||||
|
||||
val addedContent: String
|
||||
get() = _addedContent ?: ""
|
||||
|
||||
val linkType: String
|
||||
get() = _linkType ?: ""
|
||||
|
||||
val linkId: String
|
||||
get() = _linkId ?: ""
|
||||
|
||||
val linkText: String
|
||||
get() = _linkText ?: ""
|
||||
|
||||
val linkCommunity: LinkCommunity
|
||||
get() = _linkCommunity ?: LinkCommunity()
|
||||
|
||||
val display: Display
|
||||
get() = _display ?: Display()
|
||||
|
||||
val isClosable: Boolean
|
||||
get() = _displayStatus == "closable"
|
||||
}
|
||||
|
||||
data class Announcement(
|
||||
@SerializedName("_id")
|
||||
private val _id: String? = null,
|
||||
@SerializedName("image")
|
||||
private val _image: String? = null,
|
||||
@SerializedName("link_type")
|
||||
private val _linkType: String? = null,
|
||||
@SerializedName("link_id")
|
||||
private val _linkId: String? = null,
|
||||
@SerializedName("link_text")
|
||||
private val _linkText: String? = null
|
||||
) {
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
val image: String
|
||||
get() = _image ?: ""
|
||||
|
||||
val linkType: String
|
||||
get() = _linkType ?: ""
|
||||
|
||||
val linkId: String
|
||||
get() = _linkId ?: ""
|
||||
|
||||
val linkText: String
|
||||
get() = _linkText ?: ""
|
||||
}
|
||||
|
||||
data class RecommendCard(
|
||||
@SerializedName("_id")
|
||||
private val _id: String? = null,
|
||||
@SerializedName("title")
|
||||
private val _title: String? = null,
|
||||
@SerializedName("image")
|
||||
private val _image: String? = null,
|
||||
@SerializedName("tag")
|
||||
private val _tag: String? = null,
|
||||
@SerializedName("highlight")
|
||||
private val _highlight: TextWithSymbol? = null,
|
||||
@SerializedName("deletion")
|
||||
private val _deletion: TextWithSymbol? = null,
|
||||
@SerializedName("added_content")
|
||||
private val _addedContent: String? = null,
|
||||
@SerializedName("link_id")
|
||||
private val _linkId: String? = null,
|
||||
@SerializedName("link_type")
|
||||
private val _linkType: String? = null,
|
||||
@SerializedName("link_text")
|
||||
private val _linkText: String? = null,
|
||||
@SerializedName("link_community")
|
||||
private val _linkCommunity: LinkCommunity? = null,
|
||||
@SerializedName("display")
|
||||
private val _display: Display? = null
|
||||
) {
|
||||
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
val title: String
|
||||
get() = _title ?: ""
|
||||
|
||||
val image: String
|
||||
get() = _image ?: ""
|
||||
|
||||
val tag: String
|
||||
get() = _tag ?: ""
|
||||
|
||||
val highlight: TextWithSymbol
|
||||
get() = _highlight ?: TextWithSymbol()
|
||||
|
||||
val deletion: TextWithSymbol
|
||||
get() = _deletion ?: TextWithSymbol()
|
||||
|
||||
val addedContent: String
|
||||
get() = _addedContent ?: ""
|
||||
|
||||
val linkId: String
|
||||
get() = _linkId ?: ""
|
||||
|
||||
val linkType: String
|
||||
get() = _linkType ?: ""
|
||||
|
||||
val linkText: String
|
||||
get() = _linkText ?: ""
|
||||
|
||||
val linkCommunity: LinkCommunity
|
||||
get() = _linkCommunity ?: LinkCommunity()
|
||||
|
||||
val display: Display
|
||||
get() = _display ?: Display()
|
||||
|
||||
data class TextWithSymbol(
|
||||
@SerializedName("text")
|
||||
private val _text: String? = null,
|
||||
@SerializedName("is_show_currency_symbol")
|
||||
private val _isShowCurrencySymbol: Boolean? = null
|
||||
) {
|
||||
val text: String
|
||||
get() = _text ?: ""
|
||||
|
||||
val isShowCurrencySymbol: Boolean
|
||||
get() = _isShowCurrencySymbol ?: false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class LinkCommunity(
|
||||
@SerializedName("_id")
|
||||
private val _id: String? = null,
|
||||
@SerializedName("name")
|
||||
private val _name: String? = null
|
||||
) {
|
||||
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
val name: String
|
||||
get() = _name ?: ""
|
||||
}
|
||||
|
||||
data class Display(
|
||||
@SerializedName("slide")
|
||||
private val _slide: Boolean? = null,
|
||||
@SerializedName("recommend")
|
||||
private val _recommend: Boolean? = null,
|
||||
@SerializedName("refresh")
|
||||
private val _refresh: Boolean? = null,
|
||||
@SerializedName("navigation")
|
||||
private val _navigation: Boolean? = null
|
||||
) {
|
||||
|
||||
val slide: Boolean
|
||||
get() = _slide ?: false
|
||||
|
||||
val recommend: Boolean
|
||||
get() = _recommend ?: false
|
||||
|
||||
val refresh: Boolean
|
||||
get() = _refresh ?: false
|
||||
|
||||
val navigation: Boolean
|
||||
get() = _navigation ?: false
|
||||
}
|
||||
}
|
||||
@ -122,6 +122,10 @@ abstract class CustomPageItem(
|
||||
const val COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_VERTICAL_CARD = 6
|
||||
const val COMMON_CONTENT_COLLECTION_LAYOUT_VERTICAL_IMAGE_TEXT = 7
|
||||
const val COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_IMAGE_TEXT = 8
|
||||
const val COMMON_CONTENT_COLLECTION_LAYOUT_CONTENT_LABEL_LANE = 9
|
||||
const val COMMON_CONTENT_COLLECTION_LAYOUT_NOTIFICATION_COLUMN = 10
|
||||
const val COMMON_CONTENT_COLLECTION_LAYOUT_ANNOUNCEMENT_BANNER = 11
|
||||
const val COMMON_CONTENT_COLLECTION_LAYOUT_RECOMMEND_CARD = 12
|
||||
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_INVALID = -2
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_FOOTER = -1
|
||||
@ -155,6 +159,10 @@ abstract class CustomPageItem(
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_COLLECTION_REFRESH_ICON_MATRIX = 28
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_COLLECTION_REFRESH_ICON_LANE = 29
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_COLLECTION_REFRESH_SLIDE_LIST = 30
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_COMMON_CONTENT_LABEL_LANE = 31
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_COMMON_NOTIFICATION_COLUMN = 32
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_COMMON_ANNOUNCEMENT_BANNER = 33
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_COMMON_RECOMMEND_CARD = 34
|
||||
|
||||
// 专题样式 to itemType
|
||||
val subjectTypeMap: HashMap<String, Int> = hashMapOf(
|
||||
@ -237,7 +245,12 @@ abstract class CustomPageItem(
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_VERTICAL_CARD to CUSTOM_PAGE_ITEM_TYPE_COMMON_HORIZONTAL_SLIDE,
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_VERTICAL_CARD to CUSTOM_PAGE_ITEM_TYPE_COMMON_VERTICAL_TWO_CARDS,
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_VERTICAL_IMAGE_TEXT to CUSTOM_PAGE_ITEM_TYPE_COMMON_VERTICAL_TWO_CARDS,
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_IMAGE_TEXT to CUSTOM_PAGE_ITEM_TYPE_COMMON_HORIZONTAL_SLIDE
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_IMAGE_TEXT to CUSTOM_PAGE_ITEM_TYPE_COMMON_HORIZONTAL_SLIDE,
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_CONTENT_LABEL_LANE to CUSTOM_PAGE_ITEM_TYPE_COMMON_CONTENT_LABEL_LANE,
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_NOTIFICATION_COLUMN to CUSTOM_PAGE_ITEM_TYPE_COMMON_NOTIFICATION_COLUMN,
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_ANNOUNCEMENT_BANNER to CUSTOM_PAGE_ITEM_TYPE_COMMON_ANNOUNCEMENT_BANNER,
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_RECOMMEND_CARD to CUSTOM_PAGE_ITEM_TYPE_COMMON_RECOMMEND_CARD
|
||||
|
||||
)
|
||||
|
||||
// 通用内容合集 样式 to 样式名称
|
||||
@ -251,7 +264,11 @@ abstract class CustomPageItem(
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_VERTICAL_CARD to "横排竖式卡片",
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_VERTICAL_CARD to "双列竖式卡片",
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_VERTICAL_IMAGE_TEXT to "竖式图文列表",
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_IMAGE_TEXT to "横排图文列表"
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_IMAGE_TEXT to "横排图文列表",
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_CONTENT_LABEL_LANE to "内容标签泳道",
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_NOTIFICATION_COLUMN to "通知栏目",
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_ANNOUNCEMENT_BANNER to "公告横幅",
|
||||
COMMON_CONTENT_COLLECTION_LAYOUT_RECOMMEND_CARD to "推荐卡片"
|
||||
)
|
||||
|
||||
}
|
||||
@ -712,6 +729,10 @@ data class CustomCommonContentCollectionItem(
|
||||
&& position == other.position
|
||||
&& componentPosition == other.componentPosition
|
||||
}
|
||||
|
||||
// 临时变量,当样式为 通知栏目 时,记录当前显示的位置
|
||||
var selectedPosition = 0
|
||||
|
||||
}
|
||||
|
||||
// 拆分的通用内用合集
|
||||
|
||||
@ -9,6 +9,7 @@ import com.gh.common.util.GameSubstituteRepositoryHelper
|
||||
import com.gh.common.util.HomePluggableHelper
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.utils.TextHelper
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.sp2px
|
||||
@ -16,6 +17,7 @@ import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.entity.DiscoveryCardEntity
|
||||
import com.gh.gamecenter.entity.GameUpdateEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity.Count.Companion.write
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.PluginLocation
|
||||
@ -26,6 +28,8 @@ import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_BANNER
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_BANNER
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_VERTICAL_CARD
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_NOTIFICATION_COLUMN
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_RECOMMEND_CARD
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_VERTICAL_IMAGE_TEXT
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_COLLECTION_STYLE_CAROUSEL
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_COLLECTION_STYLE_RANKING_LIST
|
||||
@ -105,6 +109,9 @@ class CustomPageRepository private constructor(
|
||||
refreshDiscoverDataIfNeed(it)?.let(_customDiscoverItemLiveData::setValue)
|
||||
}
|
||||
|
||||
val hiddenNotifications: LiveData<HashMap<String, MutableSet<String>>>
|
||||
get() = shareRepository.hiddenNotifications
|
||||
|
||||
private var lastComponentType = ""
|
||||
private var lastSubjectId = ""
|
||||
private var gameChildPosition = 0
|
||||
@ -186,6 +193,7 @@ class CustomPageRepository private constructor(
|
||||
if (lastComponentType == CUSTOM_LINK_TYPE_GAME && item.link.type != CUSTOM_LINK_TYPE_GAME) {
|
||||
pageInfo.componentPositionIncrement()
|
||||
}
|
||||
|
||||
when {
|
||||
item.game != null -> {
|
||||
if (!RegionSettingHelper.shouldThisGameBeFiltered(item.game.id)) {
|
||||
@ -392,11 +400,11 @@ class CustomPageRepository private constructor(
|
||||
|
||||
}
|
||||
|
||||
item.linkCommonCollection != null -> {
|
||||
item.linkCommonCollection != null -> { // 通用内容合集
|
||||
val layout = item.linkCommonCollection.layout
|
||||
if (layout == COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_BANNER ||
|
||||
layout == COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_VERTICAL_CARD ||
|
||||
layout == COMMON_CONTENT_COLLECTION_LAYOUT_VERTICAL_IMAGE_TEXT
|
||||
if (layout == COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_BANNER
|
||||
|| layout == COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_VERTICAL_CARD
|
||||
|| layout == COMMON_CONTENT_COLLECTION_LAYOUT_VERTICAL_IMAGE_TEXT
|
||||
) {
|
||||
list.addAll(convertSplitCommonContentCollection(item))
|
||||
} else {
|
||||
@ -409,6 +417,12 @@ class CustomPageRepository private constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通知栏目
|
||||
if (layout == COMMON_CONTENT_COLLECTION_LAYOUT_NOTIFICATION_COLUMN) {
|
||||
shareRepository.initHiddenNotifications()
|
||||
}
|
||||
|
||||
list.add(
|
||||
CustomCommonContentCollectionItem(
|
||||
item.link,
|
||||
@ -661,7 +675,7 @@ class CustomPageRepository private constructor(
|
||||
*/
|
||||
private fun substituteGameIfNeeded(gameSubject: SubjectEntity) {
|
||||
if (!gameSubject.relatedColumnId.isNullOrEmpty() && gameSubject.data != null) {
|
||||
when(gameSubject.type) {
|
||||
when (gameSubject.type) {
|
||||
COMPONENTS_GAME_SUBJECT_TYPE_GAME_VERTICAL,
|
||||
COMPONENTS_SUBJECT_TYPE_GAME_VERTICAL_SLIDE,
|
||||
COMPONENTS_SUBJECT_TYPE_GAME_HORIZONTAL,
|
||||
@ -680,6 +694,9 @@ class CustomPageRepository private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun hideNotificationItem(id: String, itemId: String) {
|
||||
shareRepository.hideNotificationItem(id, itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页信息
|
||||
|
||||
@ -1,17 +1,23 @@
|
||||
package com.gh.gamecenter.home.custom.model
|
||||
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.filter.RegionSettingHelper
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.Constants.SP_HIDDEN_NOTIFICATIONS
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
import com.gh.gamecenter.core.utils.GsonUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.DiscoveryCardEntity
|
||||
import com.gh.gamecenter.entity.DiscoveryGameCardEntity
|
||||
import com.gh.gamecenter.entity.DiscoveryGameCardLabel
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
@ -25,7 +31,6 @@ class CustomPageShareRepository private constructor() {
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
|
||||
private val _discoverData = MutableLiveData<DiscoveryCardEntity>()
|
||||
val discoverData: LiveData<DiscoveryCardEntity> = _discoverData
|
||||
|
||||
@ -103,6 +108,42 @@ class CustomPageShareRepository private constructor() {
|
||||
return filteredLabels
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局保存
|
||||
*/
|
||||
private val _hiddenNotifications = MutableLiveData<HashMap<String, MutableSet<String>>>()
|
||||
val hiddenNotifications: LiveData<HashMap<String, MutableSet<String>>> = _hiddenNotifications
|
||||
|
||||
fun initHiddenNotifications() {
|
||||
val json = SPUtils.getString(SP_HIDDEN_NOTIFICATIONS)
|
||||
if (json.isNotBlank()) {
|
||||
val typeToken = object : TypeToken<HashMap<String, MutableSet<String>>>() {}
|
||||
val map: HashMap<String, MutableSet<String>> = Gson().fromJson(json, typeToken.type)
|
||||
_hiddenNotifications.postValue(map)
|
||||
} else {
|
||||
_hiddenNotifications.postValue(hashMapOf())
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
fun hideNotificationItem(id: String, itemId: String) {
|
||||
var hasUpdated = false
|
||||
val notifications = _hiddenNotifications.value ?: hashMapOf()
|
||||
val itemSet = notifications[id]
|
||||
if (itemSet == null) {
|
||||
notifications[id] = mutableSetOf(itemId)
|
||||
hasUpdated = true
|
||||
} else {
|
||||
hasUpdated = itemSet.add(itemId)
|
||||
}
|
||||
if (hasUpdated) {
|
||||
val json = notifications.toJson()
|
||||
SPUtils.setString(SP_HIDDEN_NOTIFICATIONS, json)
|
||||
|
||||
_hiddenNotifications.value = notifications
|
||||
}
|
||||
}
|
||||
|
||||
// 这个方法要在用户退出首页时调用
|
||||
fun onClear() {
|
||||
compositeDisposable.clear()
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
package com.gh.gamecenter.home.custom.viewholder
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.databinding.RecyclerContentLabelLaneCustomBinding
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.home.custom.CustomPageViewModel
|
||||
import com.gh.gamecenter.home.custom.adapter.ContentLabelLaneAdapter
|
||||
import com.gh.gamecenter.home.custom.createExposureEvent
|
||||
import com.gh.gamecenter.home.custom.eventlistener.CommonContentCollectionEventHelper
|
||||
import com.gh.gamecenter.home.custom.model.CustomCommonContentCollectionItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem
|
||||
|
||||
/**
|
||||
* 通用内容合集-内容标签泳道
|
||||
*/
|
||||
class ContentLabelLaneViewHolder(
|
||||
viewModel: CustomPageViewModel,
|
||||
private val binding: RecyclerContentLabelLaneCustomBinding
|
||||
) : BaseCustomViewHolder(viewModel, binding.root) {
|
||||
|
||||
override val childEventHelper by lazy {
|
||||
CommonContentCollectionEventHelper(viewModel)
|
||||
}
|
||||
|
||||
private val adapter by lazy {
|
||||
ContentLabelLaneAdapter(itemView.context,
|
||||
{ index, contentTag ->
|
||||
|
||||
val link =
|
||||
LinkEntity(link = contentTag.linkId, type = contentTag.linkType, linkText = contentTag.linkText)
|
||||
childEventHelper.navigateToLinkPage(link, "内容标签泳道", _item.exposureEventList.getOrNull(index))
|
||||
},
|
||||
{ index, contentTag ->
|
||||
|
||||
val item = _item as CustomCommonContentCollectionItem
|
||||
val gameEntity = if (contentTag.linkType == "game") {
|
||||
GameEntity(id = contentTag.linkId, name = contentTag.linkText)
|
||||
} else {
|
||||
GameEntity()
|
||||
}
|
||||
_item.exposureEventList.add(
|
||||
createExposureEvent(
|
||||
gameEntity.also {
|
||||
it.sequence = index
|
||||
it.outerSequence = _item.position
|
||||
},
|
||||
listOf(
|
||||
ExposureSource(
|
||||
"通用内容合集",
|
||||
"${item.data.name}+${item.data.layoutChinese}+${item.data.id}"
|
||||
),
|
||||
ExposureSource(
|
||||
item.data.layoutChinese,
|
||||
"${contentTag.title}+${contentTag.id}"
|
||||
)
|
||||
),
|
||||
pageConfigure.exposureSourceList,
|
||||
index,
|
||||
_item.componentPosition
|
||||
)
|
||||
)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
override fun bindView(item: CustomPageItem) {
|
||||
super.bindView(item)
|
||||
if (item is CustomCommonContentCollectionItem) {
|
||||
item.exposureEventList.clear()
|
||||
val contentTags = item.data.contentTags
|
||||
if (binding.rvGames.adapter == null) {
|
||||
binding.rvGames.layoutManager = LinearLayoutManager(itemView.context, RecyclerView.HORIZONTAL, false)
|
||||
binding.rvGames.adapter = adapter
|
||||
}
|
||||
adapter.submitList(contentTags)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
package com.gh.gamecenter.home.custom.viewholder
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.databinding.RecyclerAnnouncementBannerBinding
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.home.custom.BannerInRecyclerController
|
||||
import com.gh.gamecenter.home.custom.CustomPageViewModel
|
||||
import com.gh.gamecenter.home.custom.adapter.AnnouncementBannerAdapter
|
||||
import com.gh.gamecenter.home.custom.createExposureEvent
|
||||
import com.gh.gamecenter.home.custom.eventlistener.CommonContentCollectionEventHelper
|
||||
import com.gh.gamecenter.home.custom.model.CustomCommonContentCollectionItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem
|
||||
|
||||
/**
|
||||
* 通用内容合集-公告横幅
|
||||
*/
|
||||
class CustomAnnouncementBannerViewHolder(
|
||||
viewModel: CustomPageViewModel,
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
val binding: RecyclerAnnouncementBannerBinding
|
||||
) : BaseCustomViewHolder(viewModel, binding.root) {
|
||||
|
||||
private val adapter by lazy {
|
||||
AnnouncementBannerAdapter(itemView.context, object : AnnouncementBannerAdapter.OnChildEventListener {
|
||||
override fun onItemClick(childPosition: Int, announcement: CustomPageData.Announcement) {
|
||||
val link = LinkEntity(
|
||||
link = announcement.linkId,
|
||||
type = announcement.linkType,
|
||||
linkText = announcement.linkText
|
||||
)
|
||||
childEventHelper.navigateToLinkPage(link, "公告横幅", _item.exposureEventList.getOrNull(childPosition))
|
||||
}
|
||||
|
||||
override fun getCurrentPosition(): Int {
|
||||
return binding.vpBanner.currentItem
|
||||
}
|
||||
|
||||
override fun exposure(childPosition: Int, announcement: CustomPageData.Announcement) {
|
||||
val item = _item as CustomCommonContentCollectionItem
|
||||
val gameEntity = if (announcement.linkType == "game") {
|
||||
GameEntity(id = announcement.linkId, name = announcement.linkText)
|
||||
} else {
|
||||
GameEntity()
|
||||
}
|
||||
_item.exposureEventList.add(
|
||||
createExposureEvent(
|
||||
gameEntity.also {
|
||||
it.sequence = childPosition
|
||||
it.outerSequence = _item.position
|
||||
},
|
||||
listOf(
|
||||
ExposureSource(
|
||||
"通用内容合集",
|
||||
"${item.data.name}+${item.data.layoutChinese}+${item.data.id}"
|
||||
),
|
||||
ExposureSource(
|
||||
item.data.layoutChinese
|
||||
)
|
||||
),
|
||||
pageConfigure.exposureSourceList,
|
||||
childPosition,
|
||||
_item.componentPosition
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
private val bannerInRecyclerController = BannerInRecyclerController {
|
||||
if (adapter.isBanner) {
|
||||
binding.vpBanner.setCurrentItem(binding.vpBanner.currentItem + 1, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override val childEventHelper by lazy {
|
||||
CommonContentCollectionEventHelper(viewModel)
|
||||
}
|
||||
|
||||
init {
|
||||
lifecycleOwner.lifecycle.addObserver(bannerInRecyclerController)
|
||||
}
|
||||
|
||||
override fun bindView(item: CustomPageItem) {
|
||||
super.bindView(item)
|
||||
if (item is CustomCommonContentCollectionItem) {
|
||||
if (binding.vpBanner.adapter == null) {
|
||||
binding.vpBanner.adapter = adapter
|
||||
binding.vpBanner.registerOnPageChangeCallback(object : OnPageChangeCallback() {
|
||||
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
binding.bannerIndicator.onPageScrolled(adapter.getDataPosition(position), positionOffset)
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
// 页面切换,重置轮播等待时间
|
||||
(_item as CustomCommonContentCollectionItem).selectedPosition = position
|
||||
bannerInRecyclerController.start()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
adapter.submitList(item.data.announcements)
|
||||
if (item.selectedPosition != 0) {
|
||||
binding.vpBanner.setCurrentItem(item.selectedPosition, false)
|
||||
}
|
||||
with(binding.bannerIndicator) {
|
||||
pageSize = adapter.dataList.size
|
||||
notifyDataChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewAttach(parent: RecyclerView?) {
|
||||
bannerInRecyclerController.onViewAttachedToWindow(parent)
|
||||
}
|
||||
|
||||
override fun onViewDetach(parent: RecyclerView?) {
|
||||
bannerInRecyclerController.onViewDetachedFromWindow(parent)
|
||||
}
|
||||
}
|
||||
@ -77,19 +77,24 @@ class CustomHomeRecommendItemViewHolder(
|
||||
val recommends = mapData(item.data.recommends)
|
||||
val size = recommends.size
|
||||
if (size == 0) return
|
||||
val spanCount = minOf(size, MAX_SPAN_COUNT)
|
||||
if (binding.recommendGv.adapter == null) {
|
||||
val spanCount = minOf(size, MAX_SPAN_COUNT)
|
||||
binding.recommendGv.stretchMode = GridView.STRETCH_SPACING
|
||||
binding.recommendGv.numColumns = spanCount
|
||||
binding.recommendGv.columnWidth = 60F.dip2px()
|
||||
} else {
|
||||
val oldSpanCount = binding.recommendGv.numColumns
|
||||
if (oldSpanCount != spanCount) {
|
||||
binding.recommendGv.numColumns = spanCount
|
||||
}
|
||||
}
|
||||
binding.recommendGv.adapter = adapter
|
||||
adapter.submitList(recommends, _item.exposureEventList)
|
||||
adapter.submitList(recommends, spanCount, _item.exposureEventList)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
//图标最多列数
|
||||
private const val MAX_SPAN_COUNT = 5
|
||||
const val MAX_SPAN_COUNT = 5
|
||||
}
|
||||
}
|
||||
@ -33,6 +33,7 @@ import com.gh.gamecenter.entity.HomeSubSlide
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.exposure.ExposureType
|
||||
import com.gh.gamecenter.feature.view.GameIconView
|
||||
import com.gh.gamecenter.home.custom.BannerInRecyclerController
|
||||
import com.gh.gamecenter.home.custom.CustomPageViewModel
|
||||
import com.gh.gamecenter.home.custom.OnCustomPageRefreshStateListener
|
||||
@ -316,16 +317,11 @@ class CustomHomeSlideWithCardsViewHolder(
|
||||
val cardCv = homeSlideCardItemBinding.root
|
||||
val cardContainer = homeSlideCardItemBinding.cardContainer
|
||||
val cardIv = homeSlideCardItemBinding.cardIv
|
||||
val backgroundGroup = homeSlideCardItemBinding.backgroundGroup
|
||||
val titleTv = homeSlideCardItemBinding.titleTv
|
||||
val descTv = homeSlideCardItemBinding.descTv
|
||||
val textContainer = homeSlideCardItemBinding.textContainer
|
||||
val countTv = homeSlideCardItemBinding.countTv
|
||||
val labelIv = homeSlideCardItemBinding.labelIv
|
||||
val gameIconStackIv1 = homeSlideCardItemBinding.gameIconStackIv1
|
||||
val gameIconStackIv2 = homeSlideCardItemBinding.gameIconStackIv2
|
||||
val gameIconStackIv3 = homeSlideCardItemBinding.gameIconStackIv3
|
||||
val gameIconStackGroup = listOf(gameIconStackIv1, gameIconStackIv2, gameIconStackIv3)
|
||||
val gameIconIv1 = homeSlideCardItemBinding.gameIconIv1
|
||||
val gameIconIv2 = homeSlideCardItemBinding.gameIconIv2
|
||||
val gameIconIv3 = homeSlideCardItemBinding.gameIconIv3
|
||||
@ -368,53 +364,10 @@ class CustomHomeSlideWithCardsViewHolder(
|
||||
"column",
|
||||
"column_test_v2",
|
||||
"server",
|
||||
"game_explore" -> {
|
||||
titleTv.visibility = View.VISIBLE
|
||||
descTv.visibility = View.VISIBLE
|
||||
countTv.visibility = View.GONE
|
||||
labelIv.visibility = View.GONE
|
||||
backgroundGroup.visibility = View.GONE
|
||||
gameIconStackGroup.forEach { it.isVisible = homeSubSlide.cardData.games.isNotEmpty() }
|
||||
gameIconGroup.forEach { it.visibility = View.GONE }
|
||||
|
||||
descTv.text = homeSubSlide.cardDesc
|
||||
if (homeSubSlide.cardData.games.size == 1) {
|
||||
gameIconStackIv2.visibility = View.GONE
|
||||
gameIconStackIv1.visibility = View.GONE
|
||||
}
|
||||
if (homeSubSlide.cardData.games.size == 2) {
|
||||
gameIconStackIv1.visibility = View.GONE
|
||||
}
|
||||
homeSubSlide.cardData.games.take(3).forEachIndexed { index, gameEntity ->
|
||||
_item.exposureEventList.add(
|
||||
getGameExposureEvent(
|
||||
item.data,
|
||||
homeSubSlide,
|
||||
gameEntity,
|
||||
position,
|
||||
basicExposureSource
|
||||
)
|
||||
)
|
||||
when (index) {
|
||||
0 -> gameIconStackIv3.displayGameIcon(gameEntity, true)
|
||||
1 -> gameIconStackIv2.displayGameIcon(gameEntity, true)
|
||||
2 -> gameIconStackIv1.displayGameIcon(gameEntity, true)
|
||||
}
|
||||
}
|
||||
ConstraintSet().apply {
|
||||
clone(cardContainer)
|
||||
clear(textContainer.id, ConstraintSet.TOP)
|
||||
clear(textContainer.id, ConstraintSet.BOTTOM)
|
||||
connect(textContainer.id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP)
|
||||
connect(textContainer.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM)
|
||||
}.applyTo(cardContainer)
|
||||
}
|
||||
|
||||
"game_explore",
|
||||
"game_list_detail" -> {
|
||||
titleTv.visibility = View.VISIBLE
|
||||
descTv.visibility = View.GONE
|
||||
backgroundGroup.visibility = View.GONE
|
||||
gameIconStackGroup.forEach { it.visibility = View.GONE }
|
||||
gameIconGroup.forEach { it.isVisible = homeSubSlide.cardData.games.isNotEmpty() }
|
||||
|
||||
if (homeSubSlide.cardData.games.size == 1) {
|
||||
@ -424,6 +377,19 @@ class CustomHomeSlideWithCardsViewHolder(
|
||||
if (homeSubSlide.cardData.games.size == 2) {
|
||||
gameIconIv3.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun GameIconView.setGame(index: Int, game: GameEntity) {
|
||||
displayGameIcon(game, true)
|
||||
gameIconIv1.setOnClickListener {
|
||||
com.gh.common.util.NewFlatLogUtils.logRightSideCardClick(
|
||||
homeSubSlide,
|
||||
viewModel.refreshCount,
|
||||
"游戏"
|
||||
)
|
||||
childEventHelper.navigateToGameDetailPage(index, game, "右侧卡片")
|
||||
}
|
||||
}
|
||||
|
||||
homeSubSlide.cardData.games.take(3).forEachIndexed { index, gameEntity ->
|
||||
_item.exposureEventList.add(
|
||||
getGameExposureEvent(
|
||||
@ -436,41 +402,11 @@ class CustomHomeSlideWithCardsViewHolder(
|
||||
)
|
||||
|
||||
when (index) {
|
||||
0 -> {
|
||||
gameIconIv1.displayGameIcon(gameEntity, true)
|
||||
gameIconIv1.setOnClickListener {
|
||||
com.gh.common.util.NewFlatLogUtils.logRightSideCardClick(
|
||||
homeSubSlide,
|
||||
viewModel.refreshCount,
|
||||
"游戏"
|
||||
)
|
||||
childEventHelper.navigateToGameDetailPage(index, gameEntity, "右侧卡片")
|
||||
}
|
||||
}
|
||||
0 -> gameIconIv1.setGame(index, gameEntity)
|
||||
|
||||
1 -> {
|
||||
gameIconIv2.displayGameIcon(gameEntity, true)
|
||||
gameIconIv2.setOnClickListener {
|
||||
com.gh.common.util.NewFlatLogUtils.logRightSideCardClick(
|
||||
homeSubSlide,
|
||||
viewModel.refreshCount,
|
||||
"游戏"
|
||||
)
|
||||
childEventHelper.navigateToGameDetailPage(index, gameEntity, "右侧卡片")
|
||||
}
|
||||
}
|
||||
1 -> gameIconIv2.setGame(index, gameEntity)
|
||||
|
||||
2 -> {
|
||||
gameIconIv3.displayGameIcon(gameEntity, true)
|
||||
gameIconIv3.setOnClickListener {
|
||||
com.gh.common.util.NewFlatLogUtils.logRightSideCardClick(
|
||||
homeSubSlide,
|
||||
viewModel.refreshCount,
|
||||
"游戏"
|
||||
)
|
||||
childEventHelper.navigateToGameDetailPage(index, gameEntity, "右侧卡片")
|
||||
}
|
||||
}
|
||||
2 -> gameIconIv3.setGame(index, gameEntity)
|
||||
}
|
||||
}
|
||||
countTv.isVisible = homeSubSlide.cardData.gameTotal.game > 3
|
||||
@ -484,6 +420,15 @@ class CustomHomeSlideWithCardsViewHolder(
|
||||
else -> null
|
||||
}
|
||||
)
|
||||
val visibility = if (isFirst) View.VISIBLE else View.GONE
|
||||
homeSlideCardItemBinding.cardMask.visibility = visibility
|
||||
homeSlideCardItemBinding.cardGradientMask.visibility = visibility
|
||||
homeSlideCardItemBinding.cardIv.visibility = View.VISIBLE
|
||||
// 防止重复加载图片导致闪烁
|
||||
if (homeSubSlide.image != cardIv.getTag(R.string.tag_img_url_id)) {
|
||||
ImageUtils.display(cardIv, homeSubSlide.image, false, AlphaGradientProcess())
|
||||
cardIv.setTag(R.string.tag_img_url_id, homeSubSlide.image)
|
||||
}
|
||||
ConstraintSet().apply {
|
||||
clone(cardContainer)
|
||||
clear(textContainer.id, ConstraintSet.TOP)
|
||||
@ -511,13 +456,10 @@ class CustomHomeSlideWithCardsViewHolder(
|
||||
countTv.visibility = View.GONE
|
||||
labelIv.visibility = View.GONE
|
||||
|
||||
backgroundGroup.visibility = View.VISIBLE
|
||||
val visibility = if (isFirst) View.VISIBLE else View.GONE
|
||||
homeSlideCardItemBinding.cardMask.visibility = visibility
|
||||
homeSlideCardItemBinding.cardGradientMask.visibility = visibility
|
||||
homeSlideCardItemBinding.cardIv.visibility = View.VISIBLE
|
||||
|
||||
gameIconStackGroup.forEach { it.visibility = View.GONE }
|
||||
gameIconGroup.forEach { it.visibility = View.GONE }
|
||||
descTv.text = homeSubSlide.cardDesc
|
||||
// 防止重复加载图片导致闪烁
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
package com.gh.gamecenter.home.custom.viewholder
|
||||
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.databinding.RecyclerRecommendCardCustomBinding
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.home.custom.CustomPageViewModel
|
||||
import com.gh.gamecenter.home.custom.createExposureEvent
|
||||
import com.gh.gamecenter.home.custom.eventlistener.CommonContentCollectionEventHelper
|
||||
import com.gh.gamecenter.home.custom.model.CustomCommonContentCollectionItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem
|
||||
import com.gh.gamecenter.home.custom.viewholder.ui.RecommendCardUi
|
||||
|
||||
/**
|
||||
* 通用内容合集-推荐卡片
|
||||
*/
|
||||
class CustomRecommendCardViewHolder(
|
||||
viewModel: CustomPageViewModel,
|
||||
val binding: RecyclerRecommendCardCustomBinding
|
||||
) : BaseCustomViewHolder(viewModel, binding.root) {
|
||||
|
||||
private val recommendCardUi = RecommendCardUi(binding, object : RecommendCardUi.OnRecommendCardEventListener {
|
||||
override fun onItemClick(childPosition: Int, card: CustomPageData.RecommendCard) {
|
||||
val link = LinkEntity(link = card.linkId, type = card.linkType, linkText = card.linkText)
|
||||
childEventHelper.navigateToLinkPage(link, "推荐卡片", _item.exposureEventList.getOrNull(childPosition))
|
||||
}
|
||||
|
||||
override fun onItemExposure(childPosition: Int, card: CustomPageData.RecommendCard) {
|
||||
val item = _item as CustomCommonContentCollectionItem
|
||||
val gameEntity = if (card.linkType == "game") {
|
||||
GameEntity(id = card.linkId, name = card.linkText)
|
||||
} else {
|
||||
GameEntity()
|
||||
}
|
||||
_item.exposureEventList.add(
|
||||
createExposureEvent(
|
||||
gameEntity.also {
|
||||
it.sequence = childPosition
|
||||
it.outerSequence = _item.position
|
||||
},
|
||||
listOf(
|
||||
ExposureSource(
|
||||
"通用内容合集",
|
||||
"${item.data.name}+${item.data.layoutChinese}+${item.data.id}"
|
||||
)
|
||||
),
|
||||
pageConfigure.exposureSourceList,
|
||||
childPosition,
|
||||
_item.componentPosition
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onAllClick() {
|
||||
childEventHelper.navigateToCommonCollectionDetailPage(_item.link)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
override val childEventHelper by lazy {
|
||||
CommonContentCollectionEventHelper(viewModel)
|
||||
}
|
||||
|
||||
override fun bindView(item: CustomPageItem) {
|
||||
super.bindView(item)
|
||||
if (item is CustomCommonContentCollectionItem) {
|
||||
item.exposureEventList.clear()
|
||||
recommendCardUi.bind(item.data.topRightText, item.data.name, item.data.subtitle, item.data.recommendCards)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,279 @@
|
||||
package com.gh.gamecenter.home.custom.viewholder
|
||||
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.ViewGroup.LayoutParams
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
|
||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.view.ScrollEventListener
|
||||
import com.gh.gamecenter.databinding.RecyclerNotificationColumnBinding
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.home.custom.BannerInRecyclerController
|
||||
import com.gh.gamecenter.home.custom.CustomPageViewModel
|
||||
import com.gh.gamecenter.home.custom.adapter.NotificationColumnAdapter
|
||||
import com.gh.gamecenter.home.custom.createExposureEvent
|
||||
import com.gh.gamecenter.home.custom.eventlistener.CommonContentCollectionEventHelper
|
||||
import com.gh.gamecenter.home.custom.model.CustomCommonContentCollectionItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem
|
||||
import com.gh.gamecenter.home.custom.tracker.CommonContentCollectionTracker
|
||||
|
||||
/**
|
||||
* 通用内容合集-通知栏目
|
||||
*/
|
||||
class NotificationColumnViewHolder(
|
||||
viewModel: CustomPageViewModel,
|
||||
private val lifecycleOwner: LifecycleOwner,
|
||||
val binding: RecyclerNotificationColumnBinding
|
||||
) : BaseCustomViewHolder(viewModel, binding.root) {
|
||||
|
||||
private var isScrolling = false
|
||||
|
||||
private var _hiddenIds: Set<String>? = null
|
||||
|
||||
private val bannerController = BannerInRecyclerController {
|
||||
nextToPage()
|
||||
}
|
||||
|
||||
override val childEventHelper by lazy {
|
||||
CommonContentCollectionEventHelper(viewModel)
|
||||
}
|
||||
|
||||
private val adapter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
NotificationColumnAdapter(itemView.context) { index, notify ->
|
||||
val item = _item as CustomCommonContentCollectionItem
|
||||
val gameEntity = if (notify.linkType == "game") {
|
||||
GameEntity(id = notify.linkId, name = notify.linkText)
|
||||
} else {
|
||||
GameEntity()
|
||||
}
|
||||
_item.exposureEventList.add(
|
||||
createExposureEvent(
|
||||
gameEntity.also {
|
||||
it.sequence = index
|
||||
it.outerSequence = _item.position
|
||||
},
|
||||
listOf(
|
||||
ExposureSource(
|
||||
"通用内容合集",
|
||||
"${item.data.name}+${item.data.layoutChinese}+${item.data.id}"
|
||||
),
|
||||
ExposureSource(
|
||||
item.data.layoutChinese,
|
||||
"${notify.id}"
|
||||
)
|
||||
),
|
||||
pageConfigure.exposureSourceList,
|
||||
index,
|
||||
_item.componentPosition
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val layoutManager by lazy(LazyThreadSafetyMode.NONE) {
|
||||
object : LinearLayoutManager(itemView.context) {
|
||||
|
||||
override fun smoothScrollToPosition(
|
||||
recyclerView: RecyclerView?,
|
||||
state: RecyclerView.State?,
|
||||
position: Int
|
||||
) {
|
||||
val linearSmoothScroller = object : LinearSmoothScroller(itemView.context) {
|
||||
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
|
||||
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi
|
||||
}
|
||||
|
||||
}
|
||||
linearSmoothScroller.targetPosition = position
|
||||
startSmoothScroll(linearSmoothScroller)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private val scrollEventListener by lazy(LazyThreadSafetyMode.NONE) {
|
||||
ScrollEventListener(binding.rvNotification).apply {
|
||||
setOnPageChangeCallback(object : OnPageChangeCallback() {
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
if (positionOffset > 0F) {
|
||||
// position 代表的是正在移出屏幕的 itemView 的位置
|
||||
layoutManager.findViewByPosition(position)?.alpha = 1 - positionOffset
|
||||
layoutManager.findViewByPosition(position + 1)?.alpha = positionOffset
|
||||
} else {
|
||||
// position 代表的是屏幕中间的 itemView的位置
|
||||
layoutManager.findViewByPosition(position)?.alpha = 1F
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
(_item as? CustomCommonContentCollectionItem)?.selectedPosition = position
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 有新的通知栏被隐藏,检查这里是否需要刷新
|
||||
*/
|
||||
private val hiddenNotifiesObserver = Observer<HashMap<String, MutableSet<String>>> {
|
||||
val item = _item as CustomCommonContentCollectionItem
|
||||
val hiddenIds = it[item.data.id]
|
||||
// 隐藏的通知栏目有变化,更新当前列表
|
||||
if (hiddenIds != null && hiddenIds != _hiddenIds) {
|
||||
_hiddenIds = hiddenIds
|
||||
val notifies = item.data.notifies
|
||||
val dataList = notifies.filterNot { notify ->
|
||||
hiddenIds.contains(notify.id)
|
||||
}
|
||||
if (dataList.isNotEmpty()) {
|
||||
adapter.submitList(dataList)
|
||||
} else {
|
||||
setVisible(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
lifecycleOwner.lifecycle.addObserver(bannerController)
|
||||
binding.rvNotification.itemAnimator = null
|
||||
|
||||
binding.itcvContainer.setOnClickListener {
|
||||
val item = _item
|
||||
if (!isScrolling && item is CustomCommonContentCollectionItem) {
|
||||
val childPosition = adapter.getDataPosition(item.selectedPosition)
|
||||
val notify = adapter.getItem(childPosition)
|
||||
val link = LinkEntity(link = notify.linkId, type = notify.linkType, linkText = notify.linkText)
|
||||
childEventHelper.navigateToLinkPage(link, "通知栏目", item.exposureEventList.getOrNull(childPosition))
|
||||
}
|
||||
}
|
||||
|
||||
binding.vClose.setOnClickListener {
|
||||
if (!isScrolling) {
|
||||
closeItem()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindView(item: CustomPageItem) {
|
||||
super.bindView(item)
|
||||
if (item is CustomCommonContentCollectionItem) {
|
||||
item.exposureEventList.clear()
|
||||
if (item.data.notifies.isEmpty()) {
|
||||
setVisible(false)
|
||||
return
|
||||
} else {
|
||||
setVisible(true)
|
||||
}
|
||||
|
||||
if (binding.rvNotification.adapter == null) {
|
||||
binding.rvNotification.layoutManager = layoutManager
|
||||
binding.rvNotification.addOnScrollListener(scrollEventListener)
|
||||
binding.rvNotification.adapter = adapter
|
||||
binding.rvNotification.addOnScrollListener(object : OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
isScrolling = newState != RecyclerView.SCROLL_STATE_IDLE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
val notifyMap = viewModel.shareHiddenNotifications.value
|
||||
_hiddenIds = notifyMap?.get(item.data.id)
|
||||
val dataList =
|
||||
if (_hiddenIds != null) {
|
||||
item.data.notifies.filterNot {
|
||||
_hiddenIds!!.contains(it.id)
|
||||
}
|
||||
} else {
|
||||
item.data.notifies
|
||||
}
|
||||
if (dataList.isNotEmpty()) {
|
||||
setVisible(true)
|
||||
adapter.submitList(dataList)
|
||||
binding.rvNotification.scrollToPosition(item.selectedPosition)
|
||||
} else {
|
||||
setVisible(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onViewAttach(parent: RecyclerView?) {
|
||||
viewModel.shareHiddenNotifications.observe(lifecycleOwner, hiddenNotifiesObserver)
|
||||
bannerController.onViewAttachedToWindow(parent)
|
||||
}
|
||||
|
||||
override fun onViewDetach(parent: RecyclerView?) {
|
||||
viewModel.shareHiddenNotifications.removeObserver(hiddenNotifiesObserver)
|
||||
bannerController.onViewDetachedFromWindow(parent)
|
||||
}
|
||||
|
||||
private fun nextToPage() {
|
||||
if (adapter.isBanner) {
|
||||
val layoutManager = binding.rvNotification.layoutManager
|
||||
if (layoutManager is LinearLayoutManager) {
|
||||
val firstPosition = layoutManager.findFirstCompletelyVisibleItemPosition()
|
||||
if (firstPosition != -1) {
|
||||
binding.rvNotification.smoothScrollToPosition(firstPosition + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun closeItem() {
|
||||
val selectedPosition = layoutManager.findFirstCompletelyVisibleItemPosition()
|
||||
if (selectedPosition != -1) {
|
||||
val item = adapter.getItem(selectedPosition)
|
||||
if (!item.isClosable) {
|
||||
return
|
||||
}
|
||||
(_item as? CustomCommonContentCollectionItem)?.let {
|
||||
val dataList = adapter.dataList.toMutableList()
|
||||
val index = selectedPosition % dataList.size
|
||||
dataList.remove(item)
|
||||
adapter.submitList(dataList, true)
|
||||
if (adapter.dataCount == 0) {
|
||||
setVisible(false)
|
||||
}
|
||||
if (adapter.dataCount > 1) {
|
||||
binding.rvNotification.scrollToPosition(index)
|
||||
}
|
||||
val link = LinkEntity(link = item.linkId, type = item.linkType, linkText = item.linkText)
|
||||
CommonContentCollectionTracker(pageLocation).trackLinkContentCollectionClick(_item, link, "通知栏目")
|
||||
viewModel.hideNotificationItem(it.data.id, item.id)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun setVisible(isVisible: Boolean) {
|
||||
if (isVisible) {
|
||||
binding.root.goneIf(false)
|
||||
binding.root.updateLayoutParams {
|
||||
height = 80F.dip2px()
|
||||
width = LayoutParams.MATCH_PARENT
|
||||
}
|
||||
} else {
|
||||
binding.root.goneIf(true)
|
||||
binding.root.updateLayoutParams {
|
||||
height = 0
|
||||
width = LayoutParams.MATCH_PARENT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MILLISECONDS_PER_INCH = 1000f
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package com.gh.gamecenter.home.custom.viewholder.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.opengl.Visibility
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.DarkModeUtils
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.visibleIf
|
||||
import com.gh.gamecenter.databinding.RecyclerRecommendCardCustomBinding
|
||||
import com.gh.gamecenter.home.custom.adapter.RecommendCardAdapter
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
|
||||
class RecommendCardUi(
|
||||
private val binding: RecyclerRecommendCardCustomBinding,
|
||||
private val listener: OnRecommendCardEventListener
|
||||
) {
|
||||
|
||||
private val context: Context
|
||||
get() = binding.root.context
|
||||
|
||||
private val adapter by lazy {
|
||||
RecommendCardAdapter(context, listener)
|
||||
}
|
||||
|
||||
fun bind(rightTop: String, title: String, subTitle: String, recommendCards: List<CustomPageData.RecommendCard>) {
|
||||
if (binding.rvCards.adapter == null) {
|
||||
binding.rvCards.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
binding.rvCards.adapter = adapter
|
||||
}
|
||||
binding.tvRight.goneIf(rightTop.isBlank()) {
|
||||
binding.tvRight.setText(R.string.custom_home_text_all)
|
||||
}
|
||||
binding.tvTitle.goneIf(title.isBlank()) {
|
||||
binding.tvTitle.text = title
|
||||
}
|
||||
binding.tvSubTitle.goneIf(subTitle.isBlank()) {
|
||||
binding.tvSubTitle.text = subTitle
|
||||
}
|
||||
adapter.submitList(recommendCards)
|
||||
|
||||
binding.tvRight.setOnClickListener {
|
||||
listener.onAllClick()
|
||||
}
|
||||
|
||||
if (DarkModeUtils.isDarkModeOn(context)) {
|
||||
binding.vBackground.setBackgroundColor(R.color.ui_background.toColor(context))
|
||||
} else {
|
||||
binding.vBackground.setBackgroundResource(R.drawable.bg_img_recommend_card)
|
||||
}
|
||||
|
||||
binding.root.post {
|
||||
if (binding.tvSubTitle.visibility == View.VISIBLE) {
|
||||
val ellipsisStart = binding.tvSubTitle.layout?.getEllipsisStart(0) ?: 0
|
||||
binding.tvSubTitle.visibleIf(ellipsisStart == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnRecommendCardEventListener {
|
||||
|
||||
fun onItemClick(childPosition: Int, card: CustomPageData.RecommendCard)
|
||||
|
||||
fun onItemExposure(childPosition: Int, card: CustomPageData.RecommendCard)
|
||||
|
||||
fun onAllClick()
|
||||
}
|
||||
}
|
||||
@ -2580,6 +2580,12 @@ public interface ApiService {
|
||||
@GET("home/common_collection/{collection_id}/contents")
|
||||
Observable<List<CommonCollectionContentEntity>> getCommonCollectionDetail(@Path("collection_id") String collectionId, @Query("page") int page);
|
||||
|
||||
/**
|
||||
* 获取通用内容合集详情-推荐卡片分页数据
|
||||
*/
|
||||
@GET("home/common_collection/{collection_id}/contents")
|
||||
Observable<List<CustomPageData.RecommendCard>> getCommonCollectionDetailWithRecommenCards(@Path("collection_id") String collectionId, @Query("page") int page);
|
||||
|
||||
/**
|
||||
* 获取青少年模式状态
|
||||
*/
|
||||
|
||||
BIN
app/src/main/res/drawable-xxxhdpi/bg_img_notification_column.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/bg_img_notification_column.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/bg_img_recommend_card.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/bg_img_recommend_card.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/bg_king_kong_bubble.9.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/bg_king_kong_bubble.9.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/white" />
|
||||
<corners
|
||||
android:bottomLeftRadius="2dp"
|
||||
android:bottomRightRadius="2dp"
|
||||
android:topLeftRadius="8dp"
|
||||
android:topRightRadius="8dp" />
|
||||
</shape>
|
||||
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:endColor="#FF7C5C"
|
||||
android:startColor="#FF675C" />
|
||||
<corners android:radius="2dp"/>
|
||||
</shape>
|
||||
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:topLeftRadius="8dp"
|
||||
android:topRightRadius="8dp"
|
||||
android:bottomLeftRadius="8dp"/>
|
||||
<solid android:color="@color/ui_surface"/>
|
||||
</shape>
|
||||
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/ui_container_1"/>
|
||||
<corners android:radius="4dp"/>
|
||||
</shape>
|
||||
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:topLeftRadius="8dp"
|
||||
android:topRightRadius="8dp"
|
||||
android:bottomLeftRadius="8dp"/>
|
||||
<solid android:color="@color/primary_theme_10"/>
|
||||
<stroke android:width="1dp"
|
||||
android:color="@color/primary_theme_30"/>
|
||||
</shape>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/ui_surface" />
|
||||
<stroke
|
||||
android:width="0.5dp"
|
||||
android:color="@color/ui_divider" />
|
||||
<corners android:radius="8dp"/>
|
||||
</shape>
|
||||
27
app/src/main/res/drawable/ic_gift_recommend_card.xml
Normal file
27
app/src/main/res/drawable/ic_gift_recommend_card.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M7.463,5.96H12.616C12.833,5.889 13.052,5.821 13.271,5.755L13.29,5.749L13.291,5.748C14.838,5.275 16.761,4.687 16.761,2.627C16.761,1.552 16.171,0.756 15.223,0.552C13.721,0.23 11.5,1.42 9.996,3.896C8.475,1.42 6.255,0.232 4.765,0.556C3.826,0.763 3.242,1.556 3.242,2.627C3.242,4.675 5.146,5.253 6.678,5.715C6.94,5.794 7.204,5.874 7.463,5.96Z"
|
||||
android:fillColor="#FF8D3A"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M1,4.96C0.448,4.96 0,5.408 0,5.96V7.485C0,8.037 0.448,8.485 1,8.485H19C19.552,8.485 20,8.037 20,7.485V5.96C20,5.408 19.552,4.96 19,4.96H1ZM18.312,9.5H1.646V17.5C1.646,18.605 2.541,19.5 3.646,19.5H16.312C17.417,19.5 18.312,18.605 18.312,17.5V9.5Z"
|
||||
android:fillColor="#F00909"
|
||||
android:fillAlpha="0.8"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M7.5,8.5H8.5V19.5H7.5V8.5Z"
|
||||
android:fillColor="#D60E0D"/>
|
||||
<path
|
||||
android:pathData="M11.5,8.5H12.5V19.5H11.5V8.5Z"
|
||||
android:fillColor="#D60E0D"/>
|
||||
<path
|
||||
android:pathData="M1.646,8.5H18.313V10H1.646V8.5Z"
|
||||
android:fillColor="#E31C1B"/>
|
||||
<path
|
||||
android:pathData="M8.5,8.5H11.5V19.5H8.5V8.5Z"
|
||||
android:fillColor="#FFBB0D"/>
|
||||
</vector>
|
||||
13
app/src/main/res/drawable/ic_right.xml
Normal file
13
app/src/main/res/drawable/ic_right.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="6dp"
|
||||
android:height="10dp"
|
||||
android:viewportWidth="6"
|
||||
android:viewportHeight="10">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M1,1L5,5L1,9"
|
||||
android:strokeLineJoin="round"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/text_primary"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
@ -0,0 +1,26 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="8dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="8">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h16v8h-16z"/>
|
||||
<path
|
||||
android:pathData="M4,0.25L12,0.25A3.75,3.75 0,0 1,15.75 4L15.75,4A3.75,3.75 0,0 1,12 7.75L4,7.75A3.75,3.75 0,0 1,0.25 4L0.25,4A3.75,3.75 0,0 1,4 0.25z"
|
||||
android:strokeWidth="0.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#CCCCCC"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M6,2h4v4h-4z"/>
|
||||
<path
|
||||
android:pathData="M6.25,2.25L9.75,5.75M9.75,2.25L6.25,5.75"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#CCCCCC"
|
||||
android:strokeLineCap="round"/>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
@ -73,7 +73,7 @@
|
||||
android:layout_marginEnd="10dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/cl_game_icon_stack"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginEnd="10dp">
|
||||
@ -97,47 +97,6 @@
|
||||
tools:text="副标题" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/cl_game_icon_stack"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.gh.gamecenter.feature.view.GameIconView
|
||||
android:id="@+id/gameIconStackIv1"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:alpha="0.25"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/gameIconStackIv2"
|
||||
app:layout_constraintEnd_toEndOf="@+id/gameIconStackIv2"
|
||||
app:layout_constraintTop_toTopOf="@+id/gameIconStackIv2" />
|
||||
|
||||
<com.gh.gamecenter.feature.view.GameIconView
|
||||
android:id="@+id/gameIconStackIv2"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:alpha="0.5"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/gameIconStackIv3"
|
||||
app:layout_constraintEnd_toEndOf="@+id/gameIconStackIv3"
|
||||
app:layout_constraintTop_toTopOf="@+id/gameIconStackIv3" />
|
||||
|
||||
<com.gh.gamecenter.feature.view.GameIconView
|
||||
android:id="@+id/gameIconStackIv3"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.gh.gamecenter.feature.view.GameIconView
|
||||
android:id="@+id/gameIconIv1"
|
||||
android:layout_width="24dp"
|
||||
|
||||
@ -20,13 +20,13 @@
|
||||
android:id="@+id/navigationNameTv"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/secondary_size"
|
||||
android:textStyle="bold"
|
||||
@ -44,4 +44,25 @@
|
||||
app:layout_constraintEnd_toEndOf="@+id/navigationView"
|
||||
app:layout_constraintTop_toTopOf="@+id/navigationView" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_bubble_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_custom_page_navigate_bubble_background"
|
||||
app:layout_constraintBottom_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_bubble"
|
||||
style="@style/TextAnnotation1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="18dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp" />
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -18,6 +18,7 @@
|
||||
android:scrollbars="none"
|
||||
android:stretchMode="spacingWidth"
|
||||
android:verticalSpacing="12dp"
|
||||
tools:listitem="@layout/item_home_recommend_list_item" />
|
||||
android:clipChildren="false"
|
||||
tools:listitem="@layout/item_home_recommend_list_item_custom" />
|
||||
|
||||
</FrameLayout>
|
||||
@ -1,8 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
@ -10,7 +12,10 @@
|
||||
android:id="@+id/iconIv"
|
||||
style="@style/frescoStyle"
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="44dp" />
|
||||
android:layout_height="44dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nameTv"
|
||||
@ -19,6 +24,30 @@
|
||||
android:includeFontPadding="false"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="11sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/iconIv"
|
||||
tools:text="分类" />
|
||||
|
||||
</LinearLayout>
|
||||
<Space
|
||||
android:id="@+id/space"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.gh.gamecenter.home.custom.adapter.WidthUnlimitedTextView
|
||||
android:id="@+id/tv_bubble"
|
||||
style="@style/TextAnnotation2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginTop="1dp"
|
||||
android:background="@drawable/bg_king_kong_bubble"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingHorizontal="6dp"
|
||||
android:paddingTop="2dp"
|
||||
android:textColor="@color/text_aw_primary"
|
||||
app:layout_constraintStart_toStartOf="@id/space"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="1" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
48
app/src/main/res/layout/recycler_announcement_banner.xml
Normal file
48
app/src/main/res/layout/recycler_announcement_banner.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<com.gh.common.view.InterceptVerticalScrollCardView
|
||||
android:id="@+id/cv_banner_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="0dp"
|
||||
app:layout_constraintDimensionRatio="41:11"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/vp_banner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/border_search_game_first_banner" />
|
||||
</com.gh.common.view.InterceptVerticalScrollCardView>
|
||||
|
||||
<com.gh.gamecenter.common.view.ScaleIndicatorView
|
||||
android:id="@+id/bannerIndicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:elevation="20dp"
|
||||
app:checkedColor="@color/white"
|
||||
app:checkedSliderWidth="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/cv_banner_container"
|
||||
app:layout_constraintEnd_toEndOf="@id/cv_banner_container"
|
||||
app:normalColor="@color/white_alpha_40"
|
||||
app:normalSliderWidth="4dp"
|
||||
app:sliderGap="4dp"
|
||||
app:sliderHeight="4dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_games"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="8dp" />
|
||||
</FrameLayout>
|
||||
91
app/src/main/res/layout/recycler_content_label_lane_item.xml
Normal file
91
app/src/main/res/layout/recycler_content_label_lane_item.xml
Normal file
@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<View
|
||||
android:id="@+id/v_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/bg_shape_content_label_lane_item"
|
||||
app:layout_constraintEnd_toEndOf="@id/space"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.gh.gamecenter.feature.view.GameIconView
|
||||
android:id="@+id/iv_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:gameIconCornerRadius="6dp"
|
||||
app:gameIconBorderColor="@color/resource_border"
|
||||
app:gameIconBorderWidth="0.5dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_background"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/v_background" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
style="@style/TextBody2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:textColor="@color/text_primary"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_icon"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_icon"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_icon"
|
||||
app:layout_goneMarginStart="8dp"
|
||||
tools:text="七日世界" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_sub_title"
|
||||
style="@style/TextCaption2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/primary_theme"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_title"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_title"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_icon"
|
||||
tools:text=" · 超自然开放世界生存" />
|
||||
|
||||
<Space
|
||||
android:id="@+id/space"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_sub_title" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_bubble_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/bg_shape_background_content_label_lane_item_bubble"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_bubble"
|
||||
app:layout_constraintEnd_toEndOf="@id/tv_bubble"
|
||||
app:layout_constraintStart_toStartOf="@id/tv_bubble"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_bubble" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_bubble"
|
||||
style="@style/TextAnnotation1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="16dp"
|
||||
android:background="@drawable/bg_shape_content_label_lane_item_bubble"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:textColor="@color/primary_theme_70"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="奇迹之海提前上线" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/g_bubble"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="v_bubble_background,tv_bubble" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -7,6 +7,7 @@
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:clipChildren="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
35
app/src/main/res/layout/recycler_notification_column.xml
Normal file
35
app/src/main/res/layout/recycler_notification_column.xml
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:background="@drawable/bg_img_notification_column">
|
||||
|
||||
<com.gh.common.view.InterceptTouchContainView
|
||||
android:id="@+id/itcv_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_notification"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/bg_shape_notification_column_item"
|
||||
tools:listitem="@layout/recycler_notification_column_item" />
|
||||
</com.gh.common.view.InterceptTouchContainView>
|
||||
|
||||
<View
|
||||
android:id="@+id/v_close"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:layout_constraintEnd_toEndOf="@id/itcv_container"
|
||||
app:layout_constraintTop_toTopOf="@id/itcv_container" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.gh.gamecenter.feature.view.GameIconView
|
||||
android:id="@+id/iv_icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="12dp"
|
||||
app:gameIconCornerRadius="10dp"
|
||||
app:gameIconBorderWidth="0.5dp"
|
||||
app:gameIconBorderColor="@color/resource_border"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_close_background"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/icon_notification_column_item_close"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_close_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_close_background"
|
||||
app:layout_constraintStart_toStartOf="@id/v_close_background"
|
||||
app:layout_constraintTop_toTopOf="@id/v_close_background" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
style="@style/TextBody2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:ellipsize="end"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/text_theme"
|
||||
app:layout_constraintEnd_toStartOf="@id/v_close_background"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_icon"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_icon"
|
||||
tools:text="《原神》新版本快来体验《原神》新版本快来体验《原神》新版本快来体验 " />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_desc"
|
||||
style="@style/TextCaption2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/text_secondary"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_icon"
|
||||
app:layout_constraintEnd_toEndOf="@id/tv_title"
|
||||
app:layout_constraintStart_toStartOf="@id/tv_title"
|
||||
tools:text="新地图快来开荒新地图快来开荒新地图快来开荒新地图快来开荒新地图快来开荒新地图快来开荒" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/iv_cover"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="h,16:9"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:roundedCornerRadius="4dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
style="@style/TextHeadline"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/text_primary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/iv_cover"
|
||||
tools:text="少年三国志" />
|
||||
|
||||
<Space
|
||||
android:id="@+id/space"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="17dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_label"
|
||||
style="@style/TextAnnotation1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#1AFF5447"
|
||||
android:paddingHorizontal="2dp"
|
||||
android:textColor="#FF5447"
|
||||
app:layout_constraintBottom_toBottomOf="@id/space"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/space"
|
||||
tools:text="充值" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_price_symbol"
|
||||
style="@style/TextAnnotation2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="¥"
|
||||
android:textColor="#FF5447"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/tv_price"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_label" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_price"
|
||||
style="@style/TextBody2B"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="2dp"
|
||||
android:textColor="#FF5447"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_label"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_price_symbol"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_label"
|
||||
tools:text="388.8" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_original_price"
|
||||
style="@style/TextCaption1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:textColor="@color/text_tertiary"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_label"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_price"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_label"
|
||||
tools:text="¥648" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_copy"
|
||||
style="@style/TextAnnotation1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:background="@drawable/bg_recommend_card_added_content"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="4dp"
|
||||
android:textColor="@color/ui_surface"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_label"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_original_price"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_label"
|
||||
tools:text="立省421.2元" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
92
app/src/main/res/layout/recycler_recommend_card_custom.xml
Normal file
92
app/src/main/res/layout/recycler_recommend_card_custom.xml
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="258dp"
|
||||
android:layout_marginVertical="-8dp"
|
||||
android:background="@drawable/bg_img_shadow_recommend_card">
|
||||
|
||||
<View
|
||||
android:id="@+id/v_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="16dp"
|
||||
android:background="@drawable/bg_img_recommend_card"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_gift"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:src="@drawable/ic_gift_recommend_card"
|
||||
app:layout_constraintStart_toStartOf="@id/v_background"
|
||||
app:layout_constraintTop_toTopOf="@id/v_background" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_title_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_gift"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_right"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_gift"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_gift">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
style="@style/TextHeadline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingEnd="4dp"
|
||||
android:textColor="@color/text_primary"
|
||||
tools:text="新人推荐新人推荐新" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_sub_title"
|
||||
style="@style/TextAnnotation1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/text_secondary"
|
||||
tools:text="充648低至3块钱" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_right"
|
||||
style="@style/TextCaption1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:drawablePadding="4dp"
|
||||
android:textColor="@color/text_primary"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_gift"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_background"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_gift"
|
||||
tools:text="更多"
|
||||
app:drawableEndCompat="@drawable/ic_right" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_cards"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_background"
|
||||
app:layout_constraintStart_toStartOf="@id/v_background"
|
||||
app:layout_constraintTop_toBottomOf="@id/iv_gift"
|
||||
tools:listitem="@layout/recycler_recommend_card_item" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
104
app/src/main/res/layout/recycler_recommend_card_item.xml
Normal file
104
app/src/main/res/layout/recycler_recommend_card_item.xml
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="214dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginHorizontal="4dp">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/iv_cover"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="120dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:roundBottomLeft="false"
|
||||
app:roundBottomRight="false"
|
||||
app:roundTopLeft="true"
|
||||
app:roundTopRight="true"
|
||||
app:roundedCornerRadius="4dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
style="@style/TextHeadline"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/text_primary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/iv_cover" />
|
||||
|
||||
<Space
|
||||
android:id="@+id/space"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="17dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_label"
|
||||
style="@style/TextAnnotation1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#1AFF5447"
|
||||
android:paddingHorizontal="2dp"
|
||||
android:textColor="#FF5447"
|
||||
app:layout_constraintBottom_toBottomOf="@id/space"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/space"
|
||||
tools:text="充值" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_price_symbol"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="¥"
|
||||
android:textColor="#FF5447"
|
||||
android:textSize="8sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/tv_price"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_label" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_price"
|
||||
style="@style/TextBody2B"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="2dp"
|
||||
android:textColor="#FF5447"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_label"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_price_symbol"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_label"
|
||||
tools:text="388.8" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_original_price"
|
||||
style="@style/TextCaption1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:textColor="@color/text_tertiary"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/tv_price"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_price"
|
||||
tools:text="¥648" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_copy"
|
||||
style="@style/TextAnnotation1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:background="@drawable/bg_recommend_card_added_content"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="4dp"
|
||||
android:textColor="@color/ui_surface"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_label"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_original_price"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_label"
|
||||
tools:text="立省421.2元" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -540,5 +540,7 @@
|
||||
<string name="custom_home_text_all">全部</string>
|
||||
<string name="new_game_start_test">新遊開測</string>
|
||||
<string name="view_all_game">查看所有遊戲</string>
|
||||
<string name="content_tag_added_content_with_prefix"> · %1$s</string>
|
||||
<string name="price_with_symbol">¥%1$s</string>
|
||||
</resources>
|
||||
|
||||
|
||||
@ -544,4 +544,6 @@
|
||||
<string name="custom_home_text_all">全部</string>
|
||||
<string name="new_game_start_test">新游开测</string>
|
||||
<string name="view_all_game">查看全部游戏</string>
|
||||
<string name="content_tag_added_content_with_prefix"> · %1$s</string>
|
||||
<string name="price_with_symbol">¥%1$s</string>
|
||||
</resources>
|
||||
|
||||
@ -251,6 +251,9 @@ public class Constants {
|
||||
// 发现页列表数据是否强制刷新
|
||||
public static final String SP_DISCOVER_FORCE_REFRESH = "discover_force_refresh";
|
||||
|
||||
// 用户隐藏的通知栏目
|
||||
public static final String SP_HIDDEN_NOTIFICATIONS = "sp_hidden_notifications";
|
||||
|
||||
// 微信绑定地址
|
||||
public static final String WECHAT_BIND_ADDRESS_DEV = "https://dev-and-static.ghzs.com/web/wechat_bind/index.html#/";
|
||||
public static final String WECHAT_BIND_ADDRESS = "https://and-static.ghzs.com/web/wechat_bind/index.html#/";
|
||||
|
||||
@ -5,6 +5,10 @@
|
||||
<color name="primary_theme">#2888E0</color>
|
||||
<!-- 蓝-10 -->
|
||||
<color name="primary_theme_10">#1A2888E0</color>
|
||||
<!-- 蓝-30 -->
|
||||
<color name="primary_theme_30">#4D2888E0</color>
|
||||
<!-- 蓝-70 -->
|
||||
<color name="primary_theme_70">#B22888E0</color>
|
||||
|
||||
<!-- 辅助颜色 -->
|
||||
<!-- 红 -->
|
||||
|
||||
@ -5,6 +5,10 @@
|
||||
<color name="primary_theme">#2496FF</color>
|
||||
<!-- 蓝-10 -->
|
||||
<color name="primary_theme_10">#1A2496FF</color>
|
||||
<!-- 蓝-30 -->
|
||||
<color name="primary_theme_30">#4D2496FF</color>
|
||||
<!-- 蓝-70 -->
|
||||
<color name="primary_theme_70">#B22496FF</color>
|
||||
|
||||
<!-- 辅助颜色 -->
|
||||
<!-- 红 -->
|
||||
|
||||
Reference in New Issue
Block a user