pref: 修改搜索界面 UI

This commit is contained in:
HuanChengFly 2020-08-31 23:22:07 +08:00
parent 80bc8db302
commit 6cd9cba48b
52 changed files with 1150 additions and 412 deletions

View File

@ -242,6 +242,10 @@
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<activity android:name=".activities.NewSearchActivity"
android:configChanges="screenSize|screenLayout|orientation|smallestScreenSize|keyboardHidden"
android:windowSoftInputMode="adjustResize" />
<receiver android:name=".receivers.AutoSignAlarm" />
<provider

View File

@ -27,6 +27,7 @@ import com.huanchengfly.tieba.post.utils.QuickPreviewUtil.getForumName
import com.huanchengfly.tieba.post.utils.QuickPreviewUtil.getPreviewInfo
import com.huanchengfly.tieba.post.utils.QuickPreviewUtil.isForumUrl
import com.huanchengfly.tieba.post.utils.QuickPreviewUtil.isThreadUrl
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import org.intellij.lang.annotations.RegExp
import org.litepal.LitePal
import java.util.*
@ -170,6 +171,7 @@ class BaseApplication : Application() {
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
})
CrashUtil.CrashHandler.getInstance().init(this)
//CrashUtil.CrashHandler crashHandler = CrashUtil.CrashHandler.getInstance();
//crashHandler.init(this);
}

View File

@ -41,10 +41,14 @@ fun Context.getColorCompat(@ColorRes id: Int): Int {
}
}
inline fun <reified T : Activity> Activity.goToActivity() {
inline fun <reified T : Activity> Context.goToActivity() {
startActivity(Intent(this, T::class.java))
}
inline fun <reified T : Activity> Context.goToActivity(pre: Intent.() -> Intent) {
startActivity(pre(Intent(this, T::class.java)))
}
fun Context.toastShort(text: String) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}
@ -52,7 +56,3 @@ fun Context.toastShort(text: String) {
fun Context.toastShort(resId: Int) {
Toast.makeText(this, resId, Toast.LENGTH_SHORT).show()
}
inline fun <reified T : Activity> Activity.goToActivity(pre: (Intent) -> Intent) {
startActivity(pre(Intent(this, T::class.java)))
}

View File

@ -4,6 +4,7 @@ package com.huanchengfly.tieba.post.activities
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap
@ -47,6 +48,7 @@ import com.huanchengfly.tieba.post.dpToPx
import com.huanchengfly.tieba.post.fragments.ForumFragment
import com.huanchengfly.tieba.post.fragments.ForumFragment.OnRefreshedListener
import com.huanchengfly.tieba.post.fragments.ForumInfoFragment
import com.huanchengfly.tieba.post.goToActivity
import com.huanchengfly.tieba.post.interfaces.Refreshable
import com.huanchengfly.tieba.post.interfaces.ScrollTopable
import com.huanchengfly.tieba.post.models.PhotoViewBean
@ -508,5 +510,15 @@ class ForumActivity : BaseActivity(), View.OnClickListener, OnRefreshedListener
companion object {
private const val TAG = "ForumActivity"
const val EXTRA_FORUM_NAME = "forum_name"
@JvmStatic
fun launch(
context: Context,
forumName: String
) {
context.goToActivity<ForumActivity> {
putExtra(EXTRA_FORUM_NAME, forumName)
}
}
}
}

View File

@ -1,4 +1,348 @@
package com.huanchengfly.tieba.post.activities
class NewSearchActivity {
}
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.widget.TextViewCompat
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
import cn.dreamtobe.kpswitch.util.KeyboardUtil
import com.alibaba.android.vlayout.DelegateAdapter
import com.alibaba.android.vlayout.VirtualLayoutManager
import com.alibaba.android.vlayout.layout.LinearLayoutHelper
import com.google.android.material.tabs.TabLayout
import com.google.android.material.textfield.TextInputLayout
import com.huanchengfly.tieba.post.*
import com.huanchengfly.tieba.post.adapters.FragmentTabViewPagerAdapter
import com.huanchengfly.tieba.post.adapters.HeaderDelegateAdapter
import com.huanchengfly.tieba.post.adapters.HeaderDelegateAdapter.Companion.NO_ICON
import com.huanchengfly.tieba.post.adapters.SearchHistoryAdapter
import com.huanchengfly.tieba.post.adapters.SingleLayoutDelegateAdapter
import com.huanchengfly.tieba.post.adapters.base.BaseSingleTypeDelegateAdapter
import com.huanchengfly.tieba.post.api.TiebaApi
import com.huanchengfly.tieba.post.api.models.web.HotMessageListBean
import com.huanchengfly.tieba.post.components.AutoLineFeedLayoutManager
import com.huanchengfly.tieba.post.components.MyViewHolder
import com.huanchengfly.tieba.post.components.dividers.SpacesItemDecoration
import com.huanchengfly.tieba.post.fragments.SearchForumFragment
import com.huanchengfly.tieba.post.fragments.SearchThreadFragment
import com.huanchengfly.tieba.post.fragments.SearchUserFragment
import com.huanchengfly.tieba.post.interfaces.ISearchFragment
import com.huanchengfly.tieba.post.models.database.SearchHistory
import com.huanchengfly.tieba.post.ui.theme.utils.ColorStateListUtils
import com.huanchengfly.tieba.post.utils.NavigationHelper
import com.huanchengfly.tieba.post.utils.PopupUtil
import com.huanchengfly.tieba.post.widgets.MyViewPager
import com.scwang.smart.refresh.header.MaterialHeader
import org.litepal.LitePal
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class NewSearchActivity : BaseActivity(), TabLayout.OnTabSelectedListener {
private var state: State = State.DEFAULT
@BindView(R.id.search_bar)
lateinit var searchBar: TextInputLayout
@BindView(R.id.tab_layout)
lateinit var tabLayout: TabLayout
@BindView(R.id.search_edit_text)
lateinit var editText: EditText
@BindView(R.id.view_pager)
lateinit var viewPager: MyViewPager
@BindView(R.id.recycler_view)
lateinit var recyclerView: RecyclerView
@BindView(R.id.bottom_app_bar)
lateinit var bottomAppBar: View
var hotMessageListBean: HotMessageListBean? = null
private var keyword: String? = null
set(value) {
field = value
if (value != null) {
SearchHistory(value)
.saveOrUpdate("content = ?", value)
}
state = if (value == null) {
State.INPUT
} else {
State.SEARCH
}
invalidateState()
tabLayout.post {
fragmentAdapter.fragments.forEachIndexed { index, fragment ->
if (fragment is ISearchFragment) {
fragment.setKeyword(value, tabLayout.selectedTabPosition == index)
}
}
}
}
private val fragmentAdapter: FragmentTabViewPagerAdapter = FragmentTabViewPagerAdapter(supportFragmentManager)
private val virtualLayoutManager: VirtualLayoutManager = VirtualLayoutManager(this)
private val delegateAdapter: DelegateAdapter = DelegateAdapter(virtualLayoutManager)
override fun getLayoutId(): Int = R.layout.activity_new_search
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fragmentAdapter.addFragment(SearchForumFragment.newInstance(), getString(R.string.title_search_forum))
fragmentAdapter.addFragment(SearchThreadFragment.newInstance(), getString(R.string.title_search_thread))
fragmentAdapter.addFragment(SearchUserFragment.newInstance(), getString(R.string.title_search_user))
viewPager.adapter = fragmentAdapter
viewPager.offscreenPageLimit = 3
tabLayout.setupWithViewPager(viewPager)
tabLayout.addOnTabSelectedListener(this)
searchBar.setStartIconOnClickListener {
onBackPressed()
}
recyclerView.layoutManager = virtualLayoutManager
recyclerView.adapter = delegateAdapter
editText.setOnEditorActionListener { v, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
keyword = v.text.toString()
return@setOnEditorActionListener true
}
return@setOnEditorActionListener false
}
keyword = intent.getStringExtra(EXTRA_KEYWORD)
editText.post {
if (keyword == null) {
KeyboardUtil.showKeyboard(editText)
}
}
}
private fun invalidateState() {
when (state) {
State.INPUT -> {
bottomAppBar.visibility = View.GONE
viewPager.visibility = View.GONE
recyclerView.visibility = View.VISIBLE
reloadAdapters()
}
State.SEARCH -> {
bottomAppBar.visibility = View.VISIBLE
viewPager.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
}
else -> {
bottomAppBar.visibility = View.GONE
viewPager.visibility = View.GONE
recyclerView.visibility = View.GONE
}
}
}
private fun reloadAdapters() {
delegateAdapter.clear()
LitePal.order("timestamp DESC").findAsync(SearchHistory::class.java).listen { histories ->
delegateAdapter.addAdapter(HeaderDelegateAdapter(
this,
R.string.title_search_history,
R.drawable.ic_round_keyboard,
if (histories.size > 0) R.drawable.ic_round_delete else NO_ICON
).apply {
setBackgroundResource(R.drawable.bg_top_radius_8dp)
backgroundTintList = R.color.default_color_card
iconTintList = R.color.default_color_primary
titleTextColor = R.color.default_color_primary
topMargin = 8.dpToPx()
startPadding = 16.dpToPx()
endPadding = 16.dpToPx()
setOnEndIconClickListener {
LitePal.deleteAllAsync(SearchHistory::class.java).listen {
toastShort(R.string.toast_delete_success)
recyclerView.post {
reloadAdapters()
}
}
}
})
delegateAdapter.addAdapter(SearchHistoryDelegateAdapter(histories))
delegateAdapter.notifyDataSetChanged()
loadHotTopic()
}
}
private fun loadHotTopic() {
if (hotMessageListBean != null) {
addHotTopicAdapters(hotMessageListBean!!)
} else {
TiebaApi.getInstance().hotMessageList().enqueue(object : Callback<HotMessageListBean> {
override fun onResponse(call: Call<HotMessageListBean>, response: Response<HotMessageListBean>) {
response.body()?.let {
hotMessageListBean = it
addHotTopicAdapters(it)
}
}
override fun onFailure(call: Call<HotMessageListBean>, t: Throwable) {}
})
}
}
private fun addHotTopicAdapters(hotMessageListBean: HotMessageListBean) {
delegateAdapter.addAdapter(HeaderDelegateAdapter(
this@NewSearchActivity,
R.string.title_hot_message,
R.drawable.ic_round_polymer,
R.drawable.ic_round_chevron_right
).apply {
setBackgroundResource(R.drawable.bg_top_radius_8dp)
backgroundTintList = R.color.default_color_card
iconTintList = R.color.default_color_primary
titleTextColor = R.color.default_color_primary
topMargin = 8.dpToPx()
startPadding = 16.dpToPx()
endPadding = 16.dpToPx()
setOnClickListener {
goToActivity<HotMessageListActivity>()
}
})
delegateAdapter.addAdapter(HotTopicDelegateAdapter(hotMessageListBean.data.list.ret.subList(0, 5)))
}
override fun onBackPressed() {
if (state == State.SEARCH) {
state = State.INPUT
invalidateState()
KeyboardUtil.showKeyboard(editText)
} else {
finish()
}
}
enum class State {
DEFAULT,
INPUT,
SEARCH;
}
companion object {
const val EXTRA_KEYWORD = "keyword";
}
inner class SearchHistoryDelegateAdapter(
val data: List<SearchHistory>? = null
) : SingleLayoutDelegateAdapter(
this,
{
val parentLayout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
layoutParams = RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
setPadding(16.dpToPx(), 8.dpToPx(), 8.dpToPx(), 8.dpToPx())
setBackgroundResource(R.drawable.bg_bottom_radius_8dp)
backgroundTintList = ColorStateListUtils.createColorStateList(context, R.color.default_color_card)
}
RecyclerView(this).apply {
id = R.id.recyclerview
addItemDecoration(SpacesItemDecoration(0, 0, 8.dpToPx(), 8.dpToPx()))
}.also {
parentLayout.addView(it)
}
View.inflate(this, R.layout.layout_no_data, null).apply {
id = R.id.no_data
}.also {
parentLayout.addView(it)
}
parentLayout
}
) {
val adapter: SearchHistoryAdapter = SearchHistoryAdapter(context).apply {
setData(data)
setOnItemClickListener { _, item, _ ->
editText.apply {
setText(item.content)
clearFocus()
KeyboardUtil.hideKeyboard(this)
}
keyword = item.content
}
}
val layoutManager: AutoLineFeedLayoutManager = AutoLineFeedLayoutManager()
override fun convert(viewHolder: MyViewHolder, itemView: View) {
if (data.isNullOrEmpty()) {
viewHolder.getView<RecyclerView>(R.id.recyclerview).apply {
visibility = View.GONE
}
viewHolder.getView<View>(R.id.no_data).apply {
visibility = View.VISIBLE
}
} else {
viewHolder.getView<RecyclerView>(R.id.recyclerview).apply {
visibility = View.VISIBLE
layoutManager = this@SearchHistoryDelegateAdapter.layoutManager
adapter = this@SearchHistoryDelegateAdapter.adapter
}
viewHolder.getView<View>(R.id.no_data).apply {
visibility = View.GONE
}
}
}
}
inner class HotTopicDelegateAdapter(
list: List<HotMessageListBean.HotMessageRetBean>? = null
) : BaseSingleTypeDelegateAdapter<HotMessageListBean.HotMessageRetBean>(
this,
LinearLayoutHelper(),
list
) {
override fun convert(viewHolder: MyViewHolder, item: HotMessageListBean.HotMessageRetBean, position: Int) {
viewHolder.setText(R.id.hot_order, "${position + 1}")
viewHolder.setText(R.id.hot_title, item.mulName)
viewHolder.setText(R.id.hot_desc, item.topicInfo.topicDesc)
val textView = viewHolder.getView<TextView>(R.id.hot_order)
if (position > 2) {
TextViewCompat.setTextAppearance(textView, R.style.TextAppearance_Bold)
textView.setTextColor(context.getColorCompat(R.color.tieba))
} else {
TextViewCompat.setTextAppearance(textView, R.style.TextAppearance_Bold_Italic)
textView.setTextColor(context.getColorCompat(R.color.red_accent))
}
viewHolder.setVisibility(R.id.hot_desc, View.GONE)
if (position + 1 >= itemCount) {
viewHolder.itemView.setBackgroundResource(R.drawable.bg_bottom_radius_8dp)
} else {
viewHolder.itemView.setBackgroundColor(Color.WHITE)
}
viewHolder.itemView.backgroundTintList = ColorStateListUtils.createColorStateList(context, R.color.default_color_card)
}
override fun getItemLayoutId(): Int {
return R.layout.item_hot_message_list
}
init {
val navigationHelper = NavigationHelper.newInstance(context)
setOnItemClickListener { _, item, _ ->
navigationHelper.navigationByData(
NavigationHelper.ACTION_URL,
"https://tieba.baidu.com/mo/q/hotMessage?topic_id=${item.mulId}&topic_name=${item.mulName}"
)
}
}
}
override fun onTabSelected(tab: TabLayout.Tab) {}
override fun onTabUnselected(tab: TabLayout.Tab) {}
override fun onTabReselected(tab: TabLayout.Tab) {
toastShort(tab.text.toString())
}
}

