粗略完成社区的推荐Tab和论坛Tab

This commit is contained in:
lyr
2021-05-26 19:00:06 +08:00
parent 2eded37321
commit 71a61fdef0
68 changed files with 2427 additions and 459 deletions

View File

@ -20,4 +20,7 @@ object SyncFieldConstants {
// 回答数量
const val ANSWER_COUNT = "ANSWER_COUNT"
// 是否关注
const val IS_FOLLOWER = "IS_FOLLOWER"
}

View File

@ -72,7 +72,7 @@ class ImageContainerView : LinearLayout {
mPath = path
index = 0
removeAllViews()
if (entity.getPassVideos().isNullOrEmpty() && entity.images.isNullOrEmpty()) {
if (entity.getPassVideos().isNotEmpty() || entity.images.isNullOrEmpty()) {
visibility = View.GONE
return
}

View File

@ -10,7 +10,7 @@ class TaskFragment: ListFragment<TaskItemData, TaskViewModel>() {
private var mAdapter: TaskAdapter? = null
override fun provideListAdapter()= mAdapter
override fun provideListAdapter() = mAdapter
?: TaskAdapter(requireContext()).apply { mAdapter = this }
override fun provideListViewModel(): TaskViewModel = viewModelProvider()

View File

@ -15,4 +15,13 @@ data class ForumDetailEntity(
@SerializedName("zone_tab")
var zone: ZoneEntity? = null,
var me: MeEntity = MeEntity()
)
) {
fun convertForumDetailEntityToForumEntity(): ForumEntity {
val forumEntity = ForumEntity()
forumEntity.id = id
forumEntity.name = name
forumEntity.game = game
forumEntity.orderTag = System.currentTimeMillis()
return forumEntity
}
}

View File

@ -1,8 +1,12 @@
package com.gh.gamecenter.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
@Entity
data class ForumEntity(
@PrimaryKey
@SerializedName("_id")
var id: String = "",
var game: SimpleGame = SimpleGame(),
@ -10,7 +14,8 @@ data class ForumEntity(
@SerializedName("is_follow")
var isFollow: Boolean = false,
//本地字段,判断是否是推荐论坛
var isRecommend: Boolean = false
var isRecommend: Boolean = false,
var orderTag: Long = 0
)
data class ForumCategoryEntity(

View File

@ -65,6 +65,7 @@ class MeEntity(@SerializedName("is_community_voted")
@SerializedName("is_version_requested")
var isVersionRequested: Boolean = false,
@SyncPage(syncNames = [SyncFieldConstants.IS_FOLLOWER])
@SerializedName("is_follower", alternate = ["is_follow"])
var isFollower: Boolean = false, // 是否已经关注该用户

View File

@ -0,0 +1,20 @@
package com.gh.gamecenter.eventbus;
import com.gh.gamecenter.entity.ForumEntity;
public class EBForumRecordChange {
ForumEntity forumEntity;
public EBForumRecordChange(ForumEntity forumEntity) {
this.forumEntity = forumEntity;
}
public ForumEntity getForumEntity() {
return forumEntity;
}
public void setForumEntity(ForumEntity forumEntity) {
this.forumEntity = forumEntity;
}
}

View File

@ -7,19 +7,23 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.entity.ForumDetailEntity
import com.gh.gamecenter.eventbus.EBForumRecordChange
import com.gh.gamecenter.mvvm.Resource
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.room.AppDatabase
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import retrofit2.HttpException
class ForumDetailViewModel(application: Application, val bbsId: String) : AndroidViewModel(application) {
private val mApi = RetrofitManager.getInstance(application).api
private val mForumDao = AppDatabase.getInstance(HaloApp.getInstance()).forumDao()
var forumDetail = MutableLiveData<Resource<ForumDetailEntity>>()
init {
@ -34,6 +38,10 @@ class ForumDetailViewModel(application: Application, val bbsId: String) : Androi
override fun onResponse(response: ForumDetailEntity?) {
super.onResponse(response)
forumDetail.postValue(Resource.success(response))
response?.run {
mForumDao.addForum(convertForumDetailEntityToForumEntity())
EventBus.getDefault().post(EBForumRecordChange(convertForumDetailEntityToForumEntity()))
}
}
override fun onFailure(e: HttpException?) {

View File

@ -1,20 +0,0 @@
package com.gh.gamecenter.forum.follow
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.gamecenter.NormalActivity
class ForumMyFollowActivity : NormalActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNavigationTitle("我的关注")
}
companion object {
fun getIntent(context: Context): Intent {
return getTargetIntent(context, ForumMyFollowActivity::class.java, ForumMyFollowFragment::class.java)
}
}
}

View File

@ -1,89 +0,0 @@
package com.gh.gamecenter.forum.follow
import android.content.Context
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.*
import com.gh.common.view.BugFixedPopupWindow
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.ForumMyFollowBinding
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.eventbus.EBForumFollowChange
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.qa.entity.CommunitySelectEntity
import com.lightgame.adapter.BaseRecyclerAdapter
import org.greenrobot.eventbus.EventBus
class ForumMyFollowAdapter(context: Context, val mViewModel: ForumMyFollowViewModel) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
val entityList = ArrayList<ForumEntity>()
fun setListData(updateData: List<ForumEntity>) {
entityList.clear()
entityList.addAll(updateData)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return ForumMyFollowViewHolder(ForumMyFollowBinding.bind(mLayoutInflater.inflate(R.layout.forum_my_follow, parent, false)))
}
override fun getItemCount(): Int = entityList.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val forumEntity = entityList[position]
val followViewHolder = holder as ForumMyFollowViewHolder
followViewHolder.binding.entity = forumEntity
followViewHolder.binding.forumIcon.displayGameIcon(forumEntity.game.getIcon(), forumEntity.game.iconSubscript)
followViewHolder.binding.moreActionIv.setOnClickListener {
MtaHelper.onEvent("论坛首页", "我关注的论坛", "更多")
showMoreWindow(it, forumEntity)
}
followViewHolder.itemView.setOnClickListener {
MtaHelper.onEvent("论坛首页", "我关注的论坛", forumEntity.name)
mContext.startActivity(ForumDetailActivity.getIntent(mContext, forumEntity.id, "我的关注"))
}
}
private fun showMoreWindow(view: View, entity: ForumEntity) {
val inflater = LayoutInflater.from(mContext)
val layout = inflater.inflate(R.layout.layout_popup_container, null)
val popupWindow = BugFixedPopupWindow(layout,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT)
val container = layout.findViewById<LinearLayout>(R.id.container)
val dialogOptions = arrayListOf("取消关注")
for (text in dialogOptions) {
val item = inflater.inflate(R.layout.layout_popup_option_item, container, false)
container.addView(item)
val hitText = item.findViewById<TextView>(R.id.hint_text)
hitText.text = text
item.setOnClickListener {
popupWindow.dismiss()
when (text) {
"取消关注" -> {
DialogUtils.showNewAlertDialog(mContext, "提示", "确定取消关注", "暂不", "确定", null, Gravity.CENTER, false, {}, {
MtaHelper.onEvent("论坛首页", "我关注的论坛", "取消关注")
mViewModel.unFollowForum(entity.id) {
EventBus.getDefault().post(EBForumFollowChange(entity, false))
}
})
}
}
}
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.showAutoOrientation(view)
}
class ForumMyFollowViewHolder(val binding: ForumMyFollowBinding) : BaseRecyclerViewHolder<CommunitySelectEntity>(binding.root)
}

View File

@ -1,79 +0,0 @@
package com.gh.gamecenter.forum.follow
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.gh.common.AppExecutor
import com.gh.common.util.viewModelProvider
import com.gh.gamecenter.R
import com.gh.gamecenter.eventbus.EBForumFollowChange
import com.gh.gamecenter.normal.NormalFragment
import kotterknife.bindView
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class ForumMyFollowFragment : NormalFragment() {
val mRefresh by bindView<SwipeRefreshLayout>(R.id.list_refresh)
val mListRv by bindView<RecyclerView>(R.id.list_rv)
val mReuseLoading by bindView<LinearLayout>(R.id.reuse_ll_loading)
val mNoConnection by bindView<LinearLayout>(R.id.reuse_no_connection)
val mNoneData by bindView<LinearLayout>(R.id.reuse_none_data)
private var mAdapter: ForumMyFollowAdapter? = null
private var mViewModel: ForumMyFollowViewModel? = null
override fun getLayoutId(): Int = R.layout.fragment_list_base
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewModel = viewModelProvider()
mListRv.apply {
layoutManager = LinearLayoutManager(requireContext())
mAdapter = ForumMyFollowAdapter(requireContext(), mViewModel!!)
adapter = mAdapter
}
mViewModel?.forumData?.observe(viewLifecycleOwner, Observer {
mRefresh.isRefreshing = false
mReuseLoading.visibility = View.GONE
if (it != null) {
mNoConnection.visibility = View.GONE
if (it.isNotEmpty()) {
mNoneData.visibility = View.GONE
mAdapter?.setListData(it)
} else {
mNoneData.visibility = View.VISIBLE
}
} else {
mNoneData.visibility = View.GONE
mNoConnection.visibility = View.VISIBLE
}
})
mNoConnection.setOnClickListener {
mViewModel?.loadFollowsForum()
}
mRefresh.setOnRefreshListener {
mViewModel?.loadFollowsForum()
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onFollowForumChange(forumFollowChange: EBForumFollowChange) {
val entityList = mAdapter?.entityList ?: arrayListOf()
val index = entityList.indexOfFirst { it.id == forumFollowChange.forumEntity.id }
val findEntity = entityList.find { it.id == forumFollowChange.forumEntity.id }
if (!forumFollowChange.isFollow) {
entityList.remove(findEntity)
mAdapter?.notifyItemRangeRemoved(index, 1)
}
if (mAdapter?.entityList?.isEmpty() == true) {
mListRv.visibility = View.GONE
mNoneData.visibility = View.VISIBLE
}
}
}

View File

@ -1,57 +0,0 @@
package com.gh.gamecenter.forum.follow
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MediatorLiveData
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.entity.CommunitySelectEntity
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import retrofit2.HttpException
class ForumMyFollowViewModel(application: Application) : AndroidViewModel(application) {
val forumData = MediatorLiveData<List<ForumEntity>>()
init {
loadFollowsForum()
}
fun loadFollowsForum(){
RetrofitManager.getInstance(getApplication()).api
.getFollowsForum(UserManager.getInstance().userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<List<ForumEntity>>() {
override fun onResponse(response: List<ForumEntity>?) {
super.onResponse(response)
forumData.postValue(response)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
forumData.postValue(null)
}
})
}
@SuppressLint("CheckResult")
fun unFollowForum(bbsId: String, onSuccess: () -> Unit) {
RetrofitManager.getInstance(getApplication()).api
.unFollowForum(bbsId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
onSuccess.invoke()
}
})
}
}

View File

@ -0,0 +1,229 @@
package com.gh.gamecenter.forum.home
import android.app.Activity
import android.app.Application
import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.util.AttributeSet
import android.util.Log
import android.view.Surface
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.observer.MuteCallback
import com.gh.common.observer.VolumeObserver
import com.gh.common.util.ImageUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.qa.entity.CommunityVideoEntity
import com.gh.gamecenter.video.detail.CustomManager
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import kotlinx.android.synthetic.main.piece_video_control.view.*
import java.util.*
class ArticleItemVideoView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : StandardGSYVideoPlayer(context, attrs) {
private var mMuteCallback: MuteCallback
private var mVolumeObserver: VolumeObserver
private var mVideoEntity: CommunityVideoEntity? = null
var uuid = UUID.randomUUID().toString()
var thumbImage: SimpleDraweeView = findViewById(R.id.thumbImage)
var durationTv: TextView = findViewById(R.id.durationTv)
var completeContainer: LinearLayout = findViewById(R.id.completeContainer)
var replayIv: ImageView = findViewById(R.id.replayIv)
var replayTv: TextView = findViewById(R.id.replayTv)
var volume: ImageView = findViewById(R.id.volume)
override fun getLayoutId(): Int {
return R.layout.layout_article_item_video
}
init {
post {
volume.setOnClickListener { toggleMute() }
}
mMuteCallback = object : MuteCallback {
override fun onMute(isMute: Boolean) {
if (isMute) {
mute()
} else {
unMute()
}
}
}
mVolumeObserver = VolumeObserver(context, Handler(), mMuteCallback)
}
override fun updateStartImage() {
if (mStartButton is ImageView) {
val imageView = mStartButton as ImageView
when (mCurrentState) {
GSYVideoView.CURRENT_STATE_PLAYING -> imageView.setImageResource(R.drawable.icon_preview_video_pause)
GSYVideoView.CURRENT_STATE_ERROR -> imageView.setImageResource(R.drawable.icon_preview_video_play)
else -> imageView.setImageResource(R.drawable.icon_preview_video_play)
}
}
}
override fun onClickUiToggle() {
if (mCurrentState == CURRENT_STATE_PLAYING) {
if (mStartButton.visibility == View.VISIBLE) {
changeUiToPlayingClear()
} else {
changeUiToPlayingShow()
}
} else {
super.onClickUiToggle()
}
}
/******************* 下方两个重载方法,在播放开始前不屏蔽封面,不需要可屏蔽 ********************/
override fun onSurfaceUpdated(surface: Surface) {
super.onSurfaceUpdated(surface)
if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) {
mThumbImageViewLayout.visibility = View.INVISIBLE
}
}
fun updateThumb(url: String) {
ImageUtils.display(thumbImage, url)
}
fun updateDurationTv(duration: String) {
durationTv.text = duration
}
fun updateVideoData(video: CommunityVideoEntity) {
mVideoEntity = video
}
override fun setViewShowState(view: View?, visibility: Int) {
if (view === mThumbImageViewLayout && visibility != View.VISIBLE) {
return
}
super.setViewShowState(view, visibility)
}
/********************************各类UI的状态显示*********************************************/
override fun touchSurfaceMoveFullLogic(absDeltaX: Float, absDeltaY: Float) {
super.touchSurfaceMoveFullLogic(absDeltaX, absDeltaY)
//不给触摸快进,如果需要,屏蔽下方代码即可
mChangePosition = false
//不给触摸音量,如果需要,屏蔽下方代码即可
mChangeVolume = false
//不给触摸亮度,如果需要,屏蔽下方代码即可
mBrightness = false
}
override fun touchDoubleUp() {
}
override fun setStateAndUi(state: Int) {
super.setStateAndUi(state)
if (currentState == GSYVideoView.CURRENT_STATE_PREPAREING) {
setViewShowState(durationTv, View.GONE)
replayIv.setOnClickListener {
startButton.performClick()
// violenceUpdateMuteStatus()
// uploadVideoStreamingPlaying("重新播放")
}
replayTv.setOnClickListener { replayIv.performClick() }
}
// if (currentState == GSYVideoView.CURRENT_STATE_PLAYING) {
// setViewShowState(mBottomProgressBar, View.VISIBLE)
// }
if (currentState == GSYVideoView.CURRENT_STATE_AUTO_COMPLETE) {
hideAllWidget()
setViewShowState(completeContainer, View.VISIBLE)
} else {
setViewShowState(completeContainer, View.GONE)
}
}
override fun changeUiToPlayingClear() {
super.changeUiToPlayingClear()
// setViewShowState(mBottomProgressBar, View.GONE)
}
override fun changeUiToPlayingShow() {
super.changeUiToPlayingShow()
setViewShowState(mBottomProgressBar, View.VISIBLE)
}
private fun toggleMute() {
if (mVideoEntity?.videoIsMuted == true) {
unMute()
} else {
mute()
}
}
fun updateMuteStatus() {
if (mVideoEntity?.videoIsMuted == true) {
mute()
} else {
unMute()
}
}
private fun mute() {
mVideoEntity?.videoIsMuted = true
volume.setImageResource(R.drawable.ic_article_video_volume_off)
CustomManager.getCustomManager(getKey()).isNeedMute = true
}
private fun unMute() {
mVideoEntity?.videoIsMuted = false
volume.setImageResource(R.drawable.ic_article_video_volume_on)
CustomManager.getCustomManager(getKey()).isNeedMute = false
}
fun observeVolume(activity: AppCompatActivity) {
activity.contentResolver?.registerContentObserver(
android.provider.Settings.System.CONTENT_URI, true, mVolumeObserver)
activity.application?.registerActivityLifecycleCallbacks(
object : Application.ActivityLifecycleCallbacks {
override fun onActivityPaused(a: Activity) {
if (activity == a) {
activity.contentResolver?.unregisterContentObserver(mVolumeObserver)
activity.application?.unregisterActivityLifecycleCallbacks(this)
}
}
override fun onActivityStarted(activity: Activity) {
}
override fun onActivityDestroyed(activity: Activity) {
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}
override fun onActivityStopped(activity: Activity) {
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
}
override fun onActivityResumed(activity: Activity) {
}
})
}
fun getKey(): String {
return uuid
}
}

View File

@ -2,13 +2,11 @@ package com.gh.gamecenter.forum.home
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.text.set
import com.gh.base.BaseActivity
import com.gh.common.util.*
import com.gh.common.view.CenterImageSpan
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
import com.gh.gamecenter.entity.CommunityEntity
@ -22,6 +20,7 @@ import com.gh.gamecenter.qa.entity.ArticleEntity
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity
import com.gh.gamecenter.qa.questions.invite.QuestionsInviteActivity
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : BaseAnswerOrArticleItemViewHolder(binding.root) {
@ -60,6 +59,8 @@ class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : B
}
binding.imageContainer.bindData(entity, entrance, path)
bindVideoData(entity)
val user = entity.user
binding.userBadgeName.setOnClickListener { binding.userBadgeIcon.performClick() }
binding.userBadgeIcon.setOnClickListener {
@ -78,16 +79,68 @@ class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : B
MtaHelper.onEvent(getEventId(BaseActivity.mergeEntranceAndPath(entrance, path)), getKey(BaseActivity.mergeEntranceAndPath(entrance, path)), "用户名字")
DirectUtils.directToHomeActivity(binding.root.context, entity.user.id, 1, entrance, path)
}
binding.concernBtn.setOnClickListener {
debounceActionWithInterval(R.id.concernBtn, 1000) {
CheckLoginUtils.checkLogin(itemView.context, entrance) {
followUser(entity, object : EmptyCallback {
override fun onCallback() {
entity.me.isFollower = true
binding.concernBtn.visibility = View.GONE
binding.followedUserTv.visibility = View.VISIBLE
}
})
}
}
}
binding.executePendingBindings()
}
fun bindVideoData(entity: AnswerEntity) {
binding.run {
if (entity.getPassVideos().isNullOrEmpty()) {
horizontalVideoView.visibility = View.GONE
verticalVideoView.visibility = View.GONE
} else {
val video = entity.getPassVideos()[0]
val visibleView = if (video.height > video.width) {
horizontalVideoView.visibility = View.GONE
verticalVideoView.visibility = View.VISIBLE
verticalVideoView
} else {
horizontalVideoView.visibility = View.VISIBLE
verticalVideoView.visibility = View.GONE
horizontalVideoView
}
GSYVideoOptionBuilder()
.setIsTouchWiget(false)
.setUrl(video.url)
.setRotateViewAuto(false)
.setCacheWithPlay(true)
.setRotateWithSystem(false)
.setReleaseWhenLossAudio(true)
.setLooping(false)
.setShowFullAnimation(false)
.setEnlargeImageRes(R.drawable.ic_article_video_full_screen)
.build(visibleView)
visibleView.run {
updateVideoData(video)
updateThumb(video.poster)
updateDurationTv(video.duration)
updateMuteStatus()
observeVolume(itemView.context as AppCompatActivity)
}
}
}
}
override fun bindCommendAndVote(entity: AnswerEntity, entrance: String) {
if (entity.type == "community_article") {
binNormalView(entity)
} else {
if (entity.questions.answerCount > 0) {
commentCount.text = entity.questions.answerCount.toString()
commentCount.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(itemView.context, R.drawable.community_question_answer_count), null, null, null)
commentCount.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(itemView.context, R.drawable.community_comment_count), null, null, null)
} else {
commentCount.text = "我来回答"
commentCount.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(itemView.context, R.drawable.community_question_answer_edit), null, null, null)

View File

@ -1,6 +1,7 @@
package com.gh.gamecenter.forum.home
import android.content.Context
import android.graphics.Color
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
@ -9,19 +10,17 @@ import com.gh.base.BaseActivity
import com.gh.common.constant.ItemViewType
import com.gh.common.syncpage.ISyncAdapterHandler
import com.gh.common.util.MtaHelper
import com.gh.common.util.dip2px
import com.gh.common.util.goneIf
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.qa.entity.ArticleEntity
import com.gh.gamecenter.qa.entity.Questions
class ForumArticleListAdapter(context: Context, val mEntrance: String, val path: String) : ListAdapter<ArticleEntity>(context), ISyncAdapterHandler {
override fun areItemsTheSame(oldItem: ArticleEntity?, newItem: ArticleEntity?): Boolean {
return oldItem?.id == newItem?.id
}
@ -38,6 +37,7 @@ class ForumArticleListAdapter(context: Context, val mEntrance: String, val path:
view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)
FooterViewHolder(view)
}
else -> {
view = mLayoutInflater.inflate(R.layout.community_answer_item, parent, false)
ForumArticleAskItemViewHolder(CommunityAnswerItemBinding.bind(view))
@ -55,12 +55,20 @@ class ForumArticleListAdapter(context: Context, val mEntrance: String, val path:
val viewHolder = holder as ForumArticleAskItemViewHolder
val articleEntity = mEntityList[position]
articleEntity.community = CommunityEntity(articleEntity.bbs.id, articleEntity.bbs.name)
viewHolder.binding.run {
topLine.goneIf(position == 0)
contentContainer.setBackgroundColor(Color.TRANSPARENT)
bottomContainer.setBackgroundColor(Color.TRANSPARENT)
includeVoteAndComment.commentCountContainer.setBackgroundColor(Color.TRANSPARENT)
includeVoteAndComment.voteCountContainer.setBackgroundColor(Color.TRANSPARENT)
}
viewHolder.bindForumArticleItem(articleEntity, mEntrance, path)
viewHolder.itemView.setOnClickListener {
MtaHelper.onEvent("论坛首页", viewHolder.getKey(BaseActivity.mergeEntranceAndPath(mEntrance, path)), "${articleEntity.title}${articleEntity.id}")
mContext.startActivity(ArticleDetailActivity.getIntent(mContext, articleEntity.community, articleEntity.id, "", path))
}
}
ItemViewType.ITEM_FOOTER -> {
val footerViewHolder = holder as FooterViewHolder
footerViewHolder.initItemPadding()

View File

@ -1,97 +1,87 @@
package com.gh.gamecenter.forum.home
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.widget.NestedScrollView
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.iinterface.IScrollable
import com.gh.common.util.*
import com.gh.common.view.DumbRefreshLayout
import com.gh.common.view.divider.HorizontalDividerItemDecoration
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.LazyListFragment
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.baselist.ListFragment
import com.gh.gamecenter.databinding.FragmentForumListBinding
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.eventbus.EBDeleteDetail
import com.gh.gamecenter.eventbus.EBForumRecordChange
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.CommunityFragment
import com.gh.gamecenter.qa.entity.ArticleEntity
import com.gh.gamecenter.user.UserViewModel
import kotterknife.bindView
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class ForumArticleListFragment : ListFragment<ArticleEntity, ForumArticleListViewModel>(), IScrollable {
private val mNoLoginView by bindView<LinearLayout>(R.id.reuse_no_login)
private val mNoFollowView by bindView<NestedScrollView>(R.id.reuse_no_follow)
private val mLoginTv by bindView<TextView>(R.id.loginTv)
class ForumArticleListFragment : LazyListFragment<ArticleEntity, ForumArticleListViewModel>(), IScrollable {
private var mViewModel: ForumArticleListViewModel? = null
private var mUserViewModel: UserViewModel? = null
private var mBinding: FragmentForumListBinding? = null
private lateinit var mAdapter: ForumArticleListAdapter
private var mPath = ""
override fun onCreate(savedInstanceState: Bundle?) {
override fun getRealLayoutId() = R.layout.fragment_forum_list
override fun onFragmentFirstVisible() {
mPath = arguments?.getString(EntranceUtils.KEY_PATH) ?: ""
super.onCreate(savedInstanceState)
val factory = UserViewModel.Factory(requireActivity().application)
mUserViewModel = ViewModelProviders.of(this, factory)[UserViewModel::class.java]
mUserViewModel?.loginObsUserinfo?.observe(this, Observer {
if (mPath != "关注") return@Observer
if (it?.data != null) {
mNoLoginView.visibility = View.GONE
onLoadRefresh()
} else {
mNoLoginView.visibility = View.VISIBLE
}
})
super.onFragmentFirstVisible()
mViewModel?.getRecordForums()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mListRv.overScrollMode = View.OVER_SCROLL_NEVER
mListRefresh?.isEnabled = false
if (mPath == "关注" && !UserManager.getInstance().isLoggedIn) {
mNoLoginView.visibility = View.VISIBLE
} else {
mNoLoginView.visibility = View.GONE
onLoadRefresh()
override fun initRealView() {
super.initRealView()
mViewModel?.recordForumsLiveData?.observeNonNull(viewLifecycleOwner) {
mBaseHandler.postDelayed({
initRecordForums(it)
}, 500)
}
mLoginTv.setOnClickListener {
CheckLoginUtils.checkLogin(requireContext(), mEntrance, null)
mBinding?.run {
nestedScrollRoot.setOnScrollChangeListener(
NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
val dy = scrollY - oldScrollY
if (dy > CommunityFragment.FOLLOW_HINT_TRIGGER_HEIGHT) {
EventBus.getDefault().post(EBTypeChange(CommunityFragment.EB_HIDE_QUESTION_BUTTON, 0))
} else if (dy < -CommunityFragment.FOLLOW_HINT_TRIGGER_HEIGHT) {
EventBus.getDefault().post(EBTypeChange(CommunityFragment.EB_SHOW_QUESTION_BUTTON, 0))
}
}
)
}
mListRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > CommunityFragment.FOLLOW_HINT_TRIGGER_HEIGHT) {
EventBus.getDefault().post(EBTypeChange(CommunityFragment.EB_HIDE_QUESTION_BUTTON, 0))
} else if (dy < -CommunityFragment.FOLLOW_HINT_TRIGGER_HEIGHT) {
EventBus.getDefault().post(EBTypeChange(CommunityFragment.EB_SHOW_QUESTION_BUTTON, 0))
}
}
})
}
override fun onRealLayoutInflated(inflatedView: View) {
super.onRealLayoutInflated(inflatedView)
mBinding = FragmentForumListBinding.bind(inflatedView)
}
override fun provideListViewModel(): ForumArticleListViewModel {
mViewModel = viewModelProvider(ForumArticleListViewModel.Factory(mPath))
mViewModel = viewModelProvider()
return mViewModel!!
}
override fun getLayoutId(): Int = R.layout.fragment_forum_list
override fun getItemDecoration(): RecyclerView.ItemDecoration {
return HorizontalDividerItemDecoration.Builder(requireContext())
.size(0.5f.dip2px())
.margin(20f.dip2px())
.color(ContextCompat.getColor(requireContext(), R.color.text_eeeeee)).build()
}
override fun getItemDecoration() = null
override fun provideListAdapter(): ListAdapter<*> {
if (!::mAdapter.isInitialized) {
@ -100,45 +90,30 @@ class ForumArticleListFragment : ListFragment<ArticleEntity, ForumArticleListVie
return mAdapter
}
override fun onRefresh() {
super.onRefresh()
mBinding?.recordForumsContainer?.visibility = View.GONE
mViewModel?.getRecordForums()
}
private fun initRecordForums(list: List<ForumEntity>) {
mBinding?.run {
recordForumsContainer.visibility = View.VISIBLE
recordForumsMore.setOnClickListener {
(parentFragment as? NewForumHomeFragment)?.run {
setCurrentItem(NewForumHomeFragment.TAB_FORUM_INDEX)
}
}
recordForumsRv.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
recordForumsRv.adapter = ForumRecordsAdapter(requireContext(), "社区-论坛-关注论坛", ArrayList(list))
}
}
fun onRefresh(filter: String) {
mViewModel?.sort = if (filter == "最新发布") "time.edit" else "time.comment"
onRefresh()
}
override fun onLoadEmpty() {
super.onLoadEmpty()
if (mPath == "关注") {
mReuseNoData?.visibility = View.GONE
mNoFollowView.visibility = View.VISIBLE
}
getDumbRefreshLayout()?.finishRefresh()
}
override fun onLoadDone() {
super.onLoadDone()
mNoFollowView.visibility = View.GONE
getDumbRefreshLayout()?.finishRefresh()
}
override fun onLoadError() {
super.onLoadError()
getDumbRefreshLayout()?.finishRefresh()
}
private fun getDumbRefreshLayout(): DumbRefreshLayout? {
val parentFragment = parentFragment
if (parentFragment is ForumHomeFragment) {
parentFragment.refreshHeader.setFinishText("刷新完成")
if (parentFragment.refreshLayout.isRefreshing) {
ToastUtils.showToast("内容已刷新")
}
return parentFragment.refreshLayout
}
return null
}
override fun isAutomaticLoad(): Boolean = false
override fun scrollToTop() {
mListRv.scrollToPosition(0)
}
@ -154,4 +129,25 @@ class ForumArticleListFragment : ListFragment<ArticleEntity, ForumArticleListVie
mAdapter.entityList?.remove(currentEntity)
mAdapter.notifyItemRemoved(indexOf)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onForumRecordChange(change: EBForumRecordChange) {
mBinding?.run {
if (recordForumsContainer.visibility == View.VISIBLE) {
val adapter = recordForumsRv.adapter as? ForumRecordsAdapter
adapter?.run {
if (list.safelyGetInRelease(0)?.id == change.forumEntity.id) return
val findEntity = list.find { it.id == change.forumEntity.id }
if (findEntity != null) {
list.remove(findEntity)
}
list.add(0, change.forumEntity)
notifyDataSetChanged()
}
} else {
initRecordForums(listOf(change.forumEntity))
}
}
}
}

View File

@ -1,44 +1,40 @@
package com.gh.gamecenter.forum.home
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.MutableLiveData
import com.gh.common.util.UrlFilterUtils
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.qa.entity.ArticleEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.room.AppDatabase
import com.halo.assistant.HaloApp
import io.reactivex.Observable
class ForumArticleListViewModel(application: Application, val path: String) : ListViewModel<ArticleEntity, ArticleEntity>(application) {
class ForumArticleListViewModel(application: Application) : ListViewModel<ArticleEntity, ArticleEntity>(application) {
private val mForumDao = AppDatabase.getInstance(HaloApp.getInstance()).forumDao()
val recordForumsLiveData = MutableLiveData<List<ForumEntity>>()
var sort: String = "time.comment"//排序 time.edit 最新发布 time.comment 最新回复
override fun provideDataObservable(page: Int): Observable<MutableList<ArticleEntity>>? {
return if (path == "关注") {
RetrofitManager.getInstance(getApplication())
.api.getForumFollowArticle(UserManager.getInstance().userId, UrlFilterUtils.getFilterQuery(sort, "-1"), page)
} else {
RetrofitManager.getInstance(getApplication())
return RetrofitManager.getInstance(getApplication())
.api.getForumRecommendsArticle(UrlFilterUtils.getFilterQuery(sort, "-1"), page)
}
}
override fun load(loadType: LoadType?) {
if (path == "关注" && !UserManager.getInstance().isLoggedIn) return
super.load(loadType)
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) }
}
class Factory(val path: String) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ForumArticleListViewModel(HaloApp.getInstance().application, path) as T
}
@SuppressLint("CheckResult")
fun getRecordForums() {
mForumDao.getForum()
.subscribe({
it?.run {
if (it.isNotEmpty()) recordForumsLiveData.postValue(this)
}
}, { })
}
}

View File

@ -0,0 +1,167 @@
package com.gh.gamecenter.forum.home
import android.view.View
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.fragment.LazyFragment
import com.gh.common.util.viewModelProvider
import com.gh.common.view.GridSpacingItemColorDecoration
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentForumBinding
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.eventbus.EBForumFollowChange
import com.gh.gamecenter.forum.list.ForumListActivity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class ForumFragment: LazyFragment() {
private var mBinding: FragmentForumBinding? = null
private var mViewModel: ForumViewModel? = null
private var mHaveFollowForum = false
override fun getRealLayoutId(): Int {
return R.layout.fragment_forum
}
override fun onRealLayoutInflated(inflatedView: View) {
mBinding = FragmentForumBinding.bind(inflatedView)
}
override fun onFragmentFirstVisible() {
mViewModel = viewModelProvider()
super.onFragmentFirstVisible()
}
override fun initRealView() {
super.initRealView()
mViewModel?.followForums?.observe(viewLifecycleOwner, Observer {
mBinding?.run {
reuseLoading.root.visibility = View.GONE
if (it != null) {
reuseNoConnection.root.visibility = View.GONE
if (it.isNotEmpty()) {
mHaveFollowForum = true
initFollowForums(it)
}
mViewModel?.getHotForum()
} else {
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.VISIBLE
reuseNoConnection.root.setOnClickListener {
reuseLoading.root.visibility = View.VISIBLE
mViewModel?.getFollowForum()
}
}
}
})
mViewModel?.hotForums?.observe(viewLifecycleOwner, Observer {
mBinding?.run {
if (mHaveFollowForum) {
if (it != null && it.isNotEmpty()) {
initHotForums(it)
}
} else {
reuseLoading.root.visibility = View.GONE
if (it != null) {
reuseNoConnection.root.visibility = View.GONE
if (it.isNotEmpty()) {
initHotForums(it)
}
} else {
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.VISIBLE
reuseNoConnection.root.setOnClickListener {
reuseLoading.root.visibility = View.VISIBLE
mViewModel?.getHotForum()
}
}
}
}
})
initWelfare()
}
private fun initFollowForums(list: List<ForumEntity>) {
mBinding?.run {
followForumContainer.visibility = View.VISIBLE
followMore.setOnClickListener { startActivity(ForumListActivity.getIntent(requireContext(), ForumListActivity.TYPE_FOLLOW)) }
followForumRv.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
followForumRv.adapter = ForumRecordsAdapter(requireContext(), "社区-论坛-关注论坛", ArrayList(list))
}
}
private fun initHotForums(list: List<ForumEntity>) {
mBinding?.run {
hotForumContainer.visibility = View.VISIBLE
hotMore.setOnClickListener { startActivity(ForumListActivity.getIntent(requireContext(), ForumListActivity.TYPE_HOT)) }
hotForumRv.layoutManager = LinearLayoutManager(requireContext())
val newList = if (mHaveFollowForum) {
if (list.size > 5) {
list.subList(0, 5)
} else {
list
}
} else {
if (list.size > 10) {
list.subList(0, 10)
} else {
list
}
}
hotForumRv.adapter = HotForumsAdapter(requireContext(), "社区-论坛-热门论坛", mViewModel, newList)
}
}
private fun initWelfare() {
val welfareLists = arrayListOf<Pair<Int, String>>()
welfareLists.run {
add(Pair(R.drawable.ic_forum_tool_box, "工具箱"))
add(Pair(R.drawable.ic_forum_libao_center, "礼包中心"))
add(Pair(R.drawable.ic_forum_game_moment, "游戏动态"))
add(Pair(R.drawable.ic_forum_news, "资讯中心"))
add(Pair(R.drawable.ic_forum_accelerator, "万能加速器"))
}
mBinding?.run {
otherWelfareContainer.visibility = View.VISIBLE
otherWelfareRv.layoutManager = GridLayoutManager(requireContext(), 2)
otherWelfareRv.adapter = WelfaresAdapter(requireContext(), welfareLists)
otherWelfareRv.addItemDecoration(GridSpacingItemColorDecoration(requireContext(), 0, 16, R.color.transparent))
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onFollowForumChange(forumFollowChange: EBForumFollowChange) {
mBinding?.run {
if (forumFollowChange.isFollow) {
if (followForumContainer.visibility == View.VISIBLE) {
val adapter = followForumRv.adapter as? ForumRecordsAdapter
adapter?.run {
list.add(forumFollowChange.forumEntity)
notifyDataSetChanged()
}
} else {
initFollowForums(listOf(forumFollowChange.forumEntity))
}
} else {
val adapter = followForumRv.adapter as? ForumRecordsAdapter
adapter?.run {
val findEntity = list.find { it.id == forumFollowChange.forumEntity.id }
list.remove(findEntity)
if (list.isEmpty()) {
followForumContainer.visibility = View.GONE
} else {
notifyDataSetChanged()
}
}
}
}
}
}

View File

@ -30,7 +30,7 @@ import com.gh.gamecenter.entity.LinkEntity
import com.gh.gamecenter.eventbus.EBForumFollowChange
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.eventbus.EBUISwitch
import com.gh.gamecenter.forum.follow.ForumMyFollowActivity
import com.gh.gamecenter.forum.list.ForumListActivity
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
import com.gh.gamecenter.forum.select.ForumSelectActivity
import com.gh.gamecenter.fragment.MainWrapperFragment
@ -249,7 +249,7 @@ class ForumHomeFragment : BaseLazyTabFragment() {
R.id.forumFollowTv -> {
CheckLoginUtils.checkLogin(requireContext(), "论坛") {
MtaHelper.onEvent("论坛首页", "关注的论坛", "更多论坛")
requireContext().startActivity(ForumMyFollowActivity.getIntent(requireContext()))
requireContext().startActivity(ForumListActivity.getIntent(requireContext(), ForumListActivity.TYPE_FOLLOW))
}
}
}

View File

@ -0,0 +1,80 @@
package com.gh.gamecenter.forum.home
import com.gh.common.util.SPUtils
import com.gh.gamecenter.entity.ForumEntity
class ForumRecordDao {
fun add(id: String) {
val originString = SPUtils.getString(SP_KEY)
if (originString.isEmpty()) {
SPUtils.setString(SP_KEY, id)
} else {
getAll()?.let {
if (it.contains(id)) {
it.remove(id)
}
it.add(0, id)
save(it)
}
}
}
fun delete(id: String) {
val originString = SPUtils.getString(SP_KEY)
if (originString.isNotEmpty()) {
getAll()?.let {
if (it.contains(id)) {
it.remove(id)
}
save(it)
}
}
}
private fun save(it: ArrayList<String>) {
val builder = StringBuilder()
for ((index, key) in it.withIndex()) {
builder.append(key)
if (index != it.size - 1) {
builder.append(DIVIDER)
}
}
SPUtils.setString(SP_KEY, builder.toString())
}
fun sortForumList(originalForums: ArrayList<ForumEntity>?) {
if (originalForums.isNullOrEmpty()) return
val visitRecords = getAll()
val tempList = arrayListOf<ForumEntity>()
visitRecords?.forEach { id ->
val index = originalForums.indexOfFirst { it.id == id }
if (index >= 0) {
tempList.add(originalForums.removeAt(index))
}
}
tempList.addAll(originalForums)
originalForums.clear()
originalForums.addAll(tempList)
}
fun getAll(): ArrayList<String>? {
val list = SPUtils.getString(SP_KEY).split(DIVIDER)
return if (list.size == 1 && list[0].isEmpty()) null else ArrayList(list)
}
companion object {
private const val SP_KEY = "forum_recoed_key"
private const val DIVIDER = "<-||->"
@Volatile
private var instance: ForumRecordDao? = null
fun getInstance(): ForumRecordDao {
return instance ?: synchronized(this) {
instance ?: ForumRecordDao().also { instance = it }
}
}
}
}

View File

@ -0,0 +1,45 @@
package com.gh.gamecenter.forum.home
import android.content.Context
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.ForumRecordItemBinding
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.lightgame.adapter.BaseRecyclerAdapter
class ForumRecordsAdapter(context: Context,
private val entrance: String,
var list: ArrayList<ForumEntity>)
: BaseRecyclerAdapter<ForumRecordsAdapter.ForumRecordViewHolder>(context) {
override fun getItemCount() = list.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
= ForumRecordViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.forum_record_item, parent, false))
override fun onBindViewHolder(holder: ForumRecordViewHolder, position: Int) {
holder.binding.run {
root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
leftMargin = if (position == 0) 16F.dip2px() else 0
}
val forumEntity = list[position]
entity = forumEntity
executePendingBindings()
forumIv.displayGameIcon(forumEntity.game.getIcon(), forumEntity.game.iconSubscript)
root.setOnClickListener {
mContext.startActivity(ForumDetailActivity.getIntent(mContext, forumEntity.id, entrance))
}
}
}
class ForumRecordViewHolder(val binding: ForumRecordItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,95 @@
package com.gh.gamecenter.forum.home
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.*
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.LogUtils
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import retrofit2.HttpException
class ForumViewModel(application: Application) : AndroidViewModel(application) {
private val api = RetrofitManager.getInstance(getApplication()).api
val followForums = MediatorLiveData<List<ForumEntity>>()
val hotForums = MediatorLiveData<List<ForumEntity>>()
init {
if (CheckLoginUtils.isLogin()) {
getFollowForum()
} else {
getHotForum()
}
}
@SuppressLint("CheckResult")
fun getFollowForum() {
api.getFollowsForum(UserManager.getInstance().userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<List<ForumEntity>>() {
override fun onResponse(response: List<ForumEntity>?) {
super.onResponse(response)
followForums.postValue(response)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
followForums.postValue(null)
}
})
}
@SuppressLint("CheckResult")
fun getHotForum() {
api.getHotForumWithPage(1)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<List<ForumEntity>>() {
override fun onResponse(response: List<ForumEntity>?) {
super.onResponse(response)
hotForums.postValue(response)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
hotForums.postValue(null)
}
})
}
@SuppressLint("CheckResult")
fun followForum(bbsId: String, onSuccess: () -> Unit) {
RetrofitManager.getInstance(getApplication()).api
.followForum(bbsId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
onSuccess.invoke()
}
})
}
@SuppressLint("CheckResult")
fun unFollowForum(bbsId: String, onSuccess: () -> Unit) {
RetrofitManager.getInstance(getApplication()).api
.unFollowForum(bbsId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
onSuccess.invoke()
}
})
}
}

