【光环助手V5.6.0】工具箱集合页优化 https://git.shanqu.cc/pm/halo-app-issues/-/issues/1640

This commit is contained in:
leafwai
2021-12-23 16:38:21 +08:00
parent 53a9f408e7
commit 4203fdfb72
20 changed files with 952 additions and 3 deletions

View File

@ -764,6 +764,10 @@
android:name=".qa.editor.InsertGameCollectionWrapperActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.toolbox.ToolBoxBlockActivity"
android:screenOrientation="portrait" />
<activity
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"

View File

@ -38,6 +38,7 @@ public class Config {
// 这个 API_HOST 在测试包里会随着选择的环境切换,正式包里会一直保持正式 host
public static final String API_HOST = EnvHelper.getHost();
public static final String NEW_API_HOST = EnvHelper.getNewHost();
/**
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}

View File

@ -394,4 +394,10 @@ public class Constants {
// 标记下载重试标记(值为任务已下载大小,为空表示需要重试)
public static final String MARK_RETRY_DOWNLOAD = "retry_download";
// 工具箱历史记录最多4个
public static final String TOOLBOX_HISTORY = "toolbox_history";
public static final String NEW_DEV_API_HOST = "https://dev-app-api.ghzs.com/";
public static final String NEW_API_HOST = "https://app-api.ghzs.com/";
}

View File

@ -62,6 +62,7 @@ import com.gh.gamecenter.servers.GameServersActivity
import com.gh.gamecenter.subject.SubjectActivity
import com.gh.gamecenter.suggest.SuggestType
import com.gh.gamecenter.tag.TagsActivity
import com.gh.gamecenter.toolbox.ToolBoxBlockActivity
import com.gh.gamecenter.video.data.VideoDataActivity
import com.gh.gamecenter.video.detail.VideoDetailActivity
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
@ -332,7 +333,7 @@ object DirectUtils {
"video_tab" -> directToVideoTab(context)
"toolkit" -> context.startActivity(ToolBoxActivity.getIntent(context, entrance))
"toolkit" -> context.startActivity(ToolBoxBlockActivity.getIntent(context, entrance))
"column_test" -> context.startActivity(
GameServerTestActivity.getIntent(

View File

@ -24,6 +24,19 @@ object EnvHelper {
}
}
@JvmStatic
fun getNewHost(): String {
return if (!isTestEnv()) {
Constants.NEW_API_HOST
} else {
if (isDevEnv) {
Constants.NEW_DEV_API_HOST
} else {
Constants.NEW_API_HOST
}
}
}
// 包体是否为测试包
@JvmStatic
fun isTestEnv(): Boolean {

View File

@ -0,0 +1,16 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize
@Parcelize
data class ToolBoxBlockEntity(
@SerializedName("_id")
val categoryId: String = "",
@SerializedName("name")
val categoryName: String = "",
val total: Int = 0,
@SerializedName("data")
val toolboxList: List<ToolBoxEntity> = ArrayList()
) : Parcelable

View File

@ -23,6 +23,9 @@ class ToolBoxEntity : Parcelable {
var time: Long = 0
// 用户上次打开使用时间(仅用于历史记录)
var lastOpenTime: Long = 0
@SerializedName("me")
var me: MeEntity? = null
@ -41,6 +44,34 @@ class ToolBoxEntity : Parcelable {
dest.writeParcelable(this.me, flags)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as ToolBoxEntity
if (id != other.id) return false
if (icon != other.icon) return false
if (name != other.name) return false
if (des != other.des) return false
if (url != other.url) return false
if (time != other.time) return false
if (me != other.me) return false
return true
}
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + (icon?.hashCode() ?: 0)
result = 31 * result + (name?.hashCode() ?: 0)
result = 31 * result + (des?.hashCode() ?: 0)
result = 31 * result + (url?.hashCode() ?: 0)
result = 31 * result + time.hashCode()
result = 31 * result + (me?.hashCode() ?: 0)
return result
}
constructor()
protected constructor(`in`: Parcel) {

View File

@ -7,6 +7,7 @@ import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.*
import com.gh.gamecenter.*
import com.gh.gamecenter.databinding.ForumWelfareItemBinding
import com.gh.gamecenter.toolbox.ToolBoxBlockActivity
import com.lightgame.adapter.BaseRecyclerAdapter
class WelfaresAdapter(context: Context,
@ -31,7 +32,7 @@ class WelfaresAdapter(context: Context,
when (entity.second) {
"工具箱" -> {
NewLogUtils.logForumPageEvent("click_forum_toolbox")
mContext.startActivity(ToolBoxActivity.getIntent(mContext, "(社区-论坛:工具箱)"))
mContext.startActivity(ToolBoxBlockActivity.getIntent(mContext, "(社区-论坛:工具箱)"))
}
"礼包中心" -> {

View File

@ -28,6 +28,7 @@ import com.gh.gamecenter.qa.myqa.MyAskActivity
import com.gh.gamecenter.security.SecurityActivity
import com.gh.gamecenter.simulatorgame.SimulatorGameActivity
import com.gh.gamecenter.teenagermode.TeenagerModeActivity
import com.gh.gamecenter.toolbox.ToolBoxBlockActivity
import com.gh.gamecenter.user.UserViewModel
import com.gh.gamecenter.video.videomanager.VideoManagerActivity
import com.halo.assistant.HaloApp
@ -248,7 +249,7 @@ class PersonalFunctionAdapter(val context: Context, val groupName: String, var m
"工具箱" -> {
DataCollectionUtils.uploadClick(context, "工具箱", "发现")
context.startActivity(ToolBoxActivity.getIntent(context, "(发现:工具箱)"))
context.startActivity(ToolBoxBlockActivity.getIntent(context, "(发现:工具箱)"))
}
"安装包清理" -> {
DataCollectionUtils.uploadClick(context, "安装包清理", "发现")

View File

@ -31,6 +31,7 @@ public class RetrofitManager {
private static final int UPLOAD_CALL_TIME_OUT = 20; // 图片上传超时时间
private static final byte[] LOCK = new byte[0];
private final ApiService mApiService;
private final ApiService mNewApiService;
private final ApiService mUploadApiService;
public static <T> T provideService(OkHttpClient client, String url, Class<T> serviceCls) {
@ -45,6 +46,7 @@ public class RetrofitManager {
Context context = HaloApp.getInstance().getApplicationContext();
OkHttpClient okHttpNormalConfig = getOkHttpConfig(context, 0, 2);
mApiService = provideService(okHttpNormalConfig, Config.API_HOST, ApiService.class);
mNewApiService = provideService(okHttpNormalConfig, Config.NEW_API_HOST, ApiService.class);
mUploadApiService = provideService(getOkHttpConfig(context, UPLOAD_CALL_TIME_OUT, 1), Config.API_HOST, ApiService.class);
}
@ -72,6 +74,10 @@ public class RetrofitManager {
return mApiService;
}
public ApiService getNewApi() {
return mNewApiService;
}
public ApiService getUploadApi() {
return mUploadApiService;
}

View File

@ -356,6 +356,12 @@ public interface ApiService {
@POST("games/platform_requests/{platform_id}:vote")
Observable<ResponseBody> postVersionVote(@Path("platform_id") String platformId);
/**
* 获取工具箱分类数据
*/
@GET("toolkit")
Observable<List<ToolBoxBlockEntity>> getCategoryToolKits();
/**
* 根据game_id获取工具箱数据
*/

View File

@ -0,0 +1,246 @@
package com.gh.gamecenter.toolbox
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View
import android.view.View.OnFocusChangeListener
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.TextView
import androidx.activity.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.ToolBarActivity
import com.gh.common.util.*
import com.gh.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.R
import com.gh.gamecenter.SuggestionActivity
import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.databinding.ActivityToolboxBlockBinding
import com.gh.gamecenter.suggest.SuggestType
import com.google.android.material.appbar.AppBarLayout
import com.lightgame.utils.Util_System_Keyboard
import com.lightgame.utils.Utils
class ToolBoxBlockActivity : ToolBarActivity() {
private val mViewModel: ToolBoxViewModel by viewModels()
private lateinit var mBinding: ActivityToolboxBlockBinding
private lateinit var mAdapter: ToolBoxBlockAdapter
private lateinit var mSearchAdapter: ToolBoxItemAdapter
private lateinit var mLayoutManager: LinearLayoutManager
private var mIsSearch = false // 记录页面状态 搜索页面/普通页面
override fun getLayoutId() = R.layout.activity_toolbox_block
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = ActivityToolboxBlockBinding.bind(mContentView)
mAdapter = ToolBoxBlockAdapter(this)
mSearchAdapter = ToolBoxItemAdapter(this, false, mViewModel)
mLayoutManager = LinearLayoutManager(this@ToolBoxBlockActivity)
setNavigationTitle("光环工具箱")
mBinding.run {
toolboxRefresh.setColorSchemeResources(R.color.theme)
toolboxRefresh.setOnRefreshListener {
refresh()
}
feedbackTv.text = SpanBuilder("需要其他工具,点击反馈").click(7, 11, R.color.theme, false) {
SuggestionActivity.startSuggestionActivity(
this@ToolBoxBlockActivity,
SuggestType.normal,
null,
null
)
}.build()
feedbackTv.movementMethod = CustomLinkMovementMethod.getInstance()
closeIv.setOnClickListener { mBinding.feedbackCv.visibility = View.GONE }
toolboxRv.adapter = mAdapter
toolboxRv.layoutManager = mLayoutManager
toolboxAppbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
toolboxRefresh.isEnabled = verticalOffset == 0
})
toolboxRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE && mLayoutManager.findLastVisibleItemPosition() == mSearchAdapter.itemCount - 1 && mIsSearch && mViewModel.searchStatus.value == LoadStatus.LIST_LOADED) {
mViewModel.getSearchResultList()
}
}
})
}
mViewModel.toolBoxBlockList.observeNonNull(this, { list ->
mAdapter.setDataList(list)
})
mViewModel.searchResultList.observeNonNull(this, { list ->
mSearchAdapter.setDataList(list)
})
mViewModel.loadStatus.observeNonNull(this, {
when (it) {
LoadStatus.INIT_LOADED -> loadDone()
LoadStatus.INIT_EMPTY -> loadEmpty()
LoadStatus.INIT_FAILED -> loadError()
}
})
mViewModel.searchStatus.observeNonNull(this, {
when (it) {
LoadStatus.INIT_LOADED -> loadDone()
LoadStatus.INIT_EMPTY -> loadEmpty()
LoadStatus.INIT_FAILED -> loadError()
LoadStatus.INIT_OVER,
LoadStatus.LIST_LOADED,
LoadStatus.LIST_FAILED,
LoadStatus.LIST_OVER -> {
loadDone()
mSearchAdapter.notifyItemChanged(mSearchAdapter.itemCount - 1)
}
}
})
initSearch()
}
override fun onResume() {
super.onResume()
if (!mIsSearch) mViewModel.getToolBoxList()
}
private fun loadDone() {
mBinding.toolboxRv.visibility = View.VISIBLE
mBinding.toolboxRefresh.isRefreshing = false
mBinding.reuseNoneData.root.visibility = View.GONE
mBinding.reuseNoConnection.root.visibility = View.GONE
mBinding.reuseLoading.root.visibility = View.GONE
}
private fun loadError() {
mBinding.toolboxRv.visibility = View.GONE
mBinding.toolboxRefresh.isRefreshing = false
mBinding.reuseNoneData.root.visibility = View.GONE
mBinding.reuseNoConnection.root.visibility = View.VISIBLE
mBinding.reuseLoading.root.visibility = View.GONE
mBinding.reuseNoConnection.root.setOnClickListener {
refresh()
mBinding.reuseNoConnection.root.visibility = View.GONE
mBinding.reuseLoading.root.visibility = View.VISIBLE
}
}
private fun loadEmpty() {
mBinding.toolboxRv.visibility = View.GONE
mBinding.toolboxRefresh.isRefreshing = false
mBinding.reuseNoneData.root.visibility = View.VISIBLE
mBinding.reuseNoConnection.root.visibility = View.GONE
mBinding.reuseLoading.root.visibility = View.GONE
mBinding.reuseNoneData.reuseTvNoneData.text =
if (mIsSearch) "未找到结果,点我反馈" else resources.getString(R.string.game_empty)
mBinding.reuseNoneData.root.setOnClickListener {
if (mIsSearch) SuggestionActivity.startSuggestionActivity(
this,
SuggestType.functionSuggest,
null,
null
)
}
}
private fun refresh() {
if (mIsSearch) {
mViewModel.getSearchResultList(true)
} else {
mViewModel.getToolBoxList()
}
}
private fun search(isSearch: Boolean, searchKey: String) {
if (mBinding.reuseNoneData.root.visibility == View.VISIBLE) {
mBinding.reuseNoneData.root.visibility = View.GONE
}
mIsSearch = isSearch
mViewModel.mSearchKey = searchKey
changeAdapter(isSearch)
if (isSearch) {
mBinding.reuseLoading.root.visibility = View.VISIBLE
mBinding.toolboxRv.visibility = View.GONE
mViewModel.getSearchResultList(true)
}
}
private fun initSearch() {
val backTv = mBinding.reuseSearchBar.tvBack
val searchTv = mBinding.reuseSearchBar.tvSearch
val searchEt = mBinding.reuseSearchBar.etSearch
mBinding.reuseSearchBar.root.setPadding(16F.dip2px(), 8F.dip2px(), 16F.dip2px(), 8F.dip2px())
backTv.setOnClickListener {
search(false, "")
searchEt.text.clear()
}
TextHelper.limitTheLengthOfEditText(searchEt, 20,
object : TextHelper.ExceedTextLengthLimitCallback {
override fun onExceed() {
toast("最多输入20字")
}
})
searchTv.setOnClickListener {
if (searchEt.text.toString().isEmpty()) {
Utils.toast(this, R.string.search_hint)
return@setOnClickListener
}
Util_System_Keyboard.hideSoftKeyboard(this, searchEt)
search(true, searchEt.text.toString())
}
searchEt.onFocusChangeListener = OnFocusChangeListener { _: View?, hasFocus: Boolean ->
if (!hasFocus) {
Util_System_Keyboard.hideSoftKeyboard(this, searchEt)
}
}
searchEt.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
searchTv.performClick()
}
false
}
}
private fun changeAdapter(isSearch: Boolean) {
mBinding.toolboxRv.adapter = if (isSearch) mSearchAdapter else mAdapter
mBinding.reuseSearchBar.tvBack.visibility = if (mIsSearch) View.VISIBLE else View.GONE
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (ev?.action == MotionEvent.ACTION_DOWN) {
val v = currentFocus
if (isShouldHideKeyboard(v, ev)) {
Util_System_Keyboard.hideSoftKeyboard(this)
}
}
return super.dispatchTouchEvent(ev)
}
private fun isShouldHideKeyboard(v: View?, event: MotionEvent): Boolean {
if (v is EditText) {
val l = intArrayOf(0, 0)
v.getLocationInWindow(l)
val left = l[0]
val top = l[1]
val bottom = top + v.getHeight()
val right = left + v.getWidth()
return (event.x <= left || event.x >= right || event.y <= top || event.y >= bottom)
}
return false
}
companion object {
@JvmStatic
fun getIntent(context: Context, entrance: String?): Intent {
val intent = Intent(context, ToolBoxBlockActivity::class.java)
intent.putExtra(EntranceUtils.KEY_ENTRANCE, entrance)
return intent
}
}
}

