From 71a61fdef0c02f2b59cdcee4b30919b9e79d206a Mon Sep 17 00:00:00 2001 From: lyr <15622190878@163.com> Date: Wed, 26 May 2021 19:00:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B2=97=E7=95=A5=E5=AE=8C=E6=88=90=E7=A4=BE?= =?UTF-8?q?=E5=8C=BA=E7=9A=84=E6=8E=A8=E8=8D=90Tab=E5=92=8C=E8=AE=BA?= =?UTF-8?q?=E5=9D=9BTab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 4 + .../gh/common/syncpage/SyncFieldConstants.kt | 3 + .../com/gh/common/view/ImageContainerView.kt | 2 +- .../com/gh/gamecenter/energy/TaskFragment.kt | 2 +- .../gh/gamecenter/entity/ForumDetailEntity.kt | 11 +- .../com/gh/gamecenter/entity/ForumEntity.kt | 7 +- .../java/com/gh/gamecenter/entity/MeEntity.kt | 1 + .../eventbus/EBForumRecordChange.java | 20 ++ .../forum/detail/ForumDetailViewModel.kt | 8 + .../forum/follow/ForumMyFollowActivity.kt | 20 -- .../forum/follow/ForumMyFollowAdapter.kt | 89 ------ .../forum/follow/ForumMyFollowFragment.kt | 79 ------ .../forum/follow/ForumMyFollowViewModel.kt | 57 ---- .../forum/home/ArticleItemVideoView.kt | 229 ++++++++++++++++ .../home/ForumArticleAskItemViewHolder.kt | 61 ++++- .../forum/home/ForumArticleListAdapter.kt | 16 +- .../forum/home/ForumArticleListFragment.kt | 164 ++++++----- .../forum/home/ForumArticleListViewModel.kt | 38 ++- .../gh/gamecenter/forum/home/ForumFragment.kt | 167 ++++++++++++ .../forum/home/ForumHomeFragment.kt | 4 +- .../gamecenter/forum/home/ForumRecordDao.kt | 80 ++++++ .../forum/home/ForumRecordsAdapter.kt | 45 +++ .../gamecenter/forum/home/ForumViewModel.kt | 95 +++++++ .../gamecenter/forum/home/HotForumsAdapter.kt | 81 ++++++ .../forum/home/NewForumHomeFragment.kt | 257 ++++++++++++++++++ .../gamecenter/forum/home/WelfaresAdapter.kt | 70 +++++ .../forum/list/ForumListActivity.kt | 22 ++ .../gamecenter/forum/list/ForumListAdapter.kt | 113 ++++++++ .../forum/list/ForumListFragment.kt | 41 +++ .../forum/list/ForumListVIewModel.kt | 56 ++++ .../forum/search/ForumOrUserSearchFragment.kt | 5 +- .../fragment/MainWrapperFragment.java | 3 +- .../personalhome/UserHomeFragment.kt | 4 +- .../BaseAnswerOrArticleItemViewHolder.kt | 25 ++ .../article/detail/ArticleDetailViewModel.kt | 11 + .../gh/gamecenter/qa/entity/AnswerEntity.kt | 3 + .../qa/entity/CommunityVideoEntity.kt | 7 +- .../retrofit/service/ApiService.java | 6 + .../com/gh/gamecenter/room/AppDatabase.java | 21 +- .../room/converter/SimpleGameConverter.kt | 18 ++ .../com/gh/gamecenter/room/dao/ForumDao.kt | 19 ++ .../video/label/VideoLabelActivity.kt | 18 -- .../drawable-xxhdpi/community_edit_icon.webp | Bin 11650 -> 0 bytes .../drawable-xxxhdpi/community_edit_icon.webp | Bin 0 -> 13086 bytes .../ic_article_video_full_screen.webp | Bin 0 -> 870 bytes .../ic_article_video_replay.png | Bin 0 -> 2085 bytes .../ic_article_video_share.png | Bin 0 -> 2456 bytes .../ic_article_video_volume_off.webp | Bin 0 -> 1334 bytes .../ic_article_video_volume_on.webp | Bin 0 -> 1232 bytes .../ic_forum_accelerator.webp | Bin 0 -> 3366 bytes .../ic_forum_detail_game_zone_left.webp | Bin 2160 -> 3014 bytes .../ic_forum_game_moment.webp | Bin 0 -> 3420 bytes .../ic_forum_libao_center.webp | Bin 0 -> 2962 bytes .../res/drawable-xxxhdpi/ic_forum_news.webp | Bin 0 -> 2602 bytes .../drawable-xxxhdpi/ic_forum_tool_box.webp | Bin 0 -> 3026 bytes .../main/res/drawable/button_round_f0f8fa.xml | 9 + .../main/res/layout/community_answer_item.xml | 119 ++++++-- app/src/main/res/layout/forum_my_follow.xml | 80 ++++-- app/src/main/res/layout/forum_record_item.xml | 43 +++ .../main/res/layout/forum_welfare_item.xml | 36 +++ app/src/main/res/layout/fragment_forum.xml | 203 ++++++++++++++ .../main/res/layout/fragment_forum_list.xml | 66 ++++- .../res/layout/fragment_new_forum_home.xml | 91 +++++++ app/src/main/res/layout/hot_forum_item.xml | 56 ++++ .../res/layout/layout_article_item_video.xml | 131 +++++++++ .../layout/piece_article_video_control.xml | 66 +++++ .../piece_community_vote_and_comment.xml | 2 +- app/src/main/res/values/colors.xml | 2 + 68 files changed, 2427 insertions(+), 459 deletions(-) create mode 100644 app/src/main/java/com/gh/gamecenter/eventbus/EBForumRecordChange.java delete mode 100644 app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowActivity.kt delete mode 100644 app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowAdapter.kt delete mode 100644 app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowFragment.kt delete mode 100644 app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowViewModel.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/home/ArticleItemVideoView.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/home/ForumRecordDao.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/home/ForumRecordsAdapter.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/home/ForumViewModel.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/home/HotForumsAdapter.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/home/NewForumHomeFragment.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/home/WelfaresAdapter.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/list/ForumListActivity.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/list/ForumListAdapter.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/list/ForumListFragment.kt create mode 100644 app/src/main/java/com/gh/gamecenter/forum/list/ForumListVIewModel.kt create mode 100644 app/src/main/java/com/gh/gamecenter/room/converter/SimpleGameConverter.kt create mode 100644 app/src/main/java/com/gh/gamecenter/room/dao/ForumDao.kt delete mode 100644 app/src/main/res/drawable-xxhdpi/community_edit_icon.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/community_edit_icon.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_video_full_screen.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_video_replay.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_video_share.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_video_volume_off.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_video_volume_on.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_forum_accelerator.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_forum_game_moment.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_forum_libao_center.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_forum_news.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_forum_tool_box.webp create mode 100644 app/src/main/res/drawable/button_round_f0f8fa.xml create mode 100644 app/src/main/res/layout/forum_record_item.xml create mode 100644 app/src/main/res/layout/forum_welfare_item.xml create mode 100644 app/src/main/res/layout/fragment_forum.xml create mode 100644 app/src/main/res/layout/fragment_new_forum_home.xml create mode 100644 app/src/main/res/layout/hot_forum_item.xml create mode 100644 app/src/main/res/layout/layout_article_item_video.xml create mode 100644 app/src/main/res/layout/piece_article_video_control.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7946048092..049c58de7d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -674,6 +674,10 @@ android:screenOrientation="landscape" android:theme="@style/AppFullScreenTheme"/> + + () { private var mAdapter: TaskAdapter? = null - override fun provideListAdapter()= mAdapter + override fun provideListAdapter() = mAdapter ?: TaskAdapter(requireContext()).apply { mAdapter = this } override fun provideListViewModel(): TaskViewModel = viewModelProvider() diff --git a/app/src/main/java/com/gh/gamecenter/entity/ForumDetailEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ForumDetailEntity.kt index 6e8e72c3be..e9f1eec5ab 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/ForumDetailEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/ForumDetailEntity.kt @@ -15,4 +15,13 @@ data class ForumDetailEntity( @SerializedName("zone_tab") var zone: ZoneEntity? = null, var me: MeEntity = MeEntity() -) \ No newline at end of file +) { + fun convertForumDetailEntityToForumEntity(): ForumEntity { + val forumEntity = ForumEntity() + forumEntity.id = id + forumEntity.name = name + forumEntity.game = game + forumEntity.orderTag = System.currentTimeMillis() + return forumEntity + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/ForumEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ForumEntity.kt index 2761bfc5f5..4cc98bed5f 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/ForumEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/ForumEntity.kt @@ -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( diff --git a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt index 78c673a3b8..f8718ab257 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt @@ -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, // 是否已经关注该用户 diff --git a/app/src/main/java/com/gh/gamecenter/eventbus/EBForumRecordChange.java b/app/src/main/java/com/gh/gamecenter/eventbus/EBForumRecordChange.java new file mode 100644 index 0000000000..1d8f86c241 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/eventbus/EBForumRecordChange.java @@ -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; + } +} diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailViewModel.kt index 1de25fe3ff..d4b071a4de 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailViewModel.kt @@ -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>() 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?) { diff --git a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowActivity.kt b/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowActivity.kt deleted file mode 100644 index 76765bc2e9..0000000000 --- a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowActivity.kt +++ /dev/null @@ -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) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowAdapter.kt deleted file mode 100644 index 8c493c522d..0000000000 --- a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowAdapter.kt +++ /dev/null @@ -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(context) { - val entityList = ArrayList() - - fun setListData(updateData: List) { - 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(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(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(binding.root) -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowFragment.kt deleted file mode 100644 index ef0538645e..0000000000 --- a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowFragment.kt +++ /dev/null @@ -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(R.id.list_refresh) - val mListRv by bindView(R.id.list_rv) - val mReuseLoading by bindView(R.id.reuse_ll_loading) - val mNoConnection by bindView(R.id.reuse_no_connection) - val mNoneData by bindView(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 - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowViewModel.kt deleted file mode 100644 index 2876855c76..0000000000 --- a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowViewModel.kt +++ /dev/null @@ -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>() - init { - loadFollowsForum() - } - - fun loadFollowsForum(){ - RetrofitManager.getInstance(getApplication()).api - .getFollowsForum(UserManager.getInstance().userId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response>() { - override fun onResponse(response: List?) { - 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() { - override fun onSuccess(data: ResponseBody) { - onSuccess.invoke() - } - }) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ArticleItemVideoView.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ArticleItemVideoView.kt new file mode 100644 index 0000000000..3c71bf2313 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ArticleItemVideoView.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt index 9397b83b88..911134b7d3 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt @@ -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) diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListAdapter.kt index 4e5fb646db..0e37b68251 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListAdapter.kt @@ -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(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() diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListFragment.kt index fbac34bc7e..9b3903904e 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListFragment.kt @@ -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(), IScrollable { - - private val mNoLoginView by bindView(R.id.reuse_no_login) - private val mNoFollowView by bindView(R.id.reuse_no_follow) - private val mLoginTv by bindView(R.id.loginTv) +class ForumArticleListFragment : LazyListFragment(), 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) { + 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(application) { +class ForumArticleListViewModel(application: Application) : ListViewModel(application) { + + private val mForumDao = AppDatabase.getInstance(HaloApp.getInstance()).forumDao() + val recordForumsLiveData = MutableLiveData>() var sort: String = "time.comment"//排序 time.edit 最新发布 time.comment 最新回复 override fun provideDataObservable(page: Int): Observable>? { - 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 create(modelClass: Class): T { - return ForumArticleListViewModel(HaloApp.getInstance().application, path) as T - } + @SuppressLint("CheckResult") + fun getRecordForums() { + mForumDao.getForum() + .subscribe({ + it?.run { + if (it.isNotEmpty()) recordForumsLiveData.postValue(this) + } + }, { }) } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt new file mode 100644 index 0000000000..16ca7706bd --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt @@ -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) { + 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) { + 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>() + 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() + } + } + } + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumHomeFragment.kt index 2ac021888f..641c3594fc 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumHomeFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumHomeFragment.kt @@ -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)) } } } diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumRecordDao.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumRecordDao.kt new file mode 100644 index 0000000000..35ec1e0875 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumRecordDao.kt @@ -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) { + 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?) { + if (originalForums.isNullOrEmpty()) return + val visitRecords = getAll() + val tempList = arrayListOf() + 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? { + 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 } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumRecordsAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumRecordsAdapter.kt new file mode 100644 index 0000000000..e14941b20c --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumRecordsAdapter.kt @@ -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) + : BaseRecyclerAdapter(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(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumViewModel.kt new file mode 100644 index 0000000000..7ce321d7cb --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumViewModel.kt @@ -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>() + val hotForums = MediatorLiveData>() + + 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>() { + override fun onResponse(response: List?) { + 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>() { + override fun onResponse(response: List?) { + 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() { + 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() { + override fun onSuccess(data: ResponseBody) { + onSuccess.invoke() + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/HotForumsAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/home/HotForumsAdapter.kt new file mode 100644 index 0000000000..45ed048e48 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/home/HotForumsAdapter.kt @@ -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) + : BaseRecyclerAdapter(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(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/NewForumHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/NewForumHomeFragment.kt new file mode 100644 index 0000000000..d578419790 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/home/NewForumHomeFragment.kt @@ -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() + private var mTitleList = arrayListOf("推荐", "论坛") + private var mTabList = arrayListOf() + + 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(R.id.community_edit_article_container).setOnClickListener { + context?.ifLogin("论坛首页", action = { + checkStoragePermissionBeforeAction { + showRegulationTestDialogIfNeeded { + MtaHelper.onEvent("论坛首页", "发布", "发帖子") + startActivity(ArticleEditActivity.getIntent(requireContext(), null)) + dialog.dismiss() + } + } + }) + } + contentView.findViewById(R.id.community_edit_question_container).setOnClickListener { + context?.ifLogin("论坛首页", action = { + checkStoragePermissionBeforeAction { + showRegulationTestDialogIfNeeded { + MtaHelper.onEvent("论坛首页", "发布", "提问") + startActivity(QuestionEditActivity.getIntent(requireContext())) + dialog.dismiss() + } + } + }) + } + contentView.findViewById(R.id.community_edit_video_container).setOnClickListener { + checkStoragePermissionBeforeAction { + showRegulationTestDialogIfNeeded { + MtaHelper.onEvent("论坛首页", "发布", "发视频") + startActivity(VideoPublishActivity.getIntent(requireContext(), null, VideoInsertType.GAME_BBS, mEntrance, "论坛首页")) + dialog.dismiss() + } + } + } + contentView.findViewById(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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/WelfaresAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/home/WelfaresAdapter.kt new file mode 100644 index 0000000000..b080a9f15b --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/home/WelfaresAdapter.kt @@ -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>) + : BaseRecyclerAdapter(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(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/list/ForumListActivity.kt b/app/src/main/java/com/gh/gamecenter/forum/list/ForumListActivity.kt new file mode 100644 index 0000000000..bb19f73862 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/list/ForumListActivity.kt @@ -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) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/list/ForumListAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/list/ForumListAdapter.kt new file mode 100644 index 0000000000..51cff29fcf --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/list/ForumListAdapter.kt @@ -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(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(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/list/ForumListFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/list/ForumListFragment.kt new file mode 100644 index 0000000000..c989ff5952 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/list/ForumListFragment.kt @@ -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() { + + 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() + + 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) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/list/ForumListVIewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/list/ForumListVIewModel.kt new file mode 100644 index 0000000000..fd223c036e --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/list/ForumListVIewModel.kt @@ -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(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> { + 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() { + 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() { + override fun onSuccess(data: ResponseBody) { + onSuccess.invoke() + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchFragment.kt index 5fbdfd8520..01522eb819 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchFragment.kt @@ -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() diff --git a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java index 2a754435d0..7e6e6cbb30 100644 --- a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java +++ b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java @@ -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()) { diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt index a0c740afc6..764bb7e331 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt @@ -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(R.id.tab_title) - val tabCount = view.findViewById(R.id.tab_count) if (tabTitle is CheckedTextView) { tabTitle.text = title } - tabCount.text = if (count == 0) "" else count.toString() return view } diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/BaseAnswerOrArticleItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/BaseAnswerOrArticleItemViewHolder.kt index 5018ba0bac..d884906f80 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/BaseAnswerOrArticleItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/BaseAnswerOrArticleItemViewHolder.kt @@ -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() { + 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 diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt index 562cf67d46..181987f385 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt @@ -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) } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt b/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt index 09361c5e1a..f313a4f0a0 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt @@ -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 diff --git a/app/src/main/java/com/gh/gamecenter/qa/entity/CommunityVideoEntity.kt b/app/src/main/java/com/gh/gamecenter/qa/entity/CommunityVideoEntity.kt index 0f07eceb69..d8e1e40c23 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/entity/CommunityVideoEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/entity/CommunityVideoEntity.kt @@ -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 \ No newline at end of file + var height: Int = 0, + //本地数据 + @IgnoredOnParcel + var videoIsMuted: Boolean = false //是否静音标记 +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index 58f0f2087a..1bb3a24de1 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -2627,6 +2627,12 @@ public interface ApiService { @GET("./bbses:hot") Observable> getHotForum(); + /** + * 热门论坛列表 + */ + @GET("./bbses:hot") + Observable> getHotForumWithPage(@Query("page") int page); + /** * 获取论坛分类 */ diff --git a/app/src/main/java/com/gh/gamecenter/room/AppDatabase.java b/app/src/main/java/com/gh/gamecenter/room/AppDatabase.java index 12b9b51c84..859d96c1ef 100644 --- a/app/src/main/java/com/gh/gamecenter/room/AppDatabase.java +++ b/app/src/main/java/com/gh/gamecenter/room/AppDatabase.java @@ -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() diff --git a/app/src/main/java/com/gh/gamecenter/room/converter/SimpleGameConverter.kt b/app/src/main/java/com/gh/gamecenter/room/converter/SimpleGameConverter.kt new file mode 100644 index 0000000000..2ae56bf945 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/room/converter/SimpleGameConverter.kt @@ -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() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/room/dao/ForumDao.kt b/app/src/main/java/com/gh/gamecenter/room/dao/ForumDao.kt new file mode 100644 index 0000000000..92be2d4d8a --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/room/dao/ForumDao.kt @@ -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> + + @Delete + fun deleteForum(answer: ForumEntity) + +} diff --git a/app/src/main/java/com/gh/gamecenter/video/label/VideoLabelActivity.kt b/app/src/main/java/com/gh/gamecenter/video/label/VideoLabelActivity.kt index 3b6e647f50..c2f1c2bde5 100644 --- a/app/src/main/java/com/gh/gamecenter/video/label/VideoLabelActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/video/label/VideoLabelActivity.kt @@ -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() { diff --git a/app/src/main/res/drawable-xxhdpi/community_edit_icon.webp b/app/src/main/res/drawable-xxhdpi/community_edit_icon.webp deleted file mode 100644 index 55f98b4ffb2a28d835e0f6620fb8be131088bf5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11650 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 MnyjI)000000Ldnz=Kufz diff --git a/app/src/main/res/drawable-xxxhdpi/community_edit_icon.webp b/app/src/main/res/drawable-xxxhdpi/community_edit_icon.webp new file mode 100644 index 0000000000000000000000000000000000000000..58ae8dd724fcbef4e2059f400095324ddeacd7f3 GIT binary patch literal 13086 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_video_full_screen.webp b/app/src/main/res/drawable-xxxhdpi/ic_article_video_full_screen.webp new file mode 100644 index 0000000000000000000000000000000000000000..5dbb2888ad1521b38c63f440235fc5a7f0fbad1a GIT binary patch literal 870 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 W{lGVw&j6?Z0000fP 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_forum_accelerator.webp b/app/src/main/res/drawable-xxxhdpi/ic_forum_accelerator.webp new file mode 100644 index 0000000000000000000000000000000000000000..aadb56309329842f1af8fb161b673685ae4691c9 GIT binary patch literal 3366 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_forum_detail_game_zone_left.webp b/app/src/main/res/drawable-xxxhdpi/ic_forum_detail_game_zone_left.webp index 169b4b849aba4093d567f56bcc1e4a0aab00c032..b1472c908f825a0e3d1d0891c3c786b08a9c53fb 100644 GIT binary patch literal 3014 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 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_forum_game_moment.webp b/app/src/main/res/drawable-xxxhdpi/ic_forum_game_moment.webp new file mode 100644 index 0000000000000000000000000000000000000000..992d3d0d126f19bde3114ca5e9f65dd2f1db2e33 GIT binary patch literal 3420 zcmV-i4Wsf>Nk&Fg4FCXFMM6+kP&il$0000G0002L006%L06|PpNLT^@00D2Iwv8k; z`Lp*-5k?;o;gB+fz6jmRDrA0V_UEyPlzfNig@i$tZQD*NUCBAa^Fk@+$nAdvO$6P4 zHQYw@e*(lv4L2)gv)b;@>g}JoT{W`ITtmD~Gpd%I`oLUPk@*I!qQ0sR&bqKBH4EiQ zef*OQITbBkD-fA#Q~2c@1tfEAbbhPAZ2fWB^G?CZxjmxzpdj7HW6>)GYo(9EStwxX zjKJF|Xm=beI4W=%43u0Hyi5l9bqZi60|XZZF@xT`qXL;;PtH!kymNZd7Yb!SCI1wZG#!LN2vlmeK1?2#@W44!5-d| zxXC-#3AdAVQz+nhQzKWCG_T0f6pVh*Q?SCWB3ta1G&<~PxIgfjp~n)vQlcmSq1UX? zTW!(X?$P5Jy|eoM|NH;%|G)qL@BbOSGtuJ~z3mFURfAq5(UT>5WriMI^k{V0(GW}Q zmSlxpMMl_B(7Yl?Q;;=sHAxo8@y0sgcCv0Lag)3o;uhYUtx@Cb9#hm(KGZgtQG3K3 zGm0m*7O_@)hJJ?^eewJpFNzoKJzBJ1VT=~V>wj2PqDOs!6!kvn>~PvS?AJS@L{Ib` zTrgrF`cFE9n1~^N7krqAVS^(&48+jh4x1gt@Xi7mI%16aA1>6zNaF)0`&f+Eo_Ba~ zZi`X-EgG%Qv1|DT3FexZ;4fXHz*G|xorUuB`A#yVn6g#W*H6Z}u*CGusA{`U#I}k| z@iq-ND`m6V?$7V<%108l&todGJq0Kfn~F&K(NA|as^tTcEa z0|c?RaJZOp3!m}5!B{FeEKw7)s~ult$)OP$pMbqD#M71E4*}GYwbVh_(9$){CE6T_SgXY)B2bB z54W$FiIm+9qT;`@fH6q0N@hb(~lhP-f%`qZXx%o}s=dfUD>0)X^l;2?KKYJ<3qNf_{fB+hIC;C)_ z4bbG2wCw;a$8J0nYVP>(zr(@N9BqAjUv1kmm1tETDTU2*D+Q}d5+X)!YMVS>ysVuO z4bA-DJ_uCt*qrt7Wayii&Z|vzWmav)7E1k;_(Lt>*Xzo-*4~Vcf6) z0RI2sg}o`7sOv|##YpP;1njSvhcvax7AbHS|LfoEq^aguZlpoZr|RGKnn=-czD=0S zH5$ENOepj8V{jRqajZ$&qEY@v@#5DZvT3iuV8tIG#C{Akm6VGM-CYg_AJMWOHv~rD z*@xB&{=5s5FF@UQm|6+-B+E;}h#kAw`Tducc-U@q__X!FPpNUt*w-B;#YRzhe}SCR zY{Ml#2m5!{lVO%$)+{QAf#z(3PG)IjHZ#;j}}>8Q167)yFm zMd#!APD}pf0$#Bu3!zhPRy#TDXdcC0okS1&YmAnu9*Pf|g{xzrJBRcWt)o)vMUb@f z)WTIvr0=W9nWZcgBGc1i%yIzR?X&^=+r^J2_Sq5LBmZ?s@55QP-W8Nb@_xF{rKmxj zz41bsE!2@gG$t7wcgjo&z=}_PyDMA(07PMfPWUo@lPAyfQc7aYl0E0&It2eGXaZFd zStIhhnMxsX%t^#$;zao=9aPq`rg?U7m@`Xj%02Lhn)_i2xbeB?A=V5xk7B;3U(~a& z16oLe*gpa#Ef>=p*~m&|)yfBe17733X+}?`-`Cm0@dV4OHbIS#L@I0pJHy-*Vow5G3 zk}tADi$5kaxyF^rNH$D^TLY3gz&~jzbYP$2ZZz|`k*k@WDqQJUT% zBK1M}rkQx0lDK|f(z?}!w43RHuF-^OpGAD%O`-=1ff}@^t3B8w4oP<&WnF*~sTUUV zN~TZ~Grct9`X4uH+Y>SwVMe3u!whIAZ^dKHreQv-r;ZYd!MG$HOK~tW#hy-j=<+RT zx%ZbU!q{FxYXe^O8!NaWcp4|Gdpe%~8*MN8rKoQgIU0p4zGYQOSslfJU~3qPeqTiR z>plg05cYkG-Y|QZ?D(G!wflwB9MZv<79?B$aE8s z^MbltwxttPlX*l+Jm0+S?4me}?A#}f*c(i|J-Q~}@w%V6%_E&XMrkycIU8uQ%JUDw za>;b(doC72Y*NcT5pp;$#ye>PDJgB_Ov%O@XJSx*4b^cSJ8}=LmGQPopLoP^O?Iy3 zM8Zs86gjBPSG%sPXr9#aBYdb#9N&-uwX0G4gCS7=ubFz4DsQt4o~7dO+vJ?;&~h|~ zApF73N#LH6V+zZd1laKr&KNx-kU8s=s5NdK2)Jr+PP^2y{&;FDkB@D+;(ZHu=r){5 zVx2l_kJCB-G}yXB@P@YDg^0+wJnXZUyVe-o+=@v11`?zHrJjVzOMoE2MSJkP`1Vpy z|9>4ayPcCO(u_tde+Rw~9kt{h0rZ_}nfTkD2>tmBr%(IO z2P|hz?X%U&kv0KJ zanaYveyDb2*9<$bF3TDjI(S zR%iJv)kS;yOV9}^i(@TQUBZ44=Y#isx1m6`O9^|G`Nv&<__mKe_0jzjF2^bWcq0ha z6&vRp3Wod$wwbD6i6@W08*p*q;1}5bb(0z1AxjCtV5E|tJMS$b7c{@v6nv@IYGO_r;Cq0Zdcq?AsNhT4xgs-j-wSgrFkaeY*+Xp=|j{o8TD-E}#I5Q%FO~ zSsa_hrunDB1O6$V7L%io!efIg^U>LDQ(aY|2r8QAA=ki%5f79UX0BTgpkKltHxYgf z!_+ECJ?WCj(8)I+zy*D|T||32`m#8~c{&*BNl(@jYGr-SxSmGG#DHm+WPxMn50hsD zUWdD&t&=Vh` z%f#;M*ZY~gJXV34)TcFY?zRunK~|o$LrDhF241UD)}%k zh-FP=2xVvgwje6Yu}u65T-6sZRbg63YJTQ{aqja(@oN=L>zDMEt1bS`#8H2+(@ZC}yBtzWTvXO)yqHrKjZf2ab$9$XyHaY<3$yIz~T4 z)M->h9)zYJ;ENu~16;QR@7B|6V3m@~KY_s!vVZq&354yFo^Ii32r$j(`ij(YaM?`z zpaiW~iMEH96cn3JGbm{kr!_B{9V#>ZOvHwj_WlG-9a`UcXeWxUat7UAsis`hNcR&E4M20C(s_}RGt@mHmQV|^bCQ;~o zLZ^{1`{>Kpab@;&AmPlEs%01tyTV~k4)ZHa*K|ywBK^kSfSH!L#*o^%l5$^5^TL?^ zaj<)^enQ|q3+1?_*qdLC52~#Q_Uo)n&hb72L)Ft3MBkJM?DhG_%=0_`jAg_s)g}JoT{W`ITtmD~Gpd%I`oLUPk@*I!qQ0sR&bqKBH4EiQ zef*OQITbBkD-fA#Q~2c@1tfEAbbhPAZ2fWB^G?CZxjmxzpdj7HW6>)GYo(9EStwxX zjKJF|Xm=beI4W=%43u0Hyi5l9bqZi60|XZZF@xT`qXL;;PtH!kymNZd7Yb!SCI1wZG#!LN2vlmeK1?2#@W44!5-d| zxXC-#3AdAVQz+nhQzKWCG_T0f6pVh*Q?SCWB3ta1G&<~PxIgfjp~n)vQlcmSq1UX? zTW!(X?$P5Jy|eoM|NH;%|G)qL@BbOSGtuJ~z3mFURfAq5(UT>5WriMI^k{V0(GW}Q zmSlxpMMl_B(7Yl?Q;;=sHAxo8@y0sgcCv0Lag)3o;uhYUtx@Cb9#hm(KGZgtQG3K3 zGm0m*7O_@)hJJ?^eewJpFNzoKJzBJ1VT=~V>wj2PqDOs!6!kvn>~PvS?AJS@L{Ib` zTrgrF`cFE9n1~^N7krqAVS^(&48+jh4x1gt@Xi7mI%16aA1>6zNaF)0`&f+Eo_Ba~ zZi`X-EgG%Qv1|DT3FexZ;4fXHz*G|xorUuB`A#yVn6g#W*H6Z}u*CGusA{`U#I}k| z@iq-ND`m6V?$7V<%Qkb408 zVD|w26Z{YM6a0T*57l4j9>71He{%no{!`yS&^ElM>}2iI6IPXpNw z7Nv(T3T;W+Wam7B2K#FrnG>@)h>|gECK- zNB-9z4B2VfJCb4NFv}@4jfpZ^gk4zknjGXeA9kEA2lAj@4XUNiW_tiHb775sS>*L; zOB6CJPas!p$i#;+1S5#Ht;widhYJ=}FvoN}^f)+k6mkaCp1m)|!9H+~V+a5M{{JrE zHd+z70!l^N(WA%A$C{UTBT%+Lw2`CPzXn(z+z;{B^w$+O74;B)CPn^JF&t*{1pwGz zf0eC&`gFv;XTK>1s^qC*!xF;1*=i<2zO*{e<)bDsBPwySRA9lUYP(Vh+(G@^%AOGr zg%+z#`taWI6($54LG?OD^x6x5`fvky7yNNRaqco{6ngeK%XhGAt@D}w5p(}zD^Exs zj37c2^}ufzJGlbV@p66|>gHZ2=eKh5vBA^n%6IanSt&7g5M|r82*mxJevqTjK2yRE zeGUEH1U7Cf#cM5a595r;{GOe4gqm3=&@{mRNyBqk;7vgqsjn_ekP-hB4;Q}ZsJi^w za~`02of5pocI<@8RI4wax@4G9>64!bi4Wn>_078j-y8;11m77s4!L@+?i^>RFX$w0 zU{0a-`C|#RX`fbf_#&V60}iV8sZgBh#(qDQy3Cv8U8}m!??tCql&i9^A}Tz715qLC zv1gwVLVu>qM5nJL_@aAwyPA!Tz!{8v3;+OOy{5B-q&jY9K2HnfoM%h13QQLC=YMwZ zKWrm#1$^Td(>0`d36#$a8OUR(ZjhUeU?bz&;>bCiZriSx=4C9}N`UfG?XSgC37}bP zqH87F9x4!JVSJxuR^T*q!6Rq|;$4>ULzrJ75-!Q(| z#+DUJ(kZ_r{leZX&WNEbIsQ7>*)C5+>%)1=Yt!wpk`S`*`$V;r&CB>or))UfYKwRl z$i+45k*-+Y(!lP${I-&8dy49qVmq@ccHNR!YYe3uh^XdFcdl@Gol`NO&KUOMMb|d# z$3{h2A4;kIwF6LTPY4FmNGc2s^1~G_gFrL^7HVanKI=g2ZNc3&0V=phjCQGb7qfIT z5FEF~KzCG0V2g9Vh61eeN^MfWcCOUCvP!OVb0 z@VL8@eje8%asOaL+U|nk>E^CLOzX?Dk=4MvH(q^)sGc_RJ$ICCI2C|$FBcM=J=o)!F} z6ga#mLdLlCi{zgx-KAsFB2s_kKxkS%LJ=DIXQnslU7_?7>u)5(Vi|oQR0W69_Gr$o z(X}|?Mb_497jhZ&u1o~y&1e~<6M)pe7T0+KFE8u{O~4zj5uy!6g;;ye*6TK1*{TX~ zRfK)>mxRcy6j5tx;$_uk9bQ!pIUtTY%5y(!i44S!!s<%3+(w{wkgGBn&YaEdU{s5r zNzrc)q@ZWa#_MLf4(SKA;>FCk$bY#n z9ecL-6S3E>9>FX;TAIJgN(E~GBzz%hU^V53< zaaOAwuhg3QKv4*C0LZ4Nj~0Ao;Y`#V#rSwHbmTazv!>~wcKwRF;<72n%&vVLEnZTm z#aNJhv4)tTyyk~tJ4UyLvaWWoiNF98;>Wle7vH3}7tdRx-TyL@CF7Pdydd=5r(ZOD zajDMgwGI$3?c5@q;uY>-7y(N^L%8mG8VD)^FuS9e{=IIwUq(7m#qf7>T1;?DA@0lp z60OjdWXqmL70x5Gqb7RMS_wBKEh`!A5`}_w7Haa;q&Rs4r@RTUFKgG$dahBFx$wTV zl?O3#+ZFgDkP=UO>JGe&SDmEH9YGK|^H{{$!|(lm3a*L(p*;ko1-->ELIv5tQ!X}l zv_jrhf%u=`jCx=?;A)jXUW z#CRy6e2izJww0$Txx`R?pZkb#5>qPN1HHGe_LQ7j#t}z_KsLHaj6+?2SVsHq^! zjdcxHfVgRjT!;lvYv-|x>z9Q1?7cDMe&`E&ti$KY{4iGEtLt3-jW|~YnAHOC6{BTm zQ?2eiLSSIg;I^`%lov>J$KDLmpqp+hLM+lerXR5n4r=fL)l=Y^Xwf!7 I3PCIY0N^6rHUIzs literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_forum_news.webp b/app/src/main/res/drawable-xxxhdpi/ic_forum_news.webp new file mode 100644 index 0000000000000000000000000000000000000000..44ff7586fc73adaa41ce960db8da6c8f80af704b GIT binary patch literal 2602 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 MMg6_a=#Ud&0FlNnYXATM literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_forum_tool_box.webp b/app/src/main/res/drawable-xxxhdpi/ic_forum_tool_box.webp new file mode 100644 index 0000000000000000000000000000000000000000..8d345a994ccd45750780122ed350fe338e4f4880 GIT binary patch literal 3026 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 + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/community_answer_item.xml b/app/src/main/res/layout/community_answer_item.xml index 7456986130..f75193cd88 100644 --- a/app/src/main/res/layout/community_answer_item.xml +++ b/app/src/main/res/layout/community_answer_item.xml @@ -21,7 +21,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" - android:paddingLeft="12dp" + android:paddingLeft="11dp" android:paddingRight="20dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" @@ -31,6 +31,7 @@ android:id="@+id/top_line" android:layout_width="match_parent" android:layout_height="@dimen/cutting_line" + android:layout_marginLeft="9dp" android:background="@color/cutting_line" android:visibility="gone" app:layout_constraintTop_toTopOf="parent" @@ -50,26 +51,27 @@ android:id="@+id/user_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="12dp" - app:avatar_width="32dp" + android:layout_marginTop="11dp" + app:avatar_width="36dp" app:badge_width="12dp" app:border_color="@color/black_alpha_10" app:border_width="1px" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/top_line" - tools:layout_height="48dp" - tools:layout_width="48dp" /> + tools:layout_height="54dp" + tools:layout_width="54dp" /> + + + + + + - + android:gravity="center_vertical" + android:orientation="horizontal" + android:background="@drawable/bg_shape_f5_radius_999"> + + + + + + + + android:orientation="vertical"> - + - + - + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/forum_record_item.xml b/app/src/main/res/layout/forum_record_item.xml new file mode 100644 index 0000000000..a7a9253ce2 --- /dev/null +++ b/app/src/main/res/layout/forum_record_item.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/forum_welfare_item.xml b/app/src/main/res/layout/forum_welfare_item.xml new file mode 100644 index 0000000000..f27e95ecc9 --- /dev/null +++ b/app/src/main/res/layout/forum_welfare_item.xml @@ -0,0 +1,36 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_forum.xml b/app/src/main/res/layout/fragment_forum.xml new file mode 100644 index 0000000000..56308c37a8 --- /dev/null +++ b/app/src/main/res/layout/fragment_forum.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_forum_list.xml b/app/src/main/res/layout/fragment_forum_list.xml index f6014ea42c..a91edd33d8 100644 --- a/app/src/main/res/layout/fragment_forum_list.xml +++ b/app/src/main/res/layout/fragment_forum_list.xml @@ -1,5 +1,6 @@ @@ -9,12 +10,68 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:overScrollMode="never" + android:scrollbars="none"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/hot_forum_item.xml b/app/src/main/res/layout/hot_forum_item.xml new file mode 100644 index 0000000000..b351baaeb9 --- /dev/null +++ b/app/src/main/res/layout/hot_forum_item.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_article_item_video.xml b/app/src/main/res/layout/layout_article_item_video.xml new file mode 100644 index 0000000000..4432b9ef34 --- /dev/null +++ b/app/src/main/res/layout/layout_article_item_video.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/piece_article_video_control.xml b/app/src/main/res/layout/piece_article_video_control.xml new file mode 100644 index 0000000000..a608e268a1 --- /dev/null +++ b/app/src/main/res/layout/piece_article_video_control.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/piece_community_vote_and_comment.xml b/app/src/main/res/layout/piece_community_vote_and_comment.xml index 40367d5bc8..98357099ae 100644 --- a/app/src/main/res/layout/piece_community_vote_and_comment.xml +++ b/app/src/main/res/layout/piece_community_vote_and_comment.xml @@ -22,7 +22,7 @@ android:layout_height="match_parent" android:layout_gravity="center" android:drawableLeft="@drawable/community_comment_count" - android:drawablePadding="8dp" + android:drawablePadding="4dp" android:gravity="center" android:paddingTop="20dp" android:paddingBottom="20dp" diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 566005e321..97251e4145 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -260,6 +260,8 @@ #F67722 #4B4B4B #FF925C + #3087D9 + #C0C6CC #99666666 #6621282E