【光环助手V5.6.0】工具箱集合页优化 https://git.shanqu.cc/pm/halo-app-issues/-/issues/1640
This commit is contained in:
@ -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"
|
||||
|
||||
@ -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)}
|
||||
|
||||
@ -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/";
|
||||
}
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
@ -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) {
|
||||
|
||||
@ -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, "(社区-论坛:工具箱)"))
|
||||
}
|
||||
|
||||
"礼包中心" -> {
|
||||
|
||||
@ -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, "安装包清理", "发现")
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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获取工具箱数据
|
||||
*/
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
116
app/src/main/java/com/gh/gamecenter/toolbox/ToolBoxViewModel.kt
Normal file
116
app/src/main/java/com/gh/gamecenter/toolbox/ToolBoxViewModel.kt
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
app/src/main/res/drawable-xxxhdpi/ic_toolbox_cancel.webp
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_toolbox_cancel.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 666 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_toolbox_down_arrow.webp
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_toolbox_down_arrow.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 486 B |
104
app/src/main/res/layout/activity_toolbox_block.xml
Normal file
104
app/src/main/res/layout/activity_toolbox_block.xml
Normal 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>
|
||||
69
app/src/main/res/layout/item_toolbox.xml
Normal file
69
app/src/main/res/layout/item_toolbox.xml
Normal 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>
|
||||
57
app/src/main/res/layout/toolbox_block_item.xml
Normal file
57
app/src/main/res/layout/toolbox_block_item.xml
Normal 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>
|
||||
Reference in New Issue
Block a user