View File

@ -39,6 +39,7 @@ import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaException
import com.huanchengfly.tieba.post.components.MyLinearLayoutManager
import com.huanchengfly.tieba.post.components.dialogs.EditTextDialog
import com.huanchengfly.tieba.post.components.dividers.ThreadDivider
import com.huanchengfly.tieba.post.goToActivity
import com.huanchengfly.tieba.post.models.ReplyInfoBean
import com.huanchengfly.tieba.post.models.ThreadHistoryInfoBean
import com.huanchengfly.tieba.post.models.database.History
@ -862,8 +863,34 @@ class ThreadActivity : BaseActivity(), View.OnClickListener {
companion object {
const val ACTION_REPLY_SUCCESS = "com.huanchengfly.tieba.post.action.REPLY_SUCCESS"
const val EXTRA_THREAD_ID = "tid"
const val EXTRA_POST_ID = "pid"
const val EXTRA_FROM = "from"
const val EXTRA_SEE_LZ = "seeLz"
const val EXTRA_MAX_PID = "max_pid"
const val FROM_COLLECT = "collect"
const val FROM_HISTORY = "history"
const val FROM_FORUM = "forum"
@JvmOverloads
@JvmStatic
fun launch(
context: Context,
threadId: String,
postId: String? = null,
seeLz: Boolean = false,
from: String? = null,
maxPid: String? = null
) {
context.goToActivity<ThreadActivity> {
putExtra("tid", threadId)
putExtra("pid", postId ?: "")
putExtra("seeLz", seeLz)
putExtra("from", from ?: "")
putExtra("max_pid", maxPid ?: "")
}
}
}
}

View File