View File

@ -0,0 +1,81 @@
package com.gh.gamecenter.forum.home
import android.content.Context
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.HotForumItemBinding
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.eventbus.EBForumFollowChange
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.lightgame.adapter.BaseRecyclerAdapter
import org.greenrobot.eventbus.EventBus
class HotForumsAdapter(context: Context,
private val entrance: String,
private val mViewModel: ForumViewModel?,
private var mList: List<ForumEntity>)
: BaseRecyclerAdapter<HotForumsAdapter.HotForumViewHolder>(context) {
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
= HotForumViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.hot_forum_item, parent, false))
override fun onBindViewHolder(holder: HotForumViewHolder, position: Int) {
holder.binding.run {
val forumEntity = mList[position]
entity = forumEntity
executePendingBindings()
forumIv.displayGameIcon(forumEntity.game.getIcon(), forumEntity.game.iconSubscript)
followTv.run {
text = if (forumEntity.isFollow) {
setBackgroundResource(R.drawable.button_round_fafafa)
setTextColor(R.color.text_C0C6CC.toColor())
"已关注"
} else {
setBackgroundResource(R.drawable.button_round_f0f8fa)
setTextColor(R.color.theme_font.toColor())
"关注"
}
}
followTv.setOnClickListener {
debounceActionWithInterval(R.id.followTv) {
CheckLoginUtils.checkLogin(mContext, entrance) {
if (forumEntity.isFollow) {
mViewModel?.unFollowForum(forumEntity.id) {
forumEntity.isFollow = false
followTv.setBackgroundResource(R.drawable.button_round_f0f8fa)
followTv.setTextColor(R.color.theme_font.toColor())
followTv.text = "关注"
EventBus.getDefault().post(EBForumFollowChange(forumEntity, false))
}
} else {
mViewModel?.followForum(forumEntity.id) {
forumEntity.isFollow = true
followTv.setBackgroundResource(R.drawable.button_round_fafafa)
followTv.setTextColor(R.color.text_C0C6CC.toColor())
followTv.text = "已关注"
ToastUtils.showToast("关注成功")
EventBus.getDefault().post(EBForumFollowChange(forumEntity, true))
}
}
}
}
}
root.setOnClickListener {
mContext.startActivity(ForumDetailActivity.getIntent(mContext, forumEntity.id, entrance))
}
}
}
class HotForumViewHolder(val binding: HotForumItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,257 @@
package com.gh.gamecenter.forum.home
import android.graphics.Typeface
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.widget.*
import androidx.core.graphics.ColorUtils
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import butterknife.OnClick
import com.gh.base.adapter.FragmentAdapter
import com.gh.base.fragment.LazyFragment
import com.gh.common.dialog.TrackableDialog
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentNewForumHomeBinding
import com.gh.gamecenter.databinding.TabItemMainBinding
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.CommunityFragment
import com.gh.gamecenter.qa.VideoInsertType
import com.gh.gamecenter.qa.article.edit.ArticleEditActivity
import com.gh.gamecenter.qa.questions.edit.QuestionEditActivity
import com.gh.gamecenter.qa.video.publish.VideoPublishActivity
import kotlinx.android.synthetic.main.fragment_new_forum_home.*
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import kotlin.math.abs
class NewForumHomeFragment : LazyFragment() {
private var mBinding: FragmentNewForumHomeBinding? = null
private var mFragmentList = arrayListOf<Fragment>()
private var mTitleList = arrayListOf("推荐", "论坛")
private var mTabList = arrayListOf<TextView>()
override fun getRealLayoutId(): Int {
return R.layout.fragment_new_forum_home
}
override fun onRealLayoutInflated(inflatedView: View) {
mBinding = FragmentNewForumHomeBinding.bind(inflatedView)
}
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
initViewPager()
}
override fun initRealView() {
super.initRealView()
mBinding?.run {
searchContainer.setOnClickListener {
requireContext().startActivity(ForumOrUserSearchActivity.getIntent(requireContext(), "", "论坛首页"))
}
communityEditBtn.setOnClickListener {
showCommunityEditWindow()
}
}
}
override fun onFragmentResume() {
super.onFragmentResume()
DisplayUtils.setLightStatusBar(requireActivity(), true)
}
fun setCurrentItem(index: Int) {
mBinding?.viewPager?.currentItem = index
}
private fun initViewPager() {
mBinding?.run {
mFragmentList.clear()
val tag = "android:switcher:${viewPager.id}:"
val forumArticleListFragment = childFragmentManager.findFragmentByTag("${tag}0")
?: ForumArticleListFragment().with(bundleOf(EntranceUtils.KEY_ENTRANCE to "社区", EntranceUtils.KEY_PATH to "推荐"))
mFragmentList.add(forumArticleListFragment)
val forumFragment = childFragmentManager.findFragmentByTag("${tag}1")
?: ForumFragment().with(bundleOf(EntranceUtils.KEY_ENTRANCE to "社区"))
mFragmentList.add(forumFragment)
viewPager.run {
offscreenPageLimit = mFragmentList.size
adapter = FragmentAdapter(childFragmentManager, mFragmentList, mTitleList)
viewPager.doOnScroll(
onPageSelected = { position ->
updateTabTextStyle(position, 0F)
},
onPageScrolled = { position, positionOffset, _ ->
if (position + 1 != mTabList.size) {
mTabList[position].run {
textSize = (DEFAULT_TAB_TEXT_SIZE + ((1 - positionOffset) * 4)).roundTo(1)
setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, 1 - positionOffset))
}
mTabList[position + 1].run {
textSize = (DEFAULT_TAB_TEXT_SIZE + ((positionOffset) * 4)).roundTo(1)
setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, positionOffset))
}
// 多 tab 切换的时候可能会出现某些 tab 的文字没有回归到原始大小的问题的问题 (positionOffset 不保证连续)
for ((index, tabTv) in mTabList.withIndex()) {
if (abs(index - position) >= 2) {
if (tabTv.textSize != DEFAULT_TAB_TEXT_SIZE) {
tabTv.textSize = DEFAULT_TAB_TEXT_SIZE
tabTv.setTextColor(TAB_DEFAULT_COLOR)
}
}
}
}
updateTabTextStyle(position, positionOffset)
}
)
}
tabLayout.setupWithViewPager(viewPager)
indicatorView.run {
setupWithTabLayout(tabLayout)
setupWithViewPager(viewPager)
setIndicatorWidth(18)
}
for (i in 0 until tabLayout.tabCount) {
val tab = tabLayout.getTabAt(i) ?: continue
val tabTitle = if (tab.text != null) tab.text.toString() else ""
val tabViewBinding = generateTabView(tabTitle)
mTabList.add(tabViewBinding.tabTitle)
tab.customView = tabViewBinding.root
tab.view.setPadding(0, 0, 0, 0)
}
}
}
private fun updateTabTextStyle(selectedPosition: Int, positionOffset: Float) {
for ((index, titleTv) in mTabList.withIndex()) {
if (index == selectedPosition) {
titleTv.setTextColor(TAB_SELECTED_COLOR)
if (positionOffset == 0F) {
titleTv.setTypeface(null, Typeface.NORMAL)
titleTv.setTypeface(titleTv.typeface, Typeface.BOLD)
}
} else {
titleTv.setTextColor(TAB_DEFAULT_COLOR)
if (positionOffset == 0F) {
titleTv.setTypeface(null, Typeface.NORMAL)
}
}
}
}
private fun generateTabView(title: String): TabItemMainBinding {
val binding = TabItemMainBinding.inflate(LayoutInflater.from(requireContext()))
binding.tabTitle.run {
text = title
textSize = DEFAULT_TAB_TEXT_SIZE
setTextColor(TAB_DEFAULT_COLOR)
}
binding.invisibleTabTitle.run {
text = title
textSize = DEFAULT_TAB_TEXT_SIZE
}
return binding
}
private fun showCommunityEditWindow() {
val contentView = LayoutInflater.from(context).inflate(R.layout.community_edit_window, null)
val params = ViewGroup.LayoutParams(resources.displayMetrics.widthPixels, ViewGroup.LayoutParams.WRAP_CONTENT)
val dialog = TrackableDialog(
requireContext(),
R.style.DialogWindowTransparent,
"社区",
UserManager.getInstance().community.name,
null,
"发布-空白",
"发布-返回",
false)
val window = dialog.window
window?.setGravity(Gravity.BOTTOM)
window?.setWindowAnimations(R.style.community_publication_animation)
dialog.setContentView(contentView, params)
dialog.show()
contentView.findViewById<View>(R.id.community_edit_article_container).setOnClickListener {
context?.ifLogin("论坛首页", action = {
checkStoragePermissionBeforeAction {
showRegulationTestDialogIfNeeded {
MtaHelper.onEvent("论坛首页", "发布", "发帖子")
startActivity(ArticleEditActivity.getIntent(requireContext(), null))
dialog.dismiss()
}
}
})
}
contentView.findViewById<View>(R.id.community_edit_question_container).setOnClickListener {
context?.ifLogin("论坛首页", action = {
checkStoragePermissionBeforeAction {
showRegulationTestDialogIfNeeded {
MtaHelper.onEvent("论坛首页", "发布", "提问")
startActivity(QuestionEditActivity.getIntent(requireContext()))
dialog.dismiss()
}
}
})
}
contentView.findViewById<View>(R.id.community_edit_video_container).setOnClickListener {
checkStoragePermissionBeforeAction {
showRegulationTestDialogIfNeeded {
MtaHelper.onEvent("论坛首页", "发布", "发视频")
startActivity(VideoPublishActivity.getIntent(requireContext(), null, VideoInsertType.GAME_BBS, mEntrance, "论坛首页"))
dialog.dismiss()
}
}
}
contentView.findViewById<View>(R.id.community_edit_close).setOnClickListener {
dialog.dismiss()
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBTypeChange) {
if (status.type == CommunityFragment.EB_SHOW_QUESTION_BUTTON) {
setPutQuestionButtonStatus(View.VISIBLE)
} else if (status.type == CommunityFragment.EB_HIDE_QUESTION_BUTTON) {
setPutQuestionButtonStatus(View.GONE)
}
}
private fun setPutQuestionButtonStatus(visibility: Int) {
mBinding?.run {
if (communityEditBtn.visibility == visibility) return
if (visibility == View.GONE) {
val animation = AnimationUtils.loadAnimation(context, R.anim.button_anim_exit)
communityEditBtn.startAnimation(animation)
} else {
val animation = AnimationUtils.loadAnimation(context, R.anim.button_anim_enter)
communityEditBtn.startAnimation(animation)
}
communityEditBtn.visibility = visibility
}
}
companion object {
var TAB_SELECTED_COLOR: Int = R.color.text_333333.toColor()
var TAB_DEFAULT_COLOR: Int = R.color.text_666666.toColor()
var DEFAULT_TAB_TEXT_SIZE = 16F
const val TAB_RECOMMEND_INDEX = 0
const val TAB_FORUM_INDEX = 1
const val TAB_ACTIVITY_INDEX = 2
}
}

