Compare commits
7 Commits
release
...
fix/GHZSCY
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d6917d7af | |||
| e56f7a0d32 | |||
| 8f18bcc71c | |||
| 556615f57f | |||
| c5ed1fefae | |||
| 2c71803fd7 | |||
| f613bbd60c |
@ -539,6 +539,8 @@ dependencies {
|
||||
if(!gradle.ext.excludeOptionalModules || gradle.ext.enableWechatPay){
|
||||
implementation(project(":feature:wechat_pay"))
|
||||
}
|
||||
|
||||
implementation "me.xdrop:fuzzywuzzy:${fuzzyVersion}"
|
||||
}
|
||||
|
||||
File propFile = file('sign.properties')
|
||||
|
||||
@ -1534,8 +1534,8 @@ object DirectUtils {
|
||||
if (categoryId.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, CategoryV2Activity::class.java.name)
|
||||
bundle.putString(KEY_CATEGORY_ID, categoryId)
|
||||
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
|
||||
bundle.putString(KEY_PAGE_ID, categoryId)
|
||||
bundle.putString(KEY_PAGE_NAME, categoryTitle)
|
||||
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
if (exposureEvent != null) bundle.putParcelableArrayList(
|
||||
KEY_EXPOSURE_SOURCE_LIST,
|
||||
|
||||
@ -147,6 +147,15 @@ object ViewPagerFragmentHelper {
|
||||
bundle.putString(EntranceConsts.KEY_QUESTIONS_ID, linkEntity.link)
|
||||
NewQuestionDetailFragment().with(bundle)
|
||||
}
|
||||
// 专题合集详情页
|
||||
TYPE_COLUMN_COLLECTION -> {
|
||||
bundle.putString(EntranceConsts.KEY_COLLECTION_ID, linkEntity.link)
|
||||
bundle.putInt(EntranceConsts.KEY_POSITION, 0)
|
||||
bundle.putString(EntranceConsts.KEY_COLUMNNAME, linkEntity.text)
|
||||
bundle.putBoolean(EntranceConsts.KEY_IS_COLUMN_COLLECTION, true)
|
||||
bundle.putString(EntranceConsts.KEY_SUBJECT_TYPE, "tab")
|
||||
ColumnCollectionDetailFragment().with(bundle)
|
||||
}
|
||||
// 其他原来带Toolbar的Fragment
|
||||
else -> createToolbarWrapperFragment(bundle, linkEntity, isTabWrapper)
|
||||
}
|
||||
@ -176,15 +185,6 @@ object ViewPagerFragmentHelper {
|
||||
bundle.putString(EntranceConsts.KEY_SUBJECT_TYPE, "detail")
|
||||
bundle.putBoolean(EntranceConsts.KEY_SHOW_DOWNLOAD_MENU, !isTabWrapper)
|
||||
}
|
||||
// 专题合集详情页
|
||||
TYPE_COLUMN_COLLECTION -> {
|
||||
className = ColumnCollectionDetailFragment::class.java.name
|
||||
bundle.putString(EntranceConsts.KEY_COLLECTION_ID, entity.link)
|
||||
bundle.putInt(EntranceConsts.KEY_POSITION, 0)
|
||||
bundle.putString(EntranceConsts.KEY_COLUMNNAME, entity.text)
|
||||
bundle.putBoolean(EntranceConsts.KEY_IS_COLUMN_COLLECTION, true)
|
||||
bundle.putString(EntranceConsts.KEY_SUBJECT_TYPE, "tab")
|
||||
}
|
||||
// 开服表
|
||||
TYPE_SERVER -> {
|
||||
className = GameServersPublishFragment::class.java.name
|
||||
@ -199,8 +199,8 @@ object ViewPagerFragmentHelper {
|
||||
// 分类2.0
|
||||
TYPE_CATEGORY_V2 -> {
|
||||
className = CategoryV2Fragment::class.java.name
|
||||
bundle.putString(EntranceConsts.KEY_CATEGORY_ID, entity.link)
|
||||
bundle.putString(EntranceConsts.KEY_CATEGORY_TITLE, entity.text)
|
||||
bundle.putString(EntranceConsts.KEY_PAGE_ID, entity.link)
|
||||
bundle.putString(EntranceConsts.KEY_PAGE_NAME, entity.text)
|
||||
bundle.putBoolean(EntranceConsts.KEY_SHOW_DOWNLOAD_MENU, !isTabWrapper)
|
||||
}
|
||||
// 通用内容合集详情页
|
||||
|
||||
@ -1,38 +1,48 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Typeface
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import android.widget.RadioButton
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.forEach
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.setDrawableEnd
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.LayoutCategoryFilterBinding
|
||||
import com.gh.gamecenter.databinding.LayoutCategoryFilterSizeBinding
|
||||
import com.gh.gamecenter.databinding.PopCategoryFilterSizeBinding
|
||||
import com.gh.gamecenter.databinding.PopCategoryFilterTypeBinding
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
|
||||
class CategoryFilterView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private var mTypeTv: TextView
|
||||
private var mCatalogTv: TextView
|
||||
private var mSizeTv: TextView
|
||||
private var mTypeContainer: View
|
||||
private var mCatalogContainer: View
|
||||
private var mSizeContainer: View
|
||||
private val binding: LayoutCategoryFilterBinding
|
||||
|
||||
private var mTypeFilterArray = arrayOf(SortType.RECOMMENDED, SortType.NEWEST, SortType.RATING)
|
||||
private var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
|
||||
private val mTypeFilterArray = arrayOf(SortType.RECOMMENDED, SortType.NEWEST, SortType.RATING)
|
||||
private val sizeFilterArray by lazy {
|
||||
listOf(
|
||||
SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"),
|
||||
SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"),
|
||||
SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"),
|
||||
SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"),
|
||||
SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"),
|
||||
SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上")
|
||||
)
|
||||
}
|
||||
|
||||
private var mOnCategoryFilterSetupListener: OnCategoryFilterSetupListener? = null
|
||||
private var mOnFilterClickListener: OnFilterClickListener? = null
|
||||
@ -41,29 +51,28 @@ class CategoryFilterView @JvmOverloads constructor(
|
||||
private var mSizePopupWindow: PopupWindow? = null
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.layout_category_filter, this)
|
||||
|
||||
mTypeTv = findViewById(R.id.type_tv)
|
||||
mCatalogTv = findViewById(R.id.catalog_tv)
|
||||
mSizeTv = findViewById(R.id.size_tv)
|
||||
mTypeContainer = findViewById(R.id.container_type)
|
||||
mCatalogContainer = findViewById(R.id.container_category)
|
||||
mSizeContainer = findViewById(R.id.container_size)
|
||||
mTypeTv.text = mTypeFilterArray[0].value
|
||||
val inflater = LayoutInflater.from(context)
|
||||
binding = LayoutCategoryFilterBinding.inflate(inflater, this, true)
|
||||
|
||||
mTypeContainer.setOnClickListener {
|
||||
binding.ivTypeArrow.setImageResource(R.drawable.ic_arrow_down)
|
||||
binding.ivTypeArrow.imageTintList =
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_neutral.toColor(context))
|
||||
|
||||
binding.ivSizeArrow.setImageResource(R.drawable.ic_arrow_down)
|
||||
binding.ivSizeArrow.imageTintList =
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_neutral.toColor(context))
|
||||
|
||||
binding.tvType.text = mTypeFilterArray[0].value
|
||||
|
||||
binding.llTypeContainer.setOnClickListener {
|
||||
mOnFilterClickListener?.onTypeClick()
|
||||
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
|
||||
showSelectTypePopupWindow()
|
||||
}
|
||||
|
||||
mCatalogContainer.setOnClickListener {
|
||||
mOnFilterClickListener?.onCategoryClick()
|
||||
mOnCategoryFilterSetupListener?.onSetupSortCategory()
|
||||
}
|
||||
|
||||
mSizeContainer.setOnClickListener {
|
||||
binding.llSizeContainer.setOnClickListener {
|
||||
mOnFilterClickListener?.onSizeClick()
|
||||
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
|
||||
showSelectSizePopupWindow()
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,154 +85,133 @@ class CategoryFilterView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun resetSortSize() {
|
||||
mSizeTv.text = "全部大小"
|
||||
binding.tvType.text = R.string.size.toResString()
|
||||
}
|
||||
|
||||
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
|
||||
if (highlightIt) {
|
||||
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
|
||||
targetTextView.setTextColor(Color.WHITE)
|
||||
} else {
|
||||
targetTextView.background = null
|
||||
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, com.gh.gamecenter.common.R.color.text_757575))
|
||||
}
|
||||
}
|
||||
private fun showSelectTypePopupWindow() {
|
||||
binding.tvType.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
|
||||
private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) {
|
||||
typeTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
typeTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
|
||||
binding.ivTypeArrow.setImageResource(R.drawable.ic_arrow_up)
|
||||
binding.ivTypeArrow.imageTintList =
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
|
||||
val inflater = LayoutInflater.from(typeTv.context)
|
||||
val layout = inflater.inflate(R.layout.layout_filter_size, null)
|
||||
val windowWidth = typeTv.context.resources.displayMetrics.widthPixels - 80F.dip2px()
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val typeBinding = PopCategoryFilterTypeBinding.inflate(inflater, null, false)
|
||||
val windowWidth = resources.displayMetrics.widthPixels - 80F.dip2px()
|
||||
val windowHeight = mOnCategoryFilterSetupListener?.getPopHeight() ?: 0
|
||||
val popupWindow = PopupWindow(
|
||||
layout,
|
||||
typeBinding.root,
|
||||
windowWidth,
|
||||
LayoutParams.WRAP_CONTENT
|
||||
if (windowHeight == 0) ViewGroup.LayoutParams.WRAP_CONTENT else (windowHeight - height)
|
||||
).apply { mTypePopupWindow = this }
|
||||
|
||||
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
|
||||
val backgroundView = layout.findViewById<View>(R.id.background)
|
||||
|
||||
backgroundView.setOnClickListener {
|
||||
typeBinding.root.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for (type in mTypeFilterArray) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
val checkedId = when (binding.tvType.text.toString()) {
|
||||
"最新" -> R.id.rb_newest
|
||||
"评分" -> R.id.rb_score
|
||||
else -> R.id.rb_popular
|
||||
}
|
||||
|
||||
// 单列 3 个,强行设置宽度为屏幕的 1/3
|
||||
val width = windowWidth / 3
|
||||
val height = item.layoutParams.height
|
||||
val checkButton = typeBinding.root.findViewById<RadioButton>(checkedId)
|
||||
checkButton.setTypeface(checkButton.typeface, Typeface.BOLD)
|
||||
checkButton.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
checkButton.setDrawableEnd(R.drawable.ic_basic_checkmark_circle_fill)
|
||||
|
||||
item.layoutParams = ViewGroup.LayoutParams(width, height)
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
tv.text = type.value
|
||||
|
||||
toggleHighlightedTextView(tv, typeText == type.value)
|
||||
|
||||
tv.tag = type.value
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
popupWindow.dismiss()
|
||||
typeTv.text = type.value
|
||||
val onCheckedChangeListener = CompoundButton.OnCheckedChangeListener { button, isChecked ->
|
||||
if (isChecked) {
|
||||
button.setTypeface(button.typeface, Typeface.BOLD)
|
||||
button.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
button.setDrawableEnd(R.drawable.ic_basic_checkmark_circle_fill)
|
||||
|
||||
val type = when (button.id) {
|
||||
R.id.rb_newest -> SortType.NEWEST
|
||||
R.id.rb_score -> SortType.RATING
|
||||
else -> SortType.RECOMMENDED
|
||||
}
|
||||
binding.tvType.text = type.value
|
||||
mOnCategoryFilterSetupListener?.onSetupSortType(type)
|
||||
popupWindow.dismiss()
|
||||
} else {
|
||||
button.setTypeface(button.typeface, Typeface.NORMAL)
|
||||
button.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
button.setDrawableEnd(null)
|
||||
}
|
||||
}
|
||||
typeBinding.rgFilter.forEach {
|
||||
if (it is RadioButton) {
|
||||
it.setOnCheckedChangeListener(onCheckedChangeListener)
|
||||
}
|
||||
}
|
||||
|
||||
popupWindow.setOnDismissListener {
|
||||
typeTv.setTextColor(com.gh.gamecenter.common.R.color.text_757575.toColor(context))
|
||||
typeTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
|
||||
binding.tvType.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
binding.ivTypeArrow.setImageResource(R.drawable.ic_arrow_down)
|
||||
binding.ivTypeArrow.imageTintList =
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_neutral.toColor(context))
|
||||
mTypePopupWindow = null
|
||||
}
|
||||
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
popupWindow.animationStyle = 0
|
||||
popupWindow.showAsDropDown(containerView, 0, 0)
|
||||
popupWindow.showAsDropDown(this, 0, 0)
|
||||
}
|
||||
|
||||
private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) {
|
||||
sizeTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
|
||||
private fun showSelectSizePopupWindow() {
|
||||
binding.tvSize.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
binding.ivSizeArrow.setImageResource(R.drawable.ic_arrow_up)
|
||||
binding.ivSizeArrow.imageTintList =
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
|
||||
val inflater = LayoutInflater.from(sizeTv.context)
|
||||
val layout = inflater.inflate(R.layout.layout_filter_size, null)
|
||||
val windowWidth = sizeTv.context.resources.displayMetrics.widthPixels - 80F.dip2px()
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val sizeBinding = PopCategoryFilterSizeBinding.inflate(inflater, null, false)
|
||||
val windowWidth = context.resources.displayMetrics.widthPixels - 80F.dip2px()
|
||||
val windowHeight = mOnCategoryFilterSetupListener?.getPopHeight() ?: 0
|
||||
val popupWindow = PopupWindow(
|
||||
layout,
|
||||
sizeBinding.root,
|
||||
windowWidth,
|
||||
LayoutParams.WRAP_CONTENT
|
||||
if (windowHeight == 0) ViewGroup.LayoutParams.WRAP_CONTENT else (windowHeight - height)
|
||||
).apply { mSizePopupWindow = this }
|
||||
|
||||
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
|
||||
val backgroundView = layout.findViewById<View>(R.id.background)
|
||||
|
||||
sizeFilterArray = if (sizeFilterArray == null) {
|
||||
getDefaultSizeFilterArray()
|
||||
} else {
|
||||
sizeFilterArray?.apply {
|
||||
if (firstOrNull()?.text != "全部大小") {
|
||||
add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backgroundView.setOnClickListener {
|
||||
sizeBinding.root.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for (size in sizeFilterArray!!) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
|
||||
// 单列 3 个,强行设置宽度为屏幕的 1/3
|
||||
val width = windowWidth / 3
|
||||
val height = item.layoutParams.height
|
||||
|
||||
item.layoutParams = ViewGroup.LayoutParams(width, height)
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
tv.text = size.text
|
||||
|
||||
toggleHighlightedTextView(tv, sizeText == size.text)
|
||||
|
||||
tv.tag = size.text
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
popupWindow.dismiss()
|
||||
sizeTv.text = size.text
|
||||
|
||||
mOnCategoryFilterSetupListener?.onSetupSortSize(size)
|
||||
}
|
||||
sizeBinding.rvSize.setOnClickListener {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
val sizeAdapter = CategoryFilterSizeAdapter {
|
||||
if (it.min == INVALID_SIZE && it.max == INVALID_SIZE) {
|
||||
binding.tvSize.text = R.string.size.toResString()
|
||||
} else {
|
||||
binding.tvSize.text = it.text
|
||||
}
|
||||
popupWindow.dismiss()
|
||||
mOnCategoryFilterSetupListener?.onSetupSortSize(it)
|
||||
}
|
||||
sizeBinding.rvSize.layoutManager = GridLayoutManager(context, 3, RecyclerView.VERTICAL, false)
|
||||
sizeBinding.rvSize.adapter = sizeAdapter
|
||||
val selectedPosition =
|
||||
sizeFilterArray.indexOfFirst { it.text?.contains(binding.tvSize.text.toString()) == true }
|
||||
|
||||
sizeAdapter.setData(sizeFilterArray, selectedPosition)
|
||||
|
||||
popupWindow.setOnDismissListener {
|
||||
sizeTv.setTextColor(com.gh.gamecenter.common.R.color.text_757575.toColor(context))
|
||||
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
|
||||
binding.tvSize.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
binding.ivSizeArrow.setImageResource(R.drawable.ic_arrow_down)
|
||||
binding.ivSizeArrow.imageTintList =
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_neutral.toColor(context))
|
||||
mSizePopupWindow = null
|
||||
}
|
||||
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
popupWindow.animationStyle = 0
|
||||
popupWindow.showAsDropDown(containerView, 0, 0)
|
||||
}
|
||||
|
||||
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
|
||||
return arrayListOf<SubjectSettingEntity.Size>().apply {
|
||||
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
|
||||
add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"))
|
||||
add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"))
|
||||
add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"))
|
||||
add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"))
|
||||
add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上"))
|
||||
}
|
||||
popupWindow.showAsDropDown(this, 0, 0)
|
||||
}
|
||||
|
||||
fun setRootBackgroundColor(@ColorInt color: Int) {
|
||||
@ -231,21 +219,23 @@ class CategoryFilterView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun setItemTextColor(@ColorInt color: Int) {
|
||||
mTypeTv.setTextColor(color)
|
||||
mCatalogTv.setTextColor(color)
|
||||
mSizeTv.setTextColor(color)
|
||||
val colorInt = com.gh.gamecenter.common.R.color.text_neutral.toColor(context)
|
||||
binding.tvType.setTextColor(color)
|
||||
binding.tvSize.setTextColor(color)
|
||||
binding.ivTypeArrow.imageTintList = ColorStateList.valueOf(colorInt)
|
||||
binding.ivSizeArrow.imageTintList = ColorStateList.valueOf(colorInt)
|
||||
}
|
||||
|
||||
fun updatePopupWindow() {
|
||||
when {
|
||||
mTypePopupWindow != null && mTypePopupWindow!!.isShowing -> {
|
||||
mTypePopupWindow?.dismiss()
|
||||
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
|
||||
showSelectTypePopupWindow()
|
||||
}
|
||||
|
||||
mSizePopupWindow != null && mSizePopupWindow!!.isShowing -> {
|
||||
mSizePopupWindow?.dismiss()
|
||||
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
|
||||
showSelectSizePopupWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -253,18 +243,69 @@ class CategoryFilterView @JvmOverloads constructor(
|
||||
interface OnCategoryFilterSetupListener {
|
||||
fun onSetupSortSize(sortSize: SubjectSettingEntity.Size)
|
||||
fun onSetupSortType(sortType: SortType)
|
||||
fun onSetupSortCategory()
|
||||
fun getPopHeight(): Int
|
||||
}
|
||||
|
||||
interface OnFilterClickListener {
|
||||
fun onCategoryClick()
|
||||
fun onTypeClick()
|
||||
fun onSizeClick()
|
||||
}
|
||||
|
||||
enum class SortType(val value: String) {
|
||||
RECOMMENDED("热门推荐"),
|
||||
NEWEST("最新上线"),
|
||||
RATING("最高评分")
|
||||
RECOMMENDED("热门"),
|
||||
NEWEST("最新"),
|
||||
RATING("评分")
|
||||
}
|
||||
|
||||
class CategoryFilterSizeAdapter(private val itemClick: (SubjectSettingEntity.Size) -> Unit) :
|
||||
RecyclerView.Adapter<CategoryFilterSizeAdapter.SizeViewHolder>() {
|
||||
|
||||
private val dataList = arrayListOf<SubjectSettingEntity.Size>()
|
||||
private var selectedPosition = 0
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun setData(data: List<SubjectSettingEntity.Size>, position: Int) {
|
||||
dataList.clear()
|
||||
dataList.addAll(data)
|
||||
selectedPosition = position
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SizeViewHolder {
|
||||
return SizeViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return dataList.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SizeViewHolder, position: Int) {
|
||||
val item = dataList[position]
|
||||
val context = holder.binding.root.context
|
||||
if (selectedPosition == position) {
|
||||
holder.binding.root.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
holder.binding.root.setBackgroundResource(R.drawable.shape_category_filter_size_item_selected)
|
||||
} else {
|
||||
holder.binding.root.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
holder.binding.root.setBackgroundResource(R.drawable.shape_category_filter_size_item_normal)
|
||||
}
|
||||
holder.binding.root.text = item.text
|
||||
holder.binding.root.setOnClickListener {
|
||||
if (selectedPosition == holder.bindingAdapterPosition) {
|
||||
return@setOnClickListener
|
||||
}
|
||||
val lastPosition = selectedPosition
|
||||
selectedPosition = holder.bindingAdapterPosition
|
||||
notifyItemChanged(lastPosition)
|
||||
notifyItemChanged(selectedPosition)
|
||||
itemClick(item)
|
||||
}
|
||||
}
|
||||
|
||||
class SizeViewHolder(val binding: LayoutCategoryFilterSizeBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val INVALID_SIZE = -1
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,23 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CheckedTextView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.setPadding
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.setDrawableEnd
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
|
||||
@ -30,11 +35,15 @@ class ConfigFilterView @JvmOverloads constructor(
|
||||
var recommendedTv: TextView
|
||||
var updateTv: TextView //更新
|
||||
var container: View
|
||||
private var dot1: View
|
||||
private var dot2: View
|
||||
private var dot3: View
|
||||
|
||||
var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
|
||||
private var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
|
||||
|
||||
private var mOnConfigFilterSetupListener: OnConfigFilterSetupListener? = null
|
||||
private var mSelectionTvList: ArrayList<TextView>
|
||||
private var highlightedSortedType: SortType? = null
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.layout_config_filter, this)
|
||||
@ -45,6 +54,9 @@ class ConfigFilterView @JvmOverloads constructor(
|
||||
updateTv = findViewById(R.id.updateTv)
|
||||
recommendedTv = findViewById(R.id.recommended_tv)
|
||||
container = findViewById(R.id.config_controller)
|
||||
dot1 = findViewById(R.id.dot1)
|
||||
dot2 = findViewById(R.id.dot2)
|
||||
dot3 = findViewById(R.id.dot3)
|
||||
|
||||
mSelectionTvList = arrayListOf(newestTv, ratingTv, updateTv, recommendedTv)
|
||||
|
||||
@ -54,24 +66,30 @@ class ConfigFilterView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
ratingTv.setOnClickListener {
|
||||
highlightedSortedType = SortType.RATING
|
||||
mOnConfigFilterSetupListener?.onSetupSortType(SortType.RATING)
|
||||
updateHighlightedTextView(ratingTv)
|
||||
}
|
||||
|
||||
updateTv.setOnClickListener {
|
||||
highlightedSortedType = SortType.UPDATE
|
||||
mOnConfigFilterSetupListener?.onSetupSortType(SortType.UPDATE)
|
||||
updateHighlightedTextView(updateTv)
|
||||
}
|
||||
|
||||
newestTv.setOnClickListener {
|
||||
highlightedSortedType = SortType.NEWEST
|
||||
mOnConfigFilterSetupListener?.onSetupSortType(SortType.NEWEST)
|
||||
updateHighlightedTextView(newestTv)
|
||||
}
|
||||
|
||||
recommendedTv.setOnClickListener {
|
||||
highlightedSortedType = SortType.RECOMMENDED
|
||||
mOnConfigFilterSetupListener?.onSetupSortType(SortType.RECOMMENDED)
|
||||
updateHighlightedTextView(recommendedTv)
|
||||
}
|
||||
|
||||
updateAllTextView(SortType.UPDATE)
|
||||
}
|
||||
|
||||
private fun updateHighlightedTextView(highlightedTv: TextView) {
|
||||
@ -80,14 +98,17 @@ class ConfigFilterView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun updateAllTextView(sortType: SortType) {
|
||||
when (sortType) {
|
||||
SortType.RECOMMENDED -> updateHighlightedTextView(recommendedTv)
|
||||
SortType.NEWEST -> updateHighlightedTextView(newestTv)
|
||||
SortType.RATING -> updateHighlightedTextView(ratingTv)
|
||||
SortType.UPDATE -> updateHighlightedTextView(updateTv)
|
||||
fun updateAllTextView(sortType: SortType? = highlightedSortedType) {
|
||||
highlightedSortedType = sortType
|
||||
sortType?.let {
|
||||
when (it) {
|
||||
SortType.RECOMMENDED -> updateHighlightedTextView(recommendedTv)
|
||||
SortType.NEWEST -> updateHighlightedTextView(newestTv)
|
||||
SortType.RATING -> updateHighlightedTextView(ratingTv)
|
||||
SortType.UPDATE -> updateHighlightedTextView(updateTv)
|
||||
}
|
||||
mSizeTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
}
|
||||
mSizeTv.setTextColor(com.gh.gamecenter.common.R.color.text_757575.toColor(context))
|
||||
}
|
||||
|
||||
fun setOnConfigSetupListener(onConfigFilterSetupListener: OnConfigFilterSetupListener) {
|
||||
@ -96,11 +117,11 @@ class ConfigFilterView @JvmOverloads constructor(
|
||||
|
||||
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
|
||||
if (highlightIt) {
|
||||
targetTextView.background = R.drawable.bg_tag_text.toDrawable()
|
||||
targetTextView.setTextColor(com.gh.gamecenter.common.R.color.text_white.toColor(context))
|
||||
targetTextView.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
targetTextView.setTypeface(Typeface.DEFAULT, Typeface.BOLD)
|
||||
} else {
|
||||
targetTextView.background = null
|
||||
targetTextView.setTextColor(com.gh.gamecenter.common.R.color.text_757575.toColor(context))
|
||||
targetTextView.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
targetTextView.setTypeface(Typeface.DEFAULT, Typeface.NORMAL)
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,8 +133,8 @@ class ConfigFilterView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
private fun showSelectionPopupWindow(containerView: View, sizeTv: TextView, sizeText: String) {
|
||||
sizeTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(sizeTv.context))
|
||||
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
|
||||
sizeTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(sizeTv.context))
|
||||
sizeTv.setDrawableEnd(R.drawable.ic_auxiliary_arrow_up_primary_8)
|
||||
|
||||
val inflater = LayoutInflater.from(sizeTv.context)
|
||||
val layout = inflater.inflate(R.layout.layout_filter_size, null)
|
||||
@ -136,43 +157,39 @@ class ConfigFilterView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
flexboxLayout.setOnClickListener { }
|
||||
backgroundView.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for (size in sizeFilterArray!!) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
val item = inflater.inflate(R.layout.item_config_filter_size, flexboxLayout, false)
|
||||
|
||||
// 单列 4 个,强行设置宽度为屏幕的 1/4
|
||||
val width = sizeTv.context.resources.displayMetrics.widthPixels / 4
|
||||
val width = (sizeTv.context.resources.displayMetrics.widthPixels - 56F.dip2px()) / 4
|
||||
val height = item.layoutParams.height
|
||||
|
||||
item.layoutParams = ViewGroup.LayoutParams(width, height)
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
val tv = item.findViewById<CheckedTextView>(R.id.size_tv)
|
||||
tv.text = size.text
|
||||
|
||||
if (sizeText == size.text) {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
} else {
|
||||
toggleHighlightedTextView(tv, false)
|
||||
}
|
||||
|
||||
tv.isChecked = sizeText == size.text
|
||||
tv.tag = size.text
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
tv.setOnClickListener {
|
||||
flexboxLayout.forEach { checkedTv ->
|
||||
(checkedTv as CheckedTextView).isChecked = checkedTv == tv
|
||||
}
|
||||
popupWindow.dismiss()
|
||||
sizeTv.text = size.text
|
||||
|
||||
mOnConfigFilterSetupListener?.onSetupSortSize(size)
|
||||
}
|
||||
}
|
||||
|
||||
popupWindow.setOnDismissListener {
|
||||
sizeTv.setTextColor(com.gh.gamecenter.common.R.color.text_757575.toColor(sizeTv.context))
|
||||
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
|
||||
sizeTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(sizeTv.context))
|
||||
sizeTv.setDrawableEnd(R.drawable.ic_auxiliary_arrow_down_8)
|
||||
mPopupWindow = null
|
||||
}
|
||||
|
||||
@ -193,6 +210,49 @@ class ConfigFilterView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun initSubjectFilterView(subjectSetting: SubjectSettingEntity) {
|
||||
ratingTv.visibility = View.VISIBLE
|
||||
|
||||
if (subjectSetting.filterOptions.size > 1) {
|
||||
// 重排序
|
||||
subjectSetting.filterOptions.forEachIndexed { index, s ->
|
||||
when (index) {
|
||||
0 -> updateTv.text = s
|
||||
1 -> recommendedTv.text = s
|
||||
2 -> newestTv.text = s
|
||||
3 -> ratingTv.text = s
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateTv.setPadding(0)
|
||||
updateTv.setTypeface(Typeface.DEFAULT, Typeface.NORMAL)
|
||||
updateTv.isClickable = false
|
||||
updateTv.text = when (subjectSetting.filterOptions.first()) {
|
||||
"推荐" -> "根据光环推荐排序"
|
||||
"最新" -> "根据游戏上新排序"
|
||||
"评分" -> "根据游戏评分排序"
|
||||
"更新" -> "根据更新时间排序"
|
||||
else -> subjectSetting.filterOptions.first()
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏相关选项
|
||||
updateTv.goneIf(subjectSetting.filterOptions.isEmpty())
|
||||
recommendedTv.goneIf(subjectSetting.filterOptions.size <= 1)
|
||||
dot1.goneIf(subjectSetting.filterOptions.size <= 1)
|
||||
newestTv.goneIf(subjectSetting.filterOptions.size <= 2)
|
||||
dot2.goneIf(subjectSetting.filterOptions.size <= 2)
|
||||
ratingTv.goneIf(subjectSetting.filterOptions.size <= 3)
|
||||
dot3.goneIf(subjectSetting.filterOptions.size <= 3)
|
||||
sizeFilterArray = subjectSetting.filterSizes
|
||||
|
||||
if (subjectSetting.filterOptions.size == 1) {
|
||||
updateTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
updateTv.setTypeface(Typeface.DEFAULT, Typeface.NORMAL)
|
||||
highlightedSortedType = null
|
||||
}
|
||||
}
|
||||
|
||||
interface OnConfigFilterSetupListener {
|
||||
fun onShowSortSize()
|
||||
fun onSetupSortSize(sortSize: SubjectSettingEntity.Size)
|
||||
|
||||
@ -1,82 +1,89 @@
|
||||
package com.gh.gamecenter.category2
|
||||
|
||||
import android.content.Context
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.view.GridSpacingItemColorDecoration
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.databinding.CategoryDirectoryItemBinding
|
||||
import com.gh.gamecenter.entity.CategoryEntity
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
|
||||
class CategoryDirectoryAdapter(
|
||||
context: Context,
|
||||
private val mViewModel: CategoryV2ViewModel,
|
||||
private var mList: List<CategoryEntity>
|
||||
) : BaseRecyclerAdapter<CategoryDirectoryAdapter.CategoryDirectoryItemViewHolder>(context) {
|
||||
private val listener: SearchCategoryPop.OnSearchCategoryListener
|
||||
) : RecyclerView.Adapter<CategoryDirectoryAdapter.CategoryDirectoryItemViewHolder>() {
|
||||
|
||||
val width = mContext.resources.displayMetrics.widthPixels * 260 / 360
|
||||
private val data = arrayListOf<CategoryEntity>()
|
||||
|
||||
fun setListData(list: List<CategoryEntity>) {
|
||||
mList = list
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun setListData(newData: List<CategoryEntity>) {
|
||||
data.clear()
|
||||
data.addAll(newData)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun getItemCount() = mList.size
|
||||
override fun getItemCount() = data.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||
CategoryDirectoryItemViewHolder(CategoryDirectoryItemBinding.inflate(mLayoutInflater))
|
||||
CategoryDirectoryItemViewHolder(listener, parent.toBinding())
|
||||
|
||||
override fun onBindViewHolder(holder: CategoryDirectoryItemViewHolder, position: Int) {
|
||||
holder.binding.run {
|
||||
root.layoutParams = root.layoutParams?.apply {
|
||||
width = mContext.resources.displayMetrics.widthPixels * 260 / 360
|
||||
} ?: RecyclerView.LayoutParams(width, RecyclerView.LayoutParams.WRAP_CONTENT)
|
||||
holder.onBind(position, data[position])
|
||||
}
|
||||
|
||||
val padTop = if (position == 0) 16F.dip2px() else 24F.dip2px()
|
||||
root.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 0)
|
||||
override fun onBindViewHolder(holder: CategoryDirectoryItemViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
if (payloads.isEmpty()) {
|
||||
super.onBindViewHolder(holder, position, payloads)
|
||||
} else {
|
||||
holder.notifyItemSelectedChanged()
|
||||
}
|
||||
|
||||
val entity = mList[position]
|
||||
title.text = entity.name
|
||||
title.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
}
|
||||
|
||||
subCategoryRv.run {
|
||||
if (adapter is SubCategoryAdapter) {
|
||||
layoutManager = GridLayoutManager(mContext, 3)
|
||||
adapter = entity.data?.let {
|
||||
SubCategoryAdapter(
|
||||
mContext,
|
||||
mViewModel,
|
||||
it,
|
||||
position
|
||||
)
|
||||
}
|
||||
} else {
|
||||
layoutManager = GridLayoutManager(mContext, 3)
|
||||
adapter = entity.data?.let {
|
||||
SubCategoryAdapter(
|
||||
mContext,
|
||||
mViewModel,
|
||||
it,
|
||||
position
|
||||
)
|
||||
}
|
||||
addItemDecoration(
|
||||
GridSpacingItemColorDecoration(
|
||||
mContext,
|
||||
6,
|
||||
6,
|
||||
com.gh.gamecenter.common.R.color.transparent
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
fun notifyItemSelectedChanged(parentId: String) {
|
||||
val position = data.indexOfFirst { it.id == parentId }
|
||||
if (position != -1) {
|
||||
notifyItemChanged(position, "")
|
||||
}
|
||||
}
|
||||
|
||||
class CategoryDirectoryItemViewHolder(val binding: CategoryDirectoryItemBinding) :
|
||||
BaseRecyclerViewHolder<Any>(binding.root)
|
||||
class CategoryDirectoryItemViewHolder(
|
||||
private val listener: SearchCategoryPop.OnSearchCategoryListener,
|
||||
val binding: CategoryDirectoryItemBinding
|
||||
) :
|
||||
ViewHolder(binding.root) {
|
||||
|
||||
private val childAdapter by lazy {
|
||||
SubCategoryAdapter(listener)
|
||||
}
|
||||
|
||||
fun onBind(position: Int, item: CategoryEntity) {
|
||||
|
||||
val context = binding.root.context
|
||||
binding.title.text = item.name
|
||||
|
||||
if (binding.subCategoryRv.adapter == null) {
|
||||
binding.subCategoryRv.layoutManager = object : GridLayoutManager(context, 4) {
|
||||
override fun canScrollVertically(): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
binding.subCategoryRv.adapter = childAdapter
|
||||
binding.subCategoryRv.addItemDecoration(
|
||||
GridSpacingItemColorDecoration(
|
||||
context,
|
||||
8,
|
||||
8,
|
||||
com.gh.gamecenter.common.R.color.transparent
|
||||
)
|
||||
)
|
||||
}
|
||||
childAdapter.setData(position, item)
|
||||
}
|
||||
|
||||
fun notifyItemSelectedChanged() {
|
||||
childAdapter.notifyItemRangeChanged(0, childAdapter.itemCount, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,8 +37,8 @@ class CategoryV2Activity : DownloadToolbarActivity() {
|
||||
companion object {
|
||||
fun getIntent(context: Context, catalogId: String, catalogTitle: String, entrance: String): Intent {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(EntranceConsts.KEY_CATEGORY_ID, catalogId)
|
||||
bundle.putString(EntranceConsts.KEY_CATEGORY_TITLE, catalogTitle)
|
||||
bundle.putString(EntranceConsts.KEY_PAGE_ID, catalogId)
|
||||
bundle.putString(EntranceConsts.KEY_PAGE_NAME, catalogTitle)
|
||||
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance)
|
||||
return getTargetIntent(context, CategoryV2Activity::class.java, CategoryV2Fragment::class.java, bundle)
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.gamecenter.category2
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
@ -13,11 +14,13 @@ import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
|
||||
class CategoryV2Adapter(
|
||||
context: Context,
|
||||
private val mFragment: CategoryV2Fragment,
|
||||
private val mViewModel: CategoryV2ViewModel,
|
||||
private val mList: List<SidebarsEntity.SidebarEntity>
|
||||
) : BaseRecyclerAdapter<CategoryV2Adapter.CategoryV2ItemViewHolder>(context) {
|
||||
|
||||
var selectedPosition = 0
|
||||
private set
|
||||
|
||||
override fun getItemCount() = mList.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||
@ -28,25 +31,35 @@ class CategoryV2Adapter(
|
||||
val catalogEntity = mList[position]
|
||||
catalogName.text = catalogEntity.name
|
||||
recommendTag.goneIf(!catalogEntity.recommended)
|
||||
if (catalogEntity.name == mViewModel.selectedCategoryName) {
|
||||
if (position == selectedPosition) {
|
||||
selectedTag.visibility = View.VISIBLE
|
||||
catalogName.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(mContext))
|
||||
catalogName.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
catalogName.setTypeface(null, Typeface.BOLD)
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(mContext))
|
||||
} else {
|
||||
selectedTag.visibility = View.GONE
|
||||
catalogName.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
catalogName.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(mContext))
|
||||
catalogName.setTypeface(null, Typeface.NORMAL)
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(mContext))
|
||||
}
|
||||
root.setOnClickListener {
|
||||
if (catalogEntity.name != mViewModel.selectedCategoryName) {
|
||||
mViewModel.selectedCategoryName = catalogEntity.name
|
||||
mFragment.changeCategory(position)
|
||||
if (position != selectedPosition) {
|
||||
mViewModel.logClickSide()
|
||||
notifyDataSetChanged()
|
||||
mViewModel.selectSidebarsPosition(position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun selectPosition(newPosition: Int) {
|
||||
if (selectedPosition == newPosition) {
|
||||
return
|
||||
}
|
||||
val oldSelection = selectedPosition
|
||||
selectedPosition = newPosition
|
||||
notifyItemChanged(oldSelection)
|
||||
notifyItemChanged(newPosition)
|
||||
}
|
||||
|
||||
class CategoryV2ItemViewHolder(val binding: CategoryV2ItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
|
||||
}
|
||||
@ -1,14 +1,14 @@
|
||||
package com.gh.gamecenter.category2
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.core.widget.TextViewCompat
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.gh.common.util.LogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.SearchActivity
|
||||
@ -22,35 +22,49 @@ import com.gh.gamecenter.common.view.FixLinearLayoutManager
|
||||
import com.gh.gamecenter.core.utils.PageSwitchDataHelper
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.databinding.FragmentCategoryBinding
|
||||
import com.gh.gamecenter.entity.CategoryEntity
|
||||
import com.gh.gamecenter.entity.SidebarsEntity
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.wrapper.SearchToolbarTabWrapperViewModel
|
||||
|
||||
class CategoryV2Fragment : LazyFragment() {
|
||||
|
||||
private var mBinding: FragmentCategoryBinding? = null
|
||||
private var mViewModel: CategoryV2ViewModel? = null
|
||||
|
||||
private val viewModel by viewModels<CategoryV2ViewModel>()
|
||||
|
||||
private var mHomeViewModel: SearchToolbarTabWrapperViewModel? = null
|
||||
private var mEntity: SidebarsEntity? = null
|
||||
private var mSpecialCatalogFragment: SpecialCatalogFragment? = null
|
||||
private var mCategoryV2ListFragment: CategoryV2ListFragment? = null
|
||||
private var mLastPageDataMap: HashMap<String, String>? = null
|
||||
|
||||
private var mCategoryId: String = ""
|
||||
private var mCategoryTitle: String = ""
|
||||
private var pageId: String = ""
|
||||
private var pageName: String = ""
|
||||
private var mLastSelectedPosition = -1
|
||||
|
||||
private var searchCategoryPop: SearchCategoryPop? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
pageId = arguments?.getString(EntranceConsts.KEY_PAGE_ID) ?: ""
|
||||
pageName = arguments?.getString(EntranceConsts.KEY_PAGE_NAME) ?: ""
|
||||
mLastPageDataMap = PageSwitchDataHelper.popLastPageData()
|
||||
savedInstanceState?.run {
|
||||
mLastSelectedPosition = getInt(EntranceConsts.KEY_LAST_SELECTED_POSITION)
|
||||
}
|
||||
|
||||
// 除了这里以外,下面还有一个判断是否为首页 tab 栏的赋值
|
||||
var entrance = if (mEntrance.contains("首页")) "首页" else "板块"
|
||||
|
||||
val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
|
||||
if (arguments?.getBoolean(EntranceConsts.KEY_IS_HOME) == true && multiTabNavId.isNotEmpty()) {
|
||||
mHomeViewModel =
|
||||
viewModelProviderFromParent(SearchToolbarTabWrapperViewModel.Factory(multiTabNavId, ""), multiTabNavId)
|
||||
entrance = "首页Tab栏"
|
||||
}
|
||||
viewModel.init(entrance)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
mViewModel?.run {
|
||||
outState.putInt(EntranceConsts.KEY_LAST_SELECTED_POSITION, selectedCategoryPosition)
|
||||
}
|
||||
outState.putInt(EntranceConsts.KEY_LAST_SELECTED_POSITION, viewModel.selectedSidebarsPosition.value ?: 0)
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
@ -61,100 +75,40 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
}
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
mCategoryId = arguments?.getString(EntranceConsts.KEY_CATEGORY_ID) ?: ""
|
||||
mCategoryTitle = arguments?.getString(EntranceConsts.KEY_CATEGORY_TITLE) ?: ""
|
||||
mLastPageDataMap = PageSwitchDataHelper.popLastPageData()
|
||||
mViewModel = viewModelProviderFromParent(CategoryV2ViewModel.Factory(mCategoryId, mCategoryTitle), mCategoryId)
|
||||
|
||||
// 除了这里以外,下面还有一个判断是否为首页 tab 栏的赋值
|
||||
mViewModel?.entrance = if (mEntrance.contains("首页")) "首页" else "板块"
|
||||
|
||||
val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
|
||||
if (arguments?.getBoolean(EntranceConsts.KEY_IS_HOME) == true && multiTabNavId.isNotEmpty()) {
|
||||
mHomeViewModel = viewModelProviderFromParent(SearchToolbarTabWrapperViewModel.Factory(multiTabNavId, ""), multiTabNavId)
|
||||
mViewModel?.entrance = "首页Tab栏"
|
||||
}
|
||||
mViewModel?.logAppearance()
|
||||
viewModel.logAppearance()
|
||||
|
||||
super.onFragmentFirstVisible()
|
||||
|
||||
viewModel.loadData(pageId, pageName)
|
||||
}
|
||||
|
||||
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
initMenu(R.menu.menu_search)
|
||||
setNavigationTitle(mCategoryTitle)
|
||||
setNavigationTitle(pageName)
|
||||
|
||||
mBinding?.run {
|
||||
val width = resources.displayMetrics.widthPixels * 260 / 360
|
||||
drawerLayout.setScrimColor(com.gh.gamecenter.common.R.color.black_alpha_30.toColor())
|
||||
// 关闭手势滑动
|
||||
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
|
||||
override fun onDrawerStateChanged(newState: Int) {
|
||||
}
|
||||
|
||||
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
showGuide()
|
||||
}
|
||||
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
}
|
||||
|
||||
})
|
||||
directoryContainer.layoutParams.width = width
|
||||
directoryRv.layoutParams.width = width
|
||||
|
||||
// 嵌入在首页时特殊处理
|
||||
if (arguments?.getBoolean(EntranceConsts.KEY_IS_HOME) == true) {
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
|
||||
root.setPadding(0, 8F.dip2px(), 0, 0)
|
||||
directoryRv.isNestedScrollingEnabled = false
|
||||
categoryRv.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
|
||||
}
|
||||
tvMoreCategory.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
tvTagNumber.typeface =
|
||||
Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH)
|
||||
}
|
||||
|
||||
mViewModel?.directoriesLiveData?.observeNonNull(viewLifecycleOwner) {
|
||||
initDirectoryView(it)
|
||||
}
|
||||
|
||||
mViewModel?.selectedCountLiveData?.observeNonNull(viewLifecycleOwner) {
|
||||
mBinding?.run {
|
||||
if (it == 0) {
|
||||
confirmTv.text = "确定"
|
||||
} else {
|
||||
mViewModel?.run {
|
||||
if (selectedCategoryName != "全部") {
|
||||
selectedCategoryName = "全部"
|
||||
selectedCategoryPosition = if (mEntity?.hasSpecial == true) 1 else 0
|
||||
categoryRv.adapter?.notifyDataSetChanged()
|
||||
mCategoryV2ListFragment?.updateSubCategoryId("all")
|
||||
}
|
||||
}
|
||||
|
||||
confirmTv.text = "确定(已选${it})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mViewModel?.sidebarsLiveData?.observe(viewLifecycleOwner, Observer {
|
||||
viewModel.sidebarsLiveData.observe(viewLifecycleOwner) { sidebars ->
|
||||
mBinding?.run {
|
||||
reuseLoading.root.visibility = View.GONE
|
||||
if (it != null) {
|
||||
if (sidebars != null) {
|
||||
reuseNoConnection.root.visibility = View.GONE
|
||||
categoryContainer.visibility = View.VISIBLE
|
||||
reuseNoneData.root.visibility = View.GONE
|
||||
mEntity = it
|
||||
(mEntity!!.sidebars as ArrayList).run {
|
||||
mEntity = sidebars
|
||||
(sidebars.sidebars as ArrayList).run {
|
||||
val allEntity = SidebarsEntity.SidebarEntity(name = "全部", categoryId = "all")
|
||||
if (mEntity!!.hasSpecial) {
|
||||
add(0, allEntity)
|
||||
if (sidebars.hasSpecial) {
|
||||
val specialEntity = SidebarsEntity.SidebarEntity(name = "精选")
|
||||
add(0, specialEntity)
|
||||
add(1, allEntity)
|
||||
} else {
|
||||
add(0, allEntity)
|
||||
add(1, specialEntity)
|
||||
}
|
||||
}
|
||||
initView()
|
||||
@ -165,12 +119,70 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
reuseNoConnection.root.setOnClickListener {
|
||||
reuseNoConnection.root.visibility = View.GONE
|
||||
reuseLoading.root.visibility = View.VISIBLE
|
||||
mViewModel?.getSidebars()
|
||||
mViewModel?.getCategoryDirectories()
|
||||
viewModel.loadData(pageId, pageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.directoriesLiveData.observe(viewLifecycleOwner) {
|
||||
searchCategoryPop?.setData(it)
|
||||
}
|
||||
|
||||
viewModel.selectedSubCategories.observe(viewLifecycleOwner) { selectedList ->
|
||||
searchCategoryPop?.updateCategorySelected(selectedList)
|
||||
updateMoreCategory(selectedList.size)
|
||||
}
|
||||
|
||||
viewModel.selectedSidebarsPosition.observe(viewLifecycleOwner) {
|
||||
mLastSelectedPosition = it
|
||||
onSelectedPositionChanged(it)
|
||||
|
||||
val adapter = mBinding?.categoryRv?.adapter
|
||||
if (adapter is CategoryV2Adapter) {
|
||||
adapter.selectPosition(it)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.notifySubCategorySelected.observe(
|
||||
viewLifecycleOwner,
|
||||
EventObserver {
|
||||
searchCategoryPop?.notifyItemSelectedChanged(it)
|
||||
})
|
||||
}
|
||||
|
||||
private fun createSearchPop(isAutoRequestFocus: Boolean): SearchCategoryPop {
|
||||
val height = mBinding!!.root.height
|
||||
return SearchCategoryPop.newInstance(requireContext(), height, isAutoRequestFocus, pageId, pageName).apply {
|
||||
val data = viewModel.directoriesLiveData.value ?: listOf()
|
||||
setData(data)
|
||||
val selectedList = viewModel.selectedSubCategories.value
|
||||
updateCategorySelected(selectedList)
|
||||
setOnSearchCategoryListener(object : SearchCategoryPop.OnSearchCategoryListener {
|
||||
override fun isEnableSelected(): Boolean {
|
||||
val size = viewModel.selectedSubCategories.value?.size ?: 0
|
||||
return size < 5
|
||||
}
|
||||
|
||||
override fun onItemSelected(selected: CategoryV2ViewModel.SelectedTags) {
|
||||
viewModel.addSubCategorySelected(selected)
|
||||
}
|
||||
|
||||
override fun onItemRemoved(parentId: String, subCategoryId: String) {
|
||||
viewModel.removeSubCategorySelected(parentId, subCategoryId, "全部游戏")
|
||||
}
|
||||
|
||||
override fun onResetSelected() {
|
||||
viewModel.clearSelectedTag()
|
||||
viewModel.updateGameFiltered()
|
||||
}
|
||||
|
||||
override fun onSubmit() {
|
||||
viewModel.logClickDetermine()
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun removeGuide() {
|
||||
@ -181,15 +193,7 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
}
|
||||
|
||||
private fun showGuide() {
|
||||
if (!isAdded) return
|
||||
mBinding?.run {
|
||||
val isShow = SPUtils.getBoolean(Constants.SP_SHOW_CATEGORY_GUIDE)
|
||||
if (isShow) return
|
||||
|
||||
guideContainer.layoutParams = (guideContainer.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
val screenWidth = resources.displayMetrics.widthPixels
|
||||
leftMargin = screenWidth * 66F.dip2px() / 360F.dip2px()
|
||||
}
|
||||
guideContainer.visibility = View.VISIBLE
|
||||
|
||||
postDelayedRunnable({
|
||||
@ -204,7 +208,7 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
override fun onMenuItemClick(menuItem: MenuItem?) {
|
||||
menuItem?.run {
|
||||
if (itemId == R.id.menu_search) {
|
||||
LogUtils.uploadSearchGame("access_to_search", mCategoryTitle, "", "")
|
||||
LogUtils.uploadSearchGame("access_to_search", pageName, "", "")
|
||||
val intent = SearchActivity.getIntent(
|
||||
requireContext(),
|
||||
false,
|
||||
@ -217,63 +221,64 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun initDirectoryView(list: List<CategoryEntity>) {
|
||||
mBinding?.run {
|
||||
mViewModel?.run {
|
||||
if (directoryRv.adapter != null) {
|
||||
(directoryRv.adapter as? CategoryDirectoryAdapter)?.setListData(list)
|
||||
} else {
|
||||
directoryRv.layoutManager = FixLinearLayoutManager(requireContext())
|
||||
directoryRv.adapter = CategoryDirectoryAdapter(
|
||||
requireContext(),
|
||||
this,
|
||||
list
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
resetTv.setOnClickListener {
|
||||
mViewModel?.logClickReset("全部类别")
|
||||
confirmTv.text = "确定"
|
||||
mViewModel?.resetDirectoryList()
|
||||
mCategoryV2ListFragment?.changeCategoryTab()
|
||||
}
|
||||
|
||||
confirmTv.setOnClickListener {
|
||||
mViewModel?.logClickDetermine()
|
||||
drawerLayout.closeDrawer(GravityCompat.START)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
if (mEntity?.sidebars?.isNullOrEmpty() == true || mViewModel == null) return
|
||||
if (mEntity?.sidebars.isNullOrEmpty()) return
|
||||
initSelectedCategory()
|
||||
initCategoryRv()
|
||||
initContentFragment()
|
||||
|
||||
mBinding?.run {
|
||||
|
||||
vSearchCategory.setOnClickListener {
|
||||
SensorsBridge.logClassificationSearch(pageId, pageName)
|
||||
removeGuide()
|
||||
showSearchPop(true)
|
||||
}
|
||||
|
||||
vMoreCategory.setOnClickListener {
|
||||
removeGuide()
|
||||
showSearchPop(false)
|
||||
}
|
||||
}
|
||||
|
||||
val isShow = SPUtils.getBoolean(Constants.SP_SHOW_CATEGORY_GUIDE)
|
||||
if (!isShow) {
|
||||
postDelayedRunnable({
|
||||
showSearchPop(false)
|
||||
searchCategoryPop?.setOnDismissListener {
|
||||
showGuide()
|
||||
}
|
||||
}, 200)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun showSearchPop(isAutoRequestFocus: Boolean) {
|
||||
mBinding?.run {
|
||||
val location = IntArray(2)
|
||||
vSearchCategory.getLocationOnScreen(location)
|
||||
|
||||
val popTop = location[1] - 8F.dip2px()
|
||||
searchCategoryPop = createSearchPop(isAutoRequestFocus)
|
||||
searchCategoryPop?.showAtLocation(vSearchCategory, Gravity.TOP, 0, popTop)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initSelectedCategory() {
|
||||
mEntity?.run {
|
||||
mViewModel?.run {
|
||||
if (mLastSelectedPosition != -1) {
|
||||
selectedCategoryPosition = mLastSelectedPosition
|
||||
selectedCategoryName = sidebars[mLastSelectedPosition].name
|
||||
} else {
|
||||
selectedCategoryPosition = 0
|
||||
selectedCategoryName = sidebars[0].name
|
||||
}
|
||||
}
|
||||
if (mLastSelectedPosition != -1) {
|
||||
viewModel.selectSidebarsPosition(mLastSelectedPosition)
|
||||
} else {
|
||||
// 默认选中第 0 个 位置
|
||||
viewModel.selectSidebarsPosition(0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun initCategoryRv() {
|
||||
mEntity?.run {
|
||||
mViewModel?.run {
|
||||
viewModel.run {
|
||||
mBinding?.categoryRv?.layoutManager = FixLinearLayoutManager(requireContext())
|
||||
mBinding?.categoryRv?.adapter = CategoryV2Adapter(
|
||||
requireContext(),
|
||||
this@CategoryV2Fragment,
|
||||
this,
|
||||
sidebars
|
||||
)
|
||||
@ -281,226 +286,93 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun initContentFragment() {
|
||||
mEntity?.apply {
|
||||
mViewModel?.apply {
|
||||
if (hasSpecial && selectedCategoryPosition == 0) {
|
||||
initSpecialCatalogFragment()
|
||||
} else {
|
||||
initCategoryV2ListFragment()
|
||||
private fun onSelectedPositionChanged(position: Int) {
|
||||
mEntity?.run {
|
||||
viewModel.run {
|
||||
clearSelectedTag()
|
||||
childFragmentManager.fragments.find { it.isAdded }
|
||||
val targetFragment =
|
||||
if (hasSpecial && position == 1) {
|
||||
val fragment = childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.name)
|
||||
?: SpecialCatalogFragment()
|
||||
fragment.arguments = bundleOf(
|
||||
EntranceConsts.KEY_IS_CATEGORY_V2 to true,
|
||||
EntranceConsts.KEY_CATALOG_ID to pageId,
|
||||
EntranceConsts.KEY_CATALOG_TITLE to pageName,
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList<ExposureSource>(
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST
|
||||
),
|
||||
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
|
||||
)
|
||||
fragment
|
||||
|
||||
// 第一次点"全部"tab展开全部类别选择框
|
||||
// 加延迟是为了防止卡顿
|
||||
if (SPUtils.getBoolean(Constants.SP_FIRST_ENTER_CATEGORY_V2, true)) {
|
||||
SPUtils.setBoolean(Constants.SP_FIRST_ENTER_CATEGORY_V2, false)
|
||||
mBinding?.drawerLayout?.postDelayed({
|
||||
tryCatchInRelease { openDrawer() }
|
||||
}, 500L)
|
||||
} else {
|
||||
val fragment = (childFragmentManager.findFragmentByTag(CategoryV2ListFragment::class.java.name)
|
||||
?: CategoryV2ListFragment())
|
||||
fragment.arguments = bundleOf(
|
||||
EntranceConsts.KEY_PAGE_ID to id,
|
||||
EntranceConsts.KEY_PAGE_NAME to pageName,
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList<ExposureSource>(
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST
|
||||
),
|
||||
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
|
||||
)
|
||||
fragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initSpecialCatalogFragment() {
|
||||
mEntity?.run {
|
||||
mSpecialCatalogFragment = childFragmentManager
|
||||
.findFragmentByTag(SpecialCatalogFragment::class.java.name)
|
||||
as? SpecialCatalogFragment ?: SpecialCatalogFragment()
|
||||
mSpecialCatalogFragment?.arguments = bundleOf(
|
||||
EntranceConsts.KEY_IS_CATEGORY_V2 to true,
|
||||
EntranceConsts.KEY_CATALOG_ID to id,
|
||||
EntranceConsts.KEY_CATALOG_TITLE to mCategoryTitle,
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList<ExposureSource>(
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST
|
||||
),
|
||||
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
|
||||
)
|
||||
childFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(
|
||||
R.id.gamesContainer,
|
||||
mSpecialCatalogFragment!!,
|
||||
SpecialCatalogFragment::class.java.name
|
||||
)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initCategoryV2ListFragment() {
|
||||
mEntity?.run {
|
||||
mViewModel?.run {
|
||||
mCategoryV2ListFragment = childFragmentManager
|
||||
.findFragmentByTag(CategoryV2ListFragment::class.java.name)
|
||||
as? CategoryV2ListFragment ?: CategoryV2ListFragment()
|
||||
mCategoryV2ListFragment?.arguments = bundleOf(
|
||||
EntranceConsts.KEY_CATEGORY_ID to id,
|
||||
EntranceConsts.KEY_SUB_CATEGORY_ID to sidebars[selectedCategoryPosition].categoryId,
|
||||
EntranceConsts.KEY_CATEGORY_TITLE to mCategoryTitle,
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList<ExposureSource>(
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST
|
||||
),
|
||||
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
|
||||
)
|
||||
childFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(
|
||||
R.id.gamesContainer,
|
||||
mCategoryV2ListFragment!!,
|
||||
CategoryV2ListFragment::class.java.name
|
||||
)
|
||||
.replace(R.id.gamesContainer, targetFragment, targetFragment::class.java.name)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun changeCategory(position: Int) {
|
||||
mEntity?.run {
|
||||
mViewModel?.run {
|
||||
resetDirectoryList()
|
||||
|
||||
if (hasSpecial) {
|
||||
if (selectedCategoryPosition == 0) {
|
||||
mCategoryV2ListFragment = childFragmentManager
|
||||
.findFragmentByTag(CategoryV2ListFragment::class.java.name)
|
||||
as? CategoryV2ListFragment ?: CategoryV2ListFragment()
|
||||
mCategoryV2ListFragment?.arguments = bundleOf(
|
||||
EntranceConsts.KEY_CATEGORY_ID to id,
|
||||
EntranceConsts.KEY_SUB_CATEGORY_ID to sidebars[position].categoryId,
|
||||
EntranceConsts.KEY_CATALOG_TITLE to mCategoryTitle,
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList<ExposureSource>(
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST
|
||||
),
|
||||
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
|
||||
)
|
||||
childFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(
|
||||
R.id.gamesContainer,
|
||||
mCategoryV2ListFragment!!,
|
||||
CategoryV2ListFragment::class.java.name
|
||||
)
|
||||
.commitAllowingStateLoss()
|
||||
} else {
|
||||
if (position == 0) {
|
||||
removeGuide()
|
||||
|
||||
mSpecialCatalogFragment = childFragmentManager
|
||||
.findFragmentByTag(SpecialCatalogFragment::class.java.name)
|
||||
as? SpecialCatalogFragment ?: SpecialCatalogFragment()
|
||||
mSpecialCatalogFragment?.arguments = bundleOf(
|
||||
EntranceConsts.KEY_IS_CATEGORY_V2 to true,
|
||||
EntranceConsts.KEY_CATALOG_ID to id,
|
||||
EntranceConsts.KEY_CATALOG_TITLE to mCategoryTitle,
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList<ExposureSource>(
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST
|
||||
),
|
||||
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
|
||||
)
|
||||
childFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(
|
||||
R.id.gamesContainer,
|
||||
mSpecialCatalogFragment!!,
|
||||
SpecialCatalogFragment::class.java.name
|
||||
)
|
||||
.commitAllowingStateLoss()
|
||||
} else {
|
||||
if (mCategoryV2ListFragment?.isStateSaved == false) {
|
||||
mCategoryV2ListFragment?.arguments = bundleOf(
|
||||
EntranceConsts.KEY_CATEGORY_ID to id,
|
||||
EntranceConsts.KEY_SUB_CATEGORY_ID to sidebars[position].categoryId,
|
||||
EntranceConsts.KEY_CATALOG_TITLE to mCategoryTitle,
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList<ExposureSource>(
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST
|
||||
),
|
||||
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
|
||||
)
|
||||
}
|
||||
mCategoryV2ListFragment?.changeCategoryTab(sidebars[position].categoryId)
|
||||
}
|
||||
}
|
||||
|
||||
// 第一次点"全部"tab展开全部类别选择框
|
||||
// 加延迟是为了防止卡顿
|
||||
if (position == 1 && SPUtils.getBoolean(Constants.SP_FIRST_ENTER_CATEGORY_V2, true)) {
|
||||
SPUtils.setBoolean(Constants.SP_FIRST_ENTER_CATEGORY_V2, false)
|
||||
mBinding?.drawerLayout?.postDelayed({
|
||||
tryCatchInRelease { openDrawer() }
|
||||
}, 200L)
|
||||
}
|
||||
} else {
|
||||
if (mCategoryV2ListFragment?.isStateSaved == false) {
|
||||
mCategoryV2ListFragment?.arguments = bundleOf(
|
||||
EntranceConsts.KEY_CATEGORY_ID to id,
|
||||
EntranceConsts.KEY_SUB_CATEGORY_ID to sidebars[position].categoryId,
|
||||
EntranceConsts.KEY_CATALOG_TITLE to mCategoryTitle,
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList<ExposureSource>(
|
||||
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST
|
||||
),
|
||||
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
|
||||
)
|
||||
}
|
||||
mCategoryV2ListFragment?.changeCategoryTab(sidebars[position].categoryId)
|
||||
}
|
||||
selectedCategoryPosition = position
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun openDirectoryLayout() {
|
||||
private fun updateMoreCategory(size: Int) {
|
||||
mBinding?.run {
|
||||
var i = 0
|
||||
mViewModel?.run {
|
||||
mEntity?.run {
|
||||
val sidebar = sidebars[selectedCategoryPosition]
|
||||
if (sidebar.name != "全部") {
|
||||
directories.forEachIndexed { index, entity ->
|
||||
if (sidebar.type == "level_one") {
|
||||
if (sidebar.categoryId == entity.id) {
|
||||
i = index
|
||||
return@run
|
||||
}
|
||||
} else {
|
||||
if (sidebar.parentId == entity.id) {
|
||||
i = index
|
||||
return@run
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (sidebar.name == "全部" && selectedCategoryList.isNotEmpty()) {
|
||||
i = selectedCategoryList[0].primaryIndex
|
||||
}
|
||||
if (size > 0) {
|
||||
vMoreCategory.setBackgroundResource(R.drawable.bg_more_category_filtered)
|
||||
TextViewCompat.setCompoundDrawableTintList(
|
||||
tvMoreCategory,
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
|
||||
)
|
||||
tvMoreCategory.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
|
||||
tvTagNumber.goneIf(false) {
|
||||
tvTagNumber.text = "$size"
|
||||
}
|
||||
} else {
|
||||
vMoreCategory.setBackgroundResource(R.drawable.bg_more_category_default)
|
||||
TextViewCompat.setCompoundDrawableTintList(
|
||||
tvMoreCategory,
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
)
|
||||
tvMoreCategory.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
tvTagNumber.goneIf(true)
|
||||
}
|
||||
openDrawer()
|
||||
(directoryRv.layoutManager as? LinearLayoutManager)?.scrollToPositionWithOffset(i, 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openDrawer() {
|
||||
mBinding?.drawerLayout?.openDrawer(GravityCompat.START)
|
||||
|
||||
mHomeViewModel?.let {
|
||||
mBinding?.directoryContainer?.setPadding(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
requireContext().resources.getDimension(com.gh.gamecenter.common.R.dimen.main_bottom_tab_height).toInt() - it.appBarOffset
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
getItemMenu(R.id.menu_search)?.setIcon(R.drawable.ic_column_search)
|
||||
mBinding?.categoryRv?.adapter?.run {
|
||||
mBinding?.categoryRv?.recycledViewPool?.clear()
|
||||
notifyItemRangeChanged(0, itemCount)
|
||||
}
|
||||
mBinding?.directoryRv?.adapter?.run {
|
||||
mBinding?.directoryRv?.recycledViewPool?.clear()
|
||||
notifyItemRangeChanged(0, itemCount)
|
||||
mBinding?.run {
|
||||
categoryRv.adapter?.run {
|
||||
categoryRv.recycledViewPool.clear()
|
||||
notifyItemRangeChanged(0, itemCount, "")
|
||||
}
|
||||
|
||||
val selectedTagsSize = viewModel.selectedSubCategories.value?.size ?: 0
|
||||
updateMoreCategory(selectedTagsSize)
|
||||
|
||||
context?.let {
|
||||
ivSearchCategory.imageTintList =
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_instance.toColor(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val SPECIAL_CATEGORY_POSITION = 1
|
||||
}
|
||||
}
|
||||
@ -76,8 +76,15 @@ class CategoryV2ListAdapter(
|
||||
ItemViewType.GAME_NORMAL -> {
|
||||
CategoryGameItemViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
else -> {
|
||||
FooterViewHolder(mLayoutInflater.inflate(com.gh.gamecenter.common.R.layout.refresh_footerview, parent, false))
|
||||
FooterViewHolder(
|
||||
mLayoutInflater.inflate(
|
||||
com.gh.gamecenter.common.R.layout.refresh_footerview,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,20 +101,12 @@ class CategoryV2ListAdapter(
|
||||
holder.bindGameItem(gameEntity)
|
||||
holder.initServerType(gameEntity)
|
||||
|
||||
val categoryTitle = mCategoryViewModel.categoryTitle
|
||||
val selectedCategoryName = mCategoryViewModel.selectedCategoryName
|
||||
val builder = StringBuilder()
|
||||
mCategoryViewModel.selectedCategoryList.run {
|
||||
forEachIndexed { index, entity ->
|
||||
builder.append(entity.name)
|
||||
if (index != size - 1) {
|
||||
builder.append("_")
|
||||
}
|
||||
}
|
||||
}
|
||||
val selectedSubCatalogName = builder.toString()
|
||||
val sortType = mViewModel.sortType.value
|
||||
val sortSize = mViewModel.sortSize.text
|
||||
val categoryTitle = mCategoryViewModel.pageName
|
||||
val selectedCategoryName = mCategoryViewModel.selectedSidebarsName
|
||||
val selectedSubCatalogName =
|
||||
mCategoryViewModel.selectedSubCategories.value?.joinToString("-") { it.category.name ?: "" }
|
||||
val sortType = mViewModel.gameFiltered.sortType.value
|
||||
val sortSize = mViewModel.gameFiltered.size.text
|
||||
|
||||
val exposureSources = ArrayList<ExposureSource>()
|
||||
if (!mViewModel.exposureSourceList.isNullOrEmpty()) {
|
||||
@ -172,8 +171,13 @@ class CategoryV2ListAdapter(
|
||||
) {
|
||||
val trackEvent = JSONObject()
|
||||
try {
|
||||
trackEvent.put("navigation_bar_name", mCategoryViewModel.selectedCategoryName)
|
||||
trackEvent.put("game_tag", mCategoryViewModel.selectedCategoryList.map { it.name })
|
||||
trackEvent.put("navigation_bar_name", mCategoryViewModel.selectedSidebarsName)
|
||||
trackEvent.put(
|
||||
"game_tag",
|
||||
(mCategoryViewModel.selectedSubCategories.value ?: listOf())
|
||||
.map {
|
||||
it.category.name
|
||||
})
|
||||
trackEvent.put("game_status", gameEntity.category)
|
||||
trackEvent.put(
|
||||
"inclusion_size",
|
||||
@ -266,18 +270,24 @@ class CategoryV2ListAdapter(
|
||||
binding.gameKaifuType.visibility = View.GONE
|
||||
binding.gameKaifuType.text = ""
|
||||
}
|
||||
|
||||
serverLabel != null -> {
|
||||
binding.gameKaifuType.visibility = View.VISIBLE
|
||||
binding.gameKaifuType.text = serverLabel.value
|
||||
if (gameEntity.isUseDefaultServerStyle()) {
|
||||
binding.gameKaifuType.background =
|
||||
com.gh.gamecenter.feature.R.drawable.server_label_default_bg.toDrawable(binding.root.context)
|
||||
binding.gameKaifuType.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(binding.root.context))
|
||||
binding.gameKaifuType.setTextColor(
|
||||
com.gh.gamecenter.common.R.color.text_secondary.toColor(
|
||||
binding.root.context
|
||||
)
|
||||
)
|
||||
} else {
|
||||
binding.gameKaifuType.background = DrawableView.getServerDrawable(serverLabel.color)
|
||||
binding.gameKaifuType.setTextColor(com.gh.gamecenter.common.R.color.white.toColor(binding.root.context))
|
||||
}
|
||||
}
|
||||
|
||||
else -> binding.gameKaifuType.visibility = View.GONE
|
||||
}
|
||||
|
||||
|
||||
@ -2,9 +2,10 @@ package com.gh.gamecenter.category2
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.common.exposure.ExposureListener
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.view.CategoryFilterView
|
||||
@ -13,16 +14,17 @@ import com.gh.common.xapk.XapkUnzipStatus
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.ListFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.observeNonNull
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.viewModelProvider
|
||||
import com.gh.gamecenter.databinding.FragmentCategoryListBinding
|
||||
import com.gh.gamecenter.databinding.LayoutSelectedCategoryBinding
|
||||
import com.gh.gamecenter.entity.CategoryEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
@ -30,13 +32,18 @@ import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>() {
|
||||
|
||||
private var mCategoryId: String = ""
|
||||
private var mSubCategoryId: String = ""
|
||||
private var mCategoryTitle: String = ""
|
||||
private var pageId: String = ""
|
||||
private var pageName: String = ""
|
||||
private val parentViewModel by viewModels<CategoryV2ViewModel>(
|
||||
ownerProducer = { parentFragment ?: this }
|
||||
)
|
||||
|
||||
override fun isAutomaticLoad(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
private var mAdapter: CategoryV2ListAdapter? = null
|
||||
private var mSelectedViewList = ArrayList<View>()
|
||||
private var mBinding: FragmentCategoryListBinding? = null
|
||||
private var mCategoryViewModel: CategoryV2ViewModel? = null
|
||||
private var mLastPageDataMap: HashMap<String, String>? = null
|
||||
private val mDataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
@ -52,6 +59,12 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
}
|
||||
}
|
||||
|
||||
private val selectedTagsAdapter by lazy {
|
||||
SelectedTagsAdapter {
|
||||
parentViewModel.removeSubCategorySelected(it.parentId, it.category.id, "游戏列表")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLayoutId() = 0
|
||||
|
||||
override fun getInflatedLayout() =
|
||||
@ -60,8 +73,7 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
override fun provideListViewModel() =
|
||||
viewModelProvider<CategoryV2ListViewModel>(
|
||||
CategoryV2ListViewModel.Factory(
|
||||
mCategoryId,
|
||||
mSubCategoryId,
|
||||
pageId,
|
||||
arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)
|
||||
)
|
||||
)
|
||||
@ -70,12 +82,7 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
?: CategoryV2ListAdapter(
|
||||
requireContext(),
|
||||
mListViewModel ?: provideListViewModel(),
|
||||
mCategoryViewModel ?: viewModelProviderFromParent(
|
||||
CategoryV2ViewModel.Factory(
|
||||
mCategoryId,
|
||||
mCategoryTitle
|
||||
), mCategoryId
|
||||
),
|
||||
parentViewModel,
|
||||
mEntrance,
|
||||
mLastPageDataMap
|
||||
).apply { mAdapter = this }
|
||||
@ -83,12 +90,10 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
override fun getItemDecoration() = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
mCategoryId = arguments?.getString(EntranceConsts.KEY_CATEGORY_ID) ?: ""
|
||||
mSubCategoryId = arguments?.getString(EntranceConsts.KEY_SUB_CATEGORY_ID) ?: ""
|
||||
mCategoryTitle = arguments?.getString(EntranceConsts.KEY_CATEGORY_TITLE) ?: ""
|
||||
pageId = arguments?.getString(EntranceConsts.KEY_PAGE_ID) ?: ""
|
||||
pageName = arguments?.getString(EntranceConsts.KEY_PAGE_NAME) ?: ""
|
||||
mLastPageDataMap = arguments?.getSerializable(EntranceConsts.KEY_LAST_PAGE_DATA) as? HashMap<String, String>
|
||||
mCategoryViewModel =
|
||||
viewModelProviderFromParent(CategoryV2ViewModel.Factory(mCategoryId, mCategoryTitle), mCategoryId)
|
||||
|
||||
mEntrance = arguments?.getString(EntranceConsts.KEY_ENTRANCE) ?: Constants.ENTRANCE_UNKNOWN
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -104,19 +109,8 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
|
||||
initFilterView()
|
||||
|
||||
mListViewModel?.refresh?.observeNonNull(viewLifecycleOwner) { onRefresh() }
|
||||
mCategoryViewModel?.run {
|
||||
categoryPositionLiveData.observeNonNull(viewLifecycleOwner) {
|
||||
directories[it.first].data?.get(it.second)?.run {
|
||||
mBinding?.selectedCategoryContainer?.visibility = View.VISIBLE
|
||||
|
||||
if (selected) {
|
||||
addCategory(this)
|
||||
} else {
|
||||
removeCategory(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
mListViewModel?.refresh?.observeNonNull(viewLifecycleOwner) {
|
||||
onRefresh()
|
||||
}
|
||||
|
||||
mListRv.addOnScrollListener(ExposureListener(this, provideListAdapter()))
|
||||
@ -132,19 +126,40 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
.show()
|
||||
|
||||
mBinding?.reuseNoneData?.reuseResetLoadTv?.setOnClickListener {
|
||||
mCategoryViewModel?.run {
|
||||
// 重试时,
|
||||
// 清空所有筛选条件
|
||||
with(parentViewModel) {
|
||||
logClickReset("游戏列表")
|
||||
resetDirectoryList()
|
||||
clearSelectedTag()
|
||||
// 移除大小限制
|
||||
mBinding?.filterContainer?.resetSortSize()
|
||||
val size = SubjectSettingEntity.Size()
|
||||
updateGameFiltered(size)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
with(parentViewModel) {
|
||||
gameFiltered.observe(viewLifecycleOwner) {
|
||||
mListViewModel.updateSortConfig(it)
|
||||
}
|
||||
|
||||
selectedSubCategories.observe(viewLifecycleOwner) {
|
||||
updateSelectedTags(it)
|
||||
}
|
||||
resetSortSize()
|
||||
changeCategoryTab()
|
||||
// openDirectoryLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetSortSize() {
|
||||
mBinding?.filterContainer?.resetSortSize()
|
||||
mListViewModel?.sortSize = SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小")
|
||||
private fun updateSelectedTags(selectedTags: List<CategoryV2ViewModel.SelectedTags>) {
|
||||
mBinding?.run {
|
||||
flTagsContainer.goneIf(selectedTags.isEmpty()) {
|
||||
if (rvTags.adapter == null) {
|
||||
rvTags.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
|
||||
rvTags.adapter = selectedTagsAdapter
|
||||
}
|
||||
selectedTagsAdapter.submitList(selectedTags)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -154,22 +169,19 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
|
||||
setOnConfigSetupListener(object : CategoryFilterView.OnCategoryFilterSetupListener {
|
||||
override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
|
||||
mListViewModel?.updateSortConfig(sortSize = sortSize)
|
||||
parentViewModel.updateGameFiltered(size = sortSize)
|
||||
}
|
||||
|
||||
override fun onSetupSortType(sortType: CategoryFilterView.SortType) {
|
||||
mListViewModel?.updateSortConfig(sortType = sortType)
|
||||
parentViewModel.updateGameFiltered(sortType = sortType)
|
||||
}
|
||||
|
||||
override fun onSetupSortCategory() {
|
||||
openDirectoryLayout()
|
||||
override fun getPopHeight(): Int {
|
||||
return (mBinding?.root?.height ?: 0) - (mBinding?.flTagsContainer?.height ?: 0)
|
||||
}
|
||||
})
|
||||
|
||||
setOnFilterClickListener(object : CategoryFilterView.OnFilterClickListener {
|
||||
override fun onCategoryClick() {
|
||||
removeGuide()
|
||||
}
|
||||
|
||||
override fun onTypeClick() {
|
||||
removeGuide()
|
||||
@ -183,101 +195,6 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSubCategoryId(id: String) {
|
||||
mSubCategoryId = id
|
||||
}
|
||||
|
||||
fun changeCategoryTab(categoryId: String? = null) {
|
||||
mSelectedViewList.clear()
|
||||
mBinding?.selectedCategoryContainer?.run {
|
||||
removeAllViews()
|
||||
visibility = View.GONE
|
||||
}
|
||||
if (categoryId != null) mSubCategoryId = categoryId
|
||||
mListViewModel?.updateSortConfig(categoryIds = mSubCategoryId)
|
||||
}
|
||||
|
||||
private fun addCategory(entity: CategoryEntity) {
|
||||
addCategoryView(entity)
|
||||
mCategoryViewModel?.selectedCategoryList?.add(entity)
|
||||
updateCategoryGame()
|
||||
}
|
||||
|
||||
private fun removeCategory(entity: CategoryEntity) {
|
||||
mCategoryViewModel?.selectedCategoryList?.run {
|
||||
if (isEmpty()) return
|
||||
|
||||
removeCategoryView(entity.name ?: "")
|
||||
remove(entity)
|
||||
if (size == 0) {
|
||||
mBinding?.selectedCategoryContainer?.visibility = View.GONE
|
||||
mListViewModel?.updateSortConfig(categoryIds = mSubCategoryId)
|
||||
} else {
|
||||
updateCategoryGame()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCategoryView(entity: CategoryEntity) {
|
||||
val binding = LayoutSelectedCategoryBinding.inflate(layoutInflater).apply {
|
||||
val params =
|
||||
FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
params.setMargins(0, 8F.dip2px(), 8F.dip2px(), 0)
|
||||
params.height = 24F.dip2px()
|
||||
root.layoutParams = params
|
||||
|
||||
name.text = entity.name
|
||||
root.setOnClickListener {
|
||||
removeCategoryAndNotify(entity)
|
||||
}
|
||||
}
|
||||
|
||||
mSelectedViewList.add(binding.root)
|
||||
mBinding?.selectedCategoryContainer?.addView(binding.root)
|
||||
}
|
||||
|
||||
private fun removeCategoryView(categoryName: String) {
|
||||
mCategoryViewModel?.selectedCategoryList?.run {
|
||||
var i = 0
|
||||
forEachIndexed { index, categoryEntity ->
|
||||
if (categoryName == categoryEntity.name) {
|
||||
i = index
|
||||
}
|
||||
}
|
||||
|
||||
if (i < mSelectedViewList.size) {
|
||||
mBinding?.selectedCategoryContainer?.removeView(mSelectedViewList[i])
|
||||
mSelectedViewList.removeAt(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeCategoryAndNotify(entity: CategoryEntity) {
|
||||
removeCategory(entity)
|
||||
entity.selected = false
|
||||
mCategoryViewModel?.run {
|
||||
if (selectedCount > 0) {
|
||||
selectedCount--
|
||||
postSelectedCount()
|
||||
postCategoryDirectoryList()
|
||||
logClickClassificationDelete(entity.primaryIndex, entity.name ?: "", "游戏列表")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCategoryGame() {
|
||||
mCategoryViewModel?.selectedCategoryList?.run {
|
||||
val categoryIds = StringBuilder()
|
||||
forEachIndexed { index, s ->
|
||||
categoryIds.append(s.id)
|
||||
if (index != size - 1) {
|
||||
categoryIds.append("-")
|
||||
}
|
||||
}
|
||||
mListViewModel?.updateSortConfig(categoryIds = categoryIds.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeGuide() {
|
||||
(parentFragment as? CategoryV2Fragment)?.removeGuide()
|
||||
}
|
||||
@ -328,10 +245,6 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
}
|
||||
}
|
||||
|
||||
fun openDirectoryLayout() {
|
||||
(parentFragment as? CategoryV2Fragment)?.openDirectoryLayout()
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
mBinding?.filterContainer?.run {
|
||||
|
||||
@ -4,14 +4,13 @@ import android.app.Application
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.gamecenter.common.entity.ExposureEntity
|
||||
import com.gh.common.exposure.ExposureUtils
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.common.view.CategoryFilterView
|
||||
import com.gh.gamecenter.common.baselist.ListViewModel
|
||||
import com.gh.gamecenter.common.entity.ExposureEntity
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.Observable
|
||||
@ -20,14 +19,13 @@ import io.reactivex.Single
|
||||
class CategoryV2ListViewModel(
|
||||
application: Application,
|
||||
val categoryId: String,
|
||||
var categoryIds: String,
|
||||
var exposureSourceList: List<ExposureSource>?
|
||||
) : ListViewModel<GameEntity, GameEntity>(application) {
|
||||
|
||||
val refresh = MutableLiveData<Boolean>()
|
||||
|
||||
var sortType = CategoryFilterView.SortType.RECOMMENDED
|
||||
var sortSize = SubjectSettingEntity.Size()
|
||||
var gameFiltered = CategoryV2ViewModel.GameFiltered()
|
||||
private set
|
||||
|
||||
override fun provideDataObservable(page: Int): Observable<List<GameEntity>>? = null
|
||||
|
||||
@ -51,52 +49,36 @@ class CategoryV2ListViewModel(
|
||||
}
|
||||
|
||||
fun updateSortConfig(
|
||||
sortSize: SubjectSettingEntity.Size? = null,
|
||||
sortType: CategoryFilterView.SortType? = null,
|
||||
categoryIds: String? = null
|
||||
gameFiltered: CategoryV2ViewModel.GameFiltered
|
||||
) {
|
||||
when {
|
||||
sortSize != null && sortSize != this.sortSize -> {
|
||||
this.sortSize = sortSize
|
||||
refresh.postValue(true)
|
||||
}
|
||||
|
||||
sortType != null && sortType != this.sortType -> {
|
||||
this.sortType = sortType
|
||||
refresh.postValue(true)
|
||||
}
|
||||
|
||||
categoryIds != null && categoryIds != this.categoryIds -> {
|
||||
this.categoryIds = categoryIds
|
||||
refresh.postValue(true)
|
||||
}
|
||||
}
|
||||
this.gameFiltered = gameFiltered
|
||||
refresh.postValue(true)
|
||||
}
|
||||
|
||||
private fun getFilter(): String? {
|
||||
|
||||
return UrlFilterUtils.getFilterQuery(
|
||||
"category_ids", categoryIds,
|
||||
"min_size", sortSize.min.toString(),
|
||||
"max_size", sortSize.max.toString()
|
||||
"category_ids", gameFiltered.categoryIds.ifBlank { gameFiltered.sidebarCategoryId },
|
||||
"min_size", gameFiltered.size.min.toString(),
|
||||
"max_size", gameFiltered.size.max.toString()
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private fun getSortType(): String? {
|
||||
return when (sortType) {
|
||||
return when (gameFiltered.sortType) {
|
||||
CategoryFilterView.SortType.RECOMMENDED -> "download:-1"
|
||||
CategoryFilterView.SortType.NEWEST -> "publish:-1"
|
||||
CategoryFilterView.SortType.RATING -> "star:-1"
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(val categoryId: String, val categoryIds: String, val exposureSourceList: List<ExposureSource>?) :
|
||||
class Factory(val categoryId: String, val exposureSourceList: List<ExposureSource>?) :
|
||||
ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return CategoryV2ListViewModel(
|
||||
HaloApp.getInstance().application,
|
||||
categoryId,
|
||||
categoryIds,
|
||||
exposureSourceList
|
||||
) as T
|
||||
}
|
||||
|
||||
@ -1,160 +1,214 @@
|
||||
package com.gh.gamecenter.category2
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.common.util.LogUtils
|
||||
import com.gh.common.view.CategoryFilterView
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.entity.CategoryEntity
|
||||
import com.gh.gamecenter.entity.SidebarsEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
class CategoryV2ViewModel(
|
||||
application: Application,
|
||||
private val mCategoryId: String,
|
||||
val categoryTitle: String
|
||||
) : AndroidViewModel(application) {
|
||||
class CategoryV2ViewModel : ViewModel() {
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
private val api = RetrofitManager.getInstance().api
|
||||
var sidebarsLiveData = MutableLiveData<SidebarsEntity>()
|
||||
var directories = ArrayList<CategoryEntity>()
|
||||
var sidebarsLiveData = MutableLiveData<SidebarsEntity?>()
|
||||
var directoriesLiveData = MutableLiveData<List<CategoryEntity>>()
|
||||
var selectedCount = 0
|
||||
var selectedCountLiveData = MutableLiveData<Int>()
|
||||
var categoryPositionLiveData = MutableLiveData<Pair<Int, Int>>()
|
||||
|
||||
var selectedCategoryName: String = ""
|
||||
var selectedCategoryPosition: Int = 0
|
||||
var selectedCategoryList = ArrayList<CategoryEntity>()
|
||||
var entrance: String = ""
|
||||
private var pageId = ""
|
||||
var pageName = ""
|
||||
private set
|
||||
|
||||
init {
|
||||
getSidebars()
|
||||
getCategoryDirectories()
|
||||
fun init(entrance: String) {
|
||||
this.entrance = entrance
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun getSidebars() {
|
||||
api.getSidebars(mCategoryId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<SidebarsEntity>() {
|
||||
override fun onSuccess(data: SidebarsEntity) {
|
||||
sidebarsLiveData.postValue(data)
|
||||
fun loadData(pageId: String, pageName: String) {
|
||||
this.pageId = pageId
|
||||
this.pageName = pageName
|
||||
|
||||
val sidebarsObservable = api.getSidebars(pageId)
|
||||
val directoriesObservable = api.getCategoryDirectories(pageId)
|
||||
.onErrorReturnItem(listOf())
|
||||
sidebarsObservable.zipWith(directoriesObservable) { t1, t2 ->
|
||||
t1 to t2
|
||||
}.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<Pair<SidebarsEntity, List<CategoryEntity>>>() {
|
||||
override fun onSuccess(data: Pair<SidebarsEntity, List<CategoryEntity>>) {
|
||||
val (sidebarsData, directories) = data
|
||||
directoriesLiveData.value = directories
|
||||
sidebarsLiveData.value = sidebarsData
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
sidebarsLiveData.postValue(null)
|
||||
}
|
||||
})
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun getCategoryDirectories() {
|
||||
api.getCategoryDirectories(mCategoryId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<List<CategoryEntity>>() {
|
||||
override fun onSuccess(data: List<CategoryEntity>) {
|
||||
directories = ArrayList(data)
|
||||
postCategoryDirectoryList()
|
||||
fun clearSelectedTag() {
|
||||
logClickReset("全部类别")
|
||||
val filteredList = _selectedSubCategories.value
|
||||
if (!filteredList.isNullOrEmpty()) {
|
||||
_selectedSubCategories.value = mutableListOf()
|
||||
|
||||
val directories = directoriesLiveData.value ?: return
|
||||
directories.forEach {
|
||||
it.data?.forEach { child ->
|
||||
child.selected = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun postSelectedCount() {
|
||||
selectedCountLiveData.postValue(selectedCount)
|
||||
}
|
||||
|
||||
fun postCategoryPosition(primaryIndex: Int, subIndex: Int) {
|
||||
categoryPositionLiveData.postValue(Pair(primaryIndex, subIndex))
|
||||
}
|
||||
|
||||
fun postCategoryDirectoryList() {
|
||||
directoriesLiveData.postValue(directories)
|
||||
}
|
||||
|
||||
fun resetDirectoryList() {
|
||||
selectedCount = 0
|
||||
selectedCategoryList.clear()
|
||||
directories.forEach {
|
||||
it.data?.forEach { entity ->
|
||||
entity.selected = false
|
||||
}
|
||||
directoriesLiveData.value = directories
|
||||
}
|
||||
postSelectedCount()
|
||||
postCategoryDirectoryList()
|
||||
}
|
||||
|
||||
fun logAppearance() {
|
||||
LogUtils.logCategoryV2AppearanceEvent(entrance, categoryTitle)
|
||||
LogUtils.logCategoryV2AppearanceEvent(entrance, pageName)
|
||||
}
|
||||
|
||||
fun logClickSide() {
|
||||
LogUtils.logCategoryV2ClickSideEvent(entrance, categoryTitle, selectedCategoryName, selectedCategoryPosition)
|
||||
val sidebars = sidebarsLiveData.value?.sidebars
|
||||
val selectedPosition = selectedSidebarsPosition.value ?: 0
|
||||
val selectedCategoryName = sidebars?.getOrNull(selectedPosition)?.name ?: ""
|
||||
LogUtils.logCategoryV2ClickSideEvent(entrance, pageName, selectedCategoryName, selectedPosition)
|
||||
}
|
||||
|
||||
fun logClickClassification(primaryIndex: Int, categoryName: String, position: Int) {
|
||||
private fun logClickClassification(selected: SelectedTags) {
|
||||
LogUtils.logCategoryV2ClickClassificationEvent(
|
||||
entrance,
|
||||
categoryTitle,
|
||||
selectedCategoryName,
|
||||
directories[primaryIndex].name,
|
||||
categoryName,
|
||||
primaryIndex,
|
||||
position
|
||||
pageName,
|
||||
selectedSidebarsName,
|
||||
selected.parentName,
|
||||
selected.category.name ?: "",
|
||||
selected.parentPosition,
|
||||
selected.position
|
||||
)
|
||||
}
|
||||
|
||||
fun logClickClassificationDelete(primaryIndex: Int, categoryName: String, location: String) {
|
||||
private fun logClickClassificationDelete(directoryName: String, categoryName: String, location: String) {
|
||||
LogUtils.logCategoryV2ClickClassificationDeleteEvent(
|
||||
entrance,
|
||||
categoryTitle,
|
||||
directories[primaryIndex].name,
|
||||
pageName,
|
||||
directoryName,
|
||||
categoryName,
|
||||
location
|
||||
)
|
||||
}
|
||||
|
||||
fun logClickDetermine() {
|
||||
val categoryName = StringBuilder()
|
||||
selectedCategoryList.forEachIndexed { index, s ->
|
||||
categoryName.append(s.name)
|
||||
if (index != selectedCategoryList.size - 1) {
|
||||
categoryName.append("+")
|
||||
}
|
||||
}
|
||||
LogUtils.logCategoryV2ClickDetermineEvent(entrance, categoryTitle, categoryName.toString())
|
||||
val categoryNames = selectedSubCategories.value?.joinToString("+") { it.category.name ?: "" }
|
||||
LogUtils.logCategoryV2ClickDetermineEvent(entrance, pageName, categoryNames ?: "")
|
||||
}
|
||||
|
||||
fun logClickReset(location: String) {
|
||||
val categoryName = StringBuilder()
|
||||
selectedCategoryList.forEachIndexed { index, s ->
|
||||
categoryName.append(s.name)
|
||||
if (index != selectedCategoryList.size - 1) {
|
||||
categoryName.append("+")
|
||||
}
|
||||
}
|
||||
LogUtils.logCategoryV2ClickResetEvent(entrance, categoryTitle, categoryName.toString(), location)
|
||||
val categoryName = selectedSubCategories.value?.joinToString("+") { it.category.name ?: "" }
|
||||
LogUtils.logCategoryV2ClickResetEvent(entrance, pageName, categoryName ?: "", location)
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val categoryId: String,
|
||||
private val categoryTitle: String
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return CategoryV2ViewModel(
|
||||
HaloApp.getInstance().application,
|
||||
categoryId,
|
||||
categoryTitle
|
||||
) as T
|
||||
private val _notifySubCategorySelected = MutableLiveData<Event<String>>()
|
||||
val notifySubCategorySelected: LiveData<Event<String>> = _notifySubCategorySelected
|
||||
|
||||
private val _selectedSubCategories = MutableLiveData<List<SelectedTags>>()
|
||||
val selectedSubCategories: LiveData<List<SelectedTags>> = _selectedSubCategories
|
||||
fun addSubCategorySelected(selected: SelectedTags) {
|
||||
val list = _selectedSubCategories.value
|
||||
val newData = if (list == null) {
|
||||
mutableListOf(selected)
|
||||
} else {
|
||||
list + selected
|
||||
}
|
||||
selected.category.selected = true
|
||||
_selectedSubCategories.value = newData
|
||||
|
||||
// 当搜索条件发生变化时,侧边栏默认选中 “全部”
|
||||
selectSidebarsPosition(0, false)
|
||||
|
||||
updateGameFiltered()
|
||||
_notifySubCategorySelected.value = Event(selected.parentId)
|
||||
logClickClassification(selected)
|
||||
}
|
||||
|
||||
fun removeSubCategorySelected(parentId: String, categoryId: String, location: String) {
|
||||
val list = _selectedSubCategories.value ?: return
|
||||
val position = list.indexOfFirst {
|
||||
it.parentId == parentId && categoryId == it.category.id
|
||||
}
|
||||
if (position != -1) {
|
||||
val item = list[position]
|
||||
|
||||
item.category.selected = false
|
||||
_selectedSubCategories.value = list - item
|
||||
|
||||
updateGameFiltered()
|
||||
_notifySubCategorySelected.value = Event(parentId)
|
||||
|
||||
logClickClassificationDelete(item.parentName, item.category.name ?: "", location)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val _selectedSidebarsPosition = MutableLiveData<Int>()
|
||||
val selectedSidebarsPosition: LiveData<Int> = _selectedSidebarsPosition
|
||||
val selectedSidebarsName: String
|
||||
get() = sidebarsLiveData.value?.sidebars?.getOrNull(selectedSidebarsPosition.value ?: 0)?.name ?: ""
|
||||
|
||||
fun selectSidebarsPosition(position: Int, triggerSearch: Boolean = true) {
|
||||
val oldPosition = _selectedSidebarsPosition.value ?: INVALID_POSITION
|
||||
if (position != oldPosition) {
|
||||
_selectedSidebarsPosition.value = position
|
||||
// 如果是点击搜索而被动切换到 “全部” tab,则这里不需要更新筛选条件
|
||||
if (triggerSearch && position != 1) {
|
||||
updateGameFiltered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val _gameFiltered = MutableLiveData<GameFiltered>()
|
||||
val gameFiltered: LiveData<GameFiltered> = _gameFiltered
|
||||
fun updateGameFiltered(
|
||||
size: SubjectSettingEntity.Size? = null,
|
||||
sortType: CategoryFilterView.SortType? = null
|
||||
) {
|
||||
val oldFiltered = _gameFiltered.value
|
||||
val newSize = size ?: oldFiltered?.size ?: SubjectSettingEntity.Size()
|
||||
val newSortType = sortType ?: oldFiltered?.sortType ?: CategoryFilterView.SortType.RECOMMENDED
|
||||
val selectedSidebarPosition = selectedSidebarsPosition.value ?: 0
|
||||
val categoryIds = selectedSubCategories.value?.joinToString("-") { it.category.id } ?: ""
|
||||
val sidebarCategoryId =
|
||||
sidebarsLiveData.value?.sidebars?.getOrNull(selectedSidebarPosition)?.categoryId ?: "all"
|
||||
_gameFiltered.value = GameFiltered(newSize, newSortType, categoryIds, sidebarCategoryId)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val INVALID_POSITION = -1
|
||||
}
|
||||
|
||||
data class SelectedTags(
|
||||
val parentId: String,
|
||||
val parentName: String,
|
||||
val parentPosition: Int,
|
||||
val category: CategoryEntity,
|
||||
val position: Int
|
||||
)
|
||||
|
||||
data class GameFiltered(
|
||||
val size: SubjectSettingEntity.Size = SubjectSettingEntity.Size(),
|
||||
val sortType: CategoryFilterView.SortType = CategoryFilterView.SortType.RECOMMENDED,
|
||||
val categoryIds: String = "",
|
||||
val sidebarCategoryId: String = "全部"
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,292 @@
|
||||
package com.gh.gamecenter.category2
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.blankj.utilcode.util.KeyboardUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toResString
|
||||
import com.gh.gamecenter.common.view.BugFixedPopupWindow
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.PopSearchCategoryBinding
|
||||
import com.gh.gamecenter.entity.CategoryEntity
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import me.xdrop.fuzzywuzzy.FuzzySearch
|
||||
|
||||
class SearchCategoryPop(
|
||||
height: Int,
|
||||
private val isAutoRequestFocus: Boolean,
|
||||
private val pageId: String,
|
||||
private val pageName: String,
|
||||
private val binding: PopSearchCategoryBinding
|
||||
) : BugFixedPopupWindow(binding.root, ViewGroup.LayoutParams.MATCH_PARENT, height) {
|
||||
|
||||
private var listener: OnSearchCategoryListener? = null
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private var searchDataList: List<CategoryV2ViewModel.SelectedTags>? = null
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
private var isSearching = false
|
||||
|
||||
private val adapter by lazy {
|
||||
CategoryDirectoryAdapter(object : OnSearchCategoryListener {
|
||||
override fun isEnableSelected(): Boolean {
|
||||
return listener?.isEnableSelected() ?: false
|
||||
}
|
||||
|
||||
override fun onItemSelected(selected: CategoryV2ViewModel.SelectedTags) {
|
||||
listener?.onItemSelected(selected)
|
||||
|
||||
}
|
||||
|
||||
override fun onItemRemoved(parentId: String, subCategoryId: String) {
|
||||
listener?.onItemRemoved(parentId, subCategoryId)
|
||||
}
|
||||
|
||||
override fun onResetSelected() {
|
||||
listener?.onResetSelected()
|
||||
}
|
||||
|
||||
override fun onSubmit() {
|
||||
listener?.onSubmit()
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
private val resultAdapter by lazy {
|
||||
SearchCategoryResultsAdapter {
|
||||
SensorsBridge.logClassificationSearchReturnClick(
|
||||
pageId,
|
||||
pageName,
|
||||
binding.searchView.searchKey,
|
||||
it.category.name ?: ""
|
||||
)
|
||||
if (listener?.isEnableSelected() == true) {
|
||||
clearSearchKey()
|
||||
listener?.onItemSelected(it)
|
||||
} else {
|
||||
ToastUtils.toast(R.string.selected_category_tags_max_toast.toResString())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private val selectedTagAdapter by lazy {
|
||||
SelectedTagsAdapter {
|
||||
listener?.onItemRemoved(it.parentId, it.category.id)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
isOutsideTouchable = true
|
||||
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
isFocusable = true
|
||||
inputMethodMode = INPUT_METHOD_NEEDED
|
||||
softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
|
||||
|
||||
initView()
|
||||
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
binding.rvCategory.layoutManager = LinearLayoutManager(binding.root.context)
|
||||
binding.rvCategory.adapter = adapter
|
||||
|
||||
binding.tvSelectedNumber.typeface =
|
||||
Typeface.createFromAsset(binding.root.context.assets, Constants.DIN_FONT_PATH)
|
||||
|
||||
binding.root.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
binding.clContent.setOnClickListener {
|
||||
// 不需要具体实现,只是为了拦截 root 的点击事件
|
||||
}
|
||||
|
||||
binding.tvReset.setOnClickListener {
|
||||
listener?.onResetSelected()
|
||||
}
|
||||
|
||||
binding.vSubmit.setOnClickListener {
|
||||
dismiss()
|
||||
listener?.onSubmit()
|
||||
}
|
||||
|
||||
binding.searchView.addTextChangedListener {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
val key = it?.toString() ?: ""
|
||||
if (key.isEmpty()) {
|
||||
changeToSearching(false)
|
||||
} else {
|
||||
handler.postDelayed({
|
||||
search(it?.toString() ?: "")
|
||||
}, SEARCH_DELAY_DURATION)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAutoRequestFocus) {
|
||||
binding.searchView.setEditTextOnFocusChangeListener { _, hasFocus ->
|
||||
if (hasFocus) {
|
||||
SensorsBridge.logClassificationSearch(pageId, pageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setData(data: List<CategoryEntity>) {
|
||||
searchDataList = data
|
||||
.asSequence()
|
||||
.mapIndexed { index, parent ->
|
||||
parent.data?.mapIndexed { childIndex, child ->
|
||||
CategoryV2ViewModel.SelectedTags(parent.id, parent.name ?: "", index, child, childIndex)
|
||||
} ?: listOf()
|
||||
}
|
||||
.flatten()
|
||||
.toList()
|
||||
|
||||
adapter.setListData(data)
|
||||
}
|
||||
|
||||
fun updateCategorySelected(selectedList: List<CategoryV2ViewModel.SelectedTags>?) {
|
||||
val size = selectedList?.size ?: 0
|
||||
binding.tvSelectedNumber.goneIf(size == 0) {
|
||||
binding.tvSelectedNumber.text = "$size"
|
||||
}
|
||||
|
||||
if (binding.rvSelected.adapter == null) {
|
||||
binding.rvSelected.layoutManager =
|
||||
LinearLayoutManager(binding.root.context, RecyclerView.HORIZONTAL, false)
|
||||
binding.rvSelected.adapter = selectedTagAdapter
|
||||
}
|
||||
selectedTagAdapter.submitList(selectedList)
|
||||
binding.rvSelected.goneIf(selectedList.isNullOrEmpty())
|
||||
|
||||
if (isSearching) {
|
||||
search(binding.searchView.searchKey)
|
||||
}
|
||||
}
|
||||
|
||||
private fun search(key: String) {
|
||||
Single.create {
|
||||
val data = searchDataList?.filterNot { item -> item.category.selected } ?: emptyList()
|
||||
val resultList = FuzzySearch.extractSorted(key, data, { item -> item.category.name ?: "" }, 1)
|
||||
.map { item -> item.referent }
|
||||
it.onSuccess(resultList)
|
||||
}.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<List<CategoryV2ViewModel.SelectedTags>>() {
|
||||
override fun onSuccess(data: List<CategoryV2ViewModel.SelectedTags>) {
|
||||
val hasResult = data.isNotEmpty()
|
||||
SensorsBridge.logClassificationSearchReturn(pageId, pageName, key, hasResult)
|
||||
changeToSearching(true, key, data)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
SensorsBridge.logClassificationSearchReturn(pageId, pageName, key, false)
|
||||
changeToSearching(true, key)
|
||||
}
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private fun clearSearchKey() {
|
||||
binding.searchView.clear()
|
||||
}
|
||||
|
||||
private fun changeToSearching(
|
||||
isSearching: Boolean,
|
||||
key: String = "",
|
||||
results: List<CategoryV2ViewModel.SelectedTags>? = null
|
||||
) {
|
||||
this.isSearching = isSearching
|
||||
binding.rvCategory.goneIf(isSearching)
|
||||
binding.rvResults.goneIf(results.isNullOrEmpty()) {
|
||||
if (binding.rvResults.adapter == null) {
|
||||
binding.rvResults.layoutManager = LinearLayoutManager(binding.rvResults.context)
|
||||
binding.rvResults.adapter = resultAdapter
|
||||
}
|
||||
}
|
||||
resultAdapter.setData(results ?: listOf(), key)
|
||||
binding.reuseNoConnection.root.goneIf(!isSearching || !results.isNullOrEmpty()) {
|
||||
binding.reuseNoConnection.reuseNoneDataTv.text = R.string.no_relevant_content_found.toResString()
|
||||
binding.reuseNoConnection.reuseNoneDataDescTv.goneIf(false)
|
||||
binding.reuseNoConnection.reuseNoneDataDescTv.text = R.string.try_a_different_search_term.toResString()
|
||||
}
|
||||
}
|
||||
|
||||
fun setOnSearchCategoryListener(listener: OnSearchCategoryListener) {
|
||||
this.listener = listener
|
||||
}
|
||||
|
||||
fun notifyItemSelectedChanged(parentId: String) {
|
||||
adapter.notifyItemSelectedChanged(parentId)
|
||||
}
|
||||
|
||||
override fun showAtLocation(parent: View?, gravity: Int, x: Int, y: Int) {
|
||||
super.showAtLocation(parent, gravity, x, y)
|
||||
if (isAutoRequestFocus) {
|
||||
binding.searchView.requestFocus()
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
// 在某些机型上延时一下才能弹起软键盘
|
||||
handler.postDelayed({
|
||||
KeyboardUtils.showSoftInput()
|
||||
}, SHOW_SOFT_INPUT_DELAY)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
super.dismiss()
|
||||
clearSearchKey()
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
private const val SEARCH_DELAY_DURATION = 300L
|
||||
private const val SHOW_SOFT_INPUT_DELAY = 200L
|
||||
|
||||
fun newInstance(
|
||||
context: Context,
|
||||
height: Int,
|
||||
isAutoRequestFocus: Boolean,
|
||||
pageId: String,
|
||||
pageName: String
|
||||
): SearchCategoryPop {
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val binding = PopSearchCategoryBinding.inflate(inflater)
|
||||
return SearchCategoryPop(height, isAutoRequestFocus, pageId, pageName, binding)
|
||||
}
|
||||
}
|
||||
|
||||
interface OnSearchCategoryListener {
|
||||
|
||||
fun isEnableSelected(): Boolean
|
||||
|
||||
fun onItemSelected(selected: CategoryV2ViewModel.SelectedTags)
|
||||
|
||||
fun onItemRemoved(parentId: String, subCategoryId: String)
|
||||
|
||||
fun onResetSelected()
|
||||
|
||||
fun onSubmit()
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package com.gh.gamecenter.category2
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.databinding.RecyclerSearchCategoryResultBinding
|
||||
|
||||
class SearchCategoryResultsAdapter(val clickListener: (CategoryV2ViewModel.SelectedTags) -> Unit) :
|
||||
RecyclerView.Adapter<SearchCategoryResultsAdapter.ResultViewHolder>() {
|
||||
private val dataList = arrayListOf<CategoryV2ViewModel.SelectedTags>()
|
||||
private var key = ""
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun setData(data: List<CategoryV2ViewModel.SelectedTags>, newKey: String) {
|
||||
key = newKey
|
||||
dataList.clear()
|
||||
dataList.addAll(data)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ResultViewHolder {
|
||||
return ResultViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun getItemCount() = dataList.size
|
||||
|
||||
override fun onBindViewHolder(holder: ResultViewHolder, position: Int) {
|
||||
val item = dataList[position]
|
||||
val text = item.category.name ?: ""
|
||||
val spannableString = SpannableString(text)
|
||||
val highlightColor = com.gh.gamecenter.common.R.color.text_theme.toColor(holder.itemView.context)
|
||||
text.forEachIndexed { index, char ->
|
||||
if (key.contains(char)) {
|
||||
// 需要高亮
|
||||
spannableString.setSpan(
|
||||
ForegroundColorSpan(highlightColor),
|
||||
index,
|
||||
index + 1,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
}
|
||||
}
|
||||
holder.binding.root.text = spannableString
|
||||
holder.itemView.setOnClickListener {
|
||||
clickListener(item)
|
||||
}
|
||||
}
|
||||
|
||||
class ResultViewHolder(val binding: RecyclerSearchCategoryResultBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.gh.gamecenter.category2
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.databinding.RecyclerCategorySelectedTagBinding
|
||||
|
||||
class SelectedTagsAdapter(val click: (CategoryV2ViewModel.SelectedTags) -> Unit) :
|
||||
ListAdapter<CategoryV2ViewModel.SelectedTags, SelectedTagsAdapter.TagsViewHolder>(
|
||||
createDiffUtil()
|
||||
) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TagsViewHolder {
|
||||
return TagsViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TagsViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
holder.binding.root.setText(item.category.name ?: "")
|
||||
holder.itemView.setOnClickListener {
|
||||
click(item)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun createDiffUtil() = object : DiffUtil.ItemCallback<CategoryV2ViewModel.SelectedTags>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: CategoryV2ViewModel.SelectedTags,
|
||||
newItem: CategoryV2ViewModel.SelectedTags
|
||||
): Boolean {
|
||||
return oldItem.category.id == newItem.category.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: CategoryV2ViewModel.SelectedTags,
|
||||
newItem: CategoryV2ViewModel.SelectedTags
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class TagsViewHolder(val binding: RecyclerCategorySelectedTagBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
}
|
||||
@ -1,84 +1,94 @@
|
||||
package com.gh.gamecenter.category2
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.ViewGroup
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.SubCategoryItemBinding
|
||||
import com.gh.gamecenter.entity.CategoryEntity
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
|
||||
class SubCategoryAdapter(
|
||||
context: Context,
|
||||
private val mViewModel: CategoryV2ViewModel,
|
||||
private val mList: List<CategoryEntity>,
|
||||
private val mPrimaryIndex: Int
|
||||
) : BaseRecyclerAdapter<SubCategoryAdapter.SubCategoryItemViewHolder>(context) {
|
||||
private val listener: SearchCategoryPop.OnSearchCategoryListener,
|
||||
) : RecyclerView.Adapter<SubCategoryAdapter.SubCategoryItemViewHolder>() {
|
||||
|
||||
override fun getItemCount() = mList.size
|
||||
private lateinit var itemData: CategoryEntity
|
||||
private val data: List<CategoryEntity>
|
||||
get() = itemData.data ?: emptyList()
|
||||
|
||||
private var directoryPosition = 0
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun setData(directoryPosition: Int, newItem: CategoryEntity) {
|
||||
this.directoryPosition = directoryPosition
|
||||
itemData = newItem
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun getItemCount() = data.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||
SubCategoryItemViewHolder(SubCategoryItemBinding.inflate(mLayoutInflater))
|
||||
SubCategoryItemViewHolder(parent.toBinding())
|
||||
|
||||
override fun onBindViewHolder(holder: SubCategoryItemViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
if (payloads.isEmpty()) {
|
||||
super.onBindViewHolder(holder, position, payloads)
|
||||
} else {
|
||||
val item = data[position]
|
||||
updateSelectedState(item.selected, holder.binding)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SubCategoryItemViewHolder, position: Int) {
|
||||
holder.binding.run {
|
||||
val categoryEntity = mList[position]
|
||||
name.text = categoryEntity.name
|
||||
val categoryEntity = data[position]
|
||||
tvName.text = categoryEntity.name
|
||||
recommendIv.goneIf(categoryEntity.recommend == false)
|
||||
|
||||
if (categoryEntity.selected) {
|
||||
selectedIv.visibility = View.VISIBLE
|
||||
container.background = R.drawable.bg_category_selected.toDrawable(mContext)
|
||||
name.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(mContext))
|
||||
} else {
|
||||
selectedIv.visibility = View.GONE
|
||||
container.background = com.gh.gamecenter.common.R.drawable.bg_shape_space_radius_8.toDrawable(mContext)
|
||||
name.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
}
|
||||
updateSelectedState(categoryEntity.selected, this)
|
||||
|
||||
root.setOnClickListener {
|
||||
when {
|
||||
mViewModel.selectedCount >= 5 && !categoryEntity.selected -> ToastUtils.toast("最多只能选择5个类别")
|
||||
!categoryEntity.selected && !listener.isEnableSelected() -> {
|
||||
ToastUtils.toast(R.string.selected_category_tags_max_toast.toResString())
|
||||
}
|
||||
|
||||
categoryEntity.selected -> {
|
||||
categoryEntity.selected = false
|
||||
selectedIv.visibility = View.GONE
|
||||
container.background = com.gh.gamecenter.common.R.drawable.bg_shape_space_radius_8.toDrawable(mContext)
|
||||
name.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
mViewModel.run {
|
||||
if (selectedCount > 0) {
|
||||
selectedCount--
|
||||
postSelectedCount()
|
||||
postCategoryPosition(mPrimaryIndex, position)
|
||||
logClickClassificationDelete(mPrimaryIndex, categoryEntity.name ?: "", "全部类别")
|
||||
}
|
||||
}
|
||||
|
||||
listener.onItemRemoved(itemData.id, categoryEntity.id)
|
||||
}
|
||||
|
||||
!categoryEntity.selected -> {
|
||||
categoryEntity.selected = true
|
||||
categoryEntity.primaryIndex = mPrimaryIndex
|
||||
selectedIv.visibility = View.VISIBLE
|
||||
container.background = R.drawable.bg_category_selected.toDrawable(mContext)
|
||||
name.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(mContext))
|
||||
mViewModel.run {
|
||||
if (selectedCount < 5) {
|
||||
selectedCount++
|
||||
logClickClassification(mPrimaryIndex, categoryEntity.name ?: "", position)
|
||||
postSelectedCount()
|
||||
postCategoryPosition(mPrimaryIndex, position)
|
||||
}
|
||||
}
|
||||
|
||||
listener.onItemSelected(
|
||||
CategoryV2ViewModel.SelectedTags(
|
||||
itemData.id,
|
||||
itemData.name ?: "",
|
||||
directoryPosition,
|
||||
categoryEntity,
|
||||
position
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SubCategoryItemViewHolder(val binding: SubCategoryItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
|
||||
private fun updateSelectedState(isSelected: Boolean, binding: SubCategoryItemBinding) {
|
||||
with(binding) {
|
||||
val context = root.context
|
||||
if (isSelected) {
|
||||
container.background = R.drawable.bg_category_selected.toDrawable(context)
|
||||
tvName.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
} else {
|
||||
container.background = com.gh.gamecenter.common.R.drawable.bg_shape_space_radius_8.toDrawable(context)
|
||||
tvName.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SubCategoryItemViewHolder(val binding: SubCategoryItemBinding) : ViewHolder(binding.root)
|
||||
}
|
||||
@ -2,16 +2,22 @@ package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class CategoryEntity(
|
||||
@SerializedName("_id")
|
||||
var id: String? = "",
|
||||
private var _id: String? = null,
|
||||
var icon: String? = "",
|
||||
var name: String? = "",
|
||||
var recommend: Boolean? = false,
|
||||
var data: List<CategoryEntity>? = null,
|
||||
var selected: Boolean = false,
|
||||
var primaryIndex: Int = -1
|
||||
) : Parcelable
|
||||
var data: List<CategoryEntity>? = null
|
||||
) : Parcelable {
|
||||
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
@IgnoredOnParcel
|
||||
var selected: Boolean = false
|
||||
}
|
||||
@ -7,5 +7,8 @@ class GameColumnCollection(
|
||||
val id: String = "",
|
||||
val name: String = "",
|
||||
// 取值为 "1-1" 或 "1-2" 或 "top" 相应地代表 1行1个 或 1行2个 或 排行榜
|
||||
val style: String = ""
|
||||
val style: String = "",
|
||||
val custom: Boolean = false, // 自定义设置
|
||||
@SerializedName("custom_size")
|
||||
val customSize: Int = 0 // 默认显示前X个专题
|
||||
)
|
||||
@ -7,7 +7,7 @@ import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class SubjectData(
|
||||
data class SubjectData(
|
||||
// 入口必填
|
||||
var subjectId: String?,
|
||||
var subjectName: String?,
|
||||
@ -21,13 +21,28 @@ class SubjectData(
|
||||
var subjectStyle: String = "",
|
||||
var showDetailSubtitle: Boolean = false,
|
||||
var showDetailIconSubscript: Boolean = false,
|
||||
var customLimit: String = "", // unlimited(无限制)、forbidden(禁止移出)
|
||||
|
||||
var requireUpdateSetting: Boolean = false, // 多专题页面需要专题页面自行获取专题配置
|
||||
var isAdData: Boolean = false,
|
||||
var adId: String = "", // 广告ID(本地字段),不为空时为广告专题
|
||||
var codeId: String = "" // 广告CODE_ID(本地字段),不为空时为广告专题
|
||||
var codeId: String = "", // 广告CODE_ID(本地字段),不为空时为广告专题
|
||||
var tag: String = "" // 分类标签,埋点用
|
||||
) : Parcelable, Cloneable {
|
||||
|
||||
@IgnoredOnParcel
|
||||
val isForbidden
|
||||
get() = customLimit == "forbidden"
|
||||
|
||||
@IgnoredOnParcel
|
||||
val sortChinese
|
||||
get() = when {
|
||||
sort.contains("publish") -> "最新"
|
||||
sort.contains("star") -> "评分"
|
||||
sort.contains("update") -> "更新"
|
||||
else -> "推荐"
|
||||
}
|
||||
|
||||
@IgnoredOnParcel
|
||||
val subjectStyleChinese: String
|
||||
get() = CustomPageItem.subjectTypeToComponentStyle[subjectStyle] ?: ""
|
||||
|
||||
@ -13,7 +13,7 @@ class SubjectSettingEntity(
|
||||
@SerializedName("type")
|
||||
var typeEntity: TypeEntity = TypeEntity(),
|
||||
var tag: String = "",
|
||||
var filter: String = "", // rows: off/on
|
||||
var filter: String = "", // off/on
|
||||
var order: Boolean = false, // 是否显示序号
|
||||
|
||||
@SerializedName("brief_style")
|
||||
@ -34,6 +34,9 @@ class SubjectSettingEntity(
|
||||
private val _showDetailIconSubscript: Boolean? = null
|
||||
) : Parcelable {
|
||||
|
||||
val isFilterEnabled: Boolean
|
||||
get() = filter == "on"
|
||||
|
||||
val showDetailSubtitle: Boolean
|
||||
get() = _showDetailSubtitle ?: false
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ package com.gh.gamecenter.game.columncollection.detail
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.core.view.isVisible
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.baselist.LazyListFragment
|
||||
@ -14,6 +14,8 @@ import com.gh.gamecenter.common.json.json
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.observeNonNull
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.databinding.FragmentColumnCollectionDetailBinding
|
||||
import com.gh.gamecenter.entity.GameColumnCollection
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
@ -23,6 +25,7 @@ class ColumnCollectionDetailFragment : LazyListFragment<LinkEntity, ColumnCollec
|
||||
|
||||
private var mAdapter: ColumnCollectionDetailAdapter? = null
|
||||
private var mBinding: FragmentColumnCollectionDetailBinding? = null
|
||||
private var mFragment: SubjectTabFragment? = null
|
||||
|
||||
private var mTabIndex = -1
|
||||
private var mBasicExposureSourceList: ArrayList<ExposureSource>? = null
|
||||
@ -56,6 +59,11 @@ class ColumnCollectionDetailFragment : LazyListFragment<LinkEntity, ColumnCollec
|
||||
override fun onFragmentFirstVisible() {
|
||||
super.onFragmentFirstVisible()
|
||||
|
||||
if (mIsFromMainWrapper) {
|
||||
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn)
|
||||
mBinding?.statusBar?.isVisible = true
|
||||
}
|
||||
|
||||
mListViewModel.getGameColumnCollection()
|
||||
mListViewModel.columnCollection.observeNonNull(this) {
|
||||
setNavigationTitle(it.name)
|
||||
@ -91,7 +99,7 @@ class ColumnCollectionDetailFragment : LazyListFragment<LinkEntity, ColumnCollec
|
||||
}
|
||||
|
||||
override fun onChanged(list: MutableList<LinkEntity>?) {
|
||||
if (list != null && list.isNotEmpty()) {
|
||||
if (!list.isNullOrEmpty()) {
|
||||
showSubjectTab(list)
|
||||
}
|
||||
}
|
||||
@ -115,25 +123,28 @@ class ColumnCollectionDetailFragment : LazyListFragment<LinkEntity, ColumnCollec
|
||||
isOrder = false,
|
||||
requireUpdateSetting = true,
|
||||
filter = "type:全部", // 默认显示大图
|
||||
subjectType = subjectType
|
||||
subjectType = subjectType,
|
||||
customLimit = link.customLimit
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val fragment = childFragmentManager.findFragmentByTag(SubjectTabFragment::class.java.name)
|
||||
mFragment = childFragmentManager.findFragmentByTag(SubjectTabFragment::class.java.name) as? SubjectTabFragment
|
||||
?: SubjectTabFragment()
|
||||
val bundle = arguments
|
||||
mListViewModel.columnCollection.value?.let {
|
||||
bundle?.putString(EntranceConsts.KEY_COLUMN_COLLECTION_ID, it.id)
|
||||
bundle?.putString(EntranceConsts.KEY_COLUMN_COLLECTION_NAME, it.name)
|
||||
bundle?.putString(EntranceConsts.KEY_COLUMN_COLLECTION_STYLE, it.style)
|
||||
bundle?.putBoolean(EntranceConsts.KEY_COLUMN_COLLECTION_CUSTOM, it.custom)
|
||||
bundle?.putInt(EntranceConsts.KEY_COLUMN_COLLECTION_CUSTOM_SIZE, it.customSize)
|
||||
}
|
||||
bundle?.putParcelableArrayList(EntranceConsts.KEY_DATA, subjectDataList)
|
||||
bundle?.putBoolean(EntranceConsts.KEY_IS_COLUMN_COLLECTION, true)
|
||||
|
||||
fragment.arguments = bundle
|
||||
mFragment!!.arguments = bundle
|
||||
mBinding?.placeholder?.visibility = View.VISIBLE
|
||||
childFragmentManager.beginTransaction().replace(R.id.placeholder, fragment, SubjectTabFragment::class.java.name)
|
||||
childFragmentManager.beginTransaction().replace(R.id.placeholder, mFragment!!, SubjectTabFragment::class.java.name)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
|
||||
@ -167,9 +178,18 @@ class ColumnCollectionDetailFragment : LazyListFragment<LinkEntity, ColumnCollec
|
||||
arguments?.getString(EntranceConsts.KEY_COLLECTION_ID)
|
||||
?: ""
|
||||
)
|
||||
return ViewModelProviders.of(this, factory).get(ColumnCollectionDetailViewModel::class.java)
|
||||
return viewModelProviderFromParent(factory, arguments?.getString(EntranceConsts.KEY_COLLECTION_ID) ?: "")
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
if (mIsFromMainWrapper) {
|
||||
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean = mFragment?.onBackPressed() ?: false
|
||||
|
||||
companion object {
|
||||
const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column"
|
||||
const val TYPE_WECHAT_MINI_GAME_COLUMN = "wechat_mini_game_column"
|
||||
|
||||
@ -30,7 +30,9 @@ import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.CustomLinkMovementMethod
|
||||
import com.gh.gamecenter.common.view.DrawableView
|
||||
import com.gh.gamecenter.core.utils.*
|
||||
import com.gh.gamecenter.core.utils.CenterImageSpan
|
||||
import com.gh.gamecenter.core.utils.NumberUtils
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.databinding.RatingCommentItemBinding
|
||||
import com.gh.gamecenter.entity.RatingComment
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
@ -249,7 +251,7 @@ class RatingCommentItemViewHolder(val binding: RatingCommentItemBinding, val pat
|
||||
if (game.getApk().size > 0 && game.getApk()[0].version == commentData.gameVersion) {
|
||||
version.text = "当前版本"
|
||||
} else {
|
||||
version.text = ("版本:" + commentData.gameVersion)
|
||||
version.text = commentData.gameVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import android.text.Spanned
|
||||
import android.text.TextPaint
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
@ -15,6 +16,7 @@ import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
@ -27,7 +29,8 @@ import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.DrawableView
|
||||
import com.gh.gamecenter.core.utils.*
|
||||
import com.gh.gamecenter.core.utils.NumberUtils
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.databinding.ItemArticleDetailCommentBinding
|
||||
import com.gh.gamecenter.entity.RatingComment
|
||||
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
|
||||
@ -165,7 +168,36 @@ class RatingDetailCommentItemViewHolder(val binding: ItemArticleDetailCommentBin
|
||||
if (game != null && game.getApk().size > 0 && game.getApk()[0].version == commentData.gameVersion) {
|
||||
version.text = "当前版本"
|
||||
} else {
|
||||
version.text = ("版本:" + commentData.gameVersion)
|
||||
version.text = commentData.gameVersion
|
||||
}
|
||||
version.buttonDrawable = R.drawable.ic_version.toDrawable(context)
|
||||
version.post {
|
||||
ConstraintSet().apply {
|
||||
clone(bottomContainer)
|
||||
if ((version.layout?.lineCount ?: 1) > 1) {
|
||||
version.gravity = Gravity.TOP
|
||||
connect(version.id, ConstraintSet.START, device.id, ConstraintSet.START)
|
||||
connect(version.id, ConstraintSet.TOP, device.id, ConstraintSet.BOTTOM, 6F.dip2px())
|
||||
connect(version.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 16F.dip2px())
|
||||
connect(device.id, ConstraintSet.BOTTOM, version.id, ConstraintSet.TOP)
|
||||
connect(device.id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 16F.dip2px())
|
||||
clear(device.id, ConstraintSet.END)
|
||||
clear(likeCountTv.id, ConstraintSet.TOP)
|
||||
connect(likeCountTv.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 4F.dip2px())
|
||||
bottomContainer.updateLayoutParams<ConstraintLayout.LayoutParams> { height = ConstraintLayout.LayoutParams.WRAP_CONTENT }
|
||||
} else {
|
||||
version.gravity = Gravity.CENTER_VERTICAL
|
||||
connect(version.id, ConstraintSet.START, device.id, ConstraintSet.END)
|
||||
connect(version.id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 0)
|
||||
connect(version.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 0)
|
||||
connect(device.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM)
|
||||
connect(device.id, ConstraintSet.END, version.id, ConstraintSet.START)
|
||||
connect(device.id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 0)
|
||||
connect(likeCountTv.id, ConstraintSet.TOP, timeTv.id, ConstraintSet.TOP, 0)
|
||||
connect(likeCountTv.id, ConstraintSet.BOTTOM, timeTv.id, ConstraintSet.BOTTOM, 0)
|
||||
bottomContainer.updateLayoutParams<ConstraintLayout.LayoutParams> { height = 48F.dip2px() }
|
||||
}
|
||||
}.applyTo(bottomContainer)
|
||||
}
|
||||
|
||||
if (commentData.me.isCommented) {
|
||||
|
||||
@ -42,6 +42,7 @@ class SubjectAdapter(
|
||||
private val mSubjectViewModel: SubjectViewModel?,
|
||||
private val mEntrance: String?,
|
||||
private val mIsColumnCollection: Boolean,
|
||||
private val mColumnCollectionCustomPosition: Int = -1,
|
||||
private val mCollectionId: String,
|
||||
private val mCollectionName: String,
|
||||
private val mCollectionStyle: String
|
||||
@ -217,9 +218,10 @@ class SubjectAdapter(
|
||||
|
||||
mSubjectViewModel?.subjectSettingLD?.value?.let { subjectSetting ->
|
||||
subjectStyle = subjectSetting.typeEntity.layout
|
||||
isFilterOn = subjectSetting.filter == "on"
|
||||
isFilterOn = subjectSetting.isFilterEnabled
|
||||
}
|
||||
|
||||
gameEntity.sequence = position
|
||||
val exposureEvent = generateExposureEvent(gameEntity, subjectStyle, isFilterOn)
|
||||
val humanReadablePosition = position + 1
|
||||
mExposureEventSparseArray.put(position, exposureEvent)
|
||||
@ -266,7 +268,10 @@ class SubjectAdapter(
|
||||
gameColumnName = subjectData.subjectName ?: "",
|
||||
gameId = gameEntity.id,
|
||||
gameName = gameEntity.name ?: "",
|
||||
text = "游戏"
|
||||
text = "游戏",
|
||||
gameTag = mViewModel.selectedLabelList.ifEmpty { listOf(mViewModel.subjectData.tag) },
|
||||
sort = mViewModel.subjectData.sortChinese,
|
||||
inclusionSize = mViewModel.selectedFilterSize.text ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -326,7 +331,10 @@ class SubjectAdapter(
|
||||
gameColumnName = subjectData.subjectName ?: "",
|
||||
gameId = gameEntity.id,
|
||||
gameName = gameEntity.name ?: "",
|
||||
text = "按钮"
|
||||
text = "按钮",
|
||||
gameTag = mViewModel.selectedLabelList.ifEmpty { listOf(mViewModel.subjectData.tag) },
|
||||
sort = mViewModel.subjectData.sortChinese,
|
||||
inclusionSize = mViewModel.selectedFilterSize.text ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
@ -446,7 +454,10 @@ class SubjectAdapter(
|
||||
linkId = linkEntity.link ?: "",
|
||||
linkText = linkEntity.text ?: "",
|
||||
linkType = linkEntity.type ?: "",
|
||||
text = "头图"
|
||||
text = "头图",
|
||||
gameTag = mViewModel.selectedLabelList.ifEmpty { listOf(mViewModel.subjectData.tag) },
|
||||
sort = mViewModel.subjectData.sortChinese,
|
||||
inclusionSize = mViewModel.selectedFilterSize.text ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -471,13 +482,12 @@ class SubjectAdapter(
|
||||
"$mCollectionName+${CustomPageItem.collectionTypeToComponentName[mCollectionStyle] ?: mCollectionStyle}+$mCollectionId"
|
||||
)
|
||||
)
|
||||
exposureSourceList.add(ExposureSource("合集详情"))
|
||||
exposureSourceList.add(
|
||||
ExposureSource(
|
||||
"专题",
|
||||
"${subjectData.subjectName}+${subjectData.subjectStyleChinese}+${subjectData.subjectId}"
|
||||
)
|
||||
)
|
||||
exposureSourceList.add(ExposureSource(if (mColumnCollectionCustomPosition == -1) "合集详情" else "自定义合集详情"))
|
||||
var value = "${subjectData.subjectName}+${subjectData.subjectStyleChinese}+${subjectData.subjectId}"
|
||||
if (mColumnCollectionCustomPosition != -1) {
|
||||
value += "+${mColumnCollectionCustomPosition}"
|
||||
}
|
||||
exposureSourceList.add(ExposureSource("专题", value))
|
||||
} else {
|
||||
var sourceString = ""
|
||||
exposureSourceList.add(
|
||||
@ -493,12 +503,7 @@ class SubjectAdapter(
|
||||
sourceString = filter
|
||||
|
||||
if (isFilterOn) {
|
||||
val sort = when {
|
||||
subjectData.sort.contains("publish") -> "最新"
|
||||
subjectData.sort.contains("star") -> "评分"
|
||||
else -> "最热"
|
||||
}
|
||||
|
||||
val sort = subjectData.sortChinese
|
||||
val filterSize = mViewModel.selectedFilterSize.text
|
||||
|
||||
sourceString =
|
||||
@ -516,12 +521,7 @@ class SubjectAdapter(
|
||||
}
|
||||
|
||||
if (isFilterOn) {
|
||||
val sort = when {
|
||||
subjectData.sort.contains("publish") -> "最新"
|
||||
subjectData.sort.contains("star") -> "评分"
|
||||
else -> "推荐"
|
||||
}
|
||||
|
||||
val sort = subjectData.sortChinese
|
||||
val filterSize = mViewModel.selectedFilterSize.text
|
||||
|
||||
sourceString =
|
||||
@ -532,12 +532,7 @@ class SubjectAdapter(
|
||||
}
|
||||
|
||||
else -> {
|
||||
val sort = when {
|
||||
subjectData.sort.contains("publish") -> "最新"
|
||||
subjectData.sort.contains("star") -> "评分"
|
||||
else -> "推荐"
|
||||
}
|
||||
|
||||
val sort = subjectData.sortChinese
|
||||
val filterSize = mViewModel.selectedFilterSize.text
|
||||
|
||||
if (isFilterOn) {
|
||||
|
||||
@ -125,7 +125,7 @@ open class SubjectFragment : LazyFragment() {
|
||||
}
|
||||
val bundle = arguments
|
||||
bundle?.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, mViewModel?.subjectData)
|
||||
bundle?.putParcelable(SubjectSettingEntity::class.java.simpleName, entity)
|
||||
bundle?.putParcelable(EntranceConsts.KEY_SUBJECT_SETTING_DATA, entity)
|
||||
fragment.arguments = bundle
|
||||
transaction.replace(R.id.subject_content, fragment, tag)
|
||||
transaction.commitAllowingStateLoss()
|
||||
|
||||
@ -6,6 +6,8 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
import com.gh.common.exposure.ExposureListener
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.view.ConfigFilterView
|
||||
import com.gh.common.view.ConfigFilterView.SortType
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.common.xapk.XapkUnzipStatus
|
||||
import com.gh.download.DownloadManager
|
||||
@ -14,10 +16,12 @@ import com.gh.gamecenter.common.baselist.LazyListFragment
|
||||
import com.gh.gamecenter.common.baselist.LoadType
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
|
||||
import com.gh.gamecenter.common.view.SpacingItemDecoration
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
@ -43,6 +47,8 @@ open class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewMod
|
||||
private var mCollectionName = ""
|
||||
private var mCollectionStyle = ""
|
||||
private var mScrollTop = false
|
||||
private var mMaxSize = ""
|
||||
private var mMinSize = ""
|
||||
|
||||
var selectedLabelList = arrayListOf<String>()
|
||||
|
||||
@ -78,6 +84,7 @@ open class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewMod
|
||||
mSubjectViewModel,
|
||||
arguments?.getString(EntranceConsts.KEY_ENTRANCE),
|
||||
mIsColumnCollection,
|
||||
arguments?.getInt(EntranceConsts.KEY_COLUMN_COLLECTION_CUSTOM_POSITION, -1) ?: -1,
|
||||
mCollectionId,
|
||||
mCollectionName,
|
||||
mCollectionStyle
|
||||
@ -119,10 +126,14 @@ open class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewMod
|
||||
mCollectionName = arguments?.getString(EntranceConsts.KEY_COLUMN_COLLECTION_NAME, "") ?: ""
|
||||
mCollectionStyle = arguments?.getString(EntranceConsts.KEY_COLUMN_COLLECTION_STYLE, "") ?: ""
|
||||
super.onFragmentFirstVisible()
|
||||
(mListViewModel as SubjectListViewModel).lastPageDataMap =
|
||||
arguments?.get(SubjectFragment.LAST_PAGE_DATA) as? HashMap<String, String>
|
||||
(mListViewModel as SubjectListViewModel).run {
|
||||
lastPageDataMap =
|
||||
arguments?.get(SubjectFragment.LAST_PAGE_DATA) as? HashMap<String, String>
|
||||
arguments?.getString(EntranceConsts.KEY_SUBJECT_SORT_SIZE)?.let { selectedFilterSize = SubjectSettingEntity.Size(text = it) }
|
||||
}
|
||||
|
||||
mCachedView?.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
|
||||
initFilterView()
|
||||
val skeletonLayoutId = when (arguments?.getString(EntranceConsts.KEY_SUBJECT_TYPE) ?: "") {
|
||||
"detail" -> R.layout.fragment_subject_detail_skeleton
|
||||
"tab" -> R.layout.fragment_subject_tab_skeleton
|
||||
@ -140,7 +151,62 @@ open class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewMod
|
||||
mListViewModel.load(LoadType.REFRESH)
|
||||
}
|
||||
|
||||
override fun getRealLayoutId() = R.layout.fragment_list_base_skeleton
|
||||
private fun initFilterView() {
|
||||
val subjectSetting= arguments?.getParcelable<SubjectSettingEntity>(EntranceConsts.KEY_SUBJECT_SETTING_DATA) ?: return
|
||||
val originalFilter = mListViewModel.subjectData.filter
|
||||
mCachedView?.findViewById<ConfigFilterView>(R.id.filterView)?.run {
|
||||
goneIf(!subjectSetting.isFilterEnabled) {
|
||||
initSubjectFilterView(subjectSetting)
|
||||
when (updateTv.text) {
|
||||
"更新" -> mListViewModel.subjectData.sort = UrlFilterUtils.getFilterQuery("update_time", "-1")
|
||||
"最新" -> mListViewModel.subjectData.sort = UrlFilterUtils.getFilterQuery("publish", "-1")
|
||||
"评分" -> mListViewModel.subjectData.sort = UrlFilterUtils.getFilterQuery("star", "-1")
|
||||
else -> mListViewModel.subjectData.sort = UrlFilterUtils.getFilterQuery("position", "1")
|
||||
}
|
||||
setOnConfigSetupListener(object :
|
||||
ConfigFilterView.OnConfigFilterSetupListener {
|
||||
override fun onShowSortSize() {}
|
||||
|
||||
override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
|
||||
mMinSize = sortSize.min.toString()
|
||||
mMaxSize = sortSize.max.toString()
|
||||
|
||||
var filter = originalFilter.ifEmpty { "type:全部" }
|
||||
if (mMinSize.isNotEmpty() && mMinSize != "-1") {
|
||||
filter += ",${UrlFilterUtils.getFilterQuery("min_size", mMinSize)}"
|
||||
}
|
||||
if (mMaxSize.isNotEmpty() && mMaxSize != "-1") {
|
||||
filter += ",${UrlFilterUtils.getFilterQuery("max_size", mMaxSize)}"
|
||||
}
|
||||
|
||||
refreshPage(filter = filter, size = sortSize)
|
||||
}
|
||||
|
||||
override fun onSetupSortType(sortType: SortType) {
|
||||
val clickTv = when (sortType) {
|
||||
SortType.RATING -> ratingTv
|
||||
SortType.NEWEST -> newestTv
|
||||
SortType.UPDATE -> updateTv
|
||||
else -> recommendedTv
|
||||
}
|
||||
|
||||
val sort = when (clickTv.text) {
|
||||
"更新" -> UrlFilterUtils.getFilterQuery("update_time", "-1")
|
||||
"最新" -> UrlFilterUtils.getFilterQuery("publish", "-1")
|
||||
"评分" -> UrlFilterUtils.getFilterQuery("star", "-1")
|
||||
else -> UrlFilterUtils.getFilterQuery("position", "1")
|
||||
}
|
||||
|
||||
if (mListViewModel.subjectData.sort != sort) {
|
||||
refreshPage(sort = sort)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRealLayoutId() = R.layout.fragment_subject_list
|
||||
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
@ -160,7 +226,11 @@ open class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewMod
|
||||
mListRv?.addOnScrollListener(mExposureListener)
|
||||
}
|
||||
|
||||
fun refreshPage(filter: String, sort: String, size: SubjectSettingEntity.Size) {
|
||||
fun refreshPage(
|
||||
filter: String = mListViewModel.subjectData.filter,
|
||||
sort: String = mListViewModel.subjectData.sort,
|
||||
size: SubjectSettingEntity.Size = mListViewModel.selectedFilterSize
|
||||
) {
|
||||
mListViewModel.selectedFilterSize = size
|
||||
mListViewModel.selectedLabelList = selectedLabelList
|
||||
mListViewModel.subjectData.filter = filter
|
||||
@ -181,10 +251,6 @@ open class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewMod
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onFragmentResume() {
|
||||
super.onFragmentResume()
|
||||
DownloadManager.getInstance().addObserver(dataWatcher)
|
||||
@ -229,5 +295,10 @@ open class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewMod
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
mAdapter?.let { it.notifyItemRangeChanged(0, it.itemCount) }
|
||||
mCachedView?.findViewById<ConfigFilterView>(R.id.filterView)?.run {
|
||||
if (isVisible) {
|
||||
updateAllTextView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -28,7 +28,7 @@ open class SubjectListViewModel(
|
||||
var exposureSourceList: List<ExposureSource>?
|
||||
) : ListViewModel<GameEntity, GameEntity>(application) {
|
||||
|
||||
// 供专题类型为 rows 时统计用
|
||||
// 供统计用
|
||||
var selectedLabelList = arrayListOf<String>()
|
||||
var selectedFilterSize = SubjectSettingEntity.Size(text = "全部大小")
|
||||
|
||||
|
||||
@ -1,17 +1,22 @@
|
||||
package com.gh.gamecenter.subject.rows
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import android.widget.CheckedTextView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.gh.common.view.ConfigFilterView
|
||||
import com.gh.common.view.ConfigFilterView.SortType
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
@ -32,13 +37,15 @@ class SubjectRowsFragment : BaseFragment<Any>() {
|
||||
// 统计用的大小筛选选中文案
|
||||
private var mSelectedFilterSize = SubjectSettingEntity.Size(text = "全部大小")
|
||||
|
||||
private lateinit var filterView: ConfigFilterView
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.fragment_subject_rows
|
||||
}
|
||||
|
||||
override fun initView(view: View) {
|
||||
super.initView(view)
|
||||
mSettingEntity = arguments?.getParcelable(SubjectSettingEntity::class.java.simpleName)
|
||||
mSettingEntity = arguments?.getParcelable(EntranceConsts.KEY_SUBJECT_SETTING_DATA)
|
||||
?: return
|
||||
mSubjectData = arguments?.getParcelable(EntranceConsts.KEY_SUBJECT_DATA) ?: return
|
||||
|
||||
@ -55,7 +62,7 @@ class SubjectRowsFragment : BaseFragment<Any>() {
|
||||
mListFragment =
|
||||
childFragmentManager.findFragmentByTag(SubjectListFragment::class.java.name) as? SubjectListFragment
|
||||
?: SubjectListFragment()
|
||||
mListFragment.arguments = arguments
|
||||
mListFragment.arguments = (arguments?.clone() as? Bundle)?.apply { remove(EntranceConsts.KEY_SUBJECT_SETTING_DATA) }
|
||||
childFragmentManager.beginTransaction()
|
||||
.replace(R.id.rows_list_container, mListFragment, SubjectListFragment::class.java.name)
|
||||
.commitAllowingStateLoss()
|
||||
@ -64,18 +71,29 @@ class SubjectRowsFragment : BaseFragment<Any>() {
|
||||
@SuppressLint("InflateParams")
|
||||
private fun createLabelsLayout() {
|
||||
val inflater = LayoutInflater.from(context)
|
||||
for (labels in mSettingEntity.typeEntity.labels) {
|
||||
mSettingEntity.typeEntity.labels.forEachIndexed { index, labels ->
|
||||
val labelsItem = inflater.inflate(R.layout.subject_rows_label, mLabelsContainer, false)
|
||||
val labelContainer = labelsItem.findViewById<LinearLayout>(R.id.label_container)
|
||||
for (index in 0 until labels.label.size) {
|
||||
val labelName = labels.label[index]
|
||||
labelsItem.updateLayoutParams<MarginLayoutParams> {
|
||||
topMargin = if (index == 0) 0 else 12F.dip2px()
|
||||
}
|
||||
for (labelIndex in 0 until labels.label.size) {
|
||||
val labelName = labels.label[labelIndex]
|
||||
val labelItem =
|
||||
inflater.inflate(R.layout.subject_rows_label_item, labelContainer, false)
|
||||
val label = labelItem.findViewById<CheckedTextView>(R.id.label)
|
||||
if (index == 0) label.isChecked = true
|
||||
label.updateLayoutParams<MarginLayoutParams> {
|
||||
leftMargin = if (labelIndex == 0) 0 else 8F.dip2px()
|
||||
}
|
||||
if (labelIndex == 0) {
|
||||
label.isChecked = true
|
||||
label.setTypeface(Typeface.DEFAULT, Typeface.BOLD)
|
||||
} else {
|
||||
label.setTypeface(Typeface.DEFAULT, Typeface.NORMAL)
|
||||
}
|
||||
label.text = labelName
|
||||
label.setOnClickListener {
|
||||
mFilterMap[labels.name] = if (index == 0) {
|
||||
mFilterMap[labels.name] = if (labelIndex == 0) {
|
||||
""
|
||||
} else {
|
||||
labelName
|
||||
@ -92,26 +110,18 @@ class SubjectRowsFragment : BaseFragment<Any>() {
|
||||
private fun selectLabel(labelContainer: LinearLayout, label: CheckedTextView) {
|
||||
for (i in 0 until labelContainer.childCount) {
|
||||
val view = labelContainer.getChildAt(i)
|
||||
if (view is CheckedTextView && view.isChecked) view.isChecked = false
|
||||
if (view is CheckedTextView && view.isChecked) {
|
||||
view.isChecked = false
|
||||
view.setTypeface(Typeface.DEFAULT, Typeface.NORMAL)
|
||||
}
|
||||
}
|
||||
label.isChecked = true
|
||||
label.setTypeface(Typeface.DEFAULT, Typeface.BOLD)
|
||||
}
|
||||
|
||||
private fun createFilterLayout() {
|
||||
if (mSettingEntity.filter == "on") {
|
||||
val filterView = ConfigFilterView(requireContext())
|
||||
filterView.ratingTv.visibility = View.VISIBLE
|
||||
|
||||
// 重排序
|
||||
mSettingEntity.filterOptions.forEachIndexed { index, s ->
|
||||
when (index) {
|
||||
0 -> filterView.updateTv.text = s
|
||||
1 -> filterView.recommendedTv.text = s
|
||||
2 -> filterView.newestTv.text = s
|
||||
3 -> filterView.ratingTv.text = s
|
||||
}
|
||||
}
|
||||
|
||||
if (mSettingEntity.isFilterEnabled) {
|
||||
filterView = ConfigFilterView(requireContext()).apply { initSubjectFilterView(mSettingEntity) }
|
||||
// 设置默认页面链接
|
||||
when (filterView.updateTv.text) {
|
||||
"更新" -> mSubjectData.sort = UrlFilterUtils.getFilterQuery("update_time", "-1")
|
||||
@ -119,15 +129,14 @@ class SubjectRowsFragment : BaseFragment<Any>() {
|
||||
"评分" -> mSubjectData.sort = UrlFilterUtils.getFilterQuery("star", "-1")
|
||||
else -> mSubjectData.sort = UrlFilterUtils.getFilterQuery("position", "1")
|
||||
}
|
||||
|
||||
// 隐藏相关选项
|
||||
filterView.updateTv.goneIf(mSettingEntity.filterOptions.isEmpty())
|
||||
filterView.recommendedTv.goneIf(mSettingEntity.filterOptions.size <= 1)
|
||||
filterView.newestTv.goneIf(mSettingEntity.filterOptions.size <= 2)
|
||||
filterView.ratingTv.goneIf(mSettingEntity.filterOptions.size <= 3)
|
||||
filterView.sizeFilterArray = mSettingEntity.filterSizes
|
||||
|
||||
mLabelsContainer.addView(filterView)
|
||||
mLabelsContainer.addView(
|
||||
filterView,
|
||||
LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
topMargin = 8F.dip2px()
|
||||
})
|
||||
|
||||
filterView.setOnConfigSetupListener(object :
|
||||
ConfigFilterView.OnConfigFilterSetupListener {
|
||||
@ -150,11 +159,11 @@ class SubjectRowsFragment : BaseFragment<Any>() {
|
||||
)
|
||||
}
|
||||
|
||||
override fun onSetupSortType(sortType: ConfigFilterView.SortType) {
|
||||
override fun onSetupSortType(sortType: SortType) {
|
||||
val clickTv = when (sortType) {
|
||||
ConfigFilterView.SortType.RATING -> filterView.ratingTv
|
||||
ConfigFilterView.SortType.NEWEST -> filterView.newestTv
|
||||
ConfigFilterView.SortType.UPDATE -> filterView.updateTv
|
||||
SortType.RATING -> filterView.ratingTv
|
||||
SortType.NEWEST -> filterView.newestTv
|
||||
SortType.UPDATE -> filterView.updateTv
|
||||
else -> filterView.recommendedTv
|
||||
}
|
||||
|
||||
@ -171,6 +180,8 @@ class SubjectRowsFragment : BaseFragment<Any>() {
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
mLabelsContainer.setPadding(0, 8F.dip2px(), 0, 8F.dip2px())
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,4 +253,11 @@ class SubjectRowsFragment : BaseFragment<Any>() {
|
||||
mListFragment.selectedLabelList = findAllSelectedLabel(mLabelsContainer)
|
||||
mListFragment.refreshPage(mSubjectData.filter, mSubjectData.sort, mSelectedFilterSize)
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
if (::filterView.isInitialized) {
|
||||
filterView.updateAllTextView()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
package com.gh.gamecenter.subject.tab
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
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.SubjectData
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
class ColumnCollectionTabViewModel(
|
||||
application: Application,
|
||||
private val columnCollectionId: String,
|
||||
private val customSize: Int,
|
||||
private val subjectDataList: List<SubjectData>
|
||||
) : AndroidViewModel(application) {
|
||||
private val columnCollectionSp by lazy {
|
||||
HaloApp.getInstance().getSharedPreferences(Constants.SP_COLUMN_COLLECTION_CUSTOM_TAB, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
val tabListLiveData = MutableLiveData<List<SubjectData>>()
|
||||
val followListLiveData = MutableLiveData<List<SubjectData>>()
|
||||
val moreListLiveData = MutableLiveData<List<SubjectData>>()
|
||||
|
||||
val addFollowLiveData = MutableLiveData<Event<SubjectData>>()
|
||||
val addMoreLiveData = MutableLiveData<Event<SubjectData>>()
|
||||
|
||||
init {
|
||||
initData()
|
||||
}
|
||||
|
||||
private fun initData() {
|
||||
val customTabIdList = GsonUtils.fromJsonList<String>(SPUtils.getString(columnCollectionSp, columnCollectionId))
|
||||
if (customTabIdList.isEmpty()) {
|
||||
val followTabList = subjectDataList.take(customSize)
|
||||
tabListLiveData.postValue(followTabList)
|
||||
followListLiveData.postValue(followTabList)
|
||||
moreListLiveData.postValue(subjectDataList - followTabList.toSet())
|
||||
} else {
|
||||
val newAddedForbiddenList = subjectDataList.filter { it.isForbidden && it.subjectId !in customTabIdList }
|
||||
val tabList = arrayListOf<SubjectData>().apply { addAll(newAddedForbiddenList) }
|
||||
|
||||
customTabIdList.forEach { subjectId->
|
||||
subjectDataList.find { subjectId == it.subjectId }?.let {
|
||||
tabList.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
val followTabList = tabList.take(CUSTOM_MAX_TAB).ifEmpty { subjectDataList.take(customSize) }
|
||||
tabListLiveData.postValue(followTabList)
|
||||
followListLiveData.postValue(followTabList)
|
||||
moreListLiveData.postValue(subjectDataList - followTabList.toSet())
|
||||
}
|
||||
}
|
||||
|
||||
fun addFollow(subjectData: SubjectData) {
|
||||
addFollowLiveData.postValue(Event(subjectData))
|
||||
}
|
||||
|
||||
fun addMore(subjectData: SubjectData) {
|
||||
addMoreLiveData.postValue(Event(subjectData))
|
||||
}
|
||||
|
||||
fun saveCustomTab(followTabList: List<SubjectData>) {
|
||||
tabListLiveData.postValue(followTabList)
|
||||
followListLiveData.postValue(followTabList)
|
||||
moreListLiveData.postValue(subjectDataList - followTabList.toSet())
|
||||
|
||||
val followSubjectIdList = followTabList.map { it.subjectId ?: "" }.distinct()
|
||||
SPUtils.setString(columnCollectionSp, columnCollectionId, followSubjectIdList.toJson())
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CUSTOM_MAX_TAB = 15
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val columnCollectionId: String,
|
||||
private val customSize: Int,
|
||||
private val subjectDataList: List<SubjectData>
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ColumnCollectionTabViewModel(
|
||||
HaloApp.getInstance().application,
|
||||
columnCollectionId,
|
||||
customSize,
|
||||
subjectDataList
|
||||
) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.gh.gamecenter.subject.tab
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.view.Chips
|
||||
import com.gh.gamecenter.databinding.ItemColumnCollectionCustomTabBinding
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
|
||||
class CustomTabFollowAdapter(private val viewModel: ColumnCollectionTabViewModel?) :
|
||||
ListAdapter<SubjectData, CustomTabFollowAdapter.CustomTabFollowItemViewHolder>(createDiffItemCallBack()) {
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): CustomTabFollowItemViewHolder {
|
||||
return CustomTabFollowItemViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: CustomTabFollowItemViewHolder, position: Int) {
|
||||
val subjectData = currentList.getOrNull(position) ?: return
|
||||
val isForbidden = subjectData.isForbidden
|
||||
holder.binding.chips.run {
|
||||
setState(if (isForbidden) Chips.STATE_FILL else Chips.STATE_DEFAULT)
|
||||
setText(subjectData.subjectName ?: "")
|
||||
endIcon.isVisible = !isForbidden
|
||||
endIcon.setImageResource(R.drawable.ic_basic_x_8_secondary)
|
||||
endIcon.imageTintList = null
|
||||
setOnClickListener {
|
||||
if (!isForbidden) {
|
||||
viewModel?.addMore(subjectData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CustomTabFollowItemViewHolder(val binding: ItemColumnCollectionCustomTabBinding) :
|
||||
ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
|
||||
fun createDiffItemCallBack() = object : ItemCallback<SubjectData>() {
|
||||
override fun areItemsTheSame(oldItem: SubjectData, newItem: SubjectData): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: SubjectData, newItem: SubjectData): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.gh.gamecenter.subject.tab
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.view.Chips
|
||||
import com.gh.gamecenter.databinding.ItemColumnCollectionCustomTabBinding
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
|
||||
class CustomTabMoreAdapter(private val viewModel: ColumnCollectionTabViewModel?) :
|
||||
ListAdapter<SubjectData, CustomTabMoreAdapter.CustomTabMoreItemViewHolder>(createDiffItemCallBack()) {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomTabMoreItemViewHolder {
|
||||
return CustomTabMoreItemViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: CustomTabMoreItemViewHolder, position: Int) {
|
||||
val subjectData = currentList.getOrNull(position) ?: return
|
||||
holder.binding.chips.run {
|
||||
setState(Chips.STATE_DEFAULT)
|
||||
setText(subjectData.subjectName ?: "")
|
||||
startIcon.isVisible = true
|
||||
startIcon.setImageResource(R.drawable.ic_auxiliary_plus_secondary_8)
|
||||
startIcon.imageTintList = null
|
||||
setOnClickListener {
|
||||
viewModel?.addFollow(subjectData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CustomTabMoreItemViewHolder(val binding: ItemColumnCollectionCustomTabBinding) : ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
|
||||
fun createDiffItemCallBack() = object : ItemCallback<SubjectData>() {
|
||||
override fun areItemsTheSame(oldItem: SubjectData, newItem: SubjectData): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: SubjectData, newItem: SubjectData): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,56 +1,154 @@
|
||||
package com.gh.gamecenter.subject.tab
|
||||
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ValueAnimator
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import android.widget.CheckedTextView
|
||||
import android.widget.TextView
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.utils.DialogHelper.Config
|
||||
import com.gh.gamecenter.core.utils.*
|
||||
import com.gh.gamecenter.databinding.FragmentSubjectTabBinding
|
||||
import com.gh.gamecenter.databinding.LayoutColumnCollectionSettingBinding
|
||||
import com.gh.gamecenter.databinding.TabItemMainBinding
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.subject.SubjectFragment
|
||||
import com.gh.gamecenter.subject.SubjectListFragment
|
||||
import com.google.android.flexbox.FlexboxLayoutManager
|
||||
import com.google.android.flexbox.JustifyContent
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class SubjectTabFragment : BaseFragment<Any>() {
|
||||
class SubjectTabFragment : ToolbarFragment() {
|
||||
|
||||
private val mBinding by lazy { FragmentSubjectTabBinding.inflate(layoutInflater) }
|
||||
private val binding by lazy { FragmentSubjectTabBinding.inflate(layoutInflater) }
|
||||
private var settingBinding: LayoutColumnCollectionSettingBinding? = null
|
||||
private var isSubject = false
|
||||
private var isCustomEnabled = false
|
||||
private var tabStyle = TabStyle.SUBJECT_NORMAL
|
||||
private var tabBindingList = arrayListOf<TabItemMainBinding>()
|
||||
private var isSettingAnimating = false
|
||||
private var columnCollectionTabViewModel: ColumnCollectionTabViewModel? = null
|
||||
private val fragmentTag by lazy { "android:switcher:${binding.subjectViewpager.id}:" }
|
||||
private var collectionId = ""
|
||||
private var collectionName = ""
|
||||
private var collectionStyle = ""
|
||||
private val followAdapter by lazy { CustomTabFollowAdapter(columnCollectionTabViewModel) }
|
||||
private val moreAdapter by lazy { CustomTabMoreAdapter(columnCollectionTabViewModel) }
|
||||
private val showOrHideMore: (Boolean) -> Unit = { isShow ->
|
||||
settingBinding?.run {
|
||||
if (isShow == moreContainer.isVisible) return@run
|
||||
|
||||
val startHeight = if (isShow) 0 else moreContainer.height
|
||||
val endHeight = if (isShow) {
|
||||
moreContainer.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
|
||||
moreContainer.measuredHeight
|
||||
} else 0
|
||||
ValueAnimator.ofInt(startHeight, endHeight).apply {
|
||||
duration = ANIMATOR_DURATION
|
||||
interpolator = AccelerateDecelerateInterpolator()
|
||||
doOnStart {
|
||||
if (isShow) {
|
||||
moreContainer.updateLayoutParams<MarginLayoutParams> { height = 0 }
|
||||
moreContainer.isVisible = true
|
||||
} else {
|
||||
moreContainer.isInvisible = true
|
||||
}
|
||||
}
|
||||
doOnEnd {
|
||||
if (isShow) {
|
||||
moreContainer.updateLayoutParams<MarginLayoutParams> { height = MarginLayoutParams.WRAP_CONTENT }
|
||||
} else {
|
||||
moreContainer.isVisible = false
|
||||
}
|
||||
}
|
||||
addUpdateListener { animation ->
|
||||
moreContainer.updateLayoutParams<MarginLayoutParams> { height = animation.animatedValue as Int }
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
private val itemTouchHelper by lazy {
|
||||
ItemTouchHelper(object : ItemTouchHelper.Callback() {
|
||||
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
|
||||
return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.START or ItemTouchHelper.END, 0)
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
val from = viewHolder.bindingAdapterPosition
|
||||
val to = target.bindingAdapterPosition
|
||||
val newList = followAdapter.currentList.toMutableList()
|
||||
Collections.swap(newList, from, to)
|
||||
followAdapter.submitList(newList)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isLongPressDragEnabled(): Boolean = true
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||
})
|
||||
}
|
||||
|
||||
override fun getLayoutId() = 0
|
||||
override fun getInflatedLayout() = mBinding.root
|
||||
override fun getInflatedLayout() = binding.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val subjectList = arguments?.getParcelableArrayList<SubjectData>(EntranceConsts.KEY_DATA)
|
||||
val subjectList = arguments?.getParcelableArrayList<SubjectData>(EntranceConsts.KEY_DATA) ?: arrayListOf()
|
||||
isSubject = subjectList.isEmpty()
|
||||
tabStyle = when {
|
||||
mIsFromMainWrapper && !isSubject -> TabStyle.COLUMN_COLLECTION_MAIN_WRAPPER
|
||||
isSubject -> TabStyle.SUBJECT_NORMAL
|
||||
else -> TabStyle.COLUMN_COLLECTION_NORMAL
|
||||
}
|
||||
val fragments = ArrayList<Fragment>()
|
||||
var tagList = arrayListOf<String>()
|
||||
val fragmentTag = "android:switcher:${mBinding.subjectViewpager.id}:"
|
||||
if (subjectList.isNullOrEmpty()) {
|
||||
val tagList: ArrayList<String>
|
||||
if (isSubject) {
|
||||
// 专题详情
|
||||
val subjectData = arguments?.getParcelable<SubjectData>(EntranceConsts.KEY_SUBJECT_DATA)
|
||||
?: return
|
||||
val settingsEntity =
|
||||
arguments?.getParcelable<SubjectSettingEntity>(SubjectSettingEntity::class.java.simpleName)
|
||||
arguments?.getParcelable<SubjectSettingEntity>(EntranceConsts.KEY_SUBJECT_SETTING_DATA)
|
||||
?: return
|
||||
tagList = settingsEntity.typeEntity.content as ArrayList<String>
|
||||
if (tagList.size > 1) {
|
||||
mBinding.subjectTabContainer.visibility = View.VISIBLE
|
||||
binding.subjectTabContainer.visibility = View.VISIBLE
|
||||
}
|
||||
tagList.forEachIndexed { index, tag ->
|
||||
val element = childFragmentManager.findFragmentByTag("${fragmentTag}$index")
|
||||
@ -60,69 +158,192 @@ class SubjectTabFragment : BaseFragment<Any>() {
|
||||
copyData.filter = if (tag == "全部") {
|
||||
UrlFilterUtils.getFilterQuery("tags", tag, "type", "全部")
|
||||
} else {
|
||||
copyData.tag = tag
|
||||
UrlFilterUtils.getFilterQuery("tags", tag)
|
||||
}
|
||||
bundle?.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, copyData)
|
||||
bundle?.putParcelable(EntranceConsts.KEY_SUBJECT_SETTING_DATA, settingsEntity)
|
||||
element.arguments = bundle
|
||||
fragments.add(element)
|
||||
}
|
||||
if (binding.subjectTabContainer.isVisible) {
|
||||
binding.subjectTabIndicator.setupWithTabLayout(binding.subjectTab)
|
||||
binding.subjectTabIndicator.setupWithViewPager(binding.subjectViewpager)
|
||||
}
|
||||
|
||||
val adapter = object : FragmentStatePagerAdapter(childFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
||||
override fun getItem(position: Int): Fragment {
|
||||
return fragments[position]
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
return fragments.size
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence {
|
||||
return tagList[position]
|
||||
}
|
||||
|
||||
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
|
||||
// super.destroyItem(container, position, `object`)
|
||||
}
|
||||
}
|
||||
binding.subjectViewpager.adapter = adapter
|
||||
binding.subjectTab.setupWithViewPager(binding.subjectViewpager)
|
||||
initTabLayout()
|
||||
} else {
|
||||
// 专题合集详情
|
||||
mBinding.subjectTabContainer.visibility = View.VISIBLE
|
||||
isCustomEnabled = arguments?.getBoolean(EntranceConsts.KEY_COLUMN_COLLECTION_CUSTOM) ?: false
|
||||
val customSize = (arguments?.getInt(EntranceConsts.KEY_COLUMN_COLLECTION_CUSTOM_SIZE)
|
||||
?: ColumnCollectionTabViewModel.CUSTOM_MAX_TAB).coerceAtMost(ColumnCollectionTabViewModel.CUSTOM_MAX_TAB)
|
||||
collectionId = arguments?.getString(EntranceConsts.KEY_COLUMN_COLLECTION_ID, "") ?: ""
|
||||
collectionName = arguments?.getString(EntranceConsts.KEY_COLUMN_COLLECTION_NAME, "") ?: ""
|
||||
collectionStyle = arguments?.getString(EntranceConsts.KEY_COLUMN_COLLECTION_STYLE, "") ?: ""
|
||||
binding.optionIv.isVisible = isCustomEnabled
|
||||
binding.maskView.isVisible = isCustomEnabled
|
||||
binding.optionIv.setOnClickListener {
|
||||
showSettingView()
|
||||
SensorsBridge.trackColumnCollectionClick(
|
||||
location = "合集详情",
|
||||
columnCollectionName = collectionName,
|
||||
columnCollectionId = collectionId,
|
||||
text = "自定义设置",
|
||||
columnCollectionPattern = CustomPageItem.collectionTypeToComponentName[collectionStyle]
|
||||
?: collectionStyle
|
||||
)
|
||||
}
|
||||
binding.subjectTabContainer.visibility = View.VISIBLE
|
||||
if (isCustomEnabled) {
|
||||
val columnCollectionId = arguments?.getString(EntranceConsts.KEY_COLUMN_COLLECTION_ID) ?: ""
|
||||
columnCollectionTabViewModel = viewModelProvider(ColumnCollectionTabViewModel.Factory(columnCollectionId, customSize, subjectList))
|
||||
observerData()
|
||||
if (SPUtils.getBoolean(Constants.SP_SHOW_COLUMN_COLLECTION_CUSTOM_TAB_SETTING, true)) {
|
||||
mBaseHandler.post {
|
||||
showSettingView()
|
||||
}
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_COLUMN_COLLECTION_CUSTOM_TAB_SETTING, false)
|
||||
}
|
||||
} else {
|
||||
initColumnCollectionViewPager(subjectList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subjectList.filterIndexed { index, subject ->
|
||||
val element = childFragmentManager.findFragmentByTag("${fragmentTag}$index")
|
||||
?: SubjectFragment()
|
||||
val bundle = arguments?.clone() as Bundle?
|
||||
bundle?.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, subject)
|
||||
bundle?.putParcelableArrayList(EntranceConsts.KEY_DATA, null)
|
||||
element.arguments = bundle
|
||||
fragments.add(element)
|
||||
|
||||
tagList.add(subject.subjectName ?: "")
|
||||
private fun observerData() {
|
||||
columnCollectionTabViewModel?.tabListLiveData?.observe(viewLifecycleOwner) {
|
||||
binding.subjectTab.clearOnTabSelectedListeners()
|
||||
initColumnCollectionViewPager(it)
|
||||
}
|
||||
columnCollectionTabViewModel?.followListLiveData?.observe(viewLifecycleOwner) {
|
||||
followAdapter.submitList(it)
|
||||
}
|
||||
columnCollectionTabViewModel?.moreListLiveData?.observe(viewLifecycleOwner) {
|
||||
moreAdapter.submitList(it) {
|
||||
showOrHideMore.invoke(it.isNotEmpty())
|
||||
}
|
||||
}
|
||||
columnCollectionTabViewModel?.addFollowLiveData?.observe(viewLifecycleOwner, EventObserver {
|
||||
val newFollowList = followAdapter.currentList.toMutableList()
|
||||
if (newFollowList.size < ColumnCollectionTabViewModel.CUSTOM_MAX_TAB) {
|
||||
val newMoreList = moreAdapter.currentList.toMutableList().apply { remove(it) }
|
||||
followAdapter.submitList(newFollowList.apply { add(it) })
|
||||
moreAdapter.submitList(newMoreList) {
|
||||
showOrHideMore.invoke(newMoreList.isNotEmpty())
|
||||
}
|
||||
} else {
|
||||
toast("最多可以添加15个关注内容哦~")
|
||||
}
|
||||
})
|
||||
columnCollectionTabViewModel?.addMoreLiveData?.observe(viewLifecycleOwner, EventObserver {
|
||||
if (followAdapter.currentList.size == 1) {
|
||||
toast("至少添加1个内容哦~")
|
||||
return@EventObserver
|
||||
}
|
||||
|
||||
mBinding.subjectViewpager.post {
|
||||
mBinding.subjectViewpager.offscreenPageLimit = fragments.size
|
||||
var position = arguments?.getInt(EntranceConsts.KEY_POSITION, 0) ?: 0
|
||||
val columnName = arguments?.getString(EntranceConsts.KEY_COLUMNNAME) ?: ""
|
||||
if (columnName.isNotEmpty()) {
|
||||
position = subjectList.indexOfFirst { it.subjectName == columnName }
|
||||
}
|
||||
if (position < subjectList.size) {
|
||||
mBinding.subjectViewpager.setCurrentItem(position, false)
|
||||
}
|
||||
followAdapter.submitList(followAdapter.currentList.toMutableList().apply { remove(it) })
|
||||
val newMoreList = moreAdapter.currentList.toMutableList().apply { add(it) }
|
||||
moreAdapter.submitList(newMoreList) {
|
||||
showOrHideMore.invoke(newMoreList.isNotEmpty())
|
||||
}
|
||||
val categoryId = requireArguments().getString(EntranceConsts.KEY_COLUMN_COLLECTION_ID, "")
|
||||
val categoryName = requireArguments().getString(EntranceConsts.KEY_COLUMN_COLLECTION_NAME, "")
|
||||
})
|
||||
}
|
||||
|
||||
mBinding.subjectViewpager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
subjectList[position]?.let {
|
||||
MtaHelper.onEvent("游戏专题合集", "详情Tab", it.subjectName)
|
||||
NewLogUtils.logColumnCategoryDetailContentClick(
|
||||
it.subjectName ?: "", it.subjectId ?: "", categoryName, categoryId
|
||||
)
|
||||
private fun initColumnCollectionViewPager(subjectList: List<SubjectData>) {
|
||||
val fragments = arrayListOf<Fragment>()
|
||||
val tagList = arrayListOf<String>()
|
||||
subjectList.filterIndexed { index, subject ->
|
||||
val element = childFragmentManager.findFragmentByTag("${fragmentTag}$index")
|
||||
?: SubjectFragment()
|
||||
val bundle = arguments?.clone() as Bundle?
|
||||
bundle?.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, subject)
|
||||
bundle?.putParcelableArrayList(EntranceConsts.KEY_DATA, null)
|
||||
bundle?.putBoolean(EntranceConsts.KEY_IS_FROM_MAIN_WRAPPER, false)
|
||||
bundle?.putBoolean(EntranceConsts.KEY_IS_FROM_TAB_WRAPPER, false)
|
||||
bundle?.putBoolean(EntranceConsts.KEY_COLUMN_COLLECTION_CUSTOM, false)
|
||||
if (isCustomEnabled) {
|
||||
bundle?.putInt(EntranceConsts.KEY_COLUMN_COLLECTION_CUSTOM_POSITION, index)
|
||||
}
|
||||
element.arguments = bundle
|
||||
fragments.add(element)
|
||||
|
||||
if (categoryName?.contains("排行榜") == true) {
|
||||
val trackEvent = JSONObject()
|
||||
try {
|
||||
trackEvent.put("list_name", it.subjectName)
|
||||
trackEvent.put("position", position)
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
SensorsBridge.trackEvent("GameListPageSelected", trackEvent)
|
||||
tagList.add(subject.subjectName ?: "")
|
||||
}
|
||||
|
||||
binding.subjectViewpager.post {
|
||||
binding.subjectViewpager.offscreenPageLimit = fragments.size
|
||||
var position = arguments?.getInt(EntranceConsts.KEY_POSITION, 0) ?: 0
|
||||
val columnName = arguments?.getString(EntranceConsts.KEY_COLUMNNAME) ?: ""
|
||||
if (columnName.isNotEmpty()) {
|
||||
position = subjectList.indexOfFirst { it.subjectName == columnName }
|
||||
}
|
||||
if (position < subjectList.size) {
|
||||
binding.subjectViewpager.setCurrentItem(position, false)
|
||||
}
|
||||
}
|
||||
val categoryId = requireArguments().getString(EntranceConsts.KEY_COLUMN_COLLECTION_ID, "")
|
||||
val categoryName = requireArguments().getString(EntranceConsts.KEY_COLUMN_COLLECTION_NAME, "")
|
||||
|
||||
binding.subjectViewpager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
subjectList.getOrNull(position)?.let {
|
||||
MtaHelper.onEvent("游戏专题合集", "详情Tab", it.subjectName)
|
||||
NewLogUtils.logColumnCategoryDetailContentClick(
|
||||
it.subjectName ?: "", it.subjectId ?: "", categoryName, categoryId
|
||||
)
|
||||
|
||||
if (categoryName?.contains("排行榜") == true) {
|
||||
val trackEvent = JSONObject()
|
||||
try {
|
||||
trackEvent.put("list_name", it.subjectName)
|
||||
trackEvent.put("position", position)
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
SensorsBridge.trackEvent("GameListPageSelected", trackEvent)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (mBinding.subjectTabContainer.visibility == View.VISIBLE) {
|
||||
mBinding.subjectTabIndicator.setupWithTabLayout(mBinding.subjectTab)
|
||||
mBinding.subjectTabIndicator.setupWithViewPager(mBinding.subjectViewpager)
|
||||
}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
|
||||
if (mIsFromMainWrapper) {
|
||||
// 这里的 selectedPosition 指的是应该被高亮显示的 position
|
||||
val selectedPosition = try {
|
||||
(position + positionOffset).roundToInt()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// roundToInt() 方法有时候会报 Cannot round NaN value. 错误 positionOffset 的值为 NAN
|
||||
// https://sentry.shanqu.cc/organizations/lightgame/issues/301377/?project=22
|
||||
position
|
||||
}
|
||||
val positionOffsetOnRealSelectedPosition = if (positionOffset >= 0.5) {
|
||||
positionOffset - 1
|
||||
} else {
|
||||
positionOffset
|
||||
}
|
||||
updateTabStyle(selectedPosition, positionOffsetOnRealSelectedPosition)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
val adapter = object : FragmentStatePagerAdapter(childFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
||||
override fun getItem(position: Int): Fragment {
|
||||
@ -133,7 +354,7 @@ class SubjectTabFragment : BaseFragment<Any>() {
|
||||
return fragments.size
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
override fun getPageTitle(position: Int): CharSequence {
|
||||
return tagList[position]
|
||||
}
|
||||
|
||||
@ -141,76 +362,478 @@ class SubjectTabFragment : BaseFragment<Any>() {
|
||||
// super.destroyItem(container, position, `object`)
|
||||
}
|
||||
}
|
||||
mBinding.subjectViewpager.adapter = adapter
|
||||
mBinding.subjectTab.setupWithViewPager(mBinding.subjectViewpager)
|
||||
// 首页样式的 tabLayout
|
||||
if (arguments?.getBoolean(EntranceConsts.KEY_IS_HOME) == true) {
|
||||
mBinding.subjectTabIndicator.visibility = View.GONE
|
||||
for (i in 0 until mBinding.subjectTab.tabCount) {
|
||||
val tab = mBinding.subjectTab.getTabAt(i) ?: continue
|
||||
binding.subjectViewpager.adapter = adapter
|
||||
binding.subjectTab.setupWithViewPager(binding.subjectViewpager)
|
||||
binding.subjectTabIndicator.setupWithTabLayout(binding.subjectTab)
|
||||
binding.subjectTabIndicator.setupWithViewPager(binding.subjectViewpager)
|
||||
initTabLayout()
|
||||
}
|
||||
|
||||
private fun initTabLayout() {
|
||||
if (tabStyle == TabStyle.COLUMN_COLLECTION_NORMAL) {
|
||||
if (isCustomEnabled && SPUtils.getBoolean(Constants.SP_SHOW_COLUMN_COLLECTION_CUSTOM_TAB_GUIDE, true)) {
|
||||
binding.subjectTab.addOnTabSelectedListener(object : OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
showSettingGuideIfNeeded(this)
|
||||
}
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {}
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||
showSettingGuideIfNeeded(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
binding.subjectTabIndicator.run {
|
||||
setIndicatorWidth(12)
|
||||
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
bottomMargin = 10F.dip2px()
|
||||
}
|
||||
}
|
||||
for (i in 0 until binding.subjectTab.tabCount) {
|
||||
binding.subjectTab.getTabAt(i)?.view?.run {
|
||||
background = null
|
||||
if (i == 0) {
|
||||
updateLayoutParams<MarginLayoutParams> { leftMargin = 4F.dip2px() }
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tabBindingList.clear()
|
||||
|
||||
val tabCount = binding.subjectTab.tabCount
|
||||
for (i in 0 until tabCount) {
|
||||
val tab = binding.subjectTab.getTabAt(i) ?: continue
|
||||
val tabTitle = if (tab.text != null) tab.text.toString() else ""
|
||||
|
||||
tab.view.background = null
|
||||
tab.customView = provideTabView(tabTitle)
|
||||
if (i == 0) {
|
||||
tab.customView?.background = R.drawable.border_round_theme_14.toDrawable(requireContext())
|
||||
tab.customView?.findViewById<TextView>(R.id.tab_title)
|
||||
?.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
|
||||
if (tabStyle == TabStyle.COLUMN_COLLECTION_MAIN_WRAPPER) {
|
||||
tab.view.setPadding(0, 0, 0, 0)
|
||||
if (i == 0) {
|
||||
tab.view.updateLayoutParams {
|
||||
this as LinearLayout.LayoutParams
|
||||
setMargins(10F.dip2px(), 0, 0, 0)
|
||||
}
|
||||
} else if (i == tabCount - 1) {
|
||||
tab.view.updateLayoutParams {
|
||||
this as LinearLayout.LayoutParams
|
||||
setMargins(0, 0, 10F.dip2px(), 0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tab.customView?.background = R.drawable.border_round_eee_14.toDrawable(requireContext())
|
||||
tab.customView?.findViewById<TextView>(R.id.tab_title)
|
||||
?.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
}
|
||||
|
||||
when (i) {
|
||||
0 -> tab.view.setPadding(12F.dip2px(), 0, 0, 0)
|
||||
|
||||
mBinding.subjectTab.tabCount - 1 -> tab.view.setPadding(8F.dip2px(), 0, 12F.dip2px(), 0)
|
||||
|
||||
else -> tab.view.setPadding(8F.dip2px(), 0, 0, 0)
|
||||
when (i) {
|
||||
0 -> tab.view.setPadding(16F.dip2px(), 0, 0, 0)
|
||||
binding.subjectTab.tabCount - 1 -> tab.view.setPadding(8F.dip2px(), 0, 16F.dip2px(), 0)
|
||||
else -> tab.view.setPadding(8F.dip2px(), 0, 0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mBinding.subjectTab.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
||||
tab?.customView?.background = R.drawable.border_round_eee_14.toDrawable(requireContext())
|
||||
tab?.customView?.findViewById<TextView>(R.id.tab_title)
|
||||
?.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
binding.subjectTabIndicator.isVisible = mIsFromMainWrapper
|
||||
if (tabStyle == TabStyle.COLUMN_COLLECTION_MAIN_WRAPPER) {
|
||||
binding.subjectTabIndicator.run {
|
||||
setIndicatorWidth(18)
|
||||
updateIndicatorDrawable(R.drawable.ic_commodity_selected.toDrawable(requireContext()))
|
||||
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
height = 8F.dip2px()
|
||||
bottomMargin = 8F.dip2px()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
tab?.customView?.background = R.drawable.border_round_theme_14.toDrawable(requireContext())
|
||||
tab?.customView?.findViewById<TextView>(R.id.tab_title)
|
||||
?.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
|
||||
binding.settingGuideIv.updateLayoutParams<ConstraintLayout.LayoutParams> { topMargin = 40F.dip2px() }
|
||||
binding.subjectTabContainer.updateLayoutParams<ConstraintLayout.LayoutParams> { height = 56F.dip2px() }
|
||||
binding.subjectTab.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
setMargins(0, 8F.dip2px(), 8F.dip2px(), 8F.dip2px())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
binding.subjectTab.addOnTabSelectedListener(object : OnTabSelectedListener {
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
||||
tab?.customView?.findViewById<CheckedTextView>(R.id.tab_title)?.isChecked = false
|
||||
}
|
||||
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
tab?.customView?.findViewById<CheckedTextView>(R.id.tab_title)?.isChecked = true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun provideTabView(title: String): View {
|
||||
val view = LayoutInflater.from(requireContext()).inflate(R.layout.tab_item_ranking_home, null)
|
||||
val tabTitle = view.findViewById<View>(R.id.tab_title)
|
||||
if (tabTitle is CheckedTextView) {
|
||||
tabTitle.text = title
|
||||
if (tabStyle == TabStyle.COLUMN_COLLECTION_MAIN_WRAPPER) {
|
||||
val tabBinding = TabItemMainBinding.inflate(LayoutInflater.from(requireContext()))
|
||||
tabBinding.titleTv.run {
|
||||
visibility = View.VISIBLE
|
||||
text = title
|
||||
textSize = 16F
|
||||
setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
|
||||
}
|
||||
tabBinding.invisibleTitleTv.run {
|
||||
visibility = View.INVISIBLE
|
||||
text = title
|
||||
textSize = 16F
|
||||
}
|
||||
tabBindingList.add(tabBinding)
|
||||
return tabBinding.root
|
||||
} else {
|
||||
val view = LayoutInflater.from(requireContext()).inflate(R.layout.tab_item_subject_tab, null)
|
||||
val tabTitle = view.findViewById<View>(R.id.tab_title)
|
||||
if (tabTitle is CheckedTextView) {
|
||||
tabTitle.text = title
|
||||
}
|
||||
return view
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
for (i in 0 until mBinding.subjectTab.tabCount) {
|
||||
val tab = mBinding.subjectTab.getTabAt(i) ?: continue
|
||||
tab.customView?.background =
|
||||
if (tab.isSelected) R.drawable.border_round_theme_14.toDrawable(requireContext()) else R.drawable.border_round_eee_14.toDrawable(
|
||||
requireContext()
|
||||
)
|
||||
tab.customView?.findViewById<TextView>(R.id.tab_title)
|
||||
?.setTextColor(
|
||||
if (tab.isSelected) com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()) else com.gh.gamecenter.common.R.color.text_primary.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
when (tabStyle) {
|
||||
TabStyle.COLUMN_COLLECTION_NORMAL -> {
|
||||
binding.subjectTabIndicator.updateIndicatorColor(com.gh.gamecenter.common.R.color.primary_theme)
|
||||
binding.subjectTab.setTabTextColors(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()), com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
}
|
||||
TabStyle.COLUMN_COLLECTION_MAIN_WRAPPER -> updateTabStyle(binding.subjectViewpager.currentItem, 0F)
|
||||
TabStyle.SUBJECT_NORMAL -> {
|
||||
for (i in 0 until binding.subjectTab.tabCount) {
|
||||
val tab = binding.subjectTab.getTabAt(i) ?: continue
|
||||
tab.customView?.findViewById<CheckedTextView>(R.id.tab_title)?.run {
|
||||
background = R.drawable.subject_tab_background_selector.toDrawable(context)
|
||||
setTextColor(ContextCompat.getColorStateList(context, com.gh.gamecenter.common.R.color.text_tabbar_style))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settingBinding?.run {
|
||||
saveTv.background = com.gh.gamecenter.common.R.drawable.button_blue_oval.toDrawable(requireContext())
|
||||
cancelTv.background = com.gh.gamecenter.feature.R.drawable.button_round_gray_light.toDrawable(requireContext())
|
||||
cancelTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
|
||||
followAdapter.notifyItemRangeChanged(0, followAdapter.itemCount)
|
||||
moreAdapter.notifyItemRangeChanged(0, moreAdapter.itemCount)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTabStyle(selectedPosition: Int, positionOffset: Float) {
|
||||
if (tabBindingList.isEmpty()) return
|
||||
|
||||
val currentTabDefaultColor = com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext())
|
||||
val currentTabSelectedColor = com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext())
|
||||
|
||||
val prePosition = selectedPosition - 1
|
||||
val nextPosition = selectedPosition + 1
|
||||
|
||||
// positionOffset 小于零,表示 indicator 当前位置处于选中的 tab 的左边
|
||||
val indicatorOnLeft = positionOffset < 0F
|
||||
|
||||
val selectedTabBinding = tabBindingList.safelyGetInRelease(selectedPosition) ?: return
|
||||
|
||||
// 前一个 tab、当前选中的 tab、后一个 tab 的显示比例
|
||||
val preScaleRatio = 1 + abs(positionOffset) / 4
|
||||
val selectedScaleRatio = 1 + (1 - abs(positionOffset)) / 4
|
||||
val nextScaleRatio = 1 + positionOffset / 4
|
||||
|
||||
// 处理前一个 tab
|
||||
if (prePosition != -1) {
|
||||
tabBindingList[prePosition].run {
|
||||
if (indicatorOnLeft) {
|
||||
titleTv.scaleX = preScaleRatio
|
||||
titleTv.scaleY = preScaleRatio
|
||||
titleTv.setTextColor(
|
||||
ColorUtils.blendARGB(
|
||||
currentTabDefaultColor,
|
||||
currentTabSelectedColor,
|
||||
abs(positionOffset)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
titleTv.setTextColor(currentTabDefaultColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新当前选中的 tab
|
||||
selectedTabBinding.run {
|
||||
titleTv.scaleX = selectedScaleRatio
|
||||
titleTv.scaleY = selectedScaleRatio
|
||||
titleTv.setTextColor(
|
||||
ColorUtils.blendARGB(
|
||||
currentTabDefaultColor,
|
||||
currentTabSelectedColor,
|
||||
1 - abs(positionOffset)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 处理后一个 tab
|
||||
if (nextPosition < tabBindingList.size) {
|
||||
tabBindingList[nextPosition].run {
|
||||
if (!indicatorOnLeft) {
|
||||
titleTv.scaleX = nextScaleRatio
|
||||
titleTv.scaleY = nextScaleRatio
|
||||
titleTv.setTextColor(
|
||||
ColorUtils.blendARGB(
|
||||
currentTabDefaultColor,
|
||||
currentTabSelectedColor,
|
||||
positionOffset
|
||||
)
|
||||
)
|
||||
} else {
|
||||
titleTv.setTextColor(currentTabDefaultColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 多 tab 切换的时候可能会出现某些 tab 的文字没有回归到原始大小的问题的问题 (positionOffset 不保证连续)
|
||||
for ((index, tabBinding) in tabBindingList.withIndex()) {
|
||||
if (index != prePosition && index != selectedPosition && index != nextPosition) {
|
||||
if (tabBinding.titleTv.scaleX != 1F) {
|
||||
tabBinding.titleTv.scaleX = 1F
|
||||
tabBinding.titleTv.scaleY = 1F
|
||||
}
|
||||
tabBinding.titleTv.setTextColor(currentTabDefaultColor)
|
||||
if (tabBinding.titleIv.scaleX != 1F) {
|
||||
tabBinding.titleIv.scaleX = 1F
|
||||
tabBinding.titleIv.scaleY = 1F
|
||||
}
|
||||
}
|
||||
|
||||
if (index == selectedPosition) {
|
||||
if (positionOffset == 0F) {
|
||||
tabBinding.titleTv.setTextColor(currentTabSelectedColor)
|
||||
}
|
||||
|
||||
tabBinding.titleTv.setTypeface(tabBinding.titleTv.typeface, Typeface.BOLD)
|
||||
} else {
|
||||
if (positionOffset == 0F) {
|
||||
tabBinding.titleTv.setTextColor(currentTabDefaultColor)
|
||||
}
|
||||
|
||||
tabBinding.titleTv.setTypeface(null, Typeface.NORMAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSettingGuideIfNeeded(listener: OnTabSelectedListener) {
|
||||
if (isCustomEnabled && SPUtils.getBoolean(Constants.SP_SHOW_COLUMN_COLLECTION_CUSTOM_TAB_GUIDE, true)) {
|
||||
binding.skipView.setOnClickListener {
|
||||
dismissSettingGuide()
|
||||
SensorsBridge.trackColumnCollectionClick(
|
||||
location = "合集详情",
|
||||
columnCollectionName = collectionName,
|
||||
columnCollectionId = collectionId,
|
||||
text = "新手引导-取消",
|
||||
columnCollectionPattern = CustomPageItem.collectionTypeToComponentName[collectionStyle]
|
||||
?: collectionStyle
|
||||
)
|
||||
}
|
||||
binding.settingClickView.setOnClickListener {
|
||||
dismissSettingGuide()
|
||||
showSettingView()
|
||||
SensorsBridge.trackColumnCollectionClick(
|
||||
location = "合集详情",
|
||||
columnCollectionName = collectionName,
|
||||
columnCollectionId = collectionId,
|
||||
text = "新手引导-立即设置",
|
||||
columnCollectionPattern = CustomPageItem.collectionTypeToComponentName[collectionStyle]
|
||||
?: collectionStyle
|
||||
)
|
||||
}
|
||||
binding.settingGuideContainer.setOnClickListener {
|
||||
dismissSettingGuide()
|
||||
SensorsBridge.trackColumnCollectionClick(
|
||||
location = "合集详情",
|
||||
columnCollectionName = collectionName,
|
||||
columnCollectionId = collectionId,
|
||||
text = "新手引导-关闭引导",
|
||||
columnCollectionPattern = CustomPageItem.collectionTypeToComponentName[collectionStyle]
|
||||
?: collectionStyle
|
||||
)
|
||||
}
|
||||
mBaseHandler.post {
|
||||
binding.settingGuideContainer.isVisible = true
|
||||
}
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_COLUMN_COLLECTION_CUSTOM_TAB_GUIDE, false)
|
||||
binding.subjectTab.removeOnTabSelectedListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dismissSettingGuide() {
|
||||
binding.settingGuideIv.animate()?.alpha(0F)?.setDuration(200L)?.doOnEnd {
|
||||
binding.settingGuideContainer.isVisible = false
|
||||
}?.start()
|
||||
}
|
||||
|
||||
private fun showSettingView() {
|
||||
if (isSettingAnimating) return
|
||||
|
||||
binding.background.setOnClickListener {
|
||||
showDismissSettingDialogIfNeeded()
|
||||
}
|
||||
|
||||
settingBinding = LayoutColumnCollectionSettingBinding.inflate(layoutInflater, null, false).apply {
|
||||
followRv.isNestedScrollingEnabled = false
|
||||
moreRv.isNestedScrollingEnabled = false
|
||||
columnCollectionTabViewModel?.followListLiveData?.value?.let {
|
||||
followAdapter.submitList(it) {
|
||||
followRv.adapter = followAdapter
|
||||
}
|
||||
} ?: run {
|
||||
followRv.adapter = followAdapter
|
||||
}
|
||||
columnCollectionTabViewModel?.moreListLiveData?.value?.let {
|
||||
moreAdapter.submitList(it) {
|
||||
moreRv.adapter = moreAdapter
|
||||
}
|
||||
} ?: run {
|
||||
moreRv.adapter = moreAdapter
|
||||
}
|
||||
followRv.layoutManager = FlexboxLayoutManager(requireContext()).apply { justifyContent = JustifyContent.FLEX_START }
|
||||
moreRv.layoutManager = FlexboxLayoutManager(requireContext()).apply { justifyContent = JustifyContent.FLEX_START }
|
||||
itemTouchHelper.attachToRecyclerView(followRv)
|
||||
moreContainer.isVisible = !columnCollectionTabViewModel?.moreListLiveData?.value.isNullOrEmpty()
|
||||
saveTv.setOnClickListener {
|
||||
dismissSettingView {
|
||||
saveCustomTab()
|
||||
}
|
||||
}
|
||||
cancelTv.setOnClickListener {
|
||||
dismissSettingView()
|
||||
}
|
||||
root.setOnClickListener {}
|
||||
}
|
||||
|
||||
binding.settingContainer.addView(
|
||||
settingBinding!!.root,
|
||||
FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT)
|
||||
)
|
||||
binding.settingContainer.post {
|
||||
val height = binding.settingContainer.height
|
||||
binding.background.visibility = View.VISIBLE
|
||||
AnimatorSet().apply {
|
||||
val translateAnimator = ValueAnimator.ofFloat(0F, height.toFloat()).apply {
|
||||
addUpdateListener { va -> binding.settingContainer.translationY = (va.animatedValue as Float) }
|
||||
}
|
||||
val alphaAnimator = ValueAnimator.ofFloat(0F, 0.2F).apply {
|
||||
addUpdateListener { va -> binding.background.alpha = (va.animatedValue as Float) }
|
||||
}
|
||||
playTogether(translateAnimator, alphaAnimator)
|
||||
duration = ANIMATOR_DURATION
|
||||
doOnStart {
|
||||
isSettingAnimating = true
|
||||
}
|
||||
doOnEnd {
|
||||
ConstraintSet().apply {
|
||||
clone(binding.root)
|
||||
clear(binding.settingContainer.id, ConstraintSet.BOTTOM)
|
||||
connect(binding.settingContainer.id, ConstraintSet.TOP, binding.subjectTabContainer.id, ConstraintSet.TOP)
|
||||
}.applyTo(binding.root)
|
||||
binding.settingContainer.translationY = 0F
|
||||
isSettingAnimating = false
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveCustomTab() {
|
||||
if (followAdapter.currentList.isEmpty()) {
|
||||
toast("至少添加1个内容哦~")
|
||||
return
|
||||
}
|
||||
|
||||
SensorsBridge.trackEvent("ColumnCollectionCustomSetting",
|
||||
"column_collection_name", collectionName,
|
||||
"column_collection_id", collectionId,
|
||||
"original_text", columnCollectionTabViewModel?.followListLiveData?.value?.joinToString("、") { it.subjectName ?: "" } ?: "",
|
||||
"save_text", followAdapter.currentList.joinToString("、") { it.subjectName ?: "" },
|
||||
)
|
||||
columnCollectionTabViewModel?.saveCustomTab(followAdapter.currentList)
|
||||
}
|
||||
|
||||
private fun showDismissSettingDialogIfNeeded() {
|
||||
if (followAdapter.currentList == columnCollectionTabViewModel?.followListLiveData?.value) {
|
||||
dismissSettingView()
|
||||
} else {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
title = "提示",
|
||||
content = "是否保存当前自定义设置",
|
||||
confirmText = "保存设置",
|
||||
cancelText = "退出",
|
||||
confirmClickCallback = {
|
||||
dismissSettingView {
|
||||
saveCustomTab()
|
||||
}
|
||||
},
|
||||
cancelClickCallback = {
|
||||
dismissSettingView()
|
||||
},
|
||||
extraConfig = Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dismissSettingView(doOnEnd: (() -> Unit)? = null) {
|
||||
if (settingBinding == null || isSettingAnimating) return
|
||||
|
||||
val height = binding.settingContainer.height
|
||||
AnimatorSet().apply {
|
||||
val translateAnimator = ValueAnimator.ofFloat(0F, -height.toFloat()).apply {
|
||||
addUpdateListener { va -> binding.settingContainer.translationY = (va.animatedValue as Float) }
|
||||
}
|
||||
val alphaAnimator = ValueAnimator.ofFloat(0.2F, 0F).apply {
|
||||
addUpdateListener { va -> binding.background.alpha = (va.animatedValue as Float) }
|
||||
}
|
||||
playTogether(translateAnimator, alphaAnimator)
|
||||
duration = ANIMATOR_DURATION
|
||||
doOnStart {
|
||||
isSettingAnimating = true
|
||||
}
|
||||
doOnEnd {
|
||||
binding.background.visibility = View.GONE
|
||||
binding.settingContainer.removeAllViews()
|
||||
binding.settingContainer.translationY = 0F
|
||||
ConstraintSet().apply {
|
||||
clone(binding.root)
|
||||
clear(binding.settingContainer.id, ConstraintSet.TOP)
|
||||
connect(binding.settingContainer.id, ConstraintSet.BOTTOM, binding.subjectTabContainer.id, ConstraintSet.TOP)
|
||||
}.applyTo(binding.root)
|
||||
settingBinding = null
|
||||
isSettingAnimating = false
|
||||
doOnEnd?.invoke()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
if (binding.settingGuideContainer.isVisible) {
|
||||
binding.settingGuideContainer.performClick()
|
||||
return true
|
||||
}
|
||||
if (settingBinding != null) {
|
||||
showDismissSettingDialogIfNeeded()
|
||||
return true
|
||||
}
|
||||
return super.onBackPressed()
|
||||
}
|
||||
|
||||
enum class TabStyle {
|
||||
/**
|
||||
* 专题详情样式
|
||||
*/
|
||||
SUBJECT_NORMAL,
|
||||
|
||||
/**
|
||||
* 专题合集-关联首页底部Tab样式
|
||||
*/
|
||||
COLUMN_COLLECTION_MAIN_WRAPPER,
|
||||
|
||||
/**
|
||||
* 专题合集-常规样式
|
||||
*/
|
||||
COLUMN_COLLECTION_NORMAL,
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ANIMATOR_DURATION = 200L
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,19 +4,24 @@ import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.gh.common.view.ConfigFilterView
|
||||
import com.gh.common.view.ConfigFilterView.SortType
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.base.fragment.ToolbarController
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.view.GridSpacingItemDecoration
|
||||
import com.gh.gamecenter.core.utils.StringUtils
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.databinding.FragmentSubjectTiledBinding
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.gh.gamecenter.subject.SubjectListFragment
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import kotlin.math.abs
|
||||
@ -32,6 +37,28 @@ class SubjectTileFragment : BaseFragment<Any>() {
|
||||
|
||||
private var mIsTouchScreen: Boolean = false
|
||||
|
||||
private var mMaxSize = ""
|
||||
private var mMinSize = ""
|
||||
private var mSelectedFilterSize = SubjectSettingEntity.Size(text = "全部大小")
|
||||
|
||||
private val finalFilter: String
|
||||
get() {
|
||||
var filter = if (mSelectedTypeName == "全部") {
|
||||
// 全部的时候添加头图
|
||||
UrlFilterUtils.getFilterQuery("tags", mSelectedTypeName, "type", mSelectedTypeName)
|
||||
} else {
|
||||
UrlFilterUtils.getFilterQuery("tags", mSelectedTypeName)
|
||||
}
|
||||
if (mMinSize.isNotEmpty() && mMinSize != "-1") {
|
||||
filter += ",${UrlFilterUtils.getFilterQuery("min_size", mMinSize)}"
|
||||
}
|
||||
if (mMaxSize.isNotEmpty() && mMaxSize != "-1") {
|
||||
filter += ",${UrlFilterUtils.getFilterQuery("max_size", mMaxSize)}"
|
||||
}
|
||||
|
||||
return filter
|
||||
}
|
||||
|
||||
override fun getLayoutId() = 0
|
||||
override fun getInflatedLayout() = mBinding.root
|
||||
|
||||
@ -40,45 +67,75 @@ class SubjectTileFragment : BaseFragment<Any>() {
|
||||
// 初始化数据
|
||||
mSubjectData = arguments?.getParcelable(EntranceConsts.KEY_SUBJECT_DATA) ?: return
|
||||
mSettingsEntity =
|
||||
arguments?.getParcelable(SubjectSettingEntity::class.java.simpleName) ?: return
|
||||
arguments?.getParcelable(EntranceConsts.KEY_SUBJECT_SETTING_DATA) ?: return
|
||||
|
||||
mSelectedTypeName = "全部"
|
||||
mSubjectData.filter = UrlFilterUtils.getFilterQuery("type", "全部")
|
||||
mSubjectData.sort = UrlFilterUtils.getFilterQuery("position", "1")
|
||||
|
||||
mBinding.subjectFilterContainer.visibility =
|
||||
if (mSettingsEntity.filter == "on") View.VISIBLE else View.GONE
|
||||
|
||||
// 初始化顶部类型列表
|
||||
val layoutManager = object : GridLayoutManager(context, 4) {
|
||||
override fun canScrollVertically(): Boolean {
|
||||
return false
|
||||
mBinding.subjectTypeList.goneIf(mSettingsEntity.typeEntity.content.size <= 1) {
|
||||
// 初始化顶部类型列表
|
||||
val layoutManager = object : GridLayoutManager(context, 4) {
|
||||
override fun canScrollVertically(): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
mBinding.subjectTypeList.isNestedScrollingEnabled = false
|
||||
mBinding.subjectTypeList.layoutManager = layoutManager
|
||||
mBinding.subjectTabbarHottest.setOnClickListener(this)
|
||||
mBinding.subjectTabbarNewest.setOnClickListener(this)
|
||||
|
||||
if (mSettingsEntity.typeEntity.content.size > 1) {
|
||||
mBinding.subjectTypeList.isNestedScrollingEnabled = false
|
||||
mBinding.subjectTypeList.layoutManager = layoutManager
|
||||
mBinding.subjectTypeList.addItemDecoration(GridSpacingItemDecoration(4, 8F.dip2px(), false))
|
||||
val adapter = SubjectTypeListAdapter(requireContext(), mItemClickListener = {
|
||||
mSelectedTypeName = it
|
||||
if (it == "全部") {
|
||||
// 全部的时候添加头图
|
||||
mSubjectData.filter = UrlFilterUtils.getFilterQuery("tags", it, "type", it)
|
||||
} else {
|
||||
mSubjectData.filter = UrlFilterUtils.getFilterQuery("tags", it)
|
||||
}
|
||||
mSubjectData.filter = finalFilter
|
||||
mSubjectData.tag = it
|
||||
loadData()
|
||||
}, mGameType = mSettingsEntity.typeEntity.content)
|
||||
mBinding.subjectTypeList.adapter = adapter
|
||||
}
|
||||
|
||||
mBinding.filterView.goneIf(!mSettingsEntity.isFilterEnabled) {
|
||||
mBinding.filterView.run {
|
||||
initSubjectFilterView(mSettingsEntity)
|
||||
setOnConfigSetupListener(object :
|
||||
ConfigFilterView.OnConfigFilterSetupListener {
|
||||
override fun onShowSortSize() {}
|
||||
|
||||
override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
|
||||
mMinSize = sortSize.min.toString()
|
||||
mMaxSize = sortSize.max.toString()
|
||||
mSelectedFilterSize = sortSize
|
||||
mSubjectData.filter = finalFilter
|
||||
loadData()
|
||||
}
|
||||
|
||||
override fun onSetupSortType(sortType: SortType) {
|
||||
val clickTv = when (sortType) {
|
||||
SortType.RATING -> ratingTv
|
||||
SortType.NEWEST -> newestTv
|
||||
SortType.UPDATE -> updateTv
|
||||
else -> recommendedTv
|
||||
}
|
||||
|
||||
val sort = when (clickTv.text) {
|
||||
"更新" -> UrlFilterUtils.getFilterQuery("update_time", "-1")
|
||||
"最新" -> UrlFilterUtils.getFilterQuery("publish", "-1")
|
||||
"评分" -> UrlFilterUtils.getFilterQuery("star", "-1")
|
||||
else -> UrlFilterUtils.getFilterQuery("position", "1")
|
||||
}
|
||||
|
||||
if (mSubjectData.sort != sort) {
|
||||
mSubjectData.sort = sort
|
||||
loadData()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 是否为专题合集详情子页面
|
||||
val isColumnCollection = arguments?.getBoolean(EntranceConsts.KEY_IS_COLUMN_COLLECTION) ?: false
|
||||
if (!isColumnCollection) {
|
||||
// Appbar 交互
|
||||
mBinding.subjectAppbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
|
||||
mBinding.subjectAppbar.addOnOffsetChangedListener { appBarLayout, verticalOffset ->
|
||||
if (!TextUtils.isEmpty(mSubjectData.subjectName) && activity is ToolbarController) {
|
||||
val totalScrollRange = appBarLayout.totalScrollRange
|
||||
if (abs(verticalOffset) < totalScrollRange / 2) {
|
||||
@ -94,7 +151,7 @@ class SubjectTileFragment : BaseFragment<Any>() {
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
loadData()
|
||||
@ -116,23 +173,6 @@ class SubjectTileFragment : BaseFragment<Any>() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.subject_tabbar_hottest -> {
|
||||
mBinding.subjectTabbarHottest.isChecked = true
|
||||
mBinding.subjectTabbarNewest.isChecked = false
|
||||
mSubjectData.sort = UrlFilterUtils.getFilterQuery("position", "1")
|
||||
loadData()
|
||||
}
|
||||
R.id.subject_tabbar_newest -> {
|
||||
mBinding.subjectTabbarHottest.isChecked = false
|
||||
mBinding.subjectTabbarNewest.isChecked = true
|
||||
mSubjectData.sort = UrlFilterUtils.getFilterQuery("publish", "-1")
|
||||
loadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadData() {
|
||||
val transaction = childFragmentManager.beginTransaction()
|
||||
hideFragments(transaction)
|
||||
@ -151,8 +191,10 @@ class SubjectTileFragment : BaseFragment<Any>() {
|
||||
transaction.show(fragmentByTag)
|
||||
} else {
|
||||
fragmentByTag = SubjectListFragment()
|
||||
val bundle = arguments ?: Bundle()
|
||||
val bundle = arguments?.clone() as? Bundle ?: Bundle()
|
||||
bundle.remove(EntranceConsts.KEY_SUBJECT_SETTING_DATA)
|
||||
bundle.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, mSubjectData)
|
||||
bundle.putString(EntranceConsts.KEY_SUBJECT_SORT_SIZE, mSelectedFilterSize.text)
|
||||
fragmentByTag.arguments = bundle
|
||||
transaction.add(R.id.subject_content_rl, fragmentByTag, fmTag)
|
||||
}
|
||||
@ -161,6 +203,13 @@ class SubjectTileFragment : BaseFragment<Any>() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
if (mBinding.filterView.isVisible) {
|
||||
mBinding.filterView.updateAllTextView()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val OPEN_APPBAR = "openAppBar"
|
||||
}
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
package com.gh.gamecenter.subject.tile
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import android.widget.CheckedTextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
|
||||
class SubjectTypeListAdapter(
|
||||
@ -20,28 +22,26 @@ class SubjectTypeListAdapter(
|
||||
private var mCurType = "全部"
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubjectTypeViewHolder {
|
||||
return SubjectTypeViewHolder(mLayoutInflater.inflate(R.layout.item_filter_size, parent, false))
|
||||
return SubjectTypeViewHolder(mLayoutInflater.inflate(R.layout.subject_rows_label_item, parent, false))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SubjectTypeViewHolder, position: Int) {
|
||||
holder.itemView.layoutParams = holder.itemView.layoutParams.apply {
|
||||
holder.type.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
}
|
||||
holder.type.background = R.drawable.subject_label_background_style.toDrawable(mContext)
|
||||
holder.type.setTextColor(ContextCompat.getColorStateList(mContext, R.color.subject_label_text_style))
|
||||
holder.type.text = mGameType[position]
|
||||
|
||||
if (!TextUtils.isEmpty(mCurType) && mCurType == mGameType[position]) {
|
||||
holder.type.background = ContextCompat.getDrawable(mContext, R.drawable.bg_tag_text)
|
||||
holder.type.setTextColor(Color.WHITE)
|
||||
} else {
|
||||
holder.type.background = null
|
||||
holder.type.setTextColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.text_757575))
|
||||
}
|
||||
val isChecked = !TextUtils.isEmpty(mCurType) && mCurType == mGameType[position]
|
||||
holder.type.isChecked = isChecked
|
||||
holder.type.setTypeface(Typeface.DEFAULT, if (isChecked) Typeface.BOLD else Typeface.NORMAL)
|
||||
|
||||
holder.type.setOnClickListener {
|
||||
if (holder.adapterPosition == -1) return@setOnClickListener
|
||||
if (holder.bindingAdapterPosition == -1) return@setOnClickListener
|
||||
|
||||
mCurType = mGameType[holder.adapterPosition]
|
||||
mItemClickListener.invoke(mGameType[holder.adapterPosition])
|
||||
mCurType = mGameType[holder.bindingAdapterPosition]
|
||||
mItemClickListener.invoke(mGameType[holder.bindingAdapterPosition])
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
@ -51,6 +51,6 @@ class SubjectTypeListAdapter(
|
||||
}
|
||||
|
||||
inner class SubjectTypeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val type by lazy { itemView.findViewById<TextView>(R.id.size_tv) }
|
||||
val type: CheckedTextView by lazy { itemView.findViewById(R.id.label) }
|
||||
}
|
||||
}
|
||||
5
app/src/main/res/color/subject_label_text_style.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/text_tertiary" android:state_checked="false" />
|
||||
<item android:color="@color/text_theme" android:state_checked="true" />
|
||||
</selector>
|
||||
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/text_757575" android:state_checked="false" />
|
||||
<item android:color="@color/white" android:state_checked="true" />
|
||||
</selector>
|
||||
|
Before Width: | Height: | Size: 860 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 886 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 990 B |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 46 KiB |
@ -2,5 +2,5 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="8dp" />
|
||||
<solid android:color="@color/bg_EBF5FF" />
|
||||
<solid android:color="@color/primary_theme_10" />
|
||||
</shape>
|
||||
7
app/src/main/res/drawable/bg_category_selected_tag.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:endColor="@color/primary_theme_10"
|
||||
android:startColor="@color/primary_theme_40" />
|
||||
<corners android:radius="2dp" />
|
||||
</shape>
|
||||
7
app/src/main/res/drawable/bg_category_sidebar.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/ui_background" />
|
||||
<corners android:topRightRadius="8dp" />
|
||||
</shape>
|
||||
7
app/src/main/res/drawable/bg_more_category_default.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="28dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/ui_divider_2" />
|
||||
</shape>
|
||||
10
app/src/main/res/drawable/bg_more_category_filtered.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="28dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/primary_theme_20" />
|
||||
<gradient
|
||||
android:endColor="@color/theme_alpha_4"
|
||||
android:startColor="@color/theme_alpha_8" />
|
||||
</shape>
|
||||
5
app/src/main/res/drawable/bg_search_category_number.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="100dp"/>
|
||||
<solid android:color="@color/white_alpha_20"/>
|
||||
</shape>
|
||||
@ -1,9 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid android:color="@color/title" />
|
||||
|
||||
<corners android:radius="4dp" />
|
||||
|
||||
<corners android:radius="6dp" />
|
||||
<solid android:color="@color/primary_theme_10" />
|
||||
</shape>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/bg_shape_primary_theme_alpha_10_radius_6" android:state_checked="true" />
|
||||
<item android:drawable="@drawable/bg_shape_primary_theme_alpha_10_radius_6" android:state_focused="true" />
|
||||
<item android:drawable="@drawable/bg_shape_f8_radius_6" />
|
||||
</selector>
|
||||
13
app/src/main/res/drawable/ic_arrow_down.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="8dp"
|
||||
android:height="6dp"
|
||||
android:viewportWidth="8"
|
||||
android:viewportHeight="6">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M7,1.5L4,4.5L1,1.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/text_primary"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
13
app/src/main/res/drawable/ic_arrow_up.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="8dp"
|
||||
android:height="6dp"
|
||||
android:viewportWidth="8"
|
||||
android:viewportHeight="6">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M7,4.5L4,1.5L1,4.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/text_primary"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="8dp"
|
||||
android:height="6dp"
|
||||
android:viewportWidth="8"
|
||||
android:viewportHeight="6">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M7,4.5L4,1.5L1,4.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/text_primary"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_auxiliary_plus_secondary_8.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="8dp"
|
||||
android:height="8dp"
|
||||
android:viewportWidth="8"
|
||||
android:viewportHeight="8">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h8v8h-8z"/>
|
||||
<path
|
||||
android:pathData="M4,0C4.2761,0 4.5,0.2239 4.5,0.5V3.5H7.5C7.7761,3.5 8,3.7239 8,4C8,4.2761 7.7761,4.5 7.5,4.5H4.5V7.5C4.5,7.7761 4.2761,8 4,8C3.7239,8 3.5,7.7761 3.5,7.5V4.5H0.5C0.2239,4.5 0,4.2761 0,4C0,3.7239 0.2239,3.5 0.5,3.5H3.5V0.5C3.5,0.2239 3.7239,0 4,0Z"
|
||||
android:fillColor="@color/text_secondary"
|
||||
android:fillType="evenOdd"/>
|
||||
</group>
|
||||
</vector>
|
||||
21
app/src/main/res/drawable/ic_basic_checkmark_circle_fill.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="18">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h18v18h-18z"/>
|
||||
<path
|
||||
android:pathData="M1.875,9C1.875,5.065 5.065,1.875 9,1.875C12.935,1.875 16.125,5.065 16.125,9C16.125,12.935 12.935,16.125 9,16.125C5.065,16.125 1.875,12.935 1.875,9Z"
|
||||
android:fillColor="#2496FF"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M6.75,9L8.25,10.5L11.25,7.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"/>
|
||||
</group>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_basic_classification.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h16v16h-16z"/>
|
||||
<path
|
||||
android:pathData="M8.5,4.667C8.5,3.102 9.769,1.833 11.333,1.833C12.898,1.833 14.167,3.102 14.167,4.667C14.167,6.232 12.898,7.5 11.333,7.5C9.769,7.5 8.5,6.232 8.5,4.667ZM11.333,3.167C10.505,3.167 9.833,3.838 9.833,4.667C9.833,5.495 10.505,6.167 11.333,6.167C12.162,6.167 12.833,5.495 12.833,4.667C12.833,3.838 12.162,3.167 11.333,3.167ZM4,2C2.895,2 2,2.895 2,4V5.333C2,6.438 2.895,7.333 4,7.333H5.333C6.438,7.333 7.333,6.438 7.333,5.333V4C7.333,2.895 6.438,2 5.333,2H4ZM3.333,4C3.333,3.632 3.632,3.333 4,3.333H5.333C5.702,3.333 6,3.632 6,4V5.333C6,5.702 5.702,6 5.333,6H4C3.632,6 3.333,5.702 3.333,5.333V4ZM4,8.667C2.895,8.667 2,9.562 2,10.667V12C2,13.105 2.895,14 4,14H5.333C6.438,14 7.333,13.105 7.333,12V10.667C7.333,9.562 6.438,8.667 5.333,8.667H4ZM3.333,10.667C3.333,10.299 3.632,10 4,10H5.333C5.702,10 6,10.299 6,10.667V12C6,12.368 5.702,12.667 5.333,12.667H4C3.632,12.667 3.333,12.368 3.333,12V10.667ZM10.667,8.667C9.562,8.667 8.667,9.562 8.667,10.667V12C8.667,13.105 9.562,14 10.667,14H12C13.105,14 14,13.105 14,12V10.667C14,9.562 13.105,8.667 12,8.667H10.667ZM10,10.667C10,10.299 10.299,10 10.667,10H12C12.368,10 12.667,10.299 12.667,10.667V12C12.667,12.368 12.368,12.667 12,12.667H10.667C10.299,12.667 10,12.368 10,12V10.667Z"
|
||||
android:fillColor="@color/text_primary"
|
||||
android:fillType="evenOdd"/>
|
||||
</group>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_basic_x_8_secondary.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="8dp"
|
||||
android:height="8dp"
|
||||
android:viewportWidth="8"
|
||||
android:viewportHeight="8">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h8v8h-8z"/>
|
||||
<path
|
||||
android:pathData="M0.6464,0.6464C0.8417,0.4512 1.1583,0.4512 1.3535,0.6464L4,3.2929L6.6465,0.6464C6.8417,0.4512 7.1583,0.4512 7.3535,0.6464C7.5488,0.8417 7.5488,1.1583 7.3535,1.3535L4.7071,4L7.3535,6.6465C7.5488,6.8417 7.5488,7.1583 7.3535,7.3535C7.1583,7.5488 6.8417,7.5488 6.6465,7.3535L4,4.7071L1.3535,7.3535C1.1583,7.5488 0.8417,7.5488 0.6464,7.3535C0.4512,7.1583 0.4512,6.8417 0.6464,6.6465L3.2929,4L0.6464,1.3535C0.4512,1.1583 0.4512,0.8417 0.6464,0.6464Z"
|
||||
android:fillColor="@color/text_secondary"
|
||||
android:fillType="evenOdd"/>
|
||||
</group>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/ic_clear.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="14dp"
|
||||
android:viewportWidth="14"
|
||||
android:viewportHeight="14">
|
||||
<path
|
||||
android:pathData="M7,14C10.866,14 14,10.866 14,7C14,3.134 10.866,0 7,0C3.134,0 0,3.134 0,7C0,10.866 3.134,14 7,14ZM5.53,4.47C5.237,4.177 4.763,4.177 4.47,4.47C4.177,4.763 4.177,5.237 4.47,5.53L5.939,7L4.47,8.47C4.177,8.763 4.177,9.237 4.47,9.53C4.763,9.823 5.237,9.823 5.53,9.53L7,8.061L8.47,9.53C8.763,9.823 9.237,9.823 9.53,9.53C9.823,9.237 9.823,8.763 9.53,8.47L8.061,7L9.53,5.53C9.823,5.237 9.823,4.763 9.53,4.47C9.237,4.177 8.763,4.177 8.47,4.47L7,5.939L5.53,4.47Z"
|
||||
android:fillColor="#000000"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/ic_filter_dot.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/ui_divider" />
|
||||
</shape>
|
||||
14
app/src/main/res/drawable/ic_phone.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="12dp"
|
||||
android:height="12dp"
|
||||
android:viewportWidth="12"
|
||||
android:viewportHeight="12">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M4,1.5L8,1.5A1.5,1.5 0,0 1,9.5 3L9.5,9A1.5,1.5 0,0 1,8 10.5L4,10.5A1.5,1.5 0,0 1,2.5 9L2.5,3A1.5,1.5 0,0 1,4 1.5z"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/text_tertiary"/>
|
||||
<path
|
||||
android:pathData="M5.5,3L6.5,3A0.5,0.5 0,0 1,7 3.5L7,3.5A0.5,0.5 0,0 1,6.5 4L5.5,4A0.5,0.5 0,0 1,5 3.5L5,3.5A0.5,0.5 0,0 1,5.5 3z"
|
||||
android:fillColor="@color/text_tertiary"/>
|
||||
</vector>
|
||||
19
app/src/main/res/drawable/ic_version.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="12dp"
|
||||
android:height="12dp"
|
||||
android:viewportWidth="12"
|
||||
android:viewportHeight="12">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M7.5,5L5.5,7.5L5,5H4.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/text_tertiary"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M3.5,2H8.5C9.328,2 10,2.672 10,3.5V8.5C10,9.328 9.328,10 8.5,10H3.5C2.672,10 2,9.328 2,8.5V3.5C2,2.672 2.672,2 3.5,2Z"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/text_tertiary"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_x_size_8.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="8dp"
|
||||
android:height="8dp"
|
||||
android:viewportWidth="8"
|
||||
android:viewportHeight="8">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h8v8h-8z"/>
|
||||
<path
|
||||
android:pathData="M0.6464,0.6465C0.8417,0.4512 1.1583,0.4512 1.3535,0.6465L4,3.2929L6.6465,0.6465C6.8417,0.4512 7.1583,0.4512 7.3535,0.6465C7.5488,0.8417 7.5488,1.1583 7.3535,1.3536L4.7071,4L7.3535,6.6465C7.5488,6.8417 7.5488,7.1583 7.3535,7.3536C7.1583,7.5488 6.8417,7.5488 6.6465,7.3536L4,4.7071L1.3535,7.3536C1.1583,7.5488 0.8417,7.5488 0.6464,7.3536C0.4512,7.1583 0.4512,6.8417 0.6464,6.6465L3.2929,4L0.6464,1.3536C0.4512,1.1583 0.4512,0.8417 0.6464,0.6465Z"
|
||||
android:fillColor="#000000"
|
||||
android:fillType="evenOdd"/>
|
||||
</group>
|
||||
</vector>
|
||||
@ -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="6dp"/>
|
||||
</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/primary_theme_10" />
|
||||
<corners android:radius="6dp"/>
|
||||
</shape>
|
||||
6
app/src/main/res/drawable/shape_filtered_left.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:endColor="@color/ui_surface_0"
|
||||
android:startColor="@color/ui_surface" />
|
||||
</shape>
|
||||
6
app/src/main/res/drawable/shape_filtered_right.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:endColor="@color/ui_surface"
|
||||
android:startColor="@color/ui_surface_0" />
|
||||
</shape>
|
||||
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/bg_shape_primary_theme_alpha_10_radius_6" android:state_checked="true" />
|
||||
<item android:drawable="@drawable/bg_shape_primary_theme_alpha_10_radius_6" android:state_focused="true" />
|
||||
</selector>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/button_round_theme_alpha_10" android:state_pressed="true" />
|
||||
<item android:drawable="@drawable/button_round_theme_alpha_10" android:state_focused="true" />
|
||||
<item android:drawable="@drawable/button_round_theme_alpha_10" android:state_selected="true" />
|
||||
<item android:drawable="@drawable/button_round_theme_alpha_10" android:state_checked="true" />
|
||||
<item android:drawable="@drawable/bg_shape_ui_container_1_radius_999" />
|
||||
</selector>
|
||||
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@drawable/subject_tab_down" android:state_selected="true" />
|
||||
<item android:drawable="@color/white" android:state_focused="false" />
|
||||
|
||||
</selector>
|
||||
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@drawable/bg_tag_text" android:state_checked="true" />
|
||||
<item android:drawable="@drawable/bg_tag_text" android:state_focused="true" />
|
||||
|
||||
</selector>
|
||||
@ -2,20 +2,19 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="24dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:orientation="vertical">
|
||||
android:paddingBottom="24dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextHeadline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textStyle="bold"
|
||||
android:textSize="14sp"
|
||||
tools:text="玩法" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
@ -1,34 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout 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="80dp"
|
||||
android:layout_height="52dp">
|
||||
|
||||
<ImageView
|
||||
<View
|
||||
android:id="@+id/selected_tag"
|
||||
android:layout_width="14dp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="6dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="36dp"
|
||||
android:src="@drawable/ic_catalog_selected"
|
||||
android:layout_marginTop="28dp"
|
||||
android:background="@drawable/bg_category_selected_tag"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="@id/catalog_name"
|
||||
app:layout_constraintStart_toStartOf="@id/catalog_name"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/catalog_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_max="0dp"
|
||||
tools:text="精选" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/recommend_tag"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginLeft="52dp"
|
||||
android:layout_marginStart="52dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:src="@drawable/ic_recommend"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@ -1,18 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawerLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/ui_surface">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<View
|
||||
android:id="@+id/v_more_category"
|
||||
android:layout_width="92dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/bg_more_category_default"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/ui_divider" />
|
||||
<TextView
|
||||
android:id="@+id/tv_tag_number"
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="12dp"
|
||||
android:background="@drawable/background_shape_theme_radius_999"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/text_aw_primary"
|
||||
android:textSize="8sp"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_more_category"
|
||||
app:layout_constraintTop_toTopOf="@id/v_more_category"
|
||||
tools:text="5"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_more_category"
|
||||
style="@style/TextCaption1B"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/more_category"
|
||||
app:drawableStartCompat="@drawable/ic_basic_classification"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_more_category"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_more_category"
|
||||
app:layout_constraintStart_toStartOf="@id/v_more_category"
|
||||
app:layout_constraintTop_toTopOf="@id/v_more_category" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_search_category"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="@drawable/bg_shape_ui_container_2_radius_999"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_more_category"
|
||||
app:layout_constraintEnd_toStartOf="@id/v_more_category"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/v_more_category" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_search_category"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginStart="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_search_category"
|
||||
app:layout_constraintStart_toStartOf="@id/v_search_category"
|
||||
app:layout_constraintTop_toTopOf="@id/v_search_category"
|
||||
app:srcCompat="@drawable/ic_search"
|
||||
app:tint="@color/text_instance" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_search_category"
|
||||
style="@style/TextBody2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@string/search_category_tags"
|
||||
android:textColor="@color/text_instance"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_search_category"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_search_category"
|
||||
app:layout_constraintTop_toTopOf="@id/v_search_category" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/v_more_category">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/categoryContainer"
|
||||
@ -21,11 +96,24 @@
|
||||
android:layout_marginTop="1dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/categoryRv"
|
||||
<com.gh.gamecenter.common.view.RadiusCardView
|
||||
android:id="@+id/cv_category"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/ui_background" />
|
||||
android:layout_marginTop="8dp"
|
||||
app:topRightRadius="8dp">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/categoryRv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/bg_category_sidebar" />
|
||||
</com.gh.gamecenter.common.view.RadiusCardView>
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/gamesContainer"
|
||||
@ -51,62 +139,16 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true" />
|
||||
|
||||
<ImageView
|
||||
android:visibility="gone"
|
||||
android:id="@+id/guideContainer"
|
||||
android:layout_width="187dp"
|
||||
android:layout_height="63dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginLeft="66dp"
|
||||
android:src="@drawable/pic_category_guide" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/directoryContainer"
|
||||
android:layout_width="260dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:background="@color/ui_surface">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/directoryRv"
|
||||
android:layout_above="@+id/bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/resetTv"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/bg_shape_ui_container_2_radius_999"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp"
|
||||
android:text="重置" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/confirmTv"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/bg_tag_text"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"
|
||||
android:text="确定" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
<ImageView
|
||||
android:id="@+id/guideContainer"
|
||||
android:layout_width="244dp"
|
||||
android:layout_height="57dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:src="@drawable/pic_category_guide"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/v_more_category"
|
||||
tools:visibility="visible" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -1,37 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout 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"
|
||||
android:background="@color/ui_surface">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_tags_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_tags"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="12dp" />
|
||||
|
||||
<View
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:background="@drawable/shape_filtered_left" />
|
||||
|
||||
<View
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:background="@drawable/shape_filtered_right" />
|
||||
</FrameLayout>
|
||||
|
||||
<com.gh.common.view.CategoryFilterView
|
||||
android:id="@+id/filterContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:visibility="gone"
|
||||
android:layout_below="@+id/filterContainer"
|
||||
android:id="@+id/selectedCategoryContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingBottom="8dp"
|
||||
app:flexWrap="wrap" />
|
||||
android:layout_height="36dp"
|
||||
android:layout_below="@id/fl_tags_container" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/list_skeleton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/selectedCategoryContainer" />
|
||||
android:layout_below="@+id/filterContainer" />
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/list_refresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/selectedCategoryContainer">
|
||||
android:layout_below="@+id/filterContainer">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/list_rv"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
@ -7,9 +8,18 @@
|
||||
android:id="@+id/contentContainer"
|
||||
layout="@layout/fragment_list_base_skeleton" />
|
||||
|
||||
<com.gh.gamecenter.common.view.StatusBarView
|
||||
android:id="@+id/statusBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/ui_surface"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/statusBar" />
|
||||
|
||||
</RelativeLayout>
|
||||
45
app/src/main/res/layout/fragment_subject_list.xml
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/ui_surface">
|
||||
|
||||
<com.gh.common.view.ConfigFilterView
|
||||
android:id="@+id/filterView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/list_skeleton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/filterView"/>
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/list_refresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/filterView">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/list_rv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<include
|
||||
layout="@layout/reuse_loading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true" />
|
||||
|
||||
<include layout="@layout/reuse_no_connection" />
|
||||
|
||||
<include layout="@layout/reuse_none_data" />
|
||||
|
||||
<include layout="@layout/reuse_data_exception" />
|
||||
|
||||
</RelativeLayout>
|
||||
@ -1,48 +1,146 @@
|
||||
<?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="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/subject_tab_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tab_layout_height"
|
||||
android:background="@color/ui_surface"
|
||||
android:visibility="gone">
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/subject_viewpager"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/subject_tab_container" />
|
||||
|
||||
<!-- <View-->
|
||||
<!-- android:id="@+id/subject_tab_line"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="1dp"-->
|
||||
<!-- android:layout_alignParentBottom="true"-->
|
||||
<!-- android:background="@color/background"-->
|
||||
<!-- android:visibility="gone" />-->
|
||||
<View
|
||||
android:id="@+id/background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:alpha="0"
|
||||
android:background="@color/black"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/subject_tab_container"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/subject_tab_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="@color/ui_surface"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/subject_viewpager"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.gh.gamecenter.common.view.TabIndicatorView
|
||||
android:id="@+id/subject_tab_indicator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/default_tab_indicator_height"
|
||||
android:layout_alignParentBottom="true" />
|
||||
android:layout_marginEnd="8dp"
|
||||
app:disableIndicatorScaling="true"
|
||||
app:indicatorColor="@color/primary_theme"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/optionIv"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_goneMarginEnd="0dp" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
<com.gh.gamecenter.common.view.NoDefaultMinWidthTabLayout
|
||||
android:id="@+id/subject_tab"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:tabIndicatorColor="@color/primary_theme"
|
||||
app:tabMode="scrollable"
|
||||
app:tabIndicatorHeight="0dp"
|
||||
app:tabRippleColor="@color/transparent"
|
||||
app:tabSelectedTextColor="@color/primary_theme"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:overScrollMode="never"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/optionIv"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginEnd="0dp"
|
||||
app:tabIndicator="@null"
|
||||
app:tabTextAppearance="@style/TabLayoutTextAppearance" />
|
||||
app:tabIndicatorHeight="0dp"
|
||||
app:tabMaxWidth="0dp"
|
||||
app:tabMode="scrollable"
|
||||
app:tabRippleColor="@color/transparent"
|
||||
app:tabTextAppearance="@style/ColumnCollectionTabDetailTabTextAppearance" />
|
||||
|
||||
</RelativeLayout>
|
||||
<ImageView
|
||||
android:id="@+id/optionIv"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/bg_shape_ui_container_2_radius_999"
|
||||
android:padding="6dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_options"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/subject_viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<View
|
||||
android:id="@+id/maskView"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="@drawable/bg_game_detail_tab_gradient_mask"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/optionIv"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/settingContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/subject_tab_container" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/settingGuideContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/settingGuideIv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="36dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/guide_column_collection_custom_setting" />
|
||||
|
||||
<View
|
||||
android:id="@+id/skipView"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="64dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/settingClickView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/settingClickView"
|
||||
app:layout_constraintTop_toTopOf="@+id/settingClickView" />
|
||||
|
||||
<View
|
||||
android:id="@+id/settingClickView"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/settingGuideIv"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
|
||||
android:orientation="vertical">
|
||||
@ -17,44 +18,17 @@
|
||||
android:id="@+id/subject_type_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="12dp"
|
||||
app:layout_scrollFlags="scroll|enterAlwaysCollapsed" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/subject_filter_container"
|
||||
android:layout_width="wrap_content"
|
||||
<com.gh.common.view.ConfigFilterView
|
||||
android:id="@+id/filterView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="@drawable/subject_tiled_tab_background">
|
||||
|
||||
<CheckedTextView
|
||||
android:id="@+id/subject_tabbar_hottest"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:background="@drawable/subject_tiled_tab_selector"
|
||||
android:checked="true"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingRight="24dp"
|
||||
android:text="最热"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/subject_tiled_tab_color_selector"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<CheckedTextView
|
||||
android:id="@+id/subject_tabbar_newest"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:background="@drawable/subject_tiled_tab_selector"
|
||||
android:checked="false"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingRight="24dp"
|
||||
android:text="最新"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/subject_tiled_tab_color_selector"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
@ -415,15 +415,16 @@
|
||||
android:id="@+id/device"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@drawable/rating_phone_icon"
|
||||
android:drawablePadding="4dp"
|
||||
android:drawablePadding="2dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="10sp"
|
||||
android:textSize="@dimen/tag_text_size"
|
||||
android:visibility="gone"
|
||||
app:drawableStartCompat="@drawable/ic_phone"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/version"
|
||||
@ -433,19 +434,27 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="小米2S" />
|
||||
|
||||
<TextView
|
||||
<RadioButton
|
||||
android:id="@+id/version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="8dp"
|
||||
android:gravity="center"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:button="@drawable/ic_version"
|
||||
android:checked="false"
|
||||
android:clickable="false"
|
||||
android:gravity="center_vertical"
|
||||
android:includeFontPadding="false"
|
||||
android:lineSpacingExtra="2sp"
|
||||
android:paddingStart="2dp"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="10sp"
|
||||
android:textSize="@dimen/tag_text_size"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/commentCountTv"
|
||||
app:layout_constraintStart_toEndOf="@+id/device"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginStart="8dp" />
|
||||
app:layout_goneMarginStart="8dp"
|
||||
tools:text="版本号" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/likeCountTv"
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<com.gh.gamecenter.common.view.Chips
|
||||
android:id="@+id/chips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</FrameLayout>
|
||||
12
app/src/main/res/layout/item_config_filter_size.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/size_tv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="28dp"
|
||||
android:background="@drawable/config_filter_size_background_style"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:text="全部大小"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/subject_label_text_style"
|
||||
android:textSize="@dimen/little_secondary_size" />
|
||||
@ -1,36 +1,66 @@
|
||||
<?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:id="@+id/config_controller"
|
||||
style="@style/filterRoot">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="36dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_category"
|
||||
style="@style/filterItemContainer">
|
||||
android:id="@+id/ll_type_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/catalog_tv"
|
||||
style="@style/filterItem"
|
||||
android:text="全部类别" />
|
||||
android:id="@+id/tv_type"
|
||||
style="@style/TextCaption1B"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/popular"
|
||||
android:textColor="@color/text_tertiary" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_type_arrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_type"
|
||||
style="@style/filterItemContainer">
|
||||
android:id="@+id/ll_size_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/type_tv"
|
||||
style="@style/filterItem"
|
||||
tools:text="热门推荐" />
|
||||
android:id="@+id/tv_size"
|
||||
style="@style/TextCaption1B"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/size"
|
||||
android:textColor="@color/text_tertiary" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_size_arrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_size"
|
||||
style="@style/filterItemContainer">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/size_tv"
|
||||
style="@style/filterItem"
|
||||
android:text="全部大小" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
9
app/src/main/res/layout/layout_category_filter_size.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/TextCaption2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="28dp"
|
||||
android:layout_margin="4dp"
|
||||
android:gravity="center"
|
||||
tools:text="全部大小" />
|
||||
153
app/src/main/res/layout/layout_column_collection_setting.xml
Normal file
@ -0,0 +1,153 @@
|
||||
<?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:background="@drawable/background_shape_white_radius_12_bottom_only">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scrollView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="328dp"
|
||||
android:overScrollMode="never"
|
||||
android:scrollbars="none"
|
||||
app:layout_constraintBottom_toTopOf="@+id/actionContainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/followTv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="关注内容"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="@dimen/secondary_title_text_size"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/followDesTv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="长按拖动排序,最少添加1个内容,上限为15个"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="@dimen/little_secondary_size" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/followRv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:overScrollMode="never" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/moreContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/moreTv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="更多内容"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="@dimen/secondary_title_text_size"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/moreDesTv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="点击可添加至关注内容"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="@dimen/little_secondary_size" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/moreRv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:overScrollMode="never" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/actionContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/nestedScrollView">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cancelTv"
|
||||
style="@style/GrayLightButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:text="取消" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/saveTv"
|
||||
style="@style/PrimaryButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="3"
|
||||
android:gravity="center"
|
||||
android:text="保存" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/topDivider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/divider_1px"
|
||||
android:background="@color/ui_divider"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/bottomDivider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/divider_1px"
|
||||
android:background="@color/ui_divider"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/actionContainer" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -4,47 +4,71 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/config_controller"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/default_filter_row_height"
|
||||
android:layout_height="32dp"
|
||||
android:background="@color/ui_surface"
|
||||
android:paddingLeft="@dimen/default_filter_row_padding"
|
||||
android:paddingRight="@dimen/default_filter_row_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/updateTv"
|
||||
style="@style/filterOptionItem"
|
||||
android:background="@drawable/bg_tag_text"
|
||||
style="@style/ConfigFilterOptionItem"
|
||||
android:text="更新"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dot1"
|
||||
android:layout_width="2dp"
|
||||
android:layout_height="2dp"
|
||||
android:background="@drawable/ic_filter_dot"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/recommended_tv"
|
||||
app:layout_constraintStart_toEndOf="@+id/updateTv"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recommended_tv"
|
||||
style="@style/filterOptionItem"
|
||||
android:layout_marginLeft="@dimen/default_filter_row_item_margin"
|
||||
style="@style/ConfigFilterOptionItem"
|
||||
android:text="推荐"
|
||||
android:textColor="@color/text_757575"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="@id/updateTv"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginLeft="0dp" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dot2"
|
||||
android:layout_width="2dp"
|
||||
android:layout_height="2dp"
|
||||
android:background="@drawable/ic_filter_dot"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/newest_tv"
|
||||
app:layout_constraintStart_toEndOf="@+id/recommended_tv"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/newest_tv"
|
||||
style="@style/filterOptionItem"
|
||||
android:layout_marginLeft="@dimen/default_filter_row_item_margin"
|
||||
style="@style/ConfigFilterOptionItem"
|
||||
android:text="最新"
|
||||
android:textColor="@color/text_757575"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="@id/recommended_tv"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dot3"
|
||||
android:layout_width="2dp"
|
||||
android:layout_height="2dp"
|
||||
android:background="@drawable/ic_filter_dot"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/rating_tv"
|
||||
app:layout_constraintStart_toEndOf="@+id/newest_tv"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rating_tv"
|
||||
style="@style/filterOptionItem"
|
||||
android:layout_marginLeft="@dimen/default_filter_row_item_margin"
|
||||
style="@style/ConfigFilterOptionItem"
|
||||
android:text="评分"
|
||||
android:textColor="@color/text_757575"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="@id/newest_tv"
|
||||
@ -55,14 +79,14 @@
|
||||
<TextView
|
||||
android:id="@+id/size_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:drawableRight="@drawable/ic_filter_arrow_down"
|
||||
android:drawablePadding="8dp"
|
||||
android:layout_height="match_parent"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="全部大小"
|
||||
android:textColor="@color/text_757575"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
app:drawableEndCompat="@drawable/ic_auxiliary_arrow_down_8"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
@ -1,19 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout 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="match_parent"
|
||||
android:background="@color/transparent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:id="@+id/flexbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/ui_surface"
|
||||
android:paddingBottom="8dp"
|
||||
app:flexDirection="row"
|
||||
app:flexWrap="wrap" />
|
||||
android:background="@color/transparent">
|
||||
|
||||
<View
|
||||
android:id="@+id/background"
|
||||
@ -22,4 +12,17 @@
|
||||
android:alpha="0.3"
|
||||
android:background="@color/black" />
|
||||
|
||||
</LinearLayout>
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:id="@+id/flexbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/background_shape_white_radius_12_bottom_only"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="16dp"
|
||||
app:showDivider="middle"
|
||||
app:dividerDrawable="@drawable/shape_flexbox_divider_w8_h8"
|
||||
app:flexDirection="row"
|
||||
app:flexWrap="wrap" />
|
||||
|
||||
</FrameLayout>
|
||||
19
app/src/main/res/layout/pop_category_filter_size.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?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="match_parent"
|
||||
android:background="@color/bg_mask_20">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_size"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_shape_ui_surface_bottom_radius_12"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="12dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
48
app/src/main/res/layout/pop_category_filter_type.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?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="match_parent"
|
||||
android:background="@color/bg_mask_20">
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/rg_filter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="8dp"
|
||||
android:background="@drawable/bg_shape_ui_surface_bottom_radius_12"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_popular"
|
||||
style="@style/TextBody3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:button="@null"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/popular"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_newest"
|
||||
style="@style/TextBody3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:button="@null"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/newest"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_score"
|
||||
style="@style/TextBody3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:button="@null"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/score"
|
||||
android:textColor="@color/text_secondary" />
|
||||
</RadioGroup>
|
||||
</FrameLayout>
|
||||
134
app/src/main/res/layout/pop_search_category.xml
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout 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"
|
||||
android:background="@color/bg_mask_20">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/cl_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="448dp"
|
||||
android:background="@drawable/bg_shape_ui_surface_bottom_radius_12">
|
||||
|
||||
<com.gh.gamecenter.common.view.GhSearch
|
||||
android:id="@+id/search_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:search_hint="@string/search_category_tags" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_reset"
|
||||
style="@style/TextButton2"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="@drawable/bg_common_button_light_fill_gray"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:text="@string/reset"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_submit"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="@drawable/bg_common_button_fill_blue"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_reset" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_submit"
|
||||
style="@style/TextButton2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/servers_subscribed_game_unsubscribe_dialog_confirm"
|
||||
android:textColor="@color/text_aw_primary"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_submit"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_selected_number"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="@id/v_submit"
|
||||
app:layout_constraintTop_toTopOf="@id/v_submit" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_selected_number"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:background="@drawable/bg_search_category_number"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/text_aw_primary"
|
||||
android:textSize="10sp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_submit"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_submit"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_submit"
|
||||
app:layout_constraintTop_toTopOf="@id/v_submit"
|
||||
tools:text="5" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_selected"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="12dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_reset"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_baseline"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0.5dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:background="@color/ui_divider"
|
||||
app:layout_constraintBottom_toTopOf="@id/rv_selected"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_category"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:paddingTop="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/v_baseline"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/search_view" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_results"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/v_baseline"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/search_view" />
|
||||
|
||||
<include
|
||||
android:id="@+id/reuse_no_connection"
|
||||
layout="@layout/reuse_none_data"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/v_baseline"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/search_view" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
||||
@ -201,14 +201,14 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:drawableLeft="@drawable/rating_phone_icon"
|
||||
android:drawablePadding="4dp"
|
||||
android:drawablePadding="2dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="10sp"
|
||||
android:textSize="@dimen/tag_text_size"
|
||||
app:drawableStartCompat="@drawable/ic_phone"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/vote"
|
||||
app:layout_constraintEnd_toStartOf="@+id/version"
|
||||
@ -220,17 +220,23 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:drawablePadding="2dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:lines="1"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="10sp"
|
||||
android:textSize="@dimen/tag_text_size"
|
||||
app:drawableStartCompat="@drawable/ic_version"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/vote"
|
||||
app:layout_constraintEnd_toStartOf="@+id/comment"
|
||||
app:layout_constraintStart_toEndOf="@id/device"
|
||||
app:layout_constraintTop_toTopOf="@+id/vote"
|
||||
app:layout_goneMarginStart="16dp" />
|
||||
app:layout_goneMarginStart="16dp"
|
||||
tools:text="版本号版本号版本号版本号版本号版本号版本号版本号" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/comment"
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.gh.gamecenter.common.view.Chips xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
app:chips_state="selected"
|
||||
app:chips_style="small"
|
||||
app:end_icon="@drawable/ic_x_size_8" />
|
||||
12
app/src/main/res/layout/recycler_search_category_result.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/TextBody2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="46dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:textColor="@color/text_secondary"
|
||||
tools:text="标签名称">
|
||||
|
||||
</TextView>
|
||||
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout 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:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
@ -7,25 +8,24 @@
|
||||
android:background="@drawable/bg_shape_space_radius_8">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="60dp"
|
||||
android:id="@+id/tv_name"
|
||||
style="@style/TextCaption1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="12sp"
|
||||
tools:text="最多五个字啊啊啊" />
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="最多五个字" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/selectedIv"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:src="@drawable/ic_category_selected"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/recommendIv"
|
||||
@ -33,5 +33,7 @@
|
||||
android:layout_height="12dp"
|
||||
android:src="@drawable/ic_category_recommend"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -1,22 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="24dp"
|
||||
android:overScrollMode="never"
|
||||
android:scrollbars="none">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/label_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="@dimen/default_filter_row_padding"
|
||||
android:paddingRight="@dimen/default_filter_row_padding" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/label_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="@dimen/default_filter_row_padding"
|
||||
android:paddingRight="@dimen/default_filter_row_padding" />
|
||||
</HorizontalScrollView>
|
||||
@ -3,7 +3,6 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/label"
|
||||
style="@style/filterOptionItem"
|
||||
android:layout_marginRight="@dimen/default_filter_row_item_margin"
|
||||
android:background="@drawable/text_blue_or_white_style"
|
||||
android:textColor="@color/text_black_or_white_color_style"
|
||||
android:background="@drawable/subject_label_background_style"
|
||||
android:textColor="@color/subject_label_text_style"
|
||||
tools:text="全部" />
|
||||
|
||||
@ -2,17 +2,19 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/border_round_eee_14"
|
||||
android:gravity="center">
|
||||
|
||||
<CheckedTextView
|
||||
android:id="@+id/tab_title"
|
||||
android:layout_width="68dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dp"
|
||||
android:background="@drawable/subject_tab_background_selector"
|
||||
android:gravity="center"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:text="人气榜"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/text_tabbar_video_style"
|
||||
android:textColor="@color/text_tabbar_style"
|
||||
android:textSize="12sp" />
|
||||
|
||||
</LinearLayout>
|
||||
@ -180,25 +180,6 @@
|
||||
<item name="android:orientation">horizontal</item>
|
||||
</style>
|
||||
|
||||
<style name="filterItemContainer">
|
||||
<item name="android:layout_width">0dp</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:gravity">center</item>
|
||||
</style>
|
||||
|
||||
<style name="filterItem">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_marginRight">5dp</item>
|
||||
<item name="android:drawableRight">@drawable/ic_filter_arrow_down</item>
|
||||
<item name="android:drawablePadding">5dp</item>
|
||||
<item name="android:gravity">center_vertical</item>
|
||||
<item name="android:textColor">@color/text_secondary</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textSize">12sp</item>
|
||||
</style>
|
||||
|
||||
<style name="filterOptionItem">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">24dp</item>
|
||||
|
||||
@ -687,6 +687,16 @@
|
||||
<string name="go_live">上線</string>
|
||||
<string name="number_of_reservations">%1$s人預約</string>
|
||||
<string name="wechat_app_not_install_tips">請檢查是否安裝微信客戶端</string>
|
||||
<string name="more_category">更多分類</string>
|
||||
<string name="search_category_tags">搜尋分類標籤</string>
|
||||
<string name="reset">重置</string>
|
||||
<string name="popular">熱門</string>
|
||||
<string name="size">大小</string>
|
||||
<string name="newest">最新</string>
|
||||
<string name="score">評分</string>
|
||||
<string name="selected_category_tags_max_toast">最多只能選擇5個類別</string>
|
||||
<string name="no_relevant_content_found">沒有找到相關內容~</string>
|
||||
<string name="try_a_different_search_term">換個搜尋詞試試看吧~</string>
|
||||
<string name="delete_test">刪測</string>
|
||||
<string name="v_play">暢玩</string>
|
||||
<string name="update">更新</string>
|
||||
|
||||
@ -687,6 +687,16 @@
|
||||
<string name="go_live">上线</string>
|
||||
<string name="number_of_reservations">%1$s人预约</string>
|
||||
<string name="wechat_app_not_install_tips">请检查是否安装微信客户端</string>
|
||||
<string name="more_category">更多分类</string>
|
||||
<string name="search_category_tags">搜索分类标签</string>
|
||||
<string name="reset">重置</string>
|
||||
<string name="popular">热门</string>
|
||||
<string name="size">大小</string>
|
||||
<string name="newest">最新</string>
|
||||
<string name="score">评分</string>
|
||||
<string name="selected_category_tags_max_toast">最多只能选择5个类别</string>
|
||||
<string name="no_relevant_content_found">没有找到相关内容~</string>
|
||||
<string name="try_a_different_search_term">换个搜索词试试看吧~</string>
|
||||
<string name="delete_test">删测</string>
|
||||
<string name="v_play">畅玩</string>
|
||||
<string name="update">更新</string>
|
||||
|
||||