@ -2,6 +2,7 @@ package com.huanchengfly.tieba.post.adapters
import android.content.Context
import android.graphics.drawable.Drawable
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.RelativeLayout
@ -17,10 +18,11 @@ import com.huanchengfly.tieba.post.ui.theme.utils.ColorStateListUtils
import com.huanchengfly.tieba.post.widgets.theme.TintImageView
import com.huanchengfly.tieba.post.widgets.theme.TintTextView
class HeaderDelegateAdapter(
class HeaderDelegateAdapter @JvmOverloads constructor(
val context: Context,
val title: CharSequence = "",
val iconDrawable: Drawable? = null
val startIconDrawable: Drawable? = null,
val endIconDrawable: Drawable? = null
) : DelegateAdapter.Adapter<MyViewHolder>() {
var topPadding: Int = DEFAULT_PADDING_DP.dpToPx()
set(value) {
@ -69,22 +71,83 @@ class HeaderDelegateAdapter(
field = value
notifyDataSetChanged()
}
var backgroundTintList: Int = NO_TINT
var backgroundTintList: Int = R.color.default_color_card
set(value) {
field = value
notifyDataSetChanged()
}
var iconTintList: Int = NO_TINT
var iconTintList: Int = R.color.default_color_primary
set(value) {
field = value
notifyDataSetChanged()
}
var titleTextColor: Int = NO_TINT
var titleTextColor: Int = R.color.default_color_primary
set(value) {
field = value
notifyDataSetChanged()
}
var onClickListener: View.OnClickListener? = null
private set
var onStartIconClickListener: View.OnClickListener? = null
private set
var onTitleClickListener: View.OnClickListener? = null
private set
var onEndIconClickListener: View.OnClickListener? = null
private set
fun setOnStartIconClickListener(listener: View.OnClickListener?) {
onStartIconClickListener = listener
notifyDataSetChanged()
}
fun setOnStartIconClickListener(listener: ((View) -> Unit)?) {
setOnStartIconClickListener(View.OnClickListener {
if (listener != null) {
listener(it)
}
})
}
fun setOnTitleClickListener(listener: View.OnClickListener?) {
onTitleClickListener = listener
notifyDataSetChanged()
}
fun setOnTitleClickListener(listener: ((View) -> Unit)?) {
setOnTitleClickListener(View.OnClickListener {
if (listener != null) {
listener(it)
}
})
}
fun setOnEndIconClickListener(listener: View.OnClickListener?) {
onEndIconClickListener = listener
notifyDataSetChanged()
}
fun setOnEndIconClickListener(listener: ((View) -> Unit)?) {
setOnEndIconClickListener(View.OnClickListener {
if (listener != null) {
listener(it)
}
})
}
fun setOnClickListener(listener: View.OnClickListener?) {
onClickListener = listener
notifyDataSetChanged()
}
fun setOnClickListener(listener: ((View) -> Unit)?) {
setOnClickListener(View.OnClickListener {
if (listener != null) {
listener(it)
}
})
}
fun setBackgroundResource(@DrawableRes resId: Int) {
background = ContextCompat.getDrawable(context, resId)
}
@ -92,11 +155,13 @@ class HeaderDelegateAdapter(
constructor(
context: Context,
titleResId: Int = NO_TITLE,
iconResId: Int = NO_ICON
startIconResId: Int = NO_ICON,
endIconResId: Int = NO_ICON
) : this(
context,
if (titleResId == NO_TITLE) "" else context.getString(titleResId),
if (iconResId == NO_ICON) null else ContextCompat.getDrawable(context, iconResId)
if (startIconResId == NO_ICON) null else ContextCompat.getDrawable(context, startIconResId),
if (endIconResId == NO_ICON) null else ContextCompat.getDrawable(context, endIconResId)
)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder = MyViewHolder(context, R.layout.item_header_delegate)
@ -117,9 +182,24 @@ class HeaderDelegateAdapter(
rootView.background = background
rootView.backgroundTintList = ColorStateListUtils.createColorStateList(context, backgroundTintList)
holder.getView<TintImageView>(R.id.icon).setTintListResId(iconTintList)
holder.getView<TintImageView>(R.id.end_icon).setTintListResId(iconTintList)
holder.getView<TintTextView>(R.id.title).setTintResId(titleTextColor)
holder.setImageDrawable(R.id.icon, iconDrawable)
holder.setImageDrawable(R.id.icon, startIconDrawable)
holder.setVisibility(R.id.icon, if (startIconDrawable == null) View.GONE else View.VISIBLE)
holder.setImageDrawable(R.id.end_icon, endIconDrawable)
holder.setVisibility(R.id.end_icon, if (endIconDrawable == null) View.GONE else View.VISIBLE)
holder.setText(R.id.title, title)
setOnClickListener(rootView, onClickListener)
setOnClickListener(holder.getView(R.id.icon), onStartIconClickListener)
setOnClickListener(holder.getView(R.id.title), onTitleClickListener)
setOnClickListener(holder.getView(R.id.end_icon), onEndIconClickListener)
}
private fun setOnClickListener(view: View, listener: View.OnClickListener?) {
view.apply {
view.setOnClickListener(listener)
view.isClickable = listener != null
}
}
companion object {

View File

@ -18,7 +18,8 @@ public class HotMessageListAdapter extends CommonBaseAdapter<HotMessageListBean.
super(context, null, false);
addHeaderView(Util.inflate(context, R.layout.header_hot_message_list));
NavigationHelper navigationHelper = NavigationHelper.newInstance(mContext);
setOnItemClickListener((viewHolder, hotMessageRetBean, position) -> navigationHelper.navigationByData(NavigationHelper.ACTION_URL, String.format("https://tieba.baidu.com/mo/q/hotMessage?topic_id=%1$s&topic_name=%2$s", hotMessageRetBean.getMulId(), hotMessageRetBean.getMulName())));
setOnItemClickListener((viewHolder, hotMessageRetBean, position) ->
navigationHelper.navigationByData(NavigationHelper.ACTION_URL, String.format("https://tieba.baidu.com/mo/q/hotMessage?topic_id=%1$s&topic_name=%2$s", hotMessageRetBean.getMulId(), hotMessageRetBean.getMulName())));
}
@Override

View File

@ -1,7 +1,7 @@
package com.huanchengfly.tieba.post.adapters
import android.content.Context
import android.view.View
import android.graphics.Color
import com.alibaba.android.vlayout.layout.LinearLayoutHelper
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.adapters.base.BaseMultiTypeDelegateAdapter
@ -12,35 +12,29 @@ import com.huanchengfly.tieba.post.utils.ImageUtil
import com.huanchengfly.tieba.post.utils.NavigationHelper
import java.util.*
class SearchForumAdapter(context: Context?) : BaseMultiTypeDelegateAdapter<SearchForumBean.ForumInfoBean?>(context!!, LinearLayoutHelper()) {
private val navigationHelper: NavigationHelper
fun setData(data: SearchForumBean.DataBean) {
val forumInfoBeans: MutableList<SearchForumBean.ForumInfoBean?> = ArrayList()
if (data.exactMatch != null && data.exactMatch.forumNameShow != null) {
forumInfoBeans.add(data.exactMatch)
}
forumInfoBeans.addAll(data.fuzzyMatch!!)
setData(forumInfoBeans)
}
protected override fun convert(viewHolder: MyViewHolder, forumInfoBean: SearchForumBean.ForumInfoBean, position: Int, type: Int) {
viewHolder.setText(R.id.item_search_forum_title, forumInfoBean.forumNameShow + "")
viewHolder.setOnClickListener(R.id.item_search_forum) { view: View? -> navigationHelper.navigationByData(NavigationHelper.ACTION_FORUM, forumInfoBean.forumName) }
ImageUtil.load(viewHolder.getView(R.id.item_search_forum_avatar), ImageUtil.LOAD_TYPE_AVATAR, forumInfoBean.avatar)
if (type == TYPE_EXACT) {
val exactForumInfoBean = forumInfoBean as ExactForumInfoBean
class SearchForumAdapter(context: Context?) : BaseMultiTypeDelegateAdapter<SearchForumBean.ForumInfoBean>(context!!, LinearLayoutHelper()) {
override fun convert(viewHolder: MyViewHolder, item: SearchForumBean.ForumInfoBean, position: Int, viewType: Int) {
viewHolder.setText(R.id.item_search_forum_title, context.getString(R.string.title_forum, item.forumNameShow))
ImageUtil.load(viewHolder.getView(R.id.item_search_forum_avatar), ImageUtil.LOAD_TYPE_AVATAR, item.avatar)
if (viewType == TYPE_EXACT) {
val exactForumInfoBean = item as ExactForumInfoBean
viewHolder.setText(R.id.item_search_forum_subtitle, exactForumInfoBean.slogan)
}
if (position + 1 >= itemCount) {
viewHolder.itemView.setBackgroundResource(R.drawable.bg_bottom_radius_8dp_ripple)
} else {
viewHolder.itemView.setBackgroundResource(R.drawable.bg_ripple)
}
}
override fun getItemLayoutId(type: Int): Int {
return if (type == TYPE_EXACT) {
override fun getItemLayoutId(itemType: Int): Int {
return if (itemType == TYPE_EXACT) {
R.layout.item_search_forum_exact
} else R.layout.item_search_forum
}
protected override fun getViewType(i: Int, forumInfoBean: SearchForumBean.ForumInfoBean): Int {
return if (forumInfoBean is ExactForumInfoBean) {
override fun getViewType(position: Int, item: SearchForumBean.ForumInfoBean): Int {
return if (item is ExactForumInfoBean) {
TYPE_EXACT
} else TYPE_FUZZY
}
@ -49,8 +43,4 @@ class SearchForumAdapter(context: Context?) : BaseMultiTypeDelegateAdapter<Searc
const val TYPE_EXACT = 0
const val TYPE_FUZZY = 1
}
init {
navigationHelper = NavigationHelper.newInstance(context)
}
}

View File

@ -1,14 +1,15 @@
package com.huanchengfly.tieba.post.adapters
import android.content.Context
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.adapters.base.BaseSingleTypeAdapter
import com.huanchengfly.tieba.post.components.MyViewHolder
import com.huanchengfly.tieba.post.models.database.SearchHistory
class SearchHistoryAdapter(context: Context) : BaseSingleTypeAdapter<SearchHistory?>(context) {
override fun getItemLayoutId(): Int {
return 0
}
class SearchHistoryAdapter(context: Context) : BaseSingleTypeAdapter<SearchHistory>(context) {
override fun getItemLayoutId(): Int = R.layout.item_search_history_chip
protected override fun convert(viewHolder: MyViewHolder, searchHistory: SearchHistory, position: Int) {}
override fun convert(viewHolder: MyViewHolder, item: SearchHistory, position: Int) {
viewHolder.setText(R.id.text, item.content)
}
}

View File

@ -10,31 +10,34 @@ import com.huanchengfly.tieba.post.fragments.SearchThreadFragment
import com.huanchengfly.tieba.post.utils.NavigationHelper
import java.util.*
class SearchThreadAdapter(fragment: SearchThreadFragment) : BaseSingleTypeAdapter<SearchThreadBean.ThreadInfoBean?>(fragment.requireContext()) {
private val navigationHelper: NavigationHelper
private val order = 0
private val filter = 0
protected override fun convert(viewHolder: MyViewHolder, threadInfoBean: SearchThreadBean.ThreadInfoBean, position: Int) {
viewHolder.setOnClickListener(R.id.item_search_thread) { view: View? ->
val map: MutableMap<String, String?> = HashMap()
map["tid"] = threadInfoBean.tid
map["pid"] = threadInfoBean.pid
navigationHelper.navigationByData(NavigationHelper.ACTION_THREAD, map)
}
viewHolder.setText(R.id.item_search_thread_title, threadInfoBean.title)
viewHolder.setText(R.id.item_search_thread_content, threadInfoBean.content)
viewHolder.setText(R.id.item_search_thread_user, threadInfoBean.user!!.userName)
if (threadInfoBean.forumName == null) {
class SearchThreadAdapter(fragment: SearchThreadFragment) : BaseSingleTypeAdapter<SearchThreadBean.ThreadInfoBean>(fragment.requireContext()) {
override fun convert(viewHolder: MyViewHolder, item: SearchThreadBean.ThreadInfoBean, position: Int) {
viewHolder.setText(R.id.item_search_thread_title, item.title)
viewHolder.setText(R.id.item_search_thread_content, item.content)
viewHolder.setText(R.id.item_search_thread_user, item.user!!.userName)
if (item.forumName == null) {
viewHolder.setText(
R.id.item_search_thread_info,
DateUtils.getRelativeTimeSpanString(threadInfoBean.time!!.toLong() * 1000L)
DateUtils.getRelativeTimeSpanString(item.time!!.toLong() * 1000L)
)
} else {
viewHolder.setText(
R.id.item_search_thread_info,
threadInfoBean.forumName + " " + DateUtils.getRelativeTimeSpanString(threadInfoBean.time!!.toLong() * 1000L)
item.forumName + " " + DateUtils.getRelativeTimeSpanString(item.time!!.toLong() * 1000L)
)
}
viewHolder.itemView.setBackgroundResource(
if (position == 0 && position + 1 == itemCount) {
R.drawable.bg_radius_8dp_ripple
} else if (position == 0) {
R.drawable.bg_top_radius_8dp_ripple
} else if (position + 1 == itemCount) {
R.drawable.bg_radius_8dp_ripple
} else {
R.drawable.bg_ripple
}
)
}
override fun getItemLayoutId(): Int {
@ -42,8 +45,6 @@ class SearchThreadAdapter(fragment: SearchThreadFragment) : BaseSingleTypeAdapte
}
init {
val context = fragment.requireContext()
navigationHelper = NavigationHelper.newInstance(context)
/*
View headerView = Util.inflate(context, R.layout.layout_search_header);
if (headerView != null) {

View File

@ -1,4 +1,4 @@
package com.huanchengfly.tieba.post.adapters.base
package com.huanchengfly.tieba.post.adapters
import android.content.Context
import android.view.View
@ -9,7 +9,7 @@ import com.alibaba.android.vlayout.LayoutHelper
import com.alibaba.android.vlayout.layout.SingleLayoutHelper
import com.huanchengfly.tieba.post.components.MyViewHolder
abstract class BaseSingleLayoutAdapter(
open class SingleLayoutDelegateAdapter(
val context: Context,
val itemView: View
) : DelegateAdapter.Adapter<MyViewHolder>() {
@ -32,13 +32,13 @@ abstract class BaseSingleLayoutAdapter(
final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder = MyViewHolder(itemView)
final override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
convert(holder, itemView)
final override fun onBindViewHolder(viewHolder: MyViewHolder, position: Int) {
convert(viewHolder, itemView)
}
final override fun getItemCount(): Int = 1
override fun onCreateLayoutHelper(): LayoutHelper = SingleLayoutHelper()
abstract fun convert(holder: MyViewHolder, itemView: View)
open fun convert(viewHolder: MyViewHolder, itemView: View) {}
}

View File

@ -1,15 +1,15 @@
package com.huanchengfly.tieba.post.adapters.base
import android.content.Context
import androidx.recyclerview.widget.RecyclerView
import com.alibaba.android.vlayout.DelegateAdapter
import com.alibaba.android.vlayout.LayoutHelper
import com.huanchengfly.tieba.post.components.MyViewHolder
abstract class BaseDelegateAdapter<Item>(
abstract class BaseAdapter<Item>(
val context: Context,
val layoutHelper: LayoutHelper,
items: List<Item>? = null
) : DelegateAdapter.Adapter<MyViewHolder>() {
) : RecyclerView.Adapter<MyViewHolder>() {
private var itemList: MutableList<Item> = (items ?: emptyList()).toMutableList()
var onItemClickListener: OnItemClickListener<Item>? = null
@ -49,8 +49,6 @@ abstract class BaseDelegateAdapter<Item>(
override fun getItemCount(): Int = getCount()
override fun onCreateLayoutHelper(): LayoutHelper = layoutHelper
fun getItem(position: Int): Item = itemList[position]
fun getItemList(): MutableList<Item> = itemList
@ -101,12 +99,4 @@ abstract class BaseDelegateAdapter<Item>(
itemList.clear()
notifyDataSetChanged()
}
interface OnItemClickListener<Item> {
fun onClick(viewHolder: MyViewHolder, item: Item, position: Int)
}
interface OnItemLongClickListener<Item> {
fun onLongClick(viewHolder: MyViewHolder, item: Item, position: Int): Boolean
}
}

View File

@ -101,12 +101,4 @@ abstract class BaseDelegateAdapter<Item>(
itemList.clear()
notifyDataSetChanged()
}
interface OnItemClickListener<Item> {
fun onClick(viewHolder: MyViewHolder, item: Item, position: Int)
}
interface OnItemLongClickListener<Item> {
fun onLongClick(viewHolder: MyViewHolder, item: Item, position: Int): Boolean
}
}

View File

@ -6,11 +6,10 @@ import android.view.ViewGroup
import com.alibaba.android.vlayout.LayoutHelper
import com.huanchengfly.tieba.post.components.MyViewHolder
abstract class BaseMultiTypeDelegateAdapter<Item>(
context: Context,
layoutHelper: LayoutHelper
) : BaseDelegateAdapter<Item>(
context, layoutHelper
abstract class BaseMultiTypeAdapter<Item>(
context: Context
) : BaseAdapter<Item>(
context
) {
protected abstract fun getItemLayoutId(
itemType: Int
@ -28,12 +27,12 @@ abstract class BaseMultiTypeDelegateAdapter<Item>(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder = MyViewHolder(context, getItemLayoutId(viewType))
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.setItemOnClickListener(View.OnClickListener {
holder.setItemOnClickListener {
onItemClickListener?.onClick(holder, getItem(position), position)
})
holder.setItemOnLongClickListener(View.OnLongClickListener {
}
holder.setItemOnLongClickListener {
onItemLongClickListener?.onLongClick(holder, getItem(position), position) ?: false
})
}
convert(holder, getItem(position), position, getItemViewType(position))
}

View File

@ -6,23 +6,22 @@ import android.view.ViewGroup
import com.alibaba.android.vlayout.LayoutHelper
import com.huanchengfly.tieba.post.components.MyViewHolder
abstract class BaseSingleTypeDelegateAdapter<Item>(
context: Context,
layoutHelper: LayoutHelper
) : BaseDelegateAdapter<Item>(
context, layoutHelper
abstract class BaseSingleTypeAdapter<Item>(
context: Context
) : BaseAdapter<Item>(
context
) {
protected abstract fun getItemLayoutId(): Int
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder = MyViewHolder(context, getItemLayoutId())
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.setItemOnClickListener(View.OnClickListener {
holder.setItemOnClickListener {
onItemClickListener?.onClick(holder, getItem(position), position)
})
holder.setItemOnLongClickListener(View.OnLongClickListener {
}
holder.setItemOnLongClickListener {
onItemLongClickListener?.onLongClick(holder, getItem(position), position) ?: false
})
}
convert(holder, getItem(position), position)
}

View File

@ -6,11 +6,12 @@ import android.view.ViewGroup
import com.alibaba.android.vlayout.LayoutHelper
import com.huanchengfly.tieba.post.components.MyViewHolder
abstract class BaseSingleTypeDelegateAdapter<Item>(
abstract class BaseSingleTypeDelegateAdapter<Item> @JvmOverloads constructor(
context: Context,
layoutHelper: LayoutHelper
layoutHelper: LayoutHelper,
items: List<Item>? = null
) : BaseDelegateAdapter<Item>(
context, layoutHelper
context, layoutHelper, items
) {
protected abstract fun getItemLayoutId(): Int

View File

@ -1,2 +1,11 @@
package com.huanchengfly.tieba.post.adapters.base
import com.huanchengfly.tieba.post.components.MyViewHolder
interface OnItemClickListener<Item> {
fun onClick(viewHolder: MyViewHolder, item: Item, position: Int)
}
interface OnItemLongClickListener<Item> {
fun onLongClick(viewHolder: MyViewHolder, item: Item, position: Int): Boolean
}

View File

@ -1,4 +1,54 @@
package com.huanchengfly.tieba.post.components;
public class AutoLineFeedLayoutManager {
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
public class AutoLineFeedLayoutManager extends RecyclerView.LayoutManager {
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(
RecyclerView.LayoutParams.WRAP_CONTENT,
RecyclerView.LayoutParams.WRAP_CONTENT);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
int sumWidth = getWidth();
int curLineWidth = 0, curLineTop = 0;
int lastLineMaxHeight = 0;
for (int i = 0; i < getItemCount(); i++) {
View view = recycler.getViewForPosition(i);
addView(view);
measureChildWithMargins(view, 0, 0);
int width = getDecoratedMeasuredWidth(view);
int height = getDecoratedMeasuredHeight(view);
curLineWidth += width;
if (curLineWidth <= sumWidth) {//不需要换行
layoutDecorated(view, curLineWidth - width, curLineTop, curLineWidth, curLineTop + height);
//比较当前行多有item的最大高度
lastLineMaxHeight = Math.max(lastLineMaxHeight, height);
} else {//换行
curLineWidth = width;
if (lastLineMaxHeight == 0) {
lastLineMaxHeight = height;
}
//记录当前行top
curLineTop += lastLineMaxHeight;
layoutDecorated(view, 0, curLineTop, width, curLineTop + height);
lastLineMaxHeight = height;
}
}
}
@Override
public boolean isAutoMeasureEnabled() {
return true;
}
}

View File

@ -2,6 +2,7 @@ package com.huanchengfly.tieba.post.components.dividers;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
@ -24,14 +25,12 @@ public class SearchDivider extends RecyclerView.ItemDecoration implements Tintab
private int mOrientation;
private int mDividerHeight;
private int mCommonDividerHeight;
private Context mContext;
public SearchDivider(Context context) {
mContext = context;
mOrientation = LinearLayoutManager.VERTICAL;
mDivider = ContextCompat.getDrawable(context, R.drawable.drawable_divider);
mDividerHeight = DisplayUtil.dp2px(context, 8);
mCommonDividerHeight = DisplayUtil.dp2px(context, 1);
mCommonDividerHeight = DisplayUtil.dp2px(context, 0);
tint();
}
@ -95,6 +94,6 @@ public class SearchDivider extends RecyclerView.ItemDecoration implements Tintab
@Override
public void tint() {
mDivider = ThemeUtils.tintDrawable(mDivider, ThemeUtils.getColorByAttr(mContext, R.attr.colorDivider));
mDivider = ThemeUtils.tintDrawable(mDivider, Color.TRANSPARENT);
}
}

View File

@ -7,18 +7,31 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
private int leftSpace;
private int topSpace;
private int rightSpace;
private int bottomSpace;
public SpacesItemDecoration(int space) {
this.space = space;
this.leftSpace =
this.topSpace =
this.rightSpace =
this.bottomSpace = space;
}
public SpacesItemDecoration(int left, int top, int right, int bottom) {
this.topSpace = top;
this.rightSpace = right;
this.bottomSpace = bottom;
this.leftSpace = left;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
@NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
outRect.top = space;
outRect.left = leftSpace;
outRect.top = topSpace;
outRect.right = rightSpace;
outRect.bottom = bottomSpace;
}
}

View File

@ -15,12 +15,15 @@ import com.alibaba.android.vlayout.DelegateAdapter
import com.alibaba.android.vlayout.VirtualLayoutManager
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener
import com.huanchengfly.tieba.post.BaseApplication
import com.huanchengfly.tieba.post.R
import com.google.android.material.textfield.TextInputLayout
import com.huanchengfly.tieba.post.*
import com.huanchengfly.tieba.post.activities.ForumActivity
import com.huanchengfly.tieba.post.activities.NewSearchActivity
import com.huanchengfly.tieba.post.adapters.HeaderDelegateAdapter
import com.huanchengfly.tieba.post.adapters.MainForumListAdapter
import com.huanchengfly.tieba.post.adapters.base.BaseDelegateAdapter
import com.huanchengfly.tieba.post.adapters.base.OnItemClickListener
import com.huanchengfly.tieba.post.adapters.base.OnItemLongClickListener
import com.huanchengfly.tieba.post.api.Error
import com.huanchengfly.tieba.post.api.ForumSortType
import com.huanchengfly.tieba.post.api.TiebaApi
@ -29,10 +32,8 @@ import com.huanchengfly.tieba.post.api.models.ForumRecommend
import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaException
import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaLocalException
import com.huanchengfly.tieba.post.components.MyViewHolder
import com.huanchengfly.tieba.post.dpToPx
import com.huanchengfly.tieba.post.interfaces.Refreshable
import com.huanchengfly.tieba.post.models.database.TopForum
import com.huanchengfly.tieba.post.toastShort
import com.huanchengfly.tieba.post.utils.*
import com.huanchengfly.tieba.post.utils.preload.PreloadUtil
import com.huanchengfly.tieba.post.utils.preload.loaders.ForumLoader
@ -45,8 +46,8 @@ import retrofit2.Response
import kotlin.math.abs
class MainForumListFragment : BaseFragment(), Refreshable, Toolbar.OnMenuItemClickListener,
BaseDelegateAdapter.OnItemClickListener<ForumRecommend.LikeForum>,
BaseDelegateAdapter.OnItemLongClickListener<ForumRecommend.LikeForum> {
OnItemClickListener<ForumRecommend.LikeForum>,
OnItemLongClickListener<ForumRecommend.LikeForum> {
companion object {
val MOTION_START_OFFSET = 83f.dpToPx()
}
@ -57,6 +58,9 @@ class MainForumListFragment : BaseFragment(), Refreshable, Toolbar.OnMenuItemCli
@BindView(R.id.search_bar_motion)
lateinit var searchBarMotionLayout: MotionLayout
@BindView(R.id.search_bar)
lateinit var searchBar: TextInputLayout
@BindView(R.id.refresh_header)
lateinit var refreshLayoutHeader: MaterialHeader
@ -163,6 +167,12 @@ class MainForumListFragment : BaseFragment(), Refreshable, Toolbar.OnMenuItemCli
}
reloadAdapters()
toolbar.setOnMenuItemClickListener(this)
searchBar.editText?.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
v.clearFocus()
attachContext.goToActivity<NewSearchActivity>()
}
}
btnOkSign.setOnClickListener {
TiebaUtil.startSign(attachContext)
}

View File

@ -2,55 +2,73 @@ package com.huanchengfly.tieba.post.fragments
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import butterknife.BindView
import com.alibaba.android.vlayout.DelegateAdapter
import com.alibaba.android.vlayout.VirtualLayoutManager
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.activities.ForumActivity
import com.huanchengfly.tieba.post.adapters.HeaderDelegateAdapter
import com.huanchengfly.tieba.post.adapters.SearchForumAdapter
import com.huanchengfly.tieba.post.adapters.base.OnItemClickListener
import com.huanchengfly.tieba.post.api.TiebaApi.getInstance
import com.huanchengfly.tieba.post.api.models.SearchForumBean
import com.huanchengfly.tieba.post.components.MyViewHolder
import com.huanchengfly.tieba.post.dpToPx
import com.huanchengfly.tieba.post.interfaces.ISearchFragment
import com.huanchengfly.tieba.post.toastShort
import com.huanchengfly.tieba.post.utils.ThemeUtil
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class SearchForumFragment : BaseFragment(), ISearchFragment {
@BindView(R.id.fragment_search_refresh_layout)
var refreshLayout: SwipeRefreshLayout? = null
class SearchForumFragment : BaseFragment(), ISearchFragment, OnItemClickListener<SearchForumBean.ForumInfoBean> {
@JvmField
@BindView(R.id.fragment_search_refresh)
var refreshLayout: SmartRefreshLayout? = null
@BindView(R.id.fragment_search_recycler_view)
var recyclerView: RecyclerView? = null
lateinit var recyclerView: RecyclerView
private var keyword: String? = null
private var mAdapter: SearchForumAdapter? = null
private lateinit var layoutManager: VirtualLayoutManager
private lateinit var delegateAdapter: DelegateAdapter
private lateinit var exactMatchAdapter: SearchForumAdapter
private lateinit var fuzzyMatchAdapter: SearchForumAdapter
private var mData: SearchForumBean.DataBean? = null
override fun setKeyword(
keyword: String?,
needRefresh: Boolean
) {
this.keyword = keyword
if (mAdapter != null) {
if (needRefresh) {
refresh()
} else {
mData = null
mAdapter!!.reset()
}
if (needRefresh) {
refreshLayout?.autoRefresh()
} else {
mData = null
delegateAdapter.clear()
}
}
override fun onFragmentVisibleChange(isVisible: Boolean) {
if (mData == null && isVisible) {
refresh()
refreshLayout?.autoRefresh()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (arguments != null) {
keyword = arguments!!.getString(ARG_KEYWORD)
keyword = requireArguments().getString(ARG_KEYWORD)
}
layoutManager = VirtualLayoutManager(attachContext)
delegateAdapter = DelegateAdapter(layoutManager)
exactMatchAdapter = SearchForumAdapter(attachContext).apply {
setOnItemClickListener(this@SearchForumFragment)
}
fuzzyMatchAdapter = SearchForumAdapter(attachContext).apply {
setOnItemClickListener(this@SearchForumFragment)
}
}
@ -60,44 +78,73 @@ class SearchForumFragment : BaseFragment(), ISearchFragment {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView!!.layoutManager = VirtualLayoutManager(attachContext)
mAdapter = SearchForumAdapter(attachContext)
recyclerView!!.adapter = mAdapter
recyclerView.layoutManager = layoutManager
recyclerView.adapter = delegateAdapter
refreshLayout!!.setOnRefreshListener { refresh() }
ThemeUtil.setThemeForSwipeRefreshLayout(refreshLayout)
}
private fun setRefreshing(refreshing: Boolean) {
if (refreshLayout != null) refreshLayout!!.isRefreshing = refreshing
ThemeUtil.setThemeForSmartRefreshLayout(refreshLayout)
}
private fun refresh() {
if (keyword == null) {
return
}
setRefreshing(true)
getInstance().searchForum(keyword!!).enqueue(object : Callback<SearchForumBean> {
override fun onResponse(call: Call<SearchForumBean>, response: Response<SearchForumBean>) {
mData = response.body()!!.data
refreshLayout?.finishRefreshWithNoMoreData()
reloadAdapters()
setRefreshing(false)
}
override fun onFailure(call: Call<SearchForumBean>, t: Throwable) {
setRefreshing(false)
Toast.makeText(attachContext, t.message, Toast.LENGTH_SHORT).show()
t.message?.let { attachContext.toastShort(it) }
refreshLayout?.finishRefresh(false)
}
})
}
private fun reloadAdapters() {}
private fun reloadAdapters() {
delegateAdapter.clear()
if (mData != null) {
if (mData!!.exactMatch != null) {
exactMatchAdapter.setData(listOf(mData!!.exactMatch!!))
delegateAdapter.addAdapter(HeaderDelegateAdapter(
attachContext,
R.string.title_exact_match,
R.drawable.ic_round_graphic_eq
).apply {
setBackgroundResource(R.drawable.bg_top_radius_8dp)
topMargin = 8.dpToPx()
startPadding = 16.dpToPx()
endPadding = 16.dpToPx()
})
delegateAdapter.addAdapter(exactMatchAdapter)
}
if (!mData!!.fuzzyMatch.isNullOrEmpty()) {
fuzzyMatchAdapter.setData(mData!!.fuzzyMatch!!)
delegateAdapter.addAdapter(HeaderDelegateAdapter(
attachContext,
R.string.title_fuzzy_match,
R.drawable.ic_infinite
).apply {
setBackgroundResource(R.drawable.bg_top_radius_8dp)
topMargin = 8.dpToPx()
startPadding = 16.dpToPx()
endPadding = 16.dpToPx()
})
delegateAdapter.addAdapter(fuzzyMatchAdapter)
}
}
}
override fun onFragmentFirstVisible() {
refresh()
refreshLayout!!.autoRefresh()
}
companion object {
const val TAG = "SearchForumFragment"
const val ARG_KEYWORD = "keyword"
@JvmStatic
@JvmOverloads
fun newInstance(keyword: String? = null): SearchForumFragment {
val forumFragment = SearchForumFragment()
@ -107,4 +154,8 @@ class SearchForumFragment : BaseFragment(), ISearchFragment {
return forumFragment
}
}
override fun onClick(viewHolder: MyViewHolder, item: SearchForumBean.ForumInfoBean, position: Int) {
item.forumName?.let { ForumActivity.launch(attachContext, it) }
}
}

View File

@ -5,26 +5,29 @@ import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import butterknife.BindView
import com.huanchengfly.tieba.post.api.SearchThreadFilter
import com.huanchengfly.tieba.post.api.SearchThreadOrder
import com.huanchengfly.tieba.post.api.TiebaApi
import com.huanchengfly.tieba.post.api.models.SearchThreadBean
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.activities.ThreadActivity
import com.huanchengfly.tieba.post.adapters.SearchThreadAdapter
import com.huanchengfly.tieba.post.components.MyLinearLayoutManager
import com.huanchengfly.tieba.post.components.dividers.CommonDivider
import com.huanchengfly.tieba.post.interfaces.ISearchFragment
import com.huanchengfly.tieba.post.interfaces.OnOrderSwitchListener
import com.huanchengfly.tieba.post.utils.ThemeUtil
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class SearchThreadFragment : BaseFragment(), OnOrderSwitchListener {
class SearchThreadFragment : BaseFragment(), OnOrderSwitchListener, ISearchFragment {
private var keyword: String? = null
@BindView(R.id.fragment_search_refresh_layout)
lateinit var refreshLayout: SwipeRefreshLayout
@JvmField
@BindView(R.id.fragment_search_refresh)
var refreshLayout: SmartRefreshLayout? = null
@BindView(R.id.fragment_search_recycler_view)
lateinit var recyclerView: RecyclerView
private var mAdapter: SearchThreadAdapter? = null
@ -32,19 +35,25 @@ class SearchThreadFragment : BaseFragment(), OnOrderSwitchListener {
private var filter: SearchThreadFilter = SearchThreadFilter.ONLY_THREAD
private var mData: SearchThreadBean.DataBean? = null
private var page = 0
fun setKeyword(keyword: String?, refresh: Boolean) {
override fun setKeyword(
keyword: String?,
needRefresh: Boolean
) {
this.keyword = keyword
if (refresh) {
refresh()
} else {
mData = null
mAdapter!!.reset()
if (mAdapter != null) {
if (needRefresh) {
refreshLayout?.autoRefresh()
} else {
mData = null
mAdapter!!.reset()
}
}
}
override fun onFragmentVisibleChange(isVisible: Boolean) {
if (mData == null && isVisible) {
refresh()
refreshLayout?.autoRefresh()
}
}
@ -53,7 +62,7 @@ class SearchThreadFragment : BaseFragment(), OnOrderSwitchListener {
order = SearchThreadOrder.NEW
filter = SearchThreadFilter.ONLY_THREAD
if (arguments != null) {
keyword = arguments!!.getString(ARG_KEYWORD)
keyword = requireArguments().getString(ARG_KEYWORD)
}
}
@ -64,19 +73,18 @@ class SearchThreadFragment : BaseFragment(), OnOrderSwitchListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mAdapter = SearchThreadAdapter(this).apply {
setLoadingView(R.layout.layout_footer_loading)
setLoadEndView(R.layout.layout_footer_loadend)
setLoadFailedView(R.layout.layout_footer_load_failed)
setOnLoadMoreListener { isReload: Boolean -> loadMore(isReload) }
setOnItemClickListener { _, item, _ ->
ThreadActivity.launch(attachContext, item.tid!!, item.pid)
}
}
recyclerView.apply {
layoutManager = MyLinearLayoutManager(attachContext)
adapter = mAdapter
addItemDecoration(CommonDivider(attachContext, LinearLayoutManager.VERTICAL, R.drawable.drawable_divider_1dp))
}
refreshLayout.apply {
refreshLayout!!.apply {
setOnRefreshListener { refresh() }
ThemeUtil.setThemeForSwipeRefreshLayout(this)
setOnLoadMoreListener { loadMore() }
ThemeUtil.setThemeForSmartRefreshLayout(this)
}
}
@ -85,52 +93,52 @@ class SearchThreadFragment : BaseFragment(), OnOrderSwitchListener {
return false
}
if (mData!!.hasMore == 0) {
mAdapter!!.loadEnd()
refreshLayout?.setNoMoreData(true)
}
return mData!!.hasMore != 0
}
private fun refresh() {
refreshLayout.isRefreshing = true
if (keyword == null) {
return
}
page = 1
TiebaApi.getInstance().searchThread(keyword!!, page, order, filter).enqueue(object : Callback<SearchThreadBean> {
override fun onFailure(call: Call<SearchThreadBean>, t: Throwable) {
refreshLayout.isRefreshing = false
Toast.makeText(attachContext, t.message, Toast.LENGTH_SHORT).show()
refreshLayout?.finishRefresh(false)
}
override fun onResponse(call: Call<SearchThreadBean>, response: Response<SearchThreadBean>) {
val searchThreadBean = response.body()!!
mData = searchThreadBean.data
mAdapter!!.setNewData(mData!!.postList)
refreshLayout.isRefreshing = false
mAdapter!!.setData(mData!!.postList)
refreshLayout?.finishRefresh(true)
}
})
}
private fun loadMore(isReload: Boolean) {
private fun loadMore() {
if (hasMore()) {
if (!isReload) {
page += 1
}
TiebaApi.getInstance().searchThread(keyword!!, page, order, filter).enqueue(object : Callback<SearchThreadBean> {
TiebaApi.getInstance().searchThread(keyword!!, page + 1, order, filter).enqueue(object : Callback<SearchThreadBean> {
override fun onFailure(call: Call<SearchThreadBean>, t: Throwable) {
refreshLayout.isRefreshing = false
Toast.makeText(attachContext, t.message, Toast.LENGTH_SHORT).show()
refreshLayout?.finishLoadMore(false)
}
override fun onResponse(call: Call<SearchThreadBean>, response: Response<SearchThreadBean>) {
val searchThreadBean = response.body()!!
mData = searchThreadBean.data
mAdapter!!.setLoadMoreData(mData!!.postList)
refreshLayout.isRefreshing = false
mData!!.postList?.let { mAdapter!!.insert(it) }
page += 1
refreshLayout?.finishLoadMore(true)
}
})
}
}
override fun onFragmentFirstVisible() {
refresh()
refreshLayout!!.autoRefresh()
}
override fun onSwitch(type: Int, value: Int) {
@ -144,8 +152,10 @@ class SearchThreadFragment : BaseFragment(), OnOrderSwitchListener {
companion object {
const val TAG = "SearchThreadFragment"
const val ARG_KEYWORD = "keyword"
@JvmStatic
fun newInstance(keyword: String?): SearchThreadFragment {
@JvmOverloads
fun newInstance(keyword: String? = null): SearchThreadFragment {
val fragment = SearchThreadFragment()
val bundle = Bundle()
bundle.putString(ARG_KEYWORD, keyword)

View File

@ -13,39 +13,49 @@ import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.adapters.SearchUserAdapter
import com.huanchengfly.tieba.post.components.MyLinearLayoutManager
import com.huanchengfly.tieba.post.components.dividers.SearchDivider
import com.huanchengfly.tieba.post.interfaces.ISearchFragment
import com.huanchengfly.tieba.post.toastShort
import com.huanchengfly.tieba.post.utils.ThemeUtil
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class SearchUserFragment : BaseFragment() {
class SearchUserFragment : BaseFragment(), ISearchFragment {
private var keyword: String? = null
@BindView(R.id.fragment_search_refresh_layout)
lateinit var mRefreshLayout: SwipeRefreshLayout
@JvmField
@BindView(R.id.fragment_search_refresh)
var mRefreshLayout: SmartRefreshLayout? = null
@BindView(R.id.fragment_search_recycler_view)
lateinit var mRecyclerView: RecyclerView
private var mAdapter: SearchUserAdapter? = null
private var mData: SearchUserDataBean? = null
fun setKeyword(keyword: String?, refresh: Boolean) {
override fun setKeyword(
keyword: String?,
needRefresh: Boolean
) {
this.keyword = keyword
if (refresh) {
refresh()
} else {
mData = null
mAdapter!!.reset()
this.mData = null
if (mAdapter != null) {
if (needRefresh) {
mRefreshLayout?.autoRefresh()
} else {
mAdapter!!.reset()
}
}
}
override fun onFragmentVisibleChange(isVisible: Boolean) {
if (mData == null && isVisible) {
refresh()
mRefreshLayout?.autoRefresh()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (arguments != null) {
keyword = arguments!!.getString(ARG_KEYWORD)
keyword = requireArguments().getString(ARG_KEYWORD)
}
}
@ -55,53 +65,52 @@ class SearchUserFragment : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mAdapter = SearchUserAdapter(attachContext).apply {
setLoadEndView(R.layout.layout_footer_loadend)
setLoadFailedView(R.layout.layout_footer_load_failed)
}
mAdapter = SearchUserAdapter(attachContext)
mRecyclerView.apply {
layoutManager = MyLinearLayoutManager(attachContext)
addItemDecoration(SearchDivider(attachContext))
adapter = mAdapter
}
mRefreshLayout.apply {
mRefreshLayout!!.apply {
setEnableLoadMore(false)
setOnRefreshListener { refresh() }
ThemeUtil.setThemeForSwipeRefreshLayout(this)
ThemeUtil.setThemeForSmartRefreshLayout(this)
}
}
private fun refresh() {
mRefreshLayout.isRefreshing = true
if (keyword == null) {
return
}
TiebaApi.getInstance().searchUser(keyword!!).enqueue(object : Callback<SearchUserBean> {
override fun onResponse(call: Call<SearchUserBean>, response: Response<SearchUserBean>) {
val searchUserDataBean = response.body()!!.data
mData = searchUserDataBean
mAdapter!!.setData(searchUserDataBean)
mRefreshLayout.isRefreshing = false
mRefreshLayout?.finishRefreshWithNoMoreData()
if (searchUserDataBean?.hasMore == 0) mAdapter!!.loadEnd()
}
override fun onFailure(call: Call<SearchUserBean>, t: Throwable) {
mRefreshLayout.isRefreshing = false
Toast.makeText(attachContext, t.message, Toast.LENGTH_SHORT).show()
t.message?.let { attachContext.toastShort(it) }
mRefreshLayout?.finishRefresh(false)
}
})
}
override fun onFragmentFirstVisible() {
refresh()
mRefreshLayout!!.autoRefresh()
}
companion object {
const val TAG = "SearchUserFragment"
const val ARG_KEYWORD = "keyword"
@JvmStatic
fun newInstance(keyword: String?): SearchUserFragment {
val forumFragment = SearchUserFragment()
val bundle = Bundle()
bundle.putString(ARG_KEYWORD, keyword)
forumFragment.arguments = bundle
return forumFragment
@JvmOverloads
fun newInstance(keyword: String? = null): SearchUserFragment = SearchUserFragment().apply {
arguments = Bundle().apply {
putString(ARG_KEYWORD, keyword)
}
}
}
}

View File

@ -1,4 +1,8 @@
package com.huanchengfly.tieba.post.interfaces
interface ISearchFragment {
fun setKeyword(
keyword: String?,
needRefresh: Boolean = true
)
}

View File

@ -34,10 +34,9 @@ object AnimUtil {
@JvmStatic
fun bindTextSizeAnim(appBar: AppBarLayout, textView: TextView, startSize: Int, endSize: Int, endOffset: Int = 0) {
appBar.addOnOffsetChangedListener(OnOffsetChangedListener { appBarLayout: AppBarLayout, verticalOffset: Int ->
appBar.addOnOffsetChangedListener(OnOffsetChangedListener { _, verticalOffset ->
val offset = abs(verticalOffset * 1f)
if (offset <= endOffset) {
val totalScrollRange = appBarLayout.totalScrollRange
val percent = offset / endOffset
val changeSize = endSize - startSize
val size = startSize + percent * changeSize

View File

@ -10,8 +10,11 @@ import com.scwang.smart.refresh.header.MaterialHeader
class TintMaterialHeader
@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
: MaterialHeader(context, attrs), Tintable {
init {
tint()
}
override fun tint() {
setColorSchemeColors(ThemeUtils.getColorById(context, R.color.default_color_primary))
}
}

View File

@ -7,7 +7,7 @@ import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.ui.theme.interfaces.Tintable
import com.huanchengfly.tieba.post.ui.theme.utils.ColorStateListUtils
class TintEditText @JvmOverloads constructor(
class TintTextInputEditText @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.editTextStyle
) : AppCompatEditText(context, attrs, defStyleAttr), Tintable {
private var textColorResId: Int
@ -18,9 +18,9 @@ class TintEditText @JvmOverloads constructor(
textColorResId = 0
textColorHintResId = 0
} else {
val array = getContext().obtainStyledAttributes(attrs, R.styleable.TintEditText, defStyleAttr, 0)
textColorResId = array.getResourceId(R.styleable.TintEditText_textColor, 0)
textColorHintResId = array.getResourceId(R.styleable.TintEditText_android_textColorHint, 0)
val array = getContext().obtainStyledAttributes(attrs, R.styleable.TintTextInputEditText, defStyleAttr, 0)
textColorResId = array.getResourceId(R.styleable.TintTextInputEditText_textColor, 0)
textColorHintResId = array.getResourceId(R.styleable.TintTextInputEditText_android_textColorHint, 0)
array.recycle()
}
tint()

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?colorControlHighlight">
<item android:drawable="@drawable/bg_top_radius_8dp" />
<item android:drawable="@drawable/bg_bottom_radius_8dp" />
</ripple>

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners
android:radius="8dp"/>
<solid android:color="@color/white"/>
</shape>
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?colorControlHighlight">
<item android:drawable="@drawable/bg_radius_8dp" />
</ripple>

View File

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android">
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?colorControlHighlight">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/white" />
</shape>
</item>
</ripple>

View File

@ -1,7 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
<solid android:color="@color/white" />
</shape>
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?colorControlHighlight">
<item android:drawable="@drawable/bg_top_radius_8dp" />
</ripple>

View File

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<com.huanchengfly.tieba.post.widgets.theme.TintFrameLayout app:backgroundTint="@color/default_color_window_background"
<com.huanchengfly.tieba.post.widgets.theme.TintFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:backgroundTint="@color/default_color_window_background"
tools:context=".activities.ForumActivity">
<com.huanchengfly.tieba.post.widgets.theme.TintCoordinatorLayout
@ -13,11 +14,11 @@
android:layout_height="match_parent">
<com.huanchengfly.tieba.post.widgets.theme.TintAppBarLayout
app:backgroundTint="@color/default_color_toolbar"
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stateListAnimator="@animator/appbar_elevation">
android:stateListAnimator="@animator/appbar_elevation"
app:backgroundTint="@color/default_color_toolbar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"

View File

@ -1,6 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<com.huanchengfly.tieba.post.widgets.theme.TintCoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
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"
app:backgroundTint="@color/default_color_window_background">
<com.huanchengfly.tieba.post.widgets.theme.TintAppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stateListAnimator="@animator/appbar_elevation"
app:backgroundTint="@color/default_color_toolbar">
<com.huanchengfly.tieba.post.widgets.theme.TintTextInputLayout
android:id="@+id/search_bar"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:boxBackgroundColor="@color/color_toolbar_bar_background"
app:boxCollapsedPaddingTop="0dp"
app:boxCornerRadiusBottomEnd="8dp"
app:boxCornerRadiusBottomStart="8dp"
app:boxCornerRadiusTopEnd="8dp"
app:boxCornerRadiusTopStart="8dp"
app:boxStrokeWidth="0dp"
app:boxStrokeWidthFocused="0dp"
app:hintEnabled="false"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:hintTextColor="@color/default_color_primary"
app:placeholderTextColor="@color/default_color_primary"
app:startIconDrawable="@drawable/ic_round_arrow_back">
<com.huanchengfly.tieba.post.widgets.theme.TintTextInputEditText
android:imeOptions="actionSearch"
android:inputType="text"
android:id="@+id/search_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:hint="@string/hint_search"
android:textColorHint="@color/default_color_text_secondary" />
</com.huanchengfly.tieba.post.widgets.theme.TintTextInputLayout>
</com.huanchengfly.tieba.post.widgets.theme.TintAppBarLayout>
<com.huanchengfly.tieba.post.widgets.theme.TintFrameLayout
android:layout_gravity="bottom"
android:id="@+id/bottom_app_bar"
app:backgroundTint="@color/default_color_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.huanchengfly.tieba.post.widgets.theme.TintFrameLayout
android:id="@+id/tab_layout_holder"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="@drawable/bg_radius_8dp"
app:backgroundTint="@color/color_toolbar_bar_background"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.huanchengfly.tieba.post.widgets.theme.TintTabLayout
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:background="@color/transparent"
style="@style/Widget.TabLayout.Toolbar.Fixed"
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.huanchengfly.tieba.post.widgets.theme.TintFrameLayout>
</com.huanchengfly.tieba.post.widgets.theme.TintFrameLayout>
<androidx.recyclerview.widget.RecyclerView
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp"
android:clipToPadding="false"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.huanchengfly.tieba.post.widgets.MyViewPager
android:id="@+id/view_pager"
android:layout_marginBottom="72dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.huanchengfly.tieba.post.widgets.theme.TintCoordinatorLayout>

View File

@ -1,6 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
<com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_radius_8dp"
app:backgroundTint="@color/default_color_card"
app:layout_srlSpinnerStyle="Translate"
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:layout_centerHorizontal="true"
android:textSize="14sp"
android:id="@+id/footer_tip"
android:text="@string/tip_load_end"
android:gravity="center"
android:singleLine="true"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:tint="@color/default_color_text_secondary" />
</com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout>

View File

@ -39,12 +39,11 @@
app:layoutDescription="@xml/fragment_main_forum_list_scene">
<com.huanchengfly.tieba.post.widgets.theme.TintTextInputLayout
android:id="@+id/tintTextInputLayout"
android:id="@+id/search_bar"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:hint="@string/hint_search"
android:layout_height="wrap_content"
android:layout_width="0dp"
app:boxBackgroundColor="@color/default_color_divider"
app:boxBackgroundColor="@color/color_toolbar_bar_background"
app:boxCollapsedPaddingTop="0dp"
app:boxCornerRadiusBottomEnd="8dp"
app:boxCornerRadiusBottomStart="8dp"
@ -52,17 +51,18 @@
app:boxCornerRadiusTopStart="8dp"
app:boxStrokeWidth="0dp"
app:boxStrokeWidthFocused="0dp"
app:hintAnimationEnabled="false"
app:hintEnabled="true"
app:hintEnabled="false"
app:hintTextColor="@color/default_color_primary"
app:placeholderTextColor="@color/default_color_primary"
app:startIconDrawable="@drawable/ic_search">
<com.google.android.material.textfield.TextInputEditText
<com.huanchengfly.tieba.post.widgets.theme.TintTextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:enabled="false" />
android:cursorVisible="false"
android:textColorHint="@color/default_color_text_secondary"
android:hint="@string/hint_search" />
</com.huanchengfly.tieba.post.widgets.theme.TintTextInputLayout>
<com.huanchengfly.tieba.post.widgets.theme.TintImageView
@ -100,27 +100,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_radius_8dp"
app:backgroundTint="@color/default_color_card"
app:layout_srlSpinnerStyle="Translate"
<include
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:layout_centerHorizontal="true"
android:textSize="14sp"
android:id="@+id/footer_tip"
android:text="@string/tip_load_end"
android:gravity="center"
android:singleLine="true"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:tint="@color/default_color_text_secondary" />
</com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout>
layout="@layout/footer_no_more" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -40,12 +40,12 @@
</com.huanchengfly.tieba.post.widgets.theme.TintToolbar>
<FrameLayout
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="@drawable/bg_radius_8dp"
android:backgroundTint="@color/color_tab_layout_background"
android:backgroundTint="@color/color_toolbar_bar_background"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -66,5 +66,5 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:id="@+id/fragment_message_vp"
android:layout_width="match_parent"
android:layout_height="match_parent"></com.huanchengfly.tieba.post.widgets.MyViewPager>
android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -16,6 +16,7 @@
<androidx.recyclerview.widget.RecyclerView
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp"
android:layout_marginTop="8dp"
android:clipToPadding="false"
android:id="@+id/fragment_message_recycler_view"

View File

@ -1,13 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<com.huanchengfly.tieba.post.widgets.theme.TintSwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<com.scwang.smart.refresh.layout.SmartRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragment_search_refresh_layout"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:srlDragRate="0.8"
app:srlEnableOverScrollBounce="true"
app:srlEnableOverScrollDrag="true"
android:id="@+id/fragment_search_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
tools:context=".fragments.SearchForumFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/fragment_search_recycler_view"
<com.huanchengfly.tieba.post.widgets.theme.TintMaterialHeader
android:id="@+id/refresh_header"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.huanchengfly.tieba.post.widgets.theme.TintSwipeRefreshLayout>
<androidx.recyclerview.widget.RecyclerView
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp"
android:clipToPadding="false"
android:id="@+id/fragment_search_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.huanchengfly.tieba.post.components.LoadMoreFooter
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout
android:id="@+id/header_root_view"
@ -21,8 +22,16 @@
android:id="@+id/title"
android:textStyle="bold"
android:layout_marginStart="8dp"
android:layout_toStartOf="@id/end_icon"
android:layout_toEndOf="@id/icon"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true" />
<com.huanchengfly.tieba.post.widgets.theme.TintImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:id="@+id/end_icon"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
</FrameLayout>

View File

@ -1,32 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:backgroundTint="@color/default_color_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:padding="16dp">
<RelativeLayout
android:background="?attr/selectableItemBackground"
android:id="@+id/item_search_forum"
<ImageView
android:id="@+id/item_search_forum_avatar"
android:layout_marginEnd="8dp"
android:layout_width="32dp"
android:layout_height="32dp" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:layout_alignTop="@id/item_search_forum_title"
android:layout_toEndOf="@id/item_search_forum_avatar"
android:id="@+id/item_search_forum_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<ImageView
android:id="@+id/item_search_forum_avatar"
android:layout_marginEnd="8dp"
android:layout_width="32dp"
android:layout_height="32dp" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:layout_alignTop="@id/item_search_forum_title"
android:layout_toEndOf="@id/item_search_forum_avatar"
android:id="@+id/item_search_forum_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tint="@color/default_color_text"
android:textSize="16sp"
android:layout_centerVertical="true"
tools:text="Title" />
</RelativeLayout>
</FrameLayout>
app:tint="@color/default_color_text"
android:textSize="16sp"
android:layout_centerVertical="true"
tools:text="Title" />
</com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout>

View File

@ -1,44 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:backgroundTint="@color/default_color_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:padding="16dp">
<RelativeLayout
android:background="?attr/selectableItemBackground"
android:id="@+id/item_search_forum"
<ImageView
android:id="@+id/item_search_forum_avatar"
android:layout_marginEnd="8dp"
android:layout_width="48dp"
android:layout_height="48dp" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:textStyle="bold"
android:layout_alignTop="@id/item_search_forum_title"
android:layout_toEndOf="@id/item_search_forum_avatar"
android:id="@+id/item_search_forum_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
app:tint="@color/default_color_text"
android:textSize="18sp"
tools:text="Title" />
<ImageView
android:id="@+id/item_search_forum_avatar"
android:layout_marginEnd="8dp"
android:layout_width="48dp"
android:layout_height="48dp" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:textStyle="bold"
android:layout_alignTop="@id/item_search_forum_title"
android:layout_toEndOf="@id/item_search_forum_avatar"
android:id="@+id/item_search_forum_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tint="@color/default_color_text"
android:textSize="18sp"
tools:text="Title" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:layout_alignBottom="@id/item_search_forum_avatar"
android:layout_toEndOf="@id/item_search_forum_avatar"
android:gravity="bottom"
android:id="@+id/item_search_forum_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/item_search_forum_title"
app:tint="@color/default_color_text_secondary"
android:textSize="13sp"
tools:text="Sub Title" />
</RelativeLayout>
</FrameLayout>
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:layout_alignBottom="@id/item_search_forum_avatar"
android:layout_toEndOf="@id/item_search_forum_avatar"
android:gravity="bottom"
android:id="@+id/item_search_forum_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/item_search_forum_title"
app:tint="@color/default_color_text_secondary"
android:textSize="13sp"
tools:text="Sub Title" />
</com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/classify_item"
app:backgroundTint="@color/default_color_floor_card"
android:background="@drawable/bg_radius_4dp"
android:padding="6dp"
@ -13,7 +12,7 @@
android:maxLines="1"
android:textStyle="bold"
app:tint="@color/default_color_text_secondary"
android:id="@+id/classify_text"
android:id="@+id/text"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

View File

@ -1,58 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:padding="16dp"
android:id="@+id/item_search_thread"
app:backgroundTint="@color/default_color_card">
<RelativeLayout
android:background="?attr/selectableItemBackground"
android:id="@+id/item_search_thread"
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:id="@+id/item_search_thread_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
app:tint="@color/default_color_text"
android:textSize="16sp"
android:layout_marginBottom="4dp"
android:textStyle="bold"
tools:text="Title" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:id="@+id/item_search_thread_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tint="@color/default_color_text"
android:textSize="16sp"
android:layout_marginBottom="4dp"
android:textStyle="bold"
tools:text="Title" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:id="@+id/item_search_thread_content"
android:layout_below="@id/item_search_thread_title"
tools:text="Content"
android:textSize="14sp"
app:tint="@color/default_color_text"
android:layout_width="match_parent"
android:layout_marginBottom="4dp"
android:layout_height="wrap_content" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:id="@+id/item_search_thread_content"
android:layout_below="@id/item_search_thread_title"
tools:text="Content"
android:textSize="14sp"
app:tint="@color/default_color_text"
android:layout_width="match_parent"
android:layout_marginBottom="4dp"
android:layout_height="wrap_content" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:id="@+id/item_search_thread_user"
android:layout_below="@id/item_search_thread_content"
tools:text="幻了个城fly"
android:textSize="12sp"
app:tint="@color/default_color_text_secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:id="@+id/item_search_thread_user"
android:layout_below="@id/item_search_thread_content"
tools:text="幻了个城fly"
android:textSize="12sp"
app:tint="@color/default_color_text_secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:layout_alignWithParentIfMissing="true"
android:layout_toEndOf="@id/item_search_thread_user"
android:layout_alignParentEnd="true"
android:gravity="end"
android:id="@+id/item_search_thread_info"
android:layout_below="@id/item_search_thread_content"
tools:text="minecraft吧 刚刚"
android:textSize="12sp"
app:tint="@color/default_color_text_secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
</FrameLayout>
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:layout_alignWithParentIfMissing="true"
android:layout_toEndOf="@id/item_search_thread_user"
android:layout_alignParentEnd="true"
android:gravity="end"
android:id="@+id/item_search_thread_info"
android:layout_below="@id/item_search_thread_content"
tools:text="minecraft吧 刚刚"
android:textSize="12sp"
app:tint="@color/default_color_text_secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.huanchengfly.tieba.post.widgets.theme.TintRelativeLayout>

View File

@ -1,5 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.huanchengfly.tieba.post.widgets.theme.TintTextView
android:layout_centerInParent="true"
android:textSize="14sp"
android:id="@+id/footer_tip"
android:text="@string/text_no_data"
android:gravity="center"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tint="@color/default_color_text_secondary" />
</RelativeLayout>

View File

@ -1,4 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<group
android:id="@+id/order"
android:checkableBehavior="single">
<item android:title="@string/title_search_order_new" />
<item android:title="@string/title_search_order_old" />
<item android:title="@string/title_search_order_relevant" />
</group>
<group android:checkableBehavior="all">
<item android:title="@string/title_filter_only_show_thread" />
</group>
</menu>

View File

@ -147,6 +147,11 @@
<attr name="android:textColorHint" />
</declare-styleable>
<declare-styleable name="TintTextInputEditText">
<attr name="textColor" />
<attr name="android:textColorHint" />
</declare-styleable>
<declare-styleable name="ScrollCollapsingToolbarLayout">
<!-- Specifies extra space on the start, top, end and bottom
sides of the the expanded title text. Margin values should be positive. -->

View File

@ -23,6 +23,8 @@
<color name="black">#000</color>
<color name="tieba">#4477E0</color>
<color name="color_toolbar_bar_background">#EDF2F6</color>
<color name="color_text">#FF31343C</color>
<color name="color_text_secondary">#FF545967</color>
<color name="color_text_disabled">#6131343C</color>
@ -166,5 +168,4 @@
<color name="icon_blue">#FF3373EE</color>
<color name="icon_purple">#FF8E6DCA</color>
<color name="black_trans">#50000000</color>
<color name="color_tab_layout_background">#EDF2F6</color>
</resources>

View File

@ -2,4 +2,5 @@
<resources>
<item name="video_player" type="id" />
<item name="image_load_tag" type="id" />
<item name="no_data" type="id" />
</resources>

View File

@ -6,7 +6,7 @@
<string name="title_explore">动态</string>
<string name="title_user"></string>
<string name="title_search">搜索</string>
<string name="hint_search">进吧、搜贴</string>
<string name="hint_search">发现更多</string>
<string name="hint_search_in_ba">在 %1$s 吧内搜索</string>
<string name="my_info_history">浏览历史</string>
<string name="sidebar_exit">退出</string>
@ -367,4 +367,15 @@
<string name="text_pull_up_to_load">上拉加载更多</string>
<string name="text_release_to_load">释放开始加载</string>
<string name="template_two_string">%1$s·%2$s</string>
<string name="title_search_forum">搜吧</string>
<string name="title_search_thread">搜贴</string>
<string name="title_search_user">搜人</string>
<string name="title_search_history">搜索历史</string>
<string name="text_no_data">这里什么都没有</string>
<string name="title_exact_match">推荐结果</string>
<string name="title_fuzzy_match">查询结果</string>
<string name="title_filter_only_show_thread">仅看主题贴</string>
<string name="title_search_order_new">新贴在前</string>
<string name="title_search_order_old">旧贴在前</string>
<string name="title_search_order_relevant">相关度</string>
</resources>

View File

@ -13,10 +13,11 @@
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Constraint
android:id="@+id/tintTextInputLayout"
android:id="@+id/search_bar"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:layout_marginBottom="12dp"
android:layout_marginTop="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
@ -37,10 +38,11 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Constraint
android:id="@+id/tintTextInputLayout"
android:id="@+id/search_bar"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:layout_marginBottom="12dp"
android:layout_marginTop="12dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"