View File

@ -0,0 +1,70 @@
package com.gh.gamecenter.forum.home
import android.content.Context
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.MtaHelper
import com.gh.common.util.ifLogin
import com.gh.gamecenter.*
import com.gh.gamecenter.databinding.ForumWelfareItemBinding
import com.gh.gamecenter.databinding.HotForumItemBinding
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.manager.UserManager
import com.lightgame.adapter.BaseRecyclerAdapter
class WelfaresAdapter(context: Context,
private var mList: List<Pair<Int, String>>)
: BaseRecyclerAdapter<WelfaresAdapter.WelfareViewHolder>(context) {
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
= WelfareViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.forum_welfare_item, parent, false))
override fun onBindViewHolder(holder: WelfareViewHolder, position: Int) {
holder.binding.run {
// root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
// leftMargin = if (position == 0) 16F.dip2px() else 0
// }
val entity = mList[position]
welfareIv.setImageResource(entity.first)
welfareName.text = entity.second
root.setOnClickListener {
when (entity.second) {
"工具箱" -> {
mContext.startActivity(ToolBoxActivity.getIntent(mContext, "(社区-论坛:工具箱)"))
}
"礼包中心" -> {
mContext.startActivity(LibaoActivity.getIntent(mContext, "(社区-论坛:礼包中心)"))
}
"游戏动态" -> {
CheckLoginUtils.checkLogin(mContext, "社区-论坛:游戏动态") {
mContext.startActivity(ConcernInfoActivity.getIntent(mContext))
}
}
"资讯中心" -> {
mContext.startActivity(InfoActivity.getIntent(mContext))
}
"万能加速器" -> {
GameDetailActivity.startGameDetailActivity(mContext, "5c9456576b90b400137cc6a6", "社区-论坛:万能加速器")
}
}
}
}
}
class WelfareViewHolder(val binding: ForumWelfareItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,22 @@
package com.gh.gamecenter.forum.list
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.NormalActivity
class ForumListActivity : NormalActivity() {
companion object {
const val TYPE_FOLLOW = "follow"
const val TYPE_HOT = "hot"
const val TYPE_OFFICIAL = "official"
fun getIntent(context: Context, type: String): Intent {
val bundle = Bundle()
bundle.putString(EntranceUtils.KEY_TYPE, type)
return getTargetIntent(context, ForumListActivity::class.java, ForumListFragment::class.java, bundle)
}
}
}

View File

@ -0,0 +1,113 @@
package com.gh.gamecenter.forum.list
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.ItemViewType
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.ToastUtils
import com.gh.common.util.debounceActionWithInterval
import com.gh.common.util.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.databinding.ForumMyFollowBinding
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.eventbus.EBForumFollowChange
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import org.greenrobot.eventbus.EventBus
class ForumListAdapter(context: Context,
val entrance: String,
val mViewModel: ForumListViewModel?): ListAdapter<ForumEntity>(context) {
override fun getItemCount(): Int {
return if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT
}
override fun getItemViewType(position: Int): Int {
return when (position) {
itemCount - 1 -> ItemViewType.ITEM_FOOTER
else -> ItemViewType.ITEM_BODY
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ItemViewType.ITEM_FOOTER -> FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
else -> ForumItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.forum_my_follow, parent, false))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ForumItemViewHolder -> {
holder.binding.run {
val forumEntity = mEntityList[position]
entity = forumEntity
executePendingBindings()
forumIcon.displayGameIcon(forumEntity.game.getIcon(), forumEntity.game.iconSubscript)
topLine.visibility = if (position == 0) View.GONE else View.VISIBLE
if (mViewModel?.type == ForumListActivity.TYPE_FOLLOW) {
moreIv.visibility = View.VISIBLE
followTv.visibility = View.GONE
} else {
moreIv.visibility = View.GONE
followTv.visibility = View.VISIBLE
followTv.run {
text = if (forumEntity.isFollow) {
setBackgroundResource(R.drawable.button_round_fafafa)
setTextColor(R.color.text_C0C6CC.toColor())
"已关注"
} else {
setBackgroundResource(R.drawable.button_round_f0f8fa)
setTextColor(R.color.theme_font.toColor())
"关注"
}
}
followTv.setOnClickListener {
debounceActionWithInterval(R.id.followTv) {
CheckLoginUtils.checkLogin(mContext, entrance) {
if (forumEntity.isFollow) {
mViewModel?.unFollowForum(forumEntity.id) {
forumEntity.isFollow = false
followTv.setBackgroundResource(R.drawable.button_round_f0f8fa)
followTv.setTextColor(R.color.theme_font.toColor())
followTv.text = "关注"
EventBus.getDefault().post(EBForumFollowChange(forumEntity, false))
}
} else {
mViewModel?.followForum(forumEntity.id) {
forumEntity.isFollow = true
followTv.setBackgroundResource(R.drawable.button_round_fafafa)
followTv.setTextColor(R.color.text_C0C6CC.toColor())
followTv.text = "已关注"
ToastUtils.showToast("关注成功")
EventBus.getDefault().post(EBForumFollowChange(forumEntity, true))
}
}
}
}
}
}
root.setOnClickListener { mContext.startActivity(ForumDetailActivity.getIntent(mContext, forumEntity.id, entrance)) }
}
}
is FooterViewHolder -> {
holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
}
}
}
inner class ForumItemViewHolder(val binding: ForumMyFollowBinding): BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,41 @@
package com.gh.gamecenter.forum.list
import android.os.Bundle
import com.gh.common.util.EntranceUtils
import com.gh.common.util.dip2px
import com.gh.common.util.toColor
import com.gh.common.util.viewModelProvider
import com.gh.common.view.SpacingItemDecoration
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListFragment
import com.gh.gamecenter.entity.ForumEntity
class ForumListFragment: ListFragment<ForumEntity, ForumListViewModel>() {
private var mAdapter: ForumListAdapter? = null
private var mViewModel: ForumListViewModel? = null
override fun provideListAdapter() = mAdapter
?: ForumListAdapter(requireContext(), mEntrance, provideListViewModel()).apply { mAdapter = this }
override fun provideListViewModel() = viewModelProvider<ForumListViewModel>()
override fun getItemDecoration()= SpacingItemDecoration(onlyDecorateTheFirstItem = true, top = 8F.dip2px())
override fun onCreate(savedInstanceState: Bundle?) {
val type = arguments?.getString(EntranceUtils.KEY_TYPE) ?: ""
mViewModel = provideListViewModel()
mViewModel?.type = type
when (type) {
ForumListActivity.TYPE_FOLLOW -> {
setNavigationTitle("关注论坛")
mViewModel?.setOverLimitSize(1000)
}
ForumListActivity.TYPE_HOT -> setNavigationTitle("热门论坛")
ForumListActivity.TYPE_OFFICIAL -> setNavigationTitle("综合论坛")
}
super.onCreate(savedInstanceState)
}
}