View File

@ -0,0 +1,97 @@
package com.gh.gamecenter.toolbox
import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.GridLayoutManager
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.goneIf
import com.gh.common.util.safelyGetInRelease
import com.gh.gamecenter.baselist.ListExecutor
import com.gh.gamecenter.databinding.ToolboxBlockItemBinding
import com.gh.gamecenter.entity.ToolBoxBlockEntity
import com.lightgame.adapter.BaseRecyclerAdapter
import java.util.*
class ToolBoxBlockAdapter(context: Context) : BaseRecyclerAdapter<ToolBoxBlockAdapter.ToolBoxBlockViewHolder>(context) {
private var mEntityList = listOf<ToolBoxBlockEntity>()
fun setDataList(dataList: List<ToolBoxBlockEntity>) {
if (dataList.isEmpty() || mEntityList.size > dataList.size) {
mEntityList = dataList
notifyDataSetChanged()
return
}
ListExecutor.workerExecutor.execute {
val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return mEntityList.size
}
override fun getNewListSize(): Int {
return dataList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = mEntityList.safelyGetInRelease(oldItemPosition)
val newItem = dataList.safelyGetInRelease(newItemPosition)
return oldItem == newItem
}
override fun areContentsTheSame(
oldItemPosition: Int,
newItemPosition: Int
): Boolean {
val oldItem = mEntityList.safelyGetInRelease(oldItemPosition)
val newItem = dataList.safelyGetInRelease(newItemPosition)
return oldItem == newItem
}
})
ListExecutor.uiExecutor.execute {
mEntityList = ArrayList(dataList)
diffResult.dispatchUpdatesTo(this)
}
}
}
override fun onBindViewHolder(holder: ToolBoxBlockViewHolder, position: Int) {
holder.bindToolBoxBlock(mEntityList[position])
holder.binding.divider.goneIf(position == itemCount - 1 || mEntityList[position].categoryName == "最近使用")
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
ToolBoxBlockViewHolder(ToolboxBlockItemBinding.inflate(mLayoutInflater, parent, false))
override fun getItemCount() = mEntityList.size
class ToolBoxBlockViewHolder(val binding: ToolboxBlockItemBinding) :
BaseRecyclerViewHolder<ToolBoxBlockEntity>(binding.root) {
private var mIsExpand = false
private var mAdapter: ToolBoxItemAdapter? = null
fun bindToolBoxBlock(toolBoxBlockEntity: ToolBoxBlockEntity) {
val context = binding.root.context
mAdapter = ToolBoxItemAdapter(context, true)
mAdapter?.setDataList(toolBoxBlockEntity.toolboxList.take(4))
binding.titleTv.text = toolBoxBlockEntity.categoryName
binding.toolboxRv.layoutManager = GridLayoutManager(context, 2)
binding.toolboxRv.adapter = mAdapter
binding.expandContainer.goneIf(toolBoxBlockEntity.toolboxList.size < 5)
binding.expandContainer.setOnClickListener {
mIsExpand = !mIsExpand
if (mIsExpand)
mAdapter?.setDataList(toolBoxBlockEntity.toolboxList)
else
mAdapter?.setDataList(toolBoxBlockEntity.toolboxList.take(4))
binding.expandTv.text = if (mIsExpand) "收起" else "展开全部"
binding.expandIv.run {
pivotX = width / 2F
pivotY = height / 2F
rotation = if (mIsExpand) 180F else 0F
}
}
}
}
}

