diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index dd5b1a051c..d82054ae2a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -591,6 +591,14 @@ android:name=".simulatorgame.SimulatorManagementActivity" android:screenOrientation="portrait" /> + + + + diff --git a/app/src/main/java/com/gh/common/util/DirectUtils.kt b/app/src/main/java/com/gh/common/util/DirectUtils.kt index c0c7cf1d5d..9d9f092d3d 100644 --- a/app/src/main/java/com/gh/common/util/DirectUtils.kt +++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt @@ -22,6 +22,7 @@ import com.gh.common.exposure.ExposureType import com.gh.common.util.EntranceUtils.* import com.gh.gamecenter.* import com.gh.gamecenter.amway.AmwayActivity +import com.gh.gamecenter.catalog.CatalogActivity import com.gh.gamecenter.category.CategoryDirectoryActivity import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE import com.gh.gamecenter.entity.* @@ -132,7 +133,9 @@ object DirectUtils { "server", "top_game_comment", "wechat_bind", - "video") + "video", + "catalog" + ) fun directToLinkPage(context: Context, linkEntity: LinkEntity, @@ -199,6 +202,8 @@ object DirectUtils { "category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!) + "catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!) + "block", "版块" -> { if (linkEntity.link.isNullOrEmpty()) return directToBlock(context, @@ -887,6 +892,21 @@ object DirectUtils { jumpActivity(context, bundle) } + /** + * 跳转新分类 + */ + @JvmStatic + fun directCatalog(context: Context, catalogId: String, catalogTitle: String, entrance: String? = null, path: String? = "") { + if (catalogId.isEmpty()) return + val bundle = Bundle() + bundle.putString(KEY_TO, CatalogActivity::class.java.name) + bundle.putString(KEY_CATALOG_ID, catalogId) + bundle.putString(KEY_CATALOG_TITLE, catalogTitle) + bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER) + bundle.putString(KEY_PATH, path) + jumpActivity(context, bundle) + } + /** * 跳转到问题标签详情 */ diff --git a/app/src/main/java/com/gh/common/util/EntranceUtils.java b/app/src/main/java/com/gh/common/util/EntranceUtils.java index a957e24945..e32bd4e42c 100644 --- a/app/src/main/java/com/gh/common/util/EntranceUtils.java +++ b/app/src/main/java/com/gh/common/util/EntranceUtils.java @@ -216,6 +216,10 @@ public class EntranceUtils { public static final String KEY_DIAGNOSIS = "diagnosis"; public static final String KEY_SIMULATOR = "simulator"; public static final String KEY_MARKET_DETAILS = "market_details"; + public static final String KEY_CATALOG_ID = "catalogId"; + public static final String KEY_PRIMARY_CATALOG_ID = "primaryCatalogId"; + public static final String KEY_CATALOG_TITLE = "catalog_title"; + public static final String KEY_CATALOG_INIT_TITLE = "catalog_init_title"; public static void jumpActivity(Context context, Bundle bundle) { bundle.putBoolean(KEY_REQUIRE_REDIRECT, true); diff --git a/app/src/main/java/com/gh/common/view/CatalogFilterView.kt b/app/src/main/java/com/gh/common/view/CatalogFilterView.kt new file mode 100644 index 0000000000..21e02d6ef4 --- /dev/null +++ b/app/src/main/java/com/gh/common/view/CatalogFilterView.kt @@ -0,0 +1,320 @@ +package com.gh.common.view + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.PopupWindow +import android.widget.TextView +import androidx.core.content.ContextCompat +import com.gh.common.util.toColor +import com.gh.common.util.visibleIf +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.CatalogSwitch +import com.gh.gamecenter.entity.SubCatalogEntity +import com.gh.gamecenter.entity.SubjectSettingEntity +import com.google.android.flexbox.FlexboxLayout + +class CatalogFilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayout(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 var mTypeFilterArray = ArrayList() + private var mCatalogFilterArray = ArrayList() + private var sizeFilterArray: ArrayList? = null + + private var mOnCatalogFilterSetupListener: OnCatalogFilterSetupListener? = null + + init { + View.inflate(context, R.layout.layout_catalog_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_catalog) + mSizeContainer = findViewById(R.id.container_size) + + mTypeContainer.setOnClickListener { + showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString()) + } + + mCatalogContainer.setOnClickListener { + showSelectCatalogPopupWindow(this, mCatalogTv, mCatalogTv.text.toString()) + } + + mSizeContainer.setOnClickListener { + showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString()) + } + +// ratingTv.setOnClickListener { +// mOnConfigFilterSetupListener?.onSetupSortType(SortType.RATING) +// toggleHighlightedTextView(ratingTv, true) +// toggleHighlightedTextView(newestTv, false) +// toggleHighlightedTextView(recommendedTv, false) +// } +// +// newestTv.setOnClickListener { +// mOnConfigFilterSetupListener?.onSetupSortType(SortType.NEWEST) +// toggleHighlightedTextView(ratingTv, false) +// toggleHighlightedTextView(newestTv, true) +// toggleHighlightedTextView(recommendedTv, false) +// } +// +// recommendedTv.setOnClickListener { +// mOnConfigFilterSetupListener?.onSetupSortType(SortType.RECOMMENDED) +// toggleHighlightedTextView(ratingTv, false) +// toggleHighlightedTextView(newestTv, false) +// toggleHighlightedTextView(recommendedTv, true) +// } + } + + fun setTypeList(switch: CatalogSwitch) { + switch.run { + if ("on" == hotSort) mTypeFilterArray.add(SortType.RECOMMENDED) + if ("on" == newSort) mTypeFilterArray.add(SortType.NEWEST) + if ("on" == starSort) mTypeFilterArray.add(SortType.RATING) + } + if (mTypeFilterArray.isNotEmpty()) mTypeTv.text = mTypeFilterArray[0].value + } + + fun setCatalogList(subCatalogList: List, initCatalogName: String) { + mCatalogFilterArray = ArrayList(subCatalogList) + mCatalogTv.text = initCatalogName + } + + fun setOnConfigSetupListener(onCatalogFilterSetupListener: OnCatalogFilterSetupListener) { + mOnCatalogFilterSetupListener = onCatalogFilterSetupListener + } + + 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, R.color.text_757575)) + } + } + + private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) { + val drawableUp = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_up) + val drawableDown = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_down) + drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight) + drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight) + + typeTv.setTextColor(R.color.theme_font.toColor()) + typeTv.setCompoundDrawables(null, null, drawableUp, null) + + val inflater = LayoutInflater.from(typeTv.context) + val layout = inflater.inflate(R.layout.layout_filter_size, null) + val popupWindow = PopupWindow( + layout, + LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT) + + val flexboxLayout = layout.findViewById(R.id.flexbox) + val backgroundView = layout.findViewById(R.id.background) + + backgroundView.setOnClickListener { + popupWindow.dismiss() + } + + for (type in mTypeFilterArray) { + val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false) + + // 单列 3 个,强行设置宽度为屏幕的 1/3 + val width = typeTv.context.resources.displayMetrics.widthPixels / 3 + val height = item.layoutParams.height + + item.layoutParams = ViewGroup.LayoutParams(width, height) + flexboxLayout.addView(item) + + val tv = item.findViewById(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 + + mOnCatalogFilterSetupListener?.onSetupSortType(type) + } + } + + popupWindow.setOnDismissListener { + typeTv.setTextColor(R.color.text_757575.toColor()) + typeTv.setCompoundDrawables(null, null, drawableDown, null) + } + + popupWindow.isTouchable = true + popupWindow.isFocusable = true + popupWindow.showAsDropDown(containerView, 0, 0) + } + + private fun showSelectCatalogPopupWindow(containerView: View, catalogTv: TextView, catalogText: String) { + val drawableUp = ContextCompat.getDrawable(catalogTv.context, R.drawable.ic_filter_arrow_up) + val drawableDown = ContextCompat.getDrawable(catalogTv.context, R.drawable.ic_filter_arrow_down) + drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight) + drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight) + + catalogTv.setTextColor(R.color.theme_font.toColor()) + catalogTv.setCompoundDrawables(null, null, drawableUp, null) + + val inflater = LayoutInflater.from(catalogTv.context) + val layout = inflater.inflate(R.layout.layout_filter_size, null) + val popupWindow = PopupWindow( + layout, + LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT) + + val flexboxLayout = layout.findViewById(R.id.flexbox) + val backgroundView = layout.findViewById(R.id.background) + + backgroundView.setOnClickListener { + popupWindow.dismiss() + } + + for (entity in mCatalogFilterArray) { + val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false) + + // 单列 3 个,强行设置宽度为屏幕的 1/3 + val width = catalogTv.context.resources.displayMetrics.widthPixels / 3 + val height = item.layoutParams.height + + item.layoutParams = ViewGroup.LayoutParams(width, height) + flexboxLayout.addView(item) + + val tv = item.findViewById(R.id.size_tv) + val iv = item.findViewById(R.id.recommend_iv) + tv.text = entity.name + iv.visibleIf(entity.recommended) + + toggleHighlightedTextView(tv, catalogText == entity.name) + + tv.tag = entity.name + + item.setOnClickListener { + toggleHighlightedTextView(tv, true) + popupWindow.dismiss() + catalogTv.text = entity.name + + mOnCatalogFilterSetupListener?.onSetupSortCatalog(entity) + } + } + + popupWindow.setOnDismissListener { + catalogTv.setTextColor(R.color.text_757575.toColor()) + catalogTv.setCompoundDrawables(null, null, drawableDown, null) + } + + popupWindow.isTouchable = true + popupWindow.isFocusable = true + popupWindow.showAsDropDown(containerView, 0, 0) + } + + private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) { + val drawableUp = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_up) + val drawableDown = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_down) + drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight) + drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight) + + sizeTv.setTextColor(R.color.theme_font.toColor()) + sizeTv.setCompoundDrawables(null, null, drawableUp, null) + + val inflater = LayoutInflater.from(sizeTv.context) + val layout = inflater.inflate(R.layout.layout_filter_size, null) + val popupWindow = PopupWindow( + layout, + LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT) + + val flexboxLayout = layout.findViewById(R.id.flexbox) + val backgroundView = layout.findViewById(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 { + popupWindow.dismiss() + } + + for (size in sizeFilterArray!!) { + val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false) + + // 单列 3 个,强行设置宽度为屏幕的 1/3 + val width = sizeTv.context.resources.displayMetrics.widthPixels / 3 + val height = item.layoutParams.height + + item.layoutParams = ViewGroup.LayoutParams(width, height) + flexboxLayout.addView(item) + + val tv = item.findViewById(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 + + mOnCatalogFilterSetupListener?.onSetupSortSize(size) + } + } + + popupWindow.setOnDismissListener { + sizeTv.setTextColor(R.color.text_757575.toColor()) + sizeTv.setCompoundDrawables(null, null, drawableDown, null) + } + + popupWindow.isTouchable = true + popupWindow.isFocusable = true + popupWindow.showAsDropDown(containerView, 0, 0) + } + + private fun getDefaultSizeFilterArray(): ArrayList { + return arrayListOf().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 = "100M-1G")) + add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上")) + } + } + + interface OnCatalogFilterSetupListener { + fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) + fun onSetupSortType(sortType: SortType) + fun onSetupSortCatalog(sortCatalog: SubCatalogEntity) + } + + enum class SortType(val value: String) { + RECOMMENDED("热门推荐"), + NEWEST("最新上线"), + RATING("最高评分") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/view/ConfigFilterView.kt b/app/src/main/java/com/gh/common/view/ConfigFilterView.kt index cec37b79a6..e0460afa1e 100644 --- a/app/src/main/java/com/gh/common/view/ConfigFilterView.kt +++ b/app/src/main/java/com/gh/common/view/ConfigFilterView.kt @@ -12,7 +12,7 @@ import android.widget.PopupWindow import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat -import com.gh.common.util.DisplayUtils +import com.gh.common.util.toColor import com.gh.gamecenter.R import com.gh.gamecenter.entity.SubjectSettingEntity import com.google.android.flexbox.FlexboxLayout @@ -69,16 +69,13 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib mOnConfigFilterSetupListener = onConfigFilterSetupListener } - fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) { + private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) { if (highlightIt) { - targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.text_blue_background) + targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text) targetTextView.setTextColor(Color.WHITE) } else { - val colorDrawable = GradientDrawable() - colorDrawable.setColor(Color.WHITE) - colorDrawable.cornerRadius = DisplayUtils.dip2px(1.5f).toFloat() - targetTextView.background = colorDrawable - targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_3a3a3a)) + targetTextView.background = null + targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575)) } } @@ -88,8 +85,8 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight) drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight) + sizeTv.setTextColor(R.color.theme_font.toColor()) sizeTv.setCompoundDrawables(null, null, drawableUp, null) - sizeTv.text = "收起" val inflater = LayoutInflater.from(sizeTv.context) val layout = inflater.inflate(R.layout.layout_filter_size, null) @@ -146,10 +143,8 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib } popupWindow.setOnDismissListener { + sizeTv.setTextColor(R.color.text_757575.toColor()) sizeTv.setCompoundDrawables(null, null, drawableDown, null) - if (sizeTv.text == "收起") { - sizeTv.text = sizeText - } } popupWindow.isTouchable = true @@ -160,11 +155,11 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib private fun getDefaultSizeFilterArray(): ArrayList { return arrayListOf().apply { add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小")) - add(SubjectSettingEntity.Size(min = -1, max = 20, text = "20M以下")) - add(SubjectSettingEntity.Size(min = 20, max = 50, text = "20-50M")) - add(SubjectSettingEntity.Size(min = 50, max = 100, text = "50-100M")) - add(SubjectSettingEntity.Size(min = 100, max = 500, text = "100-500M")) - add(SubjectSettingEntity.Size(min = 500, max = -1, text = "500M以上")) + 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 = "100M-1G")) + add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上")) } } diff --git a/app/src/main/java/com/gh/gamecenter/catalog/CatalogActivity.kt b/app/src/main/java/com/gh/gamecenter/catalog/CatalogActivity.kt new file mode 100644 index 0000000000..e25e53dbb5 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/CatalogActivity.kt @@ -0,0 +1,33 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.gh.common.util.EntranceUtils +import com.gh.gamecenter.NormalActivity +import com.gh.gamecenter.R + +class CatalogActivity : NormalActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setToolbarMenu(R.menu.menu_download) + } + + override fun showDownloadMenu(): Boolean { + return true + } + + override fun provideNormalIntent(): Intent { + return getTargetIntent(this, CatalogActivity::class.java, CatalogFragment::class.java) + } + + companion object { + fun getIntent(context: Context, catalogId: String, catalogTitle: String): Intent { + val bundle = Bundle() + bundle.putString(EntranceUtils.KEY_CATALOG_ID, catalogId) + bundle.putString(EntranceUtils.KEY_CATALOG_TITLE, catalogTitle) + return getTargetIntent(context, CatalogActivity::class.java, CatalogFragment::class.java, bundle) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/CatalogAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/CatalogAdapter.kt new file mode 100644 index 0000000000..48e98e28a9 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/CatalogAdapter.kt @@ -0,0 +1,47 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.util.toColor +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.CatalogItemBinding +import com.gh.gamecenter.entity.SubCatalogEntity +import com.lightgame.adapter.BaseRecyclerAdapter + +class CatalogAdapter(context: Context, private val mFragment: CatalogFragment, private val mList: List) : BaseRecyclerAdapter(context) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CatalogItemViewHolder { + val view = mLayoutInflater.inflate(R.layout.catalog_item, parent, false) + return CatalogItemViewHolder(CatalogItemBinding.bind(view)) + } + + override fun getItemCount(): Int { + return mList.size + } + + override fun onBindViewHolder(holder: CatalogItemViewHolder, position: Int) { + holder.binding.run { + val catalogEntity = mList[position] + entity = catalogEntity + executePendingBindings() + if (catalogEntity.name == mFragment.selectedCatalogName) { + selectedTag.visibility = View.VISIBLE + root.setBackgroundColor(R.color.white.toColor()) + } else { + selectedTag.visibility = View.GONE + root.setBackgroundColor(R.color.text_F5F5F5.toColor()) + } + root.setOnClickListener { + if (catalogEntity.name != mFragment.selectedCatalogName) { + mFragment.selectedCatalogName = catalogEntity.name + mFragment.changeCatalog(position) + notifyDataSetChanged() + } + } + } + } + + class CatalogItemViewHolder(val binding: CatalogItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/CatalogFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/CatalogFragment.kt new file mode 100644 index 0000000000..196cbb03d2 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/CatalogFragment.kt @@ -0,0 +1,119 @@ +package com.gh.gamecenter.catalog + +import android.os.Bundle +import android.view.View +import android.widget.LinearLayout +import androidx.core.os.bundleOf +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.EntranceUtils +import com.gh.common.util.viewModelProvider +import com.gh.common.view.FixLinearLayoutManager +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.entity.SubCatalogEntity +import com.gh.gamecenter.normal.NormalFragment +import kotterknife.bindView + +class CatalogFragment : NormalFragment() { + + private val mReuseLoading by bindView(R.id.reuse_ll_loading) + private val mReuseNoConnection by bindView(R.id.reuse_no_connection) + private val mReuseNoData by bindView(R.id.reuse_none_data) + private val mCatalogContainer by bindView(R.id.container_catalog) + private val mCatalogRv by bindView(R.id.rv_catalog) + + private lateinit var mViewModel: CatalogViewModel + private lateinit var mEntity: CatalogEntity + private lateinit var mSpecialCatalogFragment: SpecialCatalogFragment + private lateinit var mSubCatalogFragment: SubCatalogFragment + private var mCatalogId: String = "" + private var mSelectedPosition = 0 + var selectedCatalogName: String = "" + + override fun getLayoutId() = R.layout.fragment_catalog + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: "" + mViewModel = viewModelProvider(CatalogViewModel.Factory(mCatalogId)) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setNavigationTitle(arguments?.getString(EntranceUtils.KEY_CATALOG_TITLE)) + mViewModel.catalogs.observe(viewLifecycleOwner, Observer { + mReuseLoading.visibility = View.GONE + if (it != null) { + mReuseNoConnection.visibility = View.GONE + if (it.subCatalog.isNotEmpty()) { + mCatalogContainer.visibility = View.VISIBLE + mReuseNoData.visibility = View.GONE + mEntity = it + if (mEntity.hasSpecial) { + val specialEntity = SubCatalogEntity(name = "精选") + (mEntity.subCatalog as ArrayList).add(0, specialEntity) + } + initView() + } else { + mCatalogContainer.visibility = View.GONE + mReuseNoData.visibility = View.VISIBLE + } + } else { + mCatalogContainer.visibility = View.GONE + mReuseNoData.visibility = View.GONE + mReuseNoConnection.visibility = View.VISIBLE + mReuseNoConnection.setOnClickListener { + mReuseLoading.visibility = View.VISIBLE + mViewModel.getCatalogs() + } + } + }) + } + + private fun initView() { + mEntity.run { + if (subCatalog.isNotEmpty()) { + selectedCatalogName = subCatalog[0].name + mCatalogRv.layoutManager = FixLinearLayoutManager(requireContext()) + mCatalogRv.adapter = CatalogAdapter(requireContext(), this@CatalogFragment, subCatalog) + + if (hasSpecial) { + mSpecialCatalogFragment = childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.simpleName) as? SpecialCatalogFragment ?: SpecialCatalogFragment() + mSpecialCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id) + childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSpecialCatalogFragment, SpecialCatalogFragment::class.java.simpleName).commitAllowingStateLoss() + } else { + mSubCatalogFragment = childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.simpleName) as? SubCatalogFragment ?: SubCatalogFragment() + mSubCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id, EntranceUtils.KEY_PRIMARY_CATALOG_ID to subCatalog[0].id) + childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSubCatalogFragment, SubCatalogFragment::class.java.simpleName).commitAllowingStateLoss() + } + } + + } + } + + fun changeCatalog(position: Int) { + mEntity.run { + if (hasSpecial) { + if (mSelectedPosition == 0) { + mSubCatalogFragment = childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.simpleName) as? SubCatalogFragment ?: SubCatalogFragment() + mSubCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id, EntranceUtils.KEY_PRIMARY_CATALOG_ID to subCatalog[position].id) + childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSubCatalogFragment, SubCatalogFragment::class.java.simpleName).commitAllowingStateLoss() + } else { + if (position == 0) { + mSpecialCatalogFragment = childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.simpleName) as? SpecialCatalogFragment ?: SpecialCatalogFragment() + mSpecialCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id) + childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSpecialCatalogFragment, SpecialCatalogFragment::class.java.simpleName).commitAllowingStateLoss() + } else { + mSubCatalogFragment.changeSubCatalog(subCatalog[position].id) + } + } + } else { + mSubCatalogFragment.changeSubCatalog(subCatalog[position].id) + } + mSelectedPosition = position + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/CatalogViewModel.kt b/app/src/main/java/com/gh/gamecenter/catalog/CatalogViewModel.kt new file mode 100644 index 0000000000..1db2a7bb14 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/CatalogViewModel.kt @@ -0,0 +1,47 @@ +package com.gh.gamecenter.catalog + +import android.annotation.SuppressLint +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +class CatalogViewModel(application: Application, private val catalogId: String) : AndroidViewModel(application) { + + private val api = RetrofitManager.getInstance(getApplication()).api + var catalogs = MutableLiveData() + + init { + getCatalogs() + } + + @SuppressLint("CheckResult") + fun getCatalogs() { + api.getCatalogs(catalogId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: CatalogEntity) { + catalogs.postValue(data) + } + + override fun onFailure(exception: Exception) { + super.onFailure(exception) + catalogs.postValue(null) + } + }) + } + + class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return CatalogViewModel(HaloApp.getInstance().application, catalogId) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListActivity.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListActivity.kt new file mode 100644 index 0000000000..9f49914251 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListActivity.kt @@ -0,0 +1,33 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.gh.common.util.EntranceUtils +import com.gh.gamecenter.NormalActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.CatalogEntity + +class NewCatalogListActivity : NormalActivity() { + + companion object { + fun getIntent(context: Context, catalogTitle: String, catalog: CatalogEntity, initTitle: String): Intent { + val bundle = Bundle() + bundle.putParcelable(EntranceUtils.KEY_DATA, catalog) + bundle.putString(EntranceUtils.KEY_NAME, catalog.name) + bundle.putString(EntranceUtils.KEY_CATALOG_TITLE, catalogTitle) + bundle.putString(EntranceUtils.KEY_CATALOG_INIT_TITLE, initTitle) + return getTargetIntent(context, NewCatalogListActivity::class.java, NewCatalogListFragment::class.java, bundle) + } + } + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setToolbarMenu(R.menu.menu_download) + } + + override fun showDownloadMenu(): Boolean { + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt new file mode 100644 index 0000000000..d8223befa7 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt @@ -0,0 +1,168 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.util.SparseArray +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.constant.ItemViewType +import com.gh.common.exposure.ExposureEvent +import com.gh.common.exposure.ExposureSource +import com.gh.common.exposure.ExposureType +import com.gh.common.exposure.IExposable +import com.gh.common.util.DownloadItemUtils +import com.gh.common.util.StringUtils +import com.gh.common.util.dip2px +import com.gh.gamecenter.GameDetailActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.adapter.viewholder.GameViewHolder +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.baselist.LoadType +import com.gh.gamecenter.databinding.GameItemBinding +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.eventbus.EBDownloadStatus +import com.gh.gamecenter.game.GameItemViewHolder +import com.lightgame.download.DownloadEntity +import java.util.* + +class NewCatalogListAdapter(context: Context, + private val mViewModel: NewCatalogListViewModel, + private val mEntrance: String?) : ListAdapter(context), IExposable { + + private val mExposureEventSparseArray: SparseArray = SparseArray() + + val positionAndPackageMap = HashMap() + + override fun setListData(updateData: MutableList?) { + // 记录游戏位置 + if (updateData != null) { + for (i in 0 until updateData.size) { + val gameEntity = updateData[i] + var packages = gameEntity.id + for (apkEntity in gameEntity.getApk()) { + packages += apkEntity.packageName + } + positionAndPackageMap[packages + i] = i + } + } + super.setListData(updateData) + } + + fun clearPositionAndPackageMap() { + positionAndPackageMap.clear() + } + + override fun areItemsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean { + return oldItem?.id == newItem?.id + } + + override fun getItemViewType(position: Int): Int { + if (position == itemCount - 1) { + return ItemViewType.ITEM_FOOTER + } + return ItemViewType.GAME_NORMAL + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + ItemViewType.GAME_NORMAL -> { + GameItemViewHolder(GameItemBinding.bind(mLayoutInflater.inflate(R.layout.game_item, parent, false))) + } + else -> { + FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)) + } + } + } + + override fun getItemCount(): Int { + return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1 + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is GameItemViewHolder) { + val gameEntity = mEntityList[position] + + holder.binding.game = gameEntity + holder.initServerType(gameEntity) + holder.binding.hideSize = true + holder.binding.executePendingBindings() + + val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px() + holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px()) + + gameEntity.sequence = position + 1 + + val sortType = mViewModel.sortType.value + val toolbarTitle = mViewModel.title + val categoryTitle = mViewModel.categoryTitle + val selectedCatalogName = mViewModel.selectedCatalog.name + + val exposureSources = ArrayList() + exposureSources.add(ExposureSource(categoryTitle, selectedCatalogName)) + exposureSources.add(ExposureSource("二级分类", "$selectedCatalogName+$sortType")) + gameEntity.sequence = position + 1 + + val event = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE) + mExposureEventSparseArray.put(position, event) + + holder.itemView.setOnClickListener { + GameDetailActivity.startGameDetailActivity( + mContext, + gameEntity, + StringUtils.buildString(mEntrance, "+(", toolbarTitle, ":列表[", selectedCatalogName, "=", sortType, "=", (position + 1).toString(), "])"), + event) + } + DownloadItemUtils.setOnClickListener(mContext, + holder.binding.downloadBtn, + gameEntity, + position, + this, + StringUtils.buildString(StringUtils.buildString(mEntrance, "+(", toolbarTitle, ":列表[", selectedCatalogName, "=", sortType, "=", (position + 1).toString(), "])")), + StringUtils.buildString(selectedCatalogName, ":", gameEntity.name), + event) + + DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding), true, "star&brief") + } else if (holder is FooterViewHolder) { + holder.initItemPadding() + holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint) + holder.itemView.setOnClickListener { + if (mIsNetworkError) { + mViewModel.load(LoadType.RETRY) + } + } + } + } + + fun notifyItemByDownload(download: DownloadEntity) { + for (key in positionAndPackageMap.keys) { + if (key.contains(download.packageName) && key.contains(download.gameId)) { + val position = positionAndPackageMap[key] + if (position != null && mEntityList != null && position < mEntityList.size) { + mEntityList[position].getEntryMap()[download.platform] = download + notifyItemChanged(position) + } + } + } + } + + fun notifyItemAndRemoveDownload(status: EBDownloadStatus) { + for (key in positionAndPackageMap.keys) { + if (key.contains(status.packageName) && key.contains(status.gameId)) { + val position = positionAndPackageMap[key] + if (position != null && mEntityList != null && position < mEntityList.size) { + mEntityList[position].getEntryMap().remove(status.platform) + notifyItemChanged(position) + } + } + } + } + + override fun getEventByPosition(pos: Int): ExposureEvent? { + return mExposureEventSparseArray.get(pos) + } + + override fun getEventListByPosition(pos: Int): List? { + return null + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt new file mode 100644 index 0000000000..08bb2be07d --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt @@ -0,0 +1,154 @@ +package com.gh.gamecenter.catalog + +import android.os.Bundle +import android.view.View +import com.ethanhua.skeleton.Skeleton +import com.gh.common.constant.Constants +import com.gh.common.exposure.ExposureListener +import com.gh.common.util.* +import com.gh.common.view.CatalogFilterView +import com.gh.common.xapk.XapkInstaller +import com.gh.common.xapk.XapkUnzipStatus +import com.gh.download.DownloadManager +import com.gh.gamecenter.R +import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.entity.* +import com.gh.gamecenter.eventbus.EBDownloadStatus +import com.gh.gamecenter.eventbus.EBPackage +import com.lightgame.download.DataWatcher +import com.lightgame.download.DownloadEntity +import kotterknife.bindView +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class NewCatalogListFragment : ListFragment() { + + private val mSkeletonView by bindView(R.id.list_skeleton) + private val mFilterView by bindView(R.id.filter_container) + + private var mPrimeCatalog: CatalogEntity? = null + private var mSubCatalogList = arrayListOf() + private var mInitCatalogName = "" + + private var mAdapter: NewCatalogListAdapter? = null + private val mDataWatcher = object : DataWatcher() { + override fun onDataChanged(downloadEntity: DownloadEntity) { + mAdapter?.notifyItemByDownload(downloadEntity) + + if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) { + showUnzipFailureDialog(downloadEntity) + } + } + } + + private lateinit var mExposureListener: ExposureListener + private lateinit var mViewModel: NewCatalogListViewModel + + override fun getLayoutId() = R.layout.fragment_catalog_list + + override fun provideListViewModel() = viewModelProvider() + + override fun provideListAdapter() = mAdapter ?: NewCatalogListAdapter(requireContext(), mViewModel, mEntrance).apply { mAdapter = this } + + override fun getItemDecoration() = null + + override fun onCreate(savedInstanceState: Bundle?) { + mViewModel = provideListViewModel() + + mViewModel.title = arguments?.getString(EntranceUtils.KEY_NAME) ?: "" + mViewModel.categoryTitle = arguments?.getString(EntranceUtils.KEY_CATALOG_TITLE) ?: "" + mEntrance = arguments?.getString(EntranceUtils.KEY_ENTRANCE) ?: Constants.ENTRANCE_UNKNOWN + mPrimeCatalog = arguments?.getParcelable(EntranceUtils.KEY_DATA) + mSubCatalogList = mPrimeCatalog?.subCatalog as ArrayList + + mInitCatalogName = arguments?.getString(EntranceUtils.KEY_CATALOG_INIT_TITLE) ?: "" + + mViewModel.selectedCatalog = mSubCatalogList.find { entity -> entity.name == mInitCatalogName } + ?: SubCatalogEntity() + + super.onCreate(savedInstanceState) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setNavigationTitle(mViewModel.title) + + initFilterView() + + mViewModel.refresh.observeNonNull(this) { onRefresh() } + + mExposureListener = ExposureListener(this, mAdapter!!) + mListRv.addOnScrollListener(mExposureListener) + + mSkeletonScreen = Skeleton.bind(mSkeletonView).shimmer(false).load(R.layout.fragment_subject_skeleton).show() + } + + private fun initFilterView() { + mFilterView.run { + visibility = View.VISIBLE + setTypeList(mPrimeCatalog?.switch ?: CatalogSwitch()) + setCatalogList(mSubCatalogList, mInitCatalogName) + setOnConfigSetupListener(object : CatalogFilterView.OnCatalogFilterSetupListener { + override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) { + mViewModel.updateSortConfig(sortSize = sortSize) + } + + override fun onSetupSortType(sortType: CatalogFilterView.SortType) { + mViewModel.updateSortConfig(sortType = sortType) + } + + override fun onSetupSortCatalog(sortCatalog: SubCatalogEntity) { + mViewModel.updateSortConfig(sortCatalog = sortCatalog) + } + }) + } + + } + + override fun onResume() { + if (isEverPause && mAdapter != null) mAdapter?.notifyDataSetChanged() + super.onResume() + DownloadManager.getInstance(context).addObserver(mDataWatcher) + } + + override fun onPause() { + super.onPause() + DownloadManager.getInstance(context).removeObserver(mDataWatcher) + } + + override fun onRefresh() { + mAdapter?.clearPositionAndPackageMap() + + super.onRefresh() + } + + // 下载被删除事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(status: EBDownloadStatus) { + if ("delete" == status.status) { + mAdapter?.notifyItemAndRemoveDownload(status) + } + } + + // 安装/卸载 事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(busFour: EBPackage) { + if ("安装" == busFour.type || "卸载" == busFour.type) { + mAdapter?.notifyDataSetChanged() + } + } + + fun showUnzipFailureDialog(downloadEntity: DownloadEntity) { + val data = mAdapter?.positionAndPackageMap ?: return + for (gameAndPosition in data) { + if (gameAndPosition.key.contains(downloadEntity.packageName)) { + val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value) + if (targetView != null) { + DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity) + return + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt new file mode 100644 index 0000000000..65971afac2 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt @@ -0,0 +1,82 @@ +package com.gh.gamecenter.catalog + +import android.app.Application +import androidx.lifecycle.MutableLiveData +import com.gh.common.util.UrlFilterUtils +import com.gh.common.view.CatalogFilterView +import com.gh.gamecenter.baselist.ListViewModel +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.entity.SubCatalogEntity +import com.gh.gamecenter.entity.SubjectSettingEntity +import com.gh.gamecenter.retrofit.RetrofitManager +import io.reactivex.Observable +import io.reactivex.Single + +class NewCatalogListViewModel(application: Application) : ListViewModel(application) { + + var title = "" // 显示在 Toolbar 的标题 + var categoryTitle = "" // 跳转进来的分类的标题 + + val refresh = MutableLiveData() + + var selectedCatalog = SubCatalogEntity() + var sortType = CatalogFilterView.SortType.RECOMMENDED + private var mSortSize = SubjectSettingEntity.Size() + private val api = RetrofitManager.getInstance(getApplication()).api + + override fun provideDataObservable(page: Int): Observable>? = null + + override fun provideDataSingle(page: Int): Single> { + return if (selectedCatalog.link.type == "column") { + api.getColumn(selectedCatalog.link.link, getSortType(), getSortSize(), page) + } else { + api.getGamesWithSpecificTag(getSortSize(), getSortType(), page) + } + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) } + } + + fun updateSortConfig(sortSize: SubjectSettingEntity.Size? = null, + sortType: CatalogFilterView.SortType? = null, + sortCatalog: SubCatalogEntity? = null) { + when { + sortSize != null && sortSize != mSortSize -> { + mSortSize = sortSize + refresh.postValue(true) + } + + sortType != null && sortType != this.sortType -> { + this.sortType = sortType + refresh.postValue(true) + } + + sortCatalog != null && sortCatalog != selectedCatalog -> { + selectedCatalog = sortCatalog + refresh.postValue(true) + } + } + } + + private fun getSortSize(): String? { + return if (selectedCatalog.link.type == "column") { + UrlFilterUtils.getFilterQuery( + "min_size", mSortSize.min.toString(), + "max_size", mSortSize.max.toString()) + } else { + UrlFilterUtils.getFilterQuery( + "tag_id", selectedCatalog.link.link, + "min_size", mSortSize.min.toString(), + "max_size", mSortSize.max.toString()) + } + } + + private fun getSortType(): String? { + return when (sortType) { + CatalogFilterView.SortType.RECOMMENDED -> "download:-1" + CatalogFilterView.SortType.NEWEST -> "publish:-1" + CatalogFilterView.SortType.RATING -> "star:-1" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogAdapter.kt new file mode 100644 index 0000000000..a945c52e5d --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogAdapter.kt @@ -0,0 +1,192 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.constant.ItemViewType +import com.gh.common.util.DirectUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.databinding.CatalogHeaderItemBinding +import com.gh.gamecenter.databinding.CatalogImageItemBinding +import com.gh.gamecenter.databinding.CatalogSubjectCollectionItemBinding +import com.gh.gamecenter.databinding.CatalogSubjectItemBinding +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.subject.SubjectActivity.Companion.startSubjectActivity + +class SpecialCatalogAdapter(context: Context) : ListAdapter(context) { + + override fun getItemCount() = if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT + + override fun areItemsTheSame(oldItem: SpecialCatalogItemData?, newItem: SpecialCatalogItemData?): Boolean { + return when { + oldItem?.header != null && newItem?.header != null -> { + oldItem.header.id == newItem.header.id + } + + oldItem?.bigImage != null && newItem?.bigImage != null -> { + oldItem.bigImage.id == newItem.bigImage.id + } + + oldItem?.subject != null && newItem?.subject != null -> { + oldItem.subject.id == newItem.subject.id + } + + oldItem?.subjectCollection != null && newItem?.subjectCollection != null -> { + oldItem.subjectCollection.id == newItem.subjectCollection.id + } + + else -> super.areItemsTheSame(oldItem, newItem) + } + } + + override fun areContentsTheSame(oldItem: SpecialCatalogItemData?, newItem: SpecialCatalogItemData?): Boolean { + return when { + oldItem?.header != null && newItem?.header != null -> { + oldItem.header.id == newItem.header.id + } + + oldItem?.bigImage != null && newItem?.bigImage != null -> { + oldItem.bigImage.id == newItem.bigImage.id + } + + oldItem?.subject != null && newItem?.subject != null -> { + oldItem.subject.id == newItem.subject.id + } + + oldItem?.subjectCollection != null && newItem?.subjectCollection != null -> { + oldItem.subjectCollection.id == newItem.subjectCollection.id + } + + else -> super.areItemsTheSame(oldItem, newItem) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val view: View + return when (viewType) { + ItemViewType.ITEM_FOOTER -> { + view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false) + FooterViewHolder(view) + } + + TYPE_HEADER -> CatalogHeaderItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_header_item, parent, false)) + + TYPE_BIG_IMAGE -> CatalogImageItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_image_item, parent, false)) + + TYPE_SUBJECT -> CatalogSubjectItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_item, parent, false)) + + TYPE_SUBJECT_COLLECTION -> CatalogSubjectCollectionItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_collection_item, parent, false)) + + else -> throw NullPointerException() + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (holder) { + is CatalogImageItemHolder -> { + val imageEntity = mEntityList[position].bigImage!! + holder.binding.run { + entity = imageEntity.image + root.setOnClickListener { DirectUtils.directToLinkPage(mContext, imageEntity.link, "新分类-精选分类", "图片") } + } + } + + is CatalogHeaderItemHolder -> { + val entity = mEntityList[position].header!! + val specialLink = entity.link + holder.binding.run { + link = specialLink + headMore.setOnClickListener { + if (entity.type == "专题合集") { + DirectUtils.directToColumnCollection(mContext, specialLink.link ?: "", -1, "(游戏-专题:" + specialLink.text + "-全部)") + } else { + startSubjectActivity(mContext, specialLink.link, specialLink.text, false, "(游戏-专题:" + specialLink.text + "-全部)") + } + } + } + } + + is CatalogSubjectItemHolder -> { + val subject = mEntityList[position].subject!! + holder.bindSubject(subject.link.data) + } + + is CatalogSubjectCollectionItemHolder -> { + val subjectCollection = mEntityList[position].subjectCollection!! + holder.bindSubjectCollection(subjectCollection.link.data) + } + + is FooterViewHolder -> { + holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint) + } + } + } + + override fun getItemViewType(position: Int): Int { + return if (position == itemCount - 1) { + ItemViewType.ITEM_FOOTER + } else { + val item = mEntityList[position] + when { + item.header != null -> TYPE_HEADER + item.bigImage != null -> TYPE_BIG_IMAGE + item.subject != null -> TYPE_SUBJECT + item.subjectCollection != null -> TYPE_SUBJECT_COLLECTION + else -> TYPE_SUBJECT_COLLECTION + } + } + } + + class CatalogImageItemHolder(val binding: CatalogImageItemBinding) : BaseRecyclerViewHolder(binding.root) + + class CatalogHeaderItemHolder(val binding: CatalogHeaderItemBinding) : BaseRecyclerViewHolder(binding.root) + + class CatalogSubjectItemHolder(val binding: CatalogSubjectItemBinding) : BaseRecyclerViewHolder(binding.root) { + + fun bindSubject(gameList: List) { + binding.gameList.run { + var subjectAdapter = adapter + if (subjectAdapter is SpecialCatalogSubjectAdapter) { + subjectAdapter.checkResetData(gameList) + return + } + subjectAdapter = SpecialCatalogSubjectAdapter(context, gameList) + layoutManager = GridLayoutManager(context, 3) + adapter = subjectAdapter + } + } + } + + class CatalogSubjectCollectionItemHolder(val binding: CatalogSubjectCollectionItemBinding) : BaseRecyclerViewHolder(binding.root) { + + fun bindSubjectCollection(subjectCollection: List) { + binding.subjectCollectionList.run { + var collectionAdapter = adapter + if (collectionAdapter is SpecialCatalogSubjectCollectionAdapter) { + collectionAdapter.checkResetData(subjectCollection) + return + } + collectionAdapter = SpecialCatalogSubjectCollectionAdapter(context, subjectCollection) + layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + adapter = collectionAdapter + } + } + } + + companion object { + private const val TYPE_HEADER = 900 + + private const val TYPE_BIG_IMAGE = 901 + + private const val TYPE_SUBJECT = 902 + + private const val TYPE_SUBJECT_COLLECTION = 903 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt new file mode 100644 index 0000000000..40a28cd5b5 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt @@ -0,0 +1,32 @@ +package com.gh.gamecenter.catalog + +import android.graphics.Color +import android.os.Bundle +import android.view.View +import com.gh.common.util.* +import com.gh.gamecenter.baselist.ListFragment + +class SpecialCatalogFragment : ListFragment() { + + private var mCatalogId = "" + + private var mAdapter: SpecialCatalogAdapter? = null + + override fun provideListViewModel() = viewModelProvider(SpecialCatalogViewModel.Factory(mCatalogId)) + + override fun provideListAdapter() = mAdapter ?: SpecialCatalogAdapter(requireContext()).apply { mAdapter = this } + + override fun getItemDecoration() = null + + override fun onCreate(savedInstanceState: Bundle?) { + mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: "" + + super.onCreate(savedInstanceState) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mListRv.setBackgroundColor(Color.WHITE) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogItemData.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogItemData.kt new file mode 100644 index 0000000000..3f39494efc --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogItemData.kt @@ -0,0 +1,10 @@ +package com.gh.gamecenter.catalog + +import com.gh.gamecenter.entity.SpecialCatalogEntity + +data class SpecialCatalogItemData( + val header: SpecialCatalogEntity? = null, + val bigImage: SpecialCatalogEntity? = null, + val subject: SpecialCatalogEntity? = null, + val subjectCollection: SpecialCatalogEntity? = null +) diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectAdapter.kt new file mode 100644 index 0000000000..d7a99b660d --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectAdapter.kt @@ -0,0 +1,57 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.gh.base.BaseRecyclerViewHolder +import com.gh.gamecenter.GameDetailActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.CatalogSubjectGameItemBinding +import com.gh.gamecenter.entity.GameEntity +import com.lightgame.adapter.BaseRecyclerAdapter + +class SpecialCatalogSubjectAdapter(context: Context, private var mList: List) : BaseRecyclerAdapter(context) { + + private val mEntrance = "精选分类" + private var countAndKey: Pair? = null + + init { + var dataIds = "" + mList.forEach { + dataIds += it.id + } + if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds) + } + + override fun getItemCount() = mList.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) + = CatalogSubjectGameItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_game_item, parent, false)) + + override fun onBindViewHolder(holder: CatalogSubjectGameItemViewHolder, position: Int) { + holder.binding.run { + val entity = mList[position] + game = entity + root.setOnClickListener { + GameDetailActivity.startGameDetailActivity(mContext, entity, "(${mEntrance})") + } + } + } + + fun checkResetData(update: List) { + var dataIds = "" + mList.forEach { dataIds += it.id } + + mList = update + if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变 + notifyItemRangeChanged(0, itemCount) + } else if (countAndKey?.first != update.size) { // 数量发生改变 + notifyDataSetChanged() + } + + // 重新刷新数据标识 + countAndKey = Pair(update.size, dataIds) + } + + class CatalogSubjectGameItemViewHolder(val binding: CatalogSubjectGameItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectCollectionAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectCollectionAdapter.kt new file mode 100644 index 0000000000..c85d2e7ba7 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectCollectionAdapter.kt @@ -0,0 +1,61 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.util.DirectUtils +import com.gh.common.util.ImageUtils +import com.gh.common.util.dip2px +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.CatalogSubjectCollectionListItemBinding +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.entity.LinkEntity +import com.lightgame.adapter.BaseRecyclerAdapter + +class SpecialCatalogSubjectCollectionAdapter(context: Context, private var mList: List) : BaseRecyclerAdapter(context) { + + private var countAndKey: Pair? = null + + init { + var dataIds = "" + mList.forEach { + dataIds += it.id + } + if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds) + } + + override fun getItemCount() = mList.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) + = CatalogSubjectCollectionListItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_collection_list_item, parent, false)) + + + override fun onBindViewHolder(holder: CatalogSubjectCollectionListItemViewHolder, position: Int) { + holder.binding.run { + root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply { + leftMargin = if (position == 0) 16F.dip2px() else 0 + } + val entity = mList[position] + ImageUtils.display(subjectCollectionImage, entity.image) + root.setOnClickListener { DirectUtils.directToLinkPage(mContext, LinkEntity(link = entity.link, type = entity.type), "精选分类", "专题合集") } + } + } + + fun checkResetData(update: List) { + var dataIds = "" + mList.forEach { dataIds += it.id } + + mList = update + if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变 + notifyItemRangeChanged(0, itemCount) + } else if (countAndKey?.first != update.size) { // 数量发生改变 + notifyDataSetChanged() + } + + // 重新刷新数据标识 + countAndKey = Pair(update.size, dataIds) + } + + class CatalogSubjectCollectionListItemViewHolder(val binding: CatalogSubjectCollectionListItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogViewModel.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogViewModel.kt new file mode 100644 index 0000000000..fcb1147d03 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogViewModel.kt @@ -0,0 +1,50 @@ +package com.gh.gamecenter.catalog + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.gh.gamecenter.baselist.ListViewModel +import com.gh.gamecenter.entity.SpecialCatalogEntity +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.Observable +import io.reactivex.Single + +class SpecialCatalogViewModel(application: Application, private val catalogId: String): ListViewModel(application) { + + override fun provideDataObservable(page: Int): Observable>? = null + + override fun provideDataSingle(page: Int): Single> { + return RetrofitManager.getInstance(getApplication()) + .sensitiveApi + .getSpecialCatalogs(catalogId, page) + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { list -> + val itemDataList = arrayListOf() + list.forEach { + when (it.type) { + "图片" -> itemDataList.add(SpecialCatalogItemData(bigImage = it)) + + "专题" -> { + itemDataList.add(SpecialCatalogItemData(header = it)) + itemDataList.add(SpecialCatalogItemData(subject = it)) + } + + "专题合集" -> { + itemDataList.add(SpecialCatalogItemData(header = it)) + itemDataList.add(SpecialCatalogItemData(subjectCollection = it)) + } + } + } + mResultLiveData.postValue(itemDataList) + } + } + + class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return SpecialCatalogViewModel(HaloApp.getInstance().application, catalogId) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogAdapter.kt new file mode 100644 index 0000000000..fed4d6a710 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogAdapter.kt @@ -0,0 +1,35 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.view.ViewGroup +import com.gh.base.BaseRecyclerViewHolder +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.SubCatalogItemBinding +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.entity.SubCatalogEntity +import com.lightgame.adapter.BaseRecyclerAdapter + +class SubCatalogAdapter(context: Context, private val mPrimaryCatalog: CatalogEntity, private var mList: List) : BaseRecyclerAdapter(context) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubCatalogItemViewHolder { + val view = mLayoutInflater.inflate(R.layout.sub_catalog_item, parent, false) + return SubCatalogItemViewHolder(SubCatalogItemBinding.bind(view)) + } + + override fun getItemCount(): Int { + return mList.size + } + + override fun onBindViewHolder(holder: SubCatalogItemViewHolder, position: Int) { + holder.binding.run { + val catalogEntity = mList[position] + entity = catalogEntity + executePendingBindings() + root.setOnClickListener { + root.context.startActivity(NewCatalogListActivity.getIntent(mContext, catalogEntity.name, mPrimaryCatalog, catalogEntity.name)) + } + } + } + + class SubCatalogItemViewHolder(val binding: SubCatalogItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogFragment.kt new file mode 100644 index 0000000000..42b4c21163 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogFragment.kt @@ -0,0 +1,84 @@ +package com.gh.gamecenter.catalog + +import android.os.Bundle +import android.view.View +import android.widget.LinearLayout +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.EntranceUtils +import com.gh.common.util.viewModelProvider +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.normal.NormalFragment +import kotterknife.bindView + +class SubCatalogFragment : NormalFragment() { + + private val mReuseLoading by bindView(R.id.reuse_ll_loading) + private val mReuseNoConnection by bindView(R.id.reuse_no_connection) + private val mReuseNoData by bindView(R.id.reuse_none_data) + private val mSubCatalogRv by bindView(R.id.rv_sub_catalog) + + private lateinit var mViewModel: SubCatalogViewModel + private lateinit var mSubCatalogAdapter: SubCatalogAdapter + private lateinit var mEntity: CatalogEntity + private var mCatalogId: String = "" + private var mPrimaryCatalogId: String = "" + + override fun getLayoutId() = R.layout.fragment_sub_catalog + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: "" + mPrimaryCatalogId = arguments?.getString(EntranceUtils.KEY_PRIMARY_CATALOG_ID) ?: "" + mViewModel = viewModelProvider(SubCatalogViewModel.Factory(mCatalogId)) + mViewModel.getSubCatalogs(mPrimaryCatalogId) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mViewModel.catalogs.observe(viewLifecycleOwner, Observer { + mReuseLoading.visibility = View.GONE + if (it != null) { + mReuseNoConnection.visibility = View.GONE + if (it.subCatalog.isNotEmpty()) { + mSubCatalogRv.visibility = View.VISIBLE + mReuseNoData.visibility = View.GONE + mEntity = it + initView() + } else { + mSubCatalogRv.visibility = View.GONE + mReuseNoData.visibility = View.VISIBLE + } + } else { + mSubCatalogRv.visibility = View.GONE + mReuseNoData.visibility = View.GONE + mReuseNoConnection.visibility = View.VISIBLE + mReuseNoConnection.setOnClickListener { + mReuseLoading.visibility = View.VISIBLE + mViewModel.getSubCatalogs(mPrimaryCatalogId) + } + } + }) + } + + private fun initView() { + mEntity.run { + mSubCatalogRv.layoutManager = GridLayoutManager(requireContext(), 3) + mSubCatalogAdapter = SubCatalogAdapter(requireContext(), mEntity, subCatalog) + mSubCatalogRv.adapter = mSubCatalogAdapter + } + } + + fun changeSubCatalog(primaryCatalogId: String) { + mPrimaryCatalogId = primaryCatalogId + mSubCatalogRv.visibility = View.GONE + mReuseNoData.visibility = View.GONE + mReuseNoConnection.visibility = View.GONE + mReuseLoading.visibility = View.VISIBLE + mViewModel.getSubCatalogs(mPrimaryCatalogId) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogViewModel.kt b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogViewModel.kt new file mode 100644 index 0000000000..12acf47463 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogViewModel.kt @@ -0,0 +1,44 @@ +package com.gh.gamecenter.catalog + +import android.annotation.SuppressLint +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +class SubCatalogViewModel(application: Application, private val catalogId: String): AndroidViewModel(application) { + + private val api = RetrofitManager.getInstance(getApplication()).api + var catalogs = MutableLiveData() + + + @SuppressLint("CheckResult") + fun getSubCatalogs(primaryCatalogId: String) { + api.getSubCatalogs(catalogId, primaryCatalogId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: CatalogEntity) { + catalogs.postValue(data) + } + + override fun onFailure(exception: Exception) { + super.onFailure(exception) + catalogs.postValue(null) + } + }) + } + + class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return SubCatalogViewModel(HaloApp.getInstance().application, catalogId) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/category/CategoryDirectoryActivity.kt b/app/src/main/java/com/gh/gamecenter/category/CategoryDirectoryActivity.kt index faf8d247c3..e528b19922 100644 --- a/app/src/main/java/com/gh/gamecenter/category/CategoryDirectoryActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/category/CategoryDirectoryActivity.kt @@ -4,7 +4,6 @@ import android.content.Context import android.content.Intent import android.os.Bundle import com.gh.common.util.EntranceUtils -import com.gh.download.DownloadManager import com.gh.gamecenter.NormalActivity import com.gh.gamecenter.R diff --git a/app/src/main/java/com/gh/gamecenter/category/NewCategoryHorizontalAdapter.kt b/app/src/main/java/com/gh/gamecenter/category/NewCategoryHorizontalAdapter.kt index 430bdfd80b..cd078096e8 100644 --- a/app/src/main/java/com/gh/gamecenter/category/NewCategoryHorizontalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/category/NewCategoryHorizontalAdapter.kt @@ -27,21 +27,16 @@ class NewCategoryHorizontalAdapter(context: Context, override fun onBindViewHolder(holder: TagsViewHolder, position: Int) { val categoryEntity = mCategoryList[position] - val gradientDrawable = GradientDrawable() - gradientDrawable.shape = GradientDrawable.RECTANGLE if (mViewModel.selectedCategory.name == categoryEntity.name) { - gradientDrawable.setColor(ContextCompat.getColor(mContext, R.color.theme)) - gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat() + holder.tagTv.background = ContextCompat.getDrawable(mContext, R.drawable.bg_tag_text) holder.tagTv.setTextColor(Color.WHITE) } else { - gradientDrawable.setColor(Color.WHITE) - gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat() - holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_3a3a3a)) + holder.tagTv.background = null + holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_757575)) } holder.tagTv.text = categoryEntity.name - holder.tagTv.background = gradientDrawable holder.tagTv.setOnClickListener { mViewModel.changeSelectedCategory(categoryEntity) notifyDataSetChanged() diff --git a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListAdapter.kt b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListAdapter.kt index affa700591..6143b0e9cb 100644 --- a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListAdapter.kt @@ -11,6 +11,7 @@ import com.gh.common.exposure.ExposureType import com.gh.common.exposure.IExposable import com.gh.common.util.DownloadItemUtils import com.gh.common.util.StringUtils +import com.gh.common.util.dip2px import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder @@ -85,6 +86,9 @@ class NewCategoryListAdapter(context: Context, holder.initServerType(gameEntity) holder.binding.executePendingBindings() + val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px() + holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px()) + gameEntity.sequence = position + 1 val sortType = if ("download:-1" == mViewModel.getSortType()) "最热" else "最新" diff --git a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt index c0be80e13e..b40ef98c2f 100644 --- a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt @@ -114,6 +114,8 @@ class NewCategoryListFragment : ListFragment = emptyList() +): Parcelable + +@Parcelize +data class SubCatalogEntity( + @SerializedName("_id") + var id: String = "", + var name: String = "", + var icon: String = "", + var link: LinkEntity = LinkEntity(), + var recommended: Boolean = false +): Parcelable + +@Parcelize +data class CatalogSwitch( + @SerializedName("sort_hot") + var hotSort: String = "", + @SerializedName("sort_new") + var newSort: String = "", + @SerializedName("sort_star") + var starSort: String = "" +): Parcelable + +@Parcelize +data class SpecialCatalogEntity( + @SerializedName("_id") + var id: String = "", + var type: String = "", + var link: SpecialLink = SpecialLink(), + var image: Image = Image() +): Parcelable + +@Parcelize +data class SpecialLink( + @SerializedName("_id") + var id: String = "", + var data: List = emptyList() +): LinkEntity(), Parcelable + +@Parcelize +data class Image( + var url: String = "", + var title: String = "" +): Parcelable diff --git a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt index cd18696a01..0786ca9217 100644 --- a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt @@ -24,6 +24,7 @@ import com.gh.gamecenter.R import com.gh.gamecenter.adapter.ImagePagerAdapter import com.gh.gamecenter.adapter.viewholder.* import com.gh.gamecenter.baselist.LoadStatus +import com.gh.gamecenter.catalog.CatalogActivity import com.gh.gamecenter.category.CategoryDirectoryActivity import com.gh.gamecenter.databinding.* import com.gh.gamecenter.entity.CommunityEntity @@ -419,6 +420,7 @@ class GameFragmentAdapter(context: Context, entity.type == "column_collection" -> DirectUtils.directToColumnCollection(mContext, entity.link!!, -1, "(推荐入口)") entity.type == "block" -> mContext.startActivity(BlockActivity.getIntent(mContext, entity, "(推荐入口)")) entity.type == "category" -> mContext.startActivity(CategoryDirectoryActivity.getIntent(mContext, entity.link!!, entity.text!!)) + entity.type == "catalog" -> mContext.startActivity(CatalogActivity.getIntent(mContext, entity.link!!, entity.text!!)) entity.type == "column" -> { SubjectActivity.startSubjectActivity(mContext, entity.link, entity.text, entity.order , StringUtils.buildString("(游戏-专题:", entity.name, "[1-", (data + 1).toString(), "]", ")")) diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt index d215037396..d4246f3c25 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt @@ -273,7 +273,7 @@ class UserHomeFragment : NormalFragment() { ?: UserVideoHistoryFragment.getInstance(mUserHomeViewModel.userId, count) val fragmentList = listOf(commentFragment, qaFragment, videoFragment) - val titleList = listOf("游戏评论", "问答", "视频") + val titleList = listOf("游戏评论", "我的论坛", "视频") val countList = listOf(count.gameComment, count.getQaCount(), count.video) viewpager.offscreenPageLimit = fragmentList.size diff --git a/app/src/main/java/com/gh/gamecenter/qa/myqa/MyAskWrapperFragment.java b/app/src/main/java/com/gh/gamecenter/qa/myqa/MyAskWrapperFragment.java index cfa97d81f6..800b729c1e 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/myqa/MyAskWrapperFragment.java +++ b/app/src/main/java/com/gh/gamecenter/qa/myqa/MyAskWrapperFragment.java @@ -44,7 +44,7 @@ public class MyAskWrapperFragment extends BaseFragment_TabLayout { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - setNavigationTitle(R.string.myask); + setNavigationTitle(R.string.my_forum); initMenu(R.menu.menu_my_ask_wrapper); } diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index 091c532484..91f5e75235 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -11,6 +11,7 @@ import com.gh.gamecenter.entity.AuthDialogEntity; import com.gh.gamecenter.entity.AvatarBorderEntity; import com.gh.gamecenter.entity.BackgroundImageEntity; import com.gh.gamecenter.entity.BadgeEntity; +import com.gh.gamecenter.entity.CatalogEntity; import com.gh.gamecenter.entity.CategoryEntity; import com.gh.gamecenter.entity.CommentEntity; import com.gh.gamecenter.entity.CommentnumEntity; @@ -60,6 +61,7 @@ import com.gh.gamecenter.entity.SettingsEntity; import com.gh.gamecenter.entity.SignEntity; import com.gh.gamecenter.entity.SimpleGameEntity; import com.gh.gamecenter.entity.SimulatorEntity; +import com.gh.gamecenter.entity.SpecialCatalogEntity; import com.gh.gamecenter.entity.SubjectEntity; import com.gh.gamecenter.entity.SubjectRecommendEntity; import com.gh.gamecenter.entity.SubjectRefreshEntity; @@ -304,7 +306,7 @@ public interface ApiService { * 获取专题数据 */ @GET("columns/{column_id}/games") - Observable> getColumn(@Path("column_id") String column_id, @Query("sort") String sort, @Query("filter") String order, @Query("page") int page); + Single> getColumn(@Path("column_id") String column_id, @Query("sort") String sort, @Query("filter") String order, @Query("page") int page); /** * 获取专题数据标题 @@ -2725,6 +2727,7 @@ public interface ApiService { Single> getSimulatorGames(@Path("device_id") String deviceId, @Query("page") int page, @Query("filter") String filter); /** +<<<<<<< HEAD * 搜索用户 */ @GET("./users:search") @@ -2759,4 +2762,22 @@ public interface ApiService { */ @GET("packages/{package}/redirect") Single redirectGameDetail(@Path("package") String packageName); + + /** + * 获取一级分类数据 + */ + @GET("catalogs/{catalog_id}") + Single getCatalogs(@Path("catalog_id") String catalogId); + + /** + * 获取一级分类数据 及其 二级分类数据 + */ + @GET("catalogs/{catalog_id}/{primary_catalog_id}") + Single getSubCatalogs(@Path("catalog_id") String catalogId, @Path("primary_catalog_id") String primaryCatalogId); + + /** + * 获取精选分类 + */ + @GET("catalogs/{catalog_id}/special") + Single> getSpecialCatalogs(@Path("catalog_id") String catalogId, @Query("page") int page); } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchDefaultFragment.kt b/app/src/main/java/com/gh/gamecenter/search/SearchDefaultFragment.kt index cff3003518..a4fd1131cf 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchDefaultFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchDefaultFragment.kt @@ -125,21 +125,22 @@ open class SearchDefaultFragment : BaseFragment() { val flexCell = TextView(context) flexView.addView(flexCell) - val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 25F.dip2px()) + val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) params.setMargins(0, 0, 16F.dip2px(), 16F.dip2px()) flexCell.layoutParams = params flexCell.setSingleLine() flexCell.ellipsize = TextUtils.TruncateAt.END - flexCell.textSize = 13f + flexCell.textSize = 12F flexCell.gravity = Gravity.CENTER flexCell.text = contentList[index] - flexCell.setTextColor(Color.WHITE) - flexCell.setPadding(10F.dip2px(), 0, 10F.dip2px(), 0) + flexCell.maxEms = 6 + flexCell.setTextColor(R.color.text_666666.toColor()) + if (!isHistoryFlex) flexCell.setPadding(8F.dip2px(), 6F.dip2px(), 8F.dip2px(), 6F.dip2px()) flexCell.background = if (isHistoryFlex) { - DrawableView.getOvalDrawable(R.color.text_d5d5d5) + null } else { - DrawableView.getOvalDrawable(R.color.theme) + DrawableView.getOvalDrawable(R.color.text_F5F5F5) } flexCell.setOnClickListener { clickListener.invoke(index) diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt index ff35b8c683..be2be22431 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt @@ -14,18 +14,18 @@ import com.gh.common.exposure.ExposureType import com.gh.common.exposure.IExposable import com.gh.common.filter.RegionSettingHelper import com.gh.common.util.* +import com.gh.common.view.DrawableView import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.SearchType import com.gh.gamecenter.adapter.viewholder.GameViewHolder import com.gh.gamecenter.adapter.viewholder.SearchHistoryViewHolder import com.gh.gamecenter.baselist.ListAdapter -import com.gh.gamecenter.databinding.GameItemBinding +import com.gh.gamecenter.databinding.SearchGameIndexItemBinding import com.gh.gamecenter.db.SearchHistoryDao import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.eventbus.EBDownloadStatus import com.gh.gamecenter.eventbus.EBSearch -import com.gh.gamecenter.game.GameItemViewHolder import com.lightgame.download.DownloadEntity import com.lightgame.utils.Util_System_Keyboard import org.greenrobot.eventbus.EventBus @@ -66,8 +66,8 @@ class SearchGameIndexAdapter(context: Context, override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == ItemViewType.GAME_NORMAL) { val itemView = LayoutInflater.from(viewGroup.context) - .inflate(R.layout.game_item, viewGroup, false) - GameItemViewHolder(GameItemBinding.bind(itemView)) + .inflate(R.layout.search_game_index_item, viewGroup, false) + SearchGameIndexItemViewHolder(SearchGameIndexItemBinding.bind(itemView)) } else { val itemView = LayoutInflater.from(viewGroup.context) .inflate(R.layout.fm_search_history_item, viewGroup, false) @@ -87,19 +87,11 @@ class SearchGameIndexAdapter(context: Context, ExposureType.EXPOSURE) exposureEventArray!!.put(position, exposureEvent) - if (holder is GameItemViewHolder) { - if (position == 0) { - holder.itemView.setPadding( - DisplayUtils.dip2px(16f), DisplayUtils.dip2px(20f), - DisplayUtils.dip2px(20f), DisplayUtils.dip2px(8f)) - } else { - holder.itemView.setPadding( - DisplayUtils.dip2px(16f), DisplayUtils.dip2px(8f), - DisplayUtils.dip2px(20f), DisplayUtils.dip2px(8f)) - } - + if (holder is SearchGameIndexItemViewHolder) { val binding = holder.binding - binding.game = gameEntity + binding.gameItemIncluded.game = gameEntity + binding.divider.goneIf(position == 0) + binding.gameItemIncluded.root.setPadding(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 16F.dip2px()) holder.initServerType(gameEntity) binding.executePendingBindings() @@ -126,7 +118,7 @@ class SearchGameIndexAdapter(context: Context, DownloadItemUtils.setOnClickListenerWithInvokeCallbackForAllState( mContext, - binding.downloadBtn, + binding.gameItemIncluded.downloadBtn, gameEntity, holder.adapterPosition, this, @@ -134,7 +126,7 @@ class SearchGameIndexAdapter(context: Context, "搜索-列表:" + gameEntity.name!!, exposureEvent, object : EmptyCallback { override fun onCallback() { - Util_System_Keyboard.hideSoftKeyboardByIBinder(mContext, binding.downloadBtn.windowToken) + Util_System_Keyboard.hideSoftKeyboardByIBinder(mContext, binding.gameItemIncluded.downloadBtn.windowToken) if (searchMap[gameEntity.id] == null) { EventBus.getDefault().post(EBSearch("search", gameEntity.id, gameEntity.name)) @@ -150,10 +142,9 @@ class SearchGameIndexAdapter(context: Context, } ) - DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(binding), true) + DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(binding.gameItemIncluded), true) } else if (holder is SearchHistoryViewHolder) { holder.searchHistoryName.text = gameEntity.name - holder.searchHistoryLine.visibility = View.GONE holder.itemView.setOnClickListener { if (searchMap[gameEntity.id] == null) { EventBus.getDefault().post(EBSearch("search", gameEntity.id, gameEntity.name)) @@ -215,4 +206,25 @@ class SearchGameIndexAdapter(context: Context, } } } + + class SearchGameIndexItemViewHolder(var binding: SearchGameIndexItemBinding) : RecyclerView.ViewHolder(binding.root) { + fun initServerType(gameEntity: GameEntity) { + val serverLabel = gameEntity.serverLabel + when { + gameEntity.test != null -> { + binding.gameItemIncluded.gameKaifuType.visibility = View.GONE + binding.gameItemIncluded.gameKaifuType.text = "" + } + serverLabel != null -> { + binding.gameItemIncluded.gameKaifuType.visibility = View.VISIBLE + binding.gameItemIncluded.gameKaifuType.text = serverLabel.value + binding.gameItemIncluded.gameKaifuType.background = DrawableView.getServerDrawable(serverLabel.color) + } + else -> binding.gameItemIncluded.gameKaifuType.visibility = View.GONE + } + + // 由于RecyclerView的复用机制 需要每次测量gameName的宽 + binding.gameItemIncluded.gameName.requestLayout() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/subject/SubjectListViewModel.kt b/app/src/main/java/com/gh/gamecenter/subject/SubjectListViewModel.kt index 24ed674125..77c65c6b18 100644 --- a/app/src/main/java/com/gh/gamecenter/subject/SubjectListViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/subject/SubjectListViewModel.kt @@ -12,6 +12,7 @@ import com.gh.gamecenter.entity.SubjectSettingEntity import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager import io.reactivex.Observable +import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import retrofit2.HttpException @@ -23,7 +24,9 @@ class SubjectListViewModel(application: Application, var selectedLabelList = arrayListOf() var selectedFilterSize = SubjectSettingEntity.Size(text = "全部大小") - override fun provideDataObservable(page: Int): Observable> { + override fun provideDataObservable(page: Int): Observable>? = null + + override fun provideDataSingle(page: Int): Single> { return RetrofitManager.getInstance(getApplication()).sensitiveApi.getColumn( subjectData.subjectId, subjectData.sort, diff --git a/app/src/main/java/com/gh/gamecenter/tag/TagsHorizontalAdapter.kt b/app/src/main/java/com/gh/gamecenter/tag/TagsHorizontalAdapter.kt index 0c5d7da21f..c68ae9a698 100644 --- a/app/src/main/java/com/gh/gamecenter/tag/TagsHorizontalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/tag/TagsHorizontalAdapter.kt @@ -2,14 +2,12 @@ package com.gh.gamecenter.tag import android.content.Context import android.graphics.Color -import android.graphics.drawable.GradientDrawable import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.core.content.ContextCompat import butterknife.BindView import com.gh.base.BaseRecyclerViewHolder -import com.gh.common.util.DisplayUtils import com.gh.gamecenter.R import com.gh.gamecenter.entity.TagEntity import com.lightgame.adapter.BaseRecyclerAdapter @@ -26,21 +24,16 @@ class TagsHorizontalAdapter(context: Context, override fun onBindViewHolder(holder: TagsViewHolder, position: Int) { val tagEntity = mTagList[position] - val gradientDrawable = GradientDrawable() - gradientDrawable.shape = GradientDrawable.RECTANGLE if (mViewModel.selectedTag.name == tagEntity.name) { - gradientDrawable.setColor(ContextCompat.getColor(mContext, R.color.theme)) - gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat() + holder.tagTv.background = ContextCompat.getDrawable(mContext, R.drawable.bg_tag_text) holder.tagTv.setTextColor(Color.WHITE) } else { - gradientDrawable.setColor(Color.WHITE) - gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat() - holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_3a3a3a)) + holder.tagTv.background = null + holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_757575)) } holder.tagTv.text = tagEntity.name - holder.tagTv.background = gradientDrawable holder.tagTv.setOnClickListener { mViewModel.changeSelectedTag(tagEntity) notifyDataSetChanged() diff --git a/app/src/main/java/com/gh/gamecenter/tag/TagsListAdapter.kt b/app/src/main/java/com/gh/gamecenter/tag/TagsListAdapter.kt index 5aa69e1f41..83d913e38d 100644 --- a/app/src/main/java/com/gh/gamecenter/tag/TagsListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/tag/TagsListAdapter.kt @@ -9,6 +9,7 @@ import com.gh.common.exposure.ExposureSource import com.gh.common.exposure.IExposable import com.gh.common.util.DownloadItemUtils import com.gh.common.util.StringUtils +import com.gh.common.util.dip2px import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder @@ -82,6 +83,9 @@ class TagsListAdapter(context: Context, holder.initServerType(gameEntity) holder.binding.executePendingBindings() + val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px() + holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px()) + gameEntity.sequence = position + 1 val exposureSource = ExposureSource("标签详情", "${mViewModel.selectedTag.name} + ${mViewModel.getSortTypeInChinese()}") diff --git a/app/src/main/java/com/gh/gamecenter/tag/TagsListFragment.kt b/app/src/main/java/com/gh/gamecenter/tag/TagsListFragment.kt index 522d781cfd..899aa3bd5b 100644 --- a/app/src/main/java/com/gh/gamecenter/tag/TagsListFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/tag/TagsListFragment.kt @@ -121,6 +121,8 @@ class TagsListFragment : ListFragment() { DownloadManager.getInstance(context).removeObserver(mDataWatcher) } + override fun getItemDecoration() = null + override fun getLayoutId(): Int { return R.layout.fragment_tags } diff --git a/app/src/main/res/drawable-xhdpi/ic_filter_arrow_down.png b/app/src/main/res/drawable-xhdpi/ic_filter_arrow_down.png deleted file mode 100644 index 3efcaad3eb..0000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_filter_arrow_down.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_filter_arrow_up.png b/app/src/main/res/drawable-xhdpi/ic_filter_arrow_up.png deleted file mode 100644 index f7b2f0d52a..0000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_filter_arrow_up.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/search_history_delete.png b/app/src/main/res/drawable-xhdpi/search_history_delete.png deleted file mode 100644 index b1803b9e40..0000000000 Binary files a/app/src/main/res/drawable-xhdpi/search_history_delete.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_catalog_selected.png b/app/src/main/res/drawable-xxhdpi/ic_catalog_selected.png new file mode 100755 index 0000000000..08fdeaa2d3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_catalog_selected.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_down.png b/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_down.png new file mode 100755 index 0000000000..cd1d3b5f3b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_down.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_up.png b/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_up.png new file mode 100755 index 0000000000..c8abc870f0 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_up.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_recommend.png b/app/src/main/res/drawable-xxhdpi/ic_recommend.png new file mode 100755 index 0000000000..17285800a7 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_recommend.png differ diff --git a/app/src/main/res/drawable-xxhdpi/search_history_delete.png b/app/src/main/res/drawable-xxhdpi/search_history_delete.png new file mode 100755 index 0000000000..420fcc7e15 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/search_history_delete.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_catalog_selected.png b/app/src/main/res/drawable-xxxhdpi/ic_catalog_selected.png new file mode 100755 index 0000000000..c08b758478 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_catalog_selected.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_down.png b/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_down.png new file mode 100755 index 0000000000..8e70509fa2 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_down.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_up.png b/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_up.png new file mode 100755 index 0000000000..39fcfcbaf4 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_up.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend.png b/app/src/main/res/drawable-xxxhdpi/ic_recommend.png new file mode 100755 index 0000000000..9c81073cd4 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_recommend.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/search_history_delete.png b/app/src/main/res/drawable-xxxhdpi/search_history_delete.png new file mode 100755 index 0000000000..313a4ee350 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/search_history_delete.png differ diff --git a/app/src/main/res/drawable/actionbar_search_bg.xml b/app/src/main/res/drawable/actionbar_search_bg.xml index 22f407e085..737aab1104 100644 --- a/app/src/main/res/drawable/actionbar_search_bg.xml +++ b/app/src/main/res/drawable/actionbar_search_bg.xml @@ -1,9 +1,9 @@ - + - + - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_sub_catalog_item.xml b/app/src/main/res/drawable/bg_sub_catalog_item.xml new file mode 100644 index 0000000000..6710f5e133 --- /dev/null +++ b/app/src/main/res/drawable/bg_sub_catalog_item.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_tag_text.xml b/app/src/main/res/drawable/bg_tag_text.xml new file mode 100644 index 0000000000..078c47dd4e --- /dev/null +++ b/app/src/main/res/drawable/bg_tag_text.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_header_item.xml b/app/src/main/res/layout/catalog_header_item.xml new file mode 100644 index 0000000000..6859798ffc --- /dev/null +++ b/app/src/main/res/layout/catalog_header_item.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_image_item.xml b/app/src/main/res/layout/catalog_image_item.xml new file mode 100644 index 0000000000..5312f8daa0 --- /dev/null +++ b/app/src/main/res/layout/catalog_image_item.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_item.xml b/app/src/main/res/layout/catalog_item.xml new file mode 100644 index 0000000000..54f3309eb9 --- /dev/null +++ b/app/src/main/res/layout/catalog_item.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_subject_collection_item.xml b/app/src/main/res/layout/catalog_subject_collection_item.xml new file mode 100644 index 0000000000..2cfeff5c6e --- /dev/null +++ b/app/src/main/res/layout/catalog_subject_collection_item.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/app/src/main/res/layout/catalog_subject_collection_list_item.xml b/app/src/main/res/layout/catalog_subject_collection_list_item.xml new file mode 100644 index 0000000000..5d1e42dee8 --- /dev/null +++ b/app/src/main/res/layout/catalog_subject_collection_list_item.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_subject_game_item.xml b/app/src/main/res/layout/catalog_subject_game_item.xml new file mode 100644 index 0000000000..33153bc6f3 --- /dev/null +++ b/app/src/main/res/layout/catalog_subject_game_item.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_subject_item.xml b/app/src/main/res/layout/catalog_subject_item.xml new file mode 100644 index 0000000000..009bbac5a7 --- /dev/null +++ b/app/src/main/res/layout/catalog_subject_item.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fm_search_history_item.xml b/app/src/main/res/layout/fm_search_history_item.xml index 4fbbf05e86..4701e1c563 100644 --- a/app/src/main/res/layout/fm_search_history_item.xml +++ b/app/src/main/res/layout/fm_search_history_item.xml @@ -1,29 +1,27 @@ - + + android:id="@+id/search_history_line" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:background="@color/text_F5F5F5" /> - - + android:id="@+id/search_history_name" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:ellipsize="end" + android:gravity="center_vertical" + android:padding="16dp" + android:singleLine="true" + android:textColor="@color/bg_303030" + android:textSize="14sp" /> + diff --git a/app/src/main/res/layout/fragment_catalog.xml b/app/src/main/res/layout/fragment_catalog.xml new file mode 100644 index 0000000000..cfa38a7b4a --- /dev/null +++ b/app/src/main/res/layout/fragment_catalog.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_catalog_list.xml b/app/src/main/res/layout/fragment_catalog_list.xml new file mode 100644 index 0000000000..3611e77cc9 --- /dev/null +++ b/app/src/main/res/layout/fragment_catalog_list.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_search_default.xml b/app/src/main/res/layout/fragment_search_default.xml index 5f97472ea5..f79380e696 100644 --- a/app/src/main/res/layout/fragment_search_default.xml +++ b/app/src/main/res/layout/fragment_search_default.xml @@ -25,16 +25,12 @@ visibleGone="@{isExistHistory}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:background="@android:color/white" android:includeFontPadding="false" - android:paddingLeft="20dp" - android:paddingTop="16dp" - android:paddingRight="20dp" - android:paddingBottom="16dp" + android:padding="16dp" android:text="@string/search_history" - android:textColor="@color/black" - android:textSize="15sp" + android:textColor="@color/text_0E0E0E" + android:textSize="14sp" android:textStyle="bold" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -44,11 +40,12 @@ visibleGone="@{isExistHistory}" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginRight="20dp" + android:layout_marginRight="16dp" android:drawableLeft="@drawable/search_history_delete" - android:drawablePadding="8dp" - android:text="@string/search_history_clean" + android:drawablePadding="4dp" + android:textColor="@color/text_999999" android:textSize="12sp" + android:text="@string/search_history_clean" app:layout_constraintBottom_toBottomOf="@id/history_title" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="@id/history_title" /> @@ -65,8 +62,7 @@ visibleGone="@{isExistHistory}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="20dp" - android:paddingBottom="5dp" + android:paddingLeft="16dp" app:flexWrap="wrap" /> @@ -75,16 +71,12 @@ visibleGone="@{isExistHotTag}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:background="@android:color/white" android:includeFontPadding="false" - android:paddingLeft="20dp" - android:paddingTop="16dp" - android:paddingRight="20dp" - android:paddingBottom="16dp" + android:padding="16dp" android:text="@string/search_hot_tag" - android:textColor="@color/black" - android:textSize="15sp" + android:textColor="@color/text_0E0E0E" + android:textSize="14sp" android:textStyle="bold" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/history_flex_container" /> @@ -101,8 +93,7 @@ visibleGone="@{isExistHotTag}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="20dp" - android:paddingBottom="7dp" + android:paddingLeft="16dp" app:flexWrap="wrap" /> @@ -111,16 +102,12 @@ visibleGone="@{isExistHotSearch}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:background="@android:color/white" android:includeFontPadding="false" - android:paddingLeft="20dp" - android:paddingTop="16dp" - android:paddingRight="20dp" - android:paddingBottom="11dp" + android:padding="16dp" android:text="@string/search_hot" - android:textColor="@color/black" - android:textSize="15sp" + android:textColor="@color/text_0E0E0E" + android:textSize="14sp" android:textStyle="bold" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/hot_tag_flex_container" /> diff --git a/app/src/main/res/layout/fragment_sub_catalog.xml b/app/src/main/res/layout/fragment_sub_catalog.xml new file mode 100644 index 0000000000..bd9d05eb74 --- /dev/null +++ b/app/src/main/res/layout/fragment_sub_catalog.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_tags.xml b/app/src/main/res/layout/fragment_tags.xml index fec4630e35..b518d6c427 100644 --- a/app/src/main/res/layout/fragment_tags.xml +++ b/app/src/main/res/layout/fragment_tags.xml @@ -8,11 +8,10 @@ android:id="@+id/tags_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:background="@color/all_white" android:clipToPadding="false" android:paddingLeft="20dp" - android:paddingTop="16dp" + android:paddingTop="8dp" android:paddingRight="12dp" android:paddingBottom="8dp" /> @@ -32,11 +31,18 @@ android:layout_height="wrap_content" android:visibility="gone" /> + + + android:layout_below="@id/divider"> + + @@ -148,11 +150,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" - android:drawableLeft="@drawable/game_horizontal_rating" + android:drawableLeft="@{game.commentCount > 3?@drawable/game_horizontal_rating: null}" android:drawablePadding="4dp" android:includeFontPadding="false" - android:paddingRight="8dp" - android:text="@{game.commentCount > 3?game.star + ``: `评分过少`}" + android:paddingRight="@{game.commentCount > 3?DisplayUtils.dip2px(8F): 0}" + android:text="@{game.commentCount > 3?(game.star == 10.0? `10` : game.star + ``): ``}" android:textColor="@{Color.parseColor(game.commentCount > 3?`#1383EB`:`#2496FF`)}" android:textStyle="bold" android:visibility="gone" /> diff --git a/app/src/main/res/layout/item_filter_size.xml b/app/src/main/res/layout/item_filter_size.xml index a65ea1370e..27fbc54b6f 100644 --- a/app/src/main/res/layout/item_filter_size.xml +++ b/app/src/main/res/layout/item_filter_size.xml @@ -1,22 +1,34 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_catalog_filter.xml b/app/src/main/res/layout/layout_catalog_filter.xml new file mode 100644 index 0000000000..ce480c9c02 --- /dev/null +++ b/app/src/main/res/layout/layout_catalog_filter.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_config_filter.xml b/app/src/main/res/layout/layout_config_filter.xml index ab6525f8e5..3bf1108a30 100644 --- a/app/src/main/res/layout/layout_config_filter.xml +++ b/app/src/main/res/layout/layout_config_filter.xml @@ -4,18 +4,17 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/config_controller" android:layout_width="match_parent" - android:layout_height="48dp" + android:layout_height="40dp" android:background="@color/all_white" android:paddingLeft="16dp" - android:paddingRight="16dp" - android:paddingBottom="8dp"> + android:paddingRight="16dp"> diff --git a/app/src/main/res/layout/search_default_hot_item.xml b/app/src/main/res/layout/search_default_hot_item.xml index 87a4f7cc79..44db71c1ba 100644 --- a/app/src/main/res/layout/search_default_hot_item.xml +++ b/app/src/main/res/layout/search_default_hot_item.xml @@ -14,34 +14,36 @@ + android:paddingLeft="16dp" + android:paddingBottom="16dp"> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/sub_catalog_item.xml b/app/src/main/res/layout/sub_catalog_item.xml new file mode 100644 index 0000000000..f353517857 --- /dev/null +++ b/app/src/main/res/layout/sub_catalog_item.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/toolbar_search.xml b/app/src/main/res/layout/toolbar_search.xml index 05a49a9d6d..e39d75e80d 100644 --- a/app/src/main/res/layout/toolbar_search.xml +++ b/app/src/main/res/layout/toolbar_search.xml @@ -2,14 +2,14 @@ + android:layout_width="44dp" + android:layout_height="match_parent"> + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index d097824ed9..c679433078 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -214,6 +214,8 @@ #f9f9f9 #FF4147 #a9a9a9 + #757575 + #0E0E0E #99666666 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d93b248eb..b58affb6fa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -553,7 +553,7 @@ 我的问答 我的草稿 我的积分 - 我的问答 + 我的论坛 已关注 回答为什么折叠? 继续撰写