View File

@ -0,0 +1,56 @@
package com.gh.gamecenter.forum.list
import android.annotation.SuppressLint
import android.app.Application
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
class ForumListViewModel(application: Application): ListViewModel<ForumEntity, ForumEntity>(application) {
private val mApi = RetrofitManager.getInstance(getApplication()).api
var type = ForumListActivity.TYPE_FOLLOW
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) }
}
override fun provideDataObservable(page: Int): Observable<MutableList<ForumEntity>> {
return when (type) {
ForumListActivity.TYPE_FOLLOW -> mApi.getFollowsForum(UserManager.getInstance().userId)
ForumListActivity.TYPE_HOT -> mApi.getHotForumWithPage(page)
else -> mApi.getHotForumWithPage(page)
}
}
@SuppressLint("CheckResult")
fun followForum(bbsId: String, onSuccess: () -> Unit) {
mApi.followForum(bbsId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
onSuccess.invoke()
}
})
}
@SuppressLint("CheckResult")
fun unFollowForum(bbsId: String, onSuccess: () -> Unit) {
mApi.unFollowForum(bbsId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
onSuccess.invoke()
}
})
}
}

View File

@ -42,10 +42,7 @@ class ForumOrUserSearchFragment : BaseFragment_TabLayout() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mTabLayout.tabMode = TabLayout.MODE_AUTO
val tabLayoutParams = mTabLayout.layoutParams as RelativeLayout.LayoutParams
tabLayoutParams.width = RelativeLayout.LayoutParams.WRAP_CONTENT
mTabLayout.layoutParams = tabLayoutParams
mTabLayout.tabMode = TabLayout.MODE_FIXED
val viewpagerParams = mViewPager.layoutParams as LinearLayout.LayoutParams
viewpagerParams.topMargin = 0.5f.dip2px()