View File

@ -0,0 +1,174 @@
package com.gh.gamecenter.toolbox
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Config
import com.gh.common.constant.Constants
import com.gh.common.constant.ItemViewType
import com.gh.common.util.*
import com.gh.common.util.ImageUtils.display
import com.gh.gamecenter.NewsDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity.Companion.getWebByCollectionTools
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.baselist.ListExecutor
import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.databinding.ItemToolboxBinding
import com.gh.gamecenter.entity.ToolBoxEntity
import com.google.gson.Gson
import com.lightgame.adapter.BaseRecyclerAdapter
import java.util.*
class ToolBoxItemAdapter(context: Context, val isBlockInside: Boolean = false, val viewModel: ToolBoxViewModel? = null) :
BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
private var mEntityList: List<ToolBoxEntity> = arrayListOf()
fun setDataList(dataList: List<ToolBoxEntity>) {
if (dataList.isEmpty() || mEntityList.size > dataList.size || viewModel?.mReset == true) {
mEntityList = dataList
notifyDataSetChanged()
return
}
ListExecutor.workerExecutor.execute {
val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return mEntityList.size
}
override fun getNewListSize(): Int {
return dataList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = mEntityList.safelyGetInRelease(oldItemPosition)
val newItem = dataList.safelyGetInRelease(newItemPosition)
return oldItem == newItem
}
override fun areContentsTheSame(
oldItemPosition: Int,
newItemPosition: Int
): Boolean {
val oldItem = mEntityList.safelyGetInRelease(oldItemPosition)
val newItem = dataList.safelyGetInRelease(newItemPosition)
return oldItem == newItem
}
})
ListExecutor.uiExecutor.execute {
mEntityList = ArrayList(dataList)
diffResult.dispatchUpdatesTo(this)
}
}
}
override fun getItemViewType(position: Int): Int {
return if (!isBlockInside && position == itemCount - 1 && itemCount != 0) {
ItemViewType.ITEM_FOOTER
} else {
ItemViewType.ITEM_BODY
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
if (viewType == ItemViewType.ITEM_FOOTER) {
FooterViewHolder(
mLayoutInflater.inflate(
R.layout.refresh_footerview,
parent,
false
)
)
} else {
ToolBoxViewHolder(
ItemToolboxBinding.bind(
mLayoutInflater.inflate(
R.layout.item_toolbox,
parent,
false
)
)
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is ToolBoxViewHolder) {
val toolBoxEntity = mEntityList[position]
initToolBoxViewHolder(holder, toolBoxEntity)
} else if (holder is FooterViewHolder) {
initFooterViewHolder(holder)
}
}
private fun initFooterViewHolder(viewHolder: FooterViewHolder) {
viewHolder.initItemPadding()
viewModel?.let {
when (viewModel.searchStatus.value) {
LoadStatus.LIST_FAILED -> {
viewHolder.loading.visibility = View.GONE
viewHolder.hint.setText(R.string.loading_failed_retry)
viewHolder.itemView.isClickable = true
viewHolder.itemView.setOnClickListener {
viewModel.getSearchResultList()
viewModel.searchStatus.postValue(LoadStatus.LIST_LOADING)
}
}
LoadStatus.INIT_OVER,
LoadStatus.LIST_OVER -> {
viewHolder.loading.visibility = View.GONE
viewHolder.hint.setText(R.string.load_over_hint)
viewHolder.itemView.isClickable = false
}
LoadStatus.LIST_LOADING -> {
viewHolder.loading.visibility = View.VISIBLE
viewHolder.hint.setText(R.string.loading)
viewHolder.itemView.isClickable = false
}
}
}
}
override fun getItemCount() = if (isBlockInside) mEntityList.size else if (mEntityList.isEmpty()) 0 else mEntityList.size + 1
private fun initToolBoxViewHolder(viewHolder: ToolBoxViewHolder, toolBoxEntity: ToolBoxEntity) {
viewHolder.binding.toolboxItemDes.text = toolBoxEntity.des
viewHolder.binding.toolboxItemTitle.text = toolBoxEntity.name
display(viewHolder.binding.toolboxItemGameThumb, toolBoxEntity.icon)
viewHolder.binding.divider.goneIf(isBlockInside)
viewHolder.binding.root.setOnClickListener {
if (SPUtils.getString(Constants.TOOLBOX_HISTORY).isEmpty()) {
SPUtils.setString(Constants.TOOLBOX_HISTORY, arrayListOf(toolBoxEntity.apply { lastOpenTime = System.currentTimeMillis() }).toJson())
} else {
val list = arrayListOf(*Gson().fromJson(SPUtils.getString(Constants.TOOLBOX_HISTORY), Array<ToolBoxEntity>::class.java)).apply {
if (contains(toolBoxEntity)) {
remove(toolBoxEntity)
}
add(0, toolBoxEntity.apply { lastOpenTime = System.currentTimeMillis() })
}
SPUtils.setString(Constants.TOOLBOX_HISTORY, list.take(4).toJson())
}
val url = toolBoxEntity.url
if (url != null && url.contains(Config.URL_ARTICLE)) {
val newsId = url.substring(url.lastIndexOf("/") + 1, url.length - 5) // 5: ".html"
val intent = NewsDetailActivity.getIntentById(mContext, newsId, "工具箱列表")
mContext.startActivity(intent)
} else {
mContext.startActivity(
getWebByCollectionTools(
mContext,
toolBoxEntity,
false
)
)
}
}
}
class ToolBoxViewHolder(val binding: ItemToolboxBinding) :
BaseRecyclerViewHolder<ToolBoxEntity?>(binding.root)
}

View File

@ -0,0 +1,116 @@
package com.gh.gamecenter.toolbox
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.entity.ToolBoxBlockEntity
import com.gh.gamecenter.entity.ToolBoxEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.google.gson.Gson
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
class ToolBoxViewModel(application: Application) : AndroidViewModel(application) {
private var mPage = 1
var mSearchKey = "" //搜索关键字
var mReset = false
val toolBoxBlockList = MutableLiveData<List<ToolBoxBlockEntity>>()
val searchResultList = MutableLiveData<List<ToolBoxEntity>>()
val loadStatus = MutableLiveData<LoadStatus>()
val searchStatus = MutableLiveData<LoadStatus>()
private val resultList = mutableListOf<ToolBoxEntity>()
fun getToolBoxList() {
RetrofitManager.getInstance().newApi.categoryToolKits
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<List<ToolBoxBlockEntity>>() {
override fun onResponse(response: List<ToolBoxBlockEntity>?) {
super.onResponse(response)
response?.let {
if (SPUtils.getString(Constants.TOOLBOX_HISTORY).isNotEmpty()) {
toolBoxBlockList.postValue(getNewList(it))
} else {
toolBoxBlockList.postValue(it)
}
}
loadStatus.postValue(if (response.isNullOrEmpty()) LoadStatus.INIT_EMPTY else LoadStatus.INIT_LOADED)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
loadStatus.postValue(LoadStatus.INIT_FAILED)
}
})
}
// 添加最近使用列表
fun getNewList(list: List<ToolBoxBlockEntity>): List<ToolBoxBlockEntity> {
val historyList = listOf(*Gson().fromJson(SPUtils.getString(Constants.TOOLBOX_HISTORY), Array<ToolBoxEntity>::class.java))
val validList = mutableListOf<ToolBoxEntity>().apply {
// 最多展示30天以内的打开记录
for (item in historyList) {
val offsetDay = TimeUtils.getBeforeDays(item.lastOpenTime / 1000)
if (offsetDay <= 30) {
add(item)
}
}
}
SPUtils.setString(Constants.TOOLBOX_HISTORY, validList.take(4).toJson())
return if (validList.isNotEmpty()) arrayListOf(ToolBoxBlockEntity(categoryName = "最近使用", toolboxList = validList)).apply {
addAll(list)
} else list
}
fun getSearchResultList(reset: Boolean = false) {
mReset = reset
if (reset) {
mPage = 1
resultList.clear()
}
RetrofitManager.getInstance().api.getToolKitData(mPage, UrlFilterUtils.getFilterQuery("keyword", mSearchKey))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<List<ToolBoxEntity>>() {
override fun onResponse(response: List<ToolBoxEntity>?) {
super.onResponse(response)
response?.let {
if (mPage != 1 && (response.isEmpty() || response.size < PAGE_SIZE)) {
searchStatus.postValue(LoadStatus.LIST_OVER)
resultList.addAll(response)
} else if (mPage == 1 && response.isEmpty()) {
searchStatus.postValue(LoadStatus.INIT_EMPTY)
resultList.clear()
} else if (mPage == 1 && response.size < PAGE_SIZE) {
searchStatus.postValue(LoadStatus.INIT_OVER)
resultList.clear()
resultList.addAll(response)
} else {
mPage++
searchStatus.postValue(if (mPage == 1) LoadStatus.INIT_LOADED else LoadStatus.LIST_LOADED)
if (mPage == 1) resultList.clear()
resultList.addAll(response)
}
searchResultList.postValue(resultList)
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
searchStatus.postValue(if (mPage == 1) LoadStatus.INIT_FAILED else LoadStatus.LIST_FAILED)
}
})
}
companion object {
const val PAGE_SIZE = 20
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/reuse_toolbar" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/toolbox_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/toolbox_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background"
android:gravity="center"
app:elevation="0dp"
app:layout_behavior="com.gh.common.view.FixAppBarLayoutBehavior">
<include
android:id="@+id/reuseSearchBar"
layout="@layout/layout_search_bar" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/toolbox_rv"
android:background="@color/white"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<androidx.cardview.widget.CardView
android:id="@+id/feedbackCv"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_alignParentBottom="true"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="15dp"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="8dp"
app:cardElevation="12dp">
<TextView
android:id="@+id/feedbackTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="需要其他工具"
android:textAlignment="center"
android:textColor="@color/text_subtitleDesc"
android:textSize="@dimen/secondary_size" />
<ImageView
android:id="@+id/closeIv"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_toolbox_cancel" />
</androidx.cardview.widget.CardView>
<include
android:id="@+id/reuseLoading"
layout="@layout/reuse_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<include
android:id="@+id/reuseNoneData"
layout="@layout/reuse_none_data"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="80dp" />
<include
android:id="@+id/reuseNoConnection"
layout="@layout/reuse_no_connection"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="80dp" />
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:paddingStart="16dp"
android:paddingLeft="16dp"
android:paddingTop="14dp"
android:paddingEnd="18dp"
android:paddingRight="18dp"
android:paddingBottom="14dp">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/toolbox_item_game_thumb"
style="@style/frescoStyle"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
fresco:roundedCornerRadius="12dp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/toolbox_item_game_thumb"
android:layout_toRightOf="@+id/toolbox_item_game_thumb">
<TextView
android:id="@+id/toolbox_item_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:textColor="@color/text_title"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/toolbox_item_des"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/toolbox_item_title"
android:layout_marginTop="6dp"
android:ellipsize="end"
android:lines="1"
android:singleLine="true"
android:textColor="@color/text_subtitleDesc"
android:textSize="12sp" />
</RelativeLayout>
</RelativeLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginStart="78dp"
android:layout_marginEnd="16dp"
android:background="@color/F2F2F2"
android:visibility="gone" />
</LinearLayout>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/titleTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="20dp"
android:paddingEnd="18dp"
android:paddingBottom="8dp"
android:text="标签分类"
android:textColor="@color/text_title"
android:textSize="@dimen/primary_title_text_size"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/toolboxRv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never" />
<LinearLayout
android:id="@+id/expandContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:paddingTop="8dp"
android:paddingBottom="20dp">
<TextView
android:id="@+id/expandTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="展开全部"
android:textColor="@color/text_subtitleDesc"
android:textSize="@dimen/secondary_size" />
<ImageView
android:id="@+id/expandIv"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginStart="4dp"
android:src="@drawable/ic_toolbox_down_arrow" />
</LinearLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/F2F2F2" />
</LinearLayout>