View File

@ -50,6 +50,7 @@ import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.eventbus.EBSkip;
import com.gh.gamecenter.eventbus.EBUISwitch;
import com.gh.gamecenter.forum.home.ForumHomeFragment;
import com.gh.gamecenter.forum.home.NewForumHomeFragment;
import com.gh.gamecenter.game.GameFragment;
import com.gh.gamecenter.message.MessageUnreadRepository;
import com.gh.gamecenter.message.MessageUnreadViewModel;
@ -147,7 +148,7 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
videoArgs.putBoolean(EntranceUtils.KEY_IS_HOME_VIDEO, true);
homeVideoFragment.setArguments(videoArgs);
fragments.add(new ForumHomeFragment());
fragments.add(new NewForumHomeFragment());
fragments.add(homeVideoFragment);
if (mViewModel.shouldHideVideoTab()) {

View File

@ -308,7 +308,7 @@ class UserHomeFragment : NormalFragment() {
?: UserVideoHistoryFragment.getInstance(mUserHomeViewModel.userId, count)
val fragmentList = listOf(gameFragment, qaFragment, videoFragment)
val titleList = listOf("游戏评论", "论坛", "视频")
val titleList = listOf("游戏", "论坛", "视频")
val countList = listOf(count.gameComment, count.getQaCount(), count.video)
viewpager.offscreenPageLimit = fragmentList.size
@ -330,11 +330,9 @@ class UserHomeFragment : NormalFragment() {
private fun getTabView(title: String, count: Int): View {
val view = LayoutInflater.from(HaloApp.getInstance().application.baseContext).inflate(R.layout.tab_item_user_home, null)
val tabTitle = view.findViewById<View>(R.id.tab_title)
val tabCount = view.findViewById<TextView>(R.id.tab_count)
if (tabTitle is CheckedTextView) {
tabTitle.text = title
}
tabCount.text = if (count == 0) "" else count.toString()
return view
}

View File

@ -20,6 +20,7 @@ import com.lightgame.utils.Utils
import com.lightgame.view.CheckableImageView
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import retrofit2.HttpException
/**
@ -34,6 +35,8 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
val commentCountContainer: View = itemView.findViewById(R.id.comment_count_container)
val voteCountContainer: View = itemView.findViewById(R.id.vote_count_container)
val forumNameTv: View = itemView.findViewById(R.id.forumNameTv)
val forumNameContainer: View? = itemView.findViewById(R.id.forumNameContainer)
val concernBtn: View? = itemView.findViewById(R.id.concernBtn)
open fun bindCommendAndVote(entity: AnswerEntity, entrance: String) {
@ -99,6 +102,10 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
LogUtils.uploadAccessToBbs(entity.community.id, "文章外所属论坛")
}
forumNameContainer?.setOnClickListener {
forumNameTv.performClick()
}
commentCountContainer.setOnClickListener {
if (filterIllegalCommentStatus(entity.commentable, entity.active)) return@setOnClickListener
@ -360,6 +367,24 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
})
}
fun followUser(entity: AnswerEntity, callback: EmptyCallback?) {
RetrofitManager.getInstance(itemView.context).api
.postFollowing(entity.user.id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
callback?.onCallback()
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
Utils.toast(itemView.context, R.string.loading_failed_hint)
}
})
}
private fun playVoteAnimation() {
voteCount.setTextColor(R.color.theme_font.toColor())
voteIcon.isChecked = true

View File

@ -177,6 +177,15 @@ class ArticleDetailViewModel(application: Application,
}
}
private fun syncFollowData(isFollow: Boolean) {
articleId.apply {
SyncPageRepository.postSyncData(SyncDataEntity(this,
SyncFieldConstants.IS_FOLLOWER,
isFollow,
checkFieldEntity = true))
}
}
fun collectionCommand(isCollection: Boolean, callback: (isFollow: Boolean) -> Unit) {
val observable = if (isCollection) {
mApi.postCommunityArticleFavorites(UserManager.getInstance().userId, communityId, articleId)
@ -233,9 +242,11 @@ class ArticleDetailViewModel(application: Application,
if (isFollow) {
// 关注成功
mFollowLiveData.postValue(true)
syncFollowData(true)
} else {
// 取消关注成功
mFollowLiveData.postValue(false)
syncFollowData(false)
}
}

View File

@ -70,6 +70,9 @@ class AnswerEntity() : Parcelable {
@SerializedName("community_name")
var communityName: String? = null
@SerializedName("community_icon")
var communityIcon: String = ""
@SyncPage(syncNames = [SyncFieldConstants.ANSWER_COMMENT_COUNT, SyncFieldConstants.ARTICLE_COMMENT_COUNT])
@SerializedName("comment_count")
var commentCount: Int = 0

View File

@ -1,6 +1,7 @@
package com.gh.gamecenter.qa.entity
import android.os.Parcelable
import kotlinx.android.parcel.IgnoredOnParcel
import kotlinx.android.parcel.Parcelize
@Parcelize
@ -10,4 +11,8 @@ data class CommunityVideoEntity(val id: String = "",
var status: String = "", // 有三种状态 pass通过fail未通过pending审核中
val poster: String = "",
var width: Int = 0,
var height: Int = 0) : Parcelable
var height: Int = 0,
//本地数据
@IgnoredOnParcel
var videoIsMuted: Boolean = false //是否静音标记
) : Parcelable

View File

@ -2627,6 +2627,12 @@ public interface ApiService {
@GET("./bbses:hot")
Observable<List<ForumEntity>> getHotForum();
/**
* 热门论坛列表
*/
@GET("./bbses:hot")
Observable<List<ForumEntity>> getHotForumWithPage(@Query("page") int page);
/**
* 获取论坛分类
*/

View File

@ -13,16 +13,19 @@ import androidx.sqlite.db.SupportSQLiteDatabase;
import com.gh.common.videolog.VideoRecordDao;
import com.gh.common.videolog.VideoRecordEntity;
import com.gh.gamecenter.entity.CommentDraft;
import com.gh.gamecenter.entity.ForumEntity;
import com.gh.gamecenter.entity.HomePluggableFilterEntity;
import com.gh.gamecenter.entity.SignEntity;
import com.gh.gamecenter.entity.SimulatorGameRecordEntity;
import com.gh.gamecenter.qa.entity.AnswerEntity;
import com.gh.gamecenter.room.converter.ApkArrayListConverter;
import com.gh.gamecenter.room.converter.SimpleGameConverter;
import com.gh.gamecenter.room.converter.SimulatorConverter;
import com.gh.gamecenter.room.converter.StringArrayListConverter;
import com.gh.gamecenter.room.converter.TagStyleListConverter;
import com.gh.gamecenter.room.dao.AnswerDao;
import com.gh.gamecenter.room.dao.CommentDraftDao;
import com.gh.gamecenter.room.dao.ForumDao;
import com.gh.gamecenter.room.dao.HomePluggableFilterDao;
import com.gh.gamecenter.room.dao.SignDao;
import com.gh.gamecenter.room.dao.SimulatorGameDao;
@ -39,12 +42,14 @@ import com.gh.gamecenter.video.upload.UploadEntity;
CommentDraft.class,
HomePluggableFilterEntity.class,
VideoRecordEntity.class,
SimulatorGameRecordEntity.class}, version = 18, exportSchema = false)
SimulatorGameRecordEntity.class,
ForumEntity.class}, version = 19, exportSchema = false)
@TypeConverters({
StringArrayListConverter.class,
TagStyleListConverter.class,
SimulatorConverter.class,
ApkArrayListConverter.class
ApkArrayListConverter.class,
SimpleGameConverter.class
})
public abstract class AppDatabase extends RoomDatabase {
@ -62,6 +67,8 @@ public abstract class AppDatabase extends RoomDatabase {
public abstract SimulatorGameDao simulatorGameDao();
public abstract ForumDao forumDao();
private static AppDatabase sInstance;
private static final String DATABASE_NAME = "gh-db";
@ -187,6 +194,13 @@ public abstract class AppDatabase extends RoomDatabase {
}
};
static final Migration MIGRATION_18_19 = new Migration(18, 19) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE ForumEntity (id TEXT NOT NULL PRIMARY KEY, game TEXT NOT NULL, name TEXT NOT NULL, isFollow INTEGER NOT NULL DEFAULT 0, isRecommend INTEGER NOT NULL DEFAULT 0, orderTag INTEGER NOT NULL DEFAULT 0)");
}
};
private static AppDatabase buildDatabase(Context context) {
return Room.databaseBuilder(context, AppDatabase.class, DATABASE_NAME)
.addMigrations(
@ -204,7 +218,8 @@ public abstract class AppDatabase extends RoomDatabase {
MIGRATION_14_15,
MIGRATION_15_16,
MIGRATION_16_17,
MIGRATION_17_18
MIGRATION_17_18,
MIGRATION_18_19
)
// 不允许主线程查询
.allowMainThreadQueries()

View File

@ -0,0 +1,18 @@
package com.gh.gamecenter.room.converter
import androidx.room.TypeConverter
import com.gh.common.util.toJson
import com.gh.common.util.toObject
import com.gh.gamecenter.entity.SimpleGame
class SimpleGameConverter {
@TypeConverter
fun toSimpleGameString(data: SimpleGame?): String {
return data?.toJson() ?: ""
}
@TypeConverter
fun toSimpleGameEntity(token: String?): SimpleGame {
return token?.toObject() ?: SimpleGame()
}
}

View File

@ -0,0 +1,19 @@
package com.gh.gamecenter.room.dao
import androidx.room.*
import com.gh.gamecenter.entity.ForumEntity
import io.reactivex.Single
@Dao
interface ForumDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun addForum(forum: ForumEntity)
@Query("select * from ForumEntity order by orderTag desc")
fun getForum(): Single<List<ForumEntity>>
@Delete
fun deleteForum(answer: ForumEntity)
}

View File

@ -3,25 +3,7 @@ package com.gh.gamecenter.video.label
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.gh.common.util.dip2px
import com.gh.common.util.viewModelProvider
import com.gh.common.view.divider.HorizontalDividerItemDecoration
import com.gh.gamecenter.NormalActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListActivity
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.forum.follow.ForumMyFollowActivity
import com.gh.gamecenter.forum.follow.ForumMyFollowAdapter
import com.gh.gamecenter.forum.follow.ForumMyFollowFragment
import com.gh.gamecenter.normal.NormalFragment
import kotterknife.bindView
@Deprecated("v5.0.0废弃")
class VideoLabelActivity : NormalActivity() {