From 37bca1ee1c7fc2bcde71bfb7cf48fbe4fc315ebf Mon Sep 17 00:00:00 2001 From: kehaoyuan Date: Wed, 18 Jul 2018 17:32:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=20ListViewModel=20=E6=89=80=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E7=9A=84=20ListRepository=20=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E5=88=B0=20ListViewModel=20=E4=B8=AD,BaseList=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E6=95=B4=E7=90=86=E5=88=86=E5=B1=82=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 2 +- .../com/gh/gamecenter/SubjectActivity.java | 23 +-- .../gh/gamecenter/baselist/ListViewModel.java | 15 ++ .../category/CategoryListTabFragment.kt | 10 +- .../com/gh/gamecenter/entity/SubjectData.kt | 13 ++ ...tHeadEntity.kt => SubjectSettingEntity.kt} | 6 +- .../gamecenter/kuaichuan/HtmlUriHandler.java | 2 +- .../retrofit/service/ApiService.java | 4 +- .../subject/SubjectTileFragment.java | 10 +- .../subject/SubjectWrapperFragment.java | 10 +- .../subject/refactor/SubjectActivity.kt | 86 ++++++++ .../subject/refactor/SubjectAdapter.kt | 190 ++++++++++++++++++ .../subject/refactor/SubjectListFragment.kt | 106 ++++++++++ .../subject/refactor/SubjectListViewModel.kt | 34 ++++ .../subject/refactor/SubjectViewModel.kt | 95 +++++++++ .../refactor/tab/SubjectTabFragment.kt | 47 +++++ .../refactor/tile/SubjectTileFragment.kt | 145 +++++++++++++ .../refactor/tile/SubjectTypeListAdapter.kt | 67 ++++++ app/src/main/res/layout/activity_subject.xml | 31 +++ .../main/res/layout/fragment_subject_tab.xml | 23 +++ .../res/layout/fragment_subject_tiled.xml | 18 +- channel.txt | 10 + 22 files changed, 904 insertions(+), 43 deletions(-) create mode 100644 app/src/main/java/com/gh/gamecenter/entity/SubjectData.kt rename app/src/main/java/com/gh/gamecenter/entity/{SubjectHeadEntity.kt => SubjectSettingEntity.kt} (66%) create mode 100644 app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectActivity.kt create mode 100644 app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectAdapter.kt create mode 100644 app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectListFragment.kt create mode 100644 app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectListViewModel.kt create mode 100644 app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectViewModel.kt create mode 100644 app/src/main/java/com/gh/gamecenter/subject/refactor/tab/SubjectTabFragment.kt create mode 100644 app/src/main/java/com/gh/gamecenter/subject/refactor/tile/SubjectTileFragment.kt create mode 100644 app/src/main/java/com/gh/gamecenter/subject/refactor/tile/SubjectTypeListAdapter.kt create mode 100644 app/src/main/res/layout/activity_subject.xml create mode 100644 app/src/main/res/layout/fragment_subject_tab.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 44a8572aa4..82834336f7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -107,7 +107,7 @@ android:name = "com.gh.gamecenter.ConcernActivity" android:screenOrientation = "portrait" /> extends Ba if (previousData == null || curStatus == LoadStatus.INIT) { previousData = new ArrayList<>(); } + + // 针对游戏的一些操作(过滤隐藏APK,增加下载数据) + if (response.size() > 0 && response.get(0) instanceof GameEntity) { + for (LD entity : response) { + GameEntity game = (GameEntity) entity; + game.setEntryMap(DownloadManager.getInstance(HaloApp.getInstance() + .getApplication()).getEntryMap(game.getName())); + ApkActiveUtils.filterHideApk(game); + } + } + previousData.addAll(response); mListLiveData.postValue(previousData); } diff --git a/app/src/main/java/com/gh/gamecenter/category/CategoryListTabFragment.kt b/app/src/main/java/com/gh/gamecenter/category/CategoryListTabFragment.kt index e83ec6bfe7..5fb0bdb5bf 100644 --- a/app/src/main/java/com/gh/gamecenter/category/CategoryListTabFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/category/CategoryListTabFragment.kt @@ -32,9 +32,9 @@ class CategoryListTabFragment : BaseFragment(), SubjectTypeAdapter.OnSel lateinit var mSubjectRv: RecyclerView @BindView(R.id.subject_appbar) lateinit var mAppbar: AppBarLayout - @BindView(R.id.subject_tabbar_hot_tv) + @BindView(R.id.subject_tabbar_hottest) lateinit var mTabbarHotTv: TextView - @BindView(R.id.subject_tabbar_new_tv) + @BindView(R.id.subject_tabbar_newest) lateinit var mTabbarNewTv: TextView val OPEN_APPBAR = "openAppBar" @@ -160,10 +160,10 @@ class CategoryListTabFragment : BaseFragment(), SubjectTypeAdapter.OnSel loadData() } - @OnClick(R.id.subject_tabbar_hot_tv, R.id.subject_tabbar_new_tv) + @OnClick(R.id.subject_tabbar_hottest, R.id.subject_tabbar_newest) override fun onClick(view: View) { when (view.id) { - R.id.subject_tabbar_hot_tv -> { + R.id.subject_tabbar_hottest -> { mTabbarHotTv.setTextColor(Color.WHITE) mTabbarHotTv.setBackgroundResource(R.drawable.tabbar_left_bg) mTabbarNewTv.setTextColor(Color.BLACK) @@ -171,7 +171,7 @@ class CategoryListTabFragment : BaseFragment(), SubjectTypeAdapter.OnSel mListOrder = "download:-1" loadData() } - R.id.subject_tabbar_new_tv -> { + R.id.subject_tabbar_newest -> { mTabbarHotTv.setTextColor(Color.BLACK) mTabbarHotTv.setBackgroundDrawable(ColorDrawable(0)) mTabbarNewTv.setTextColor(Color.WHITE) diff --git a/app/src/main/java/com/gh/gamecenter/entity/SubjectData.kt b/app/src/main/java/com/gh/gamecenter/entity/SubjectData.kt new file mode 100644 index 0000000000..3abbd26e3c --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/entity/SubjectData.kt @@ -0,0 +1,13 @@ +package com.gh.gamecenter.entity + +import android.os.Parcelable +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class SubjectData(var subjectId: String?, + var subjectName: String?, + var isOrder: Boolean?, + var listOrder: String?, + var tagType: String?, + var mTileType: String?, + var typeList: List?) : Parcelable diff --git a/app/src/main/java/com/gh/gamecenter/entity/SubjectHeadEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SubjectSettingEntity.kt similarity index 66% rename from app/src/main/java/com/gh/gamecenter/entity/SubjectHeadEntity.kt rename to app/src/main/java/com/gh/gamecenter/entity/SubjectSettingEntity.kt index 8f4b0a3246..d7f79ad940 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/SubjectHeadEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/SubjectSettingEntity.kt @@ -6,16 +6,16 @@ import com.google.gson.annotations.SerializedName * Created by khy on 28/05/17. */ -class SubjectHeadEntity { +class SubjectSettingEntity { @SerializedName("type") - var typeEntity: TypeEntity? = null + var typeEntity: TypeEntity = TypeEntity() var tag: String? = null inner class TypeEntity { - var content: List? = null + var content: MutableList = ArrayList() var layout: String? = null } diff --git a/app/src/main/java/com/gh/gamecenter/kuaichuan/HtmlUriHandler.java b/app/src/main/java/com/gh/gamecenter/kuaichuan/HtmlUriHandler.java index 65f3fe0aee..e45e34c3c4 100644 --- a/app/src/main/java/com/gh/gamecenter/kuaichuan/HtmlUriHandler.java +++ b/app/src/main/java/com/gh/gamecenter/kuaichuan/HtmlUriHandler.java @@ -44,7 +44,7 @@ public class HtmlUriHandler implements KcUriHandler { } homeHtml = baos.toString("UTF-8"); - } catch (IOException e) { + } catch (Exception e) { Utils.log("===加载asset HTML文件异常" + e.toString()); e.printStackTrace(); } 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 40cf84ce54..ef44c81388 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 @@ -23,7 +23,7 @@ import com.gh.gamecenter.entity.SettingsEntity; import com.gh.gamecenter.entity.SignEntity; import com.gh.gamecenter.entity.SlideEntity; import com.gh.gamecenter.entity.SubjectEntity; -import com.gh.gamecenter.entity.SubjectHeadEntity; +import com.gh.gamecenter.entity.SubjectSettingEntity; import com.gh.gamecenter.entity.SubjectRecommendEntity; import com.gh.gamecenter.entity.TagEntity; import com.gh.gamecenter.entity.ToolBoxEntity; @@ -236,7 +236,7 @@ public interface ApiService { * 获取专题数据标题 */ @GET("columns/{column_id}/setting") - Observable getColumnSettings(@Path("column_id") String column_id); + Observable getColumnSettings(@Path("column_id") String column_id); // /** // * 获取界面设置参数 diff --git a/app/src/main/java/com/gh/gamecenter/subject/SubjectTileFragment.java b/app/src/main/java/com/gh/gamecenter/subject/SubjectTileFragment.java index 94ee7574f3..4719dcee62 100644 --- a/app/src/main/java/com/gh/gamecenter/subject/SubjectTileFragment.java +++ b/app/src/main/java/com/gh/gamecenter/subject/SubjectTileFragment.java @@ -41,9 +41,9 @@ public class SubjectTileFragment extends BaseFragment implements SubjectTypeAdap RecyclerView mSubjectRv; @BindView(R.id.subject_appbar) AppBarLayout mAppbar; - @BindView(R.id.subject_tabbar_hot_tv) + @BindView(R.id.subject_tabbar_hottest) TextView mTabbarHotTv; - @BindView(R.id.subject_tabbar_new_tv) + @BindView(R.id.subject_tabbar_newest) TextView mTabbarNewTv; public final static String OPEN_APPBAR = "openAppBar"; @@ -160,10 +160,10 @@ public class SubjectTileFragment extends BaseFragment implements SubjectTypeAdap loadData(); } - @OnClick({R.id.subject_tabbar_hot_tv, R.id.subject_tabbar_new_tv}) + @OnClick({R.id.subject_tabbar_hottest, R.id.subject_tabbar_newest}) public void onClick(View view) { switch (view.getId()) { - case R.id.subject_tabbar_hot_tv: + case R.id.subject_tabbar_hottest: mTabbarHotTv.setTextColor(Color.WHITE); mTabbarHotTv.setBackgroundResource(R.drawable.tabbar_left_bg); mTabbarNewTv.setTextColor(Color.BLACK); @@ -171,7 +171,7 @@ public class SubjectTileFragment extends BaseFragment implements SubjectTypeAdap mListOrder = ""; loadData(); break; - case R.id.subject_tabbar_new_tv: + case R.id.subject_tabbar_newest: mTabbarHotTv.setTextColor(Color.BLACK); mTabbarHotTv.setBackgroundDrawable(new ColorDrawable(0)); mTabbarNewTv.setTextColor(Color.WHITE); diff --git a/app/src/main/java/com/gh/gamecenter/subject/SubjectWrapperFragment.java b/app/src/main/java/com/gh/gamecenter/subject/SubjectWrapperFragment.java index d4ff31a52d..a8e8b7af87 100644 --- a/app/src/main/java/com/gh/gamecenter/subject/SubjectWrapperFragment.java +++ b/app/src/main/java/com/gh/gamecenter/subject/SubjectWrapperFragment.java @@ -13,7 +13,7 @@ import android.widget.LinearLayout; import com.gh.common.constant.Config; import com.gh.common.util.EntranceUtils; import com.gh.gamecenter.R; -import com.gh.gamecenter.entity.SubjectHeadEntity; +import com.gh.gamecenter.entity.SubjectSettingEntity; import com.gh.gamecenter.normal.NormalFragment; import com.gh.gamecenter.retrofit.JSONObjectResponse; import com.gh.gamecenter.retrofit.Response; @@ -124,9 +124,9 @@ public class SubjectWrapperFragment extends NormalFragment { .getColumnSettings(mId) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response() { + .subscribe(new Response() { @Override - public void onResponse(SubjectHeadEntity response) { + public void onResponse(SubjectSettingEntity response) { super.onResponse(response); mLoading.setVisibility(View.GONE); List content = response.getTypeEntity().getContent(); @@ -143,8 +143,8 @@ public class SubjectWrapperFragment extends NormalFragment { }); } - private void initView(SubjectHeadEntity headEntity) { - SubjectHeadEntity.TypeEntity typeEntity = headEntity.getTypeEntity(); + private void initView(SubjectSettingEntity headEntity) { + SubjectSettingEntity.TypeEntity typeEntity = headEntity.getTypeEntity(); if (typeEntity == null) { return; } diff --git a/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectActivity.kt b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectActivity.kt new file mode 100644 index 0000000000..72b075778e --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectActivity.kt @@ -0,0 +1,86 @@ +package com.gh.gamecenter.subject.refactor + +import android.arch.lifecycle.Observer +import android.arch.lifecycle.ViewModelProviders +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.support.v4.app.Fragment +import android.view.View +import com.gh.base.BaseActivity +import com.gh.common.util.DataUtils +import com.gh.common.util.EntranceUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.SubjectData +import com.gh.gamecenter.entity.SubjectSettingEntity +import com.gh.gamecenter.subject.refactor.tab.SubjectTabFragment +import com.gh.gamecenter.subject.refactor.tile.SubjectTileFragment +import com.halo.assistant.HaloApp +import kotterknife.bindView + +class SubjectActivity : BaseActivity() { + + private val mLoading by bindView(R.id.list_loading) + private val mNoConn by bindView(R.id.list_loading) + + private var mViewModel: SubjectViewModel? = null + + override fun getLayoutId(): Int { + return R.layout.activity_subject + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val factory = SubjectViewModel.Factory(HaloApp.getInstance().application, intent.getParcelableExtra(EntranceUtils.KEY_SUBJECT_DATA)) + mViewModel = ViewModelProviders.of(this, factory).get(SubjectViewModel::class.java) + + mViewModel?.subjectSettingLD?.observe(this, Observer { + mLoading.visibility = View.GONE + if (it == null) { + mNoConn.visibility = View.VISIBLE + } else { + initContentView(it) + } + }) + + mViewModel?.subjectNameLD?.observe(this, Observer { + setNavigationTitle(it) + }) + + mNoConn.setOnClickListener({ + mLoading.visibility = View.VISIBLE + mViewModel?.initData() + }) + } + + + private fun initContentView(entity: SubjectSettingEntity) { + val transaction = supportFragmentManager.beginTransaction() + val fragment: Fragment = if ("tile" == entity.typeEntity.layout) { + SubjectTileFragment() + } else { + SubjectTabFragment() + } + val bundle = Bundle() + bundle.putParcelable(EntranceUtils.KEY_SUBJECT_DATA, mViewModel?.subjectData) + fragment.arguments = bundle + transaction.replace(R.id.subject_content, fragment) + transaction.commitAllowingStateLoss() + } + + + companion object { + /** + * 启动专题页面 + */ + fun startSubjectActivity(context: Context, id: String?, name: String?, isOrder: Boolean, entrance: String?) { + DataUtils.onMtaEvent(context, "详情页面", "专题详情", name) + + val intent = Intent(context, SubjectActivity::class.java) + intent.putExtra(EntranceUtils.KEY_SUBJECT_DATA, SubjectData(id, name, isOrder, null, null, null, null)) + intent.putExtra(EntranceUtils.KEY_ENTRANCE, entrance) + context.startActivity(intent) + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectAdapter.kt b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectAdapter.kt new file mode 100644 index 0000000000..329c8ef330 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectAdapter.kt @@ -0,0 +1,190 @@ +package com.gh.gamecenter.subject.refactor + +import android.content.Context +import android.support.v7.widget.RecyclerView +import android.text.TextUtils +import android.util.SparseArray +import android.view.View +import android.view.ViewGroup +import com.gh.common.constant.ItemViewType +import com.gh.common.exposure.ExposureEvent +import com.gh.common.exposure.ExposureSource +import com.gh.common.exposure.ExposureType +import com.gh.common.exposure.IExposable +import com.gh.common.util.* +import com.gh.gamecenter.GameDetailActivity +import com.gh.gamecenter.NewsDetailActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.SubjectActivity +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.adapter.viewholder.GameImageViewHolder +import com.gh.gamecenter.adapter.viewholder.GameViewHolder +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.databinding.GameItemBinding +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.entity.SubjectData +import com.gh.gamecenter.eventbus.EBDownloadStatus +import com.gh.gamecenter.game.GameItemViewHolder +import com.lightgame.download.DownloadEntity +import java.util.* + +class SubjectAdapter(context: Context, + private val subjectData: SubjectData, + private val mEntrance: String?) : ListAdapter(context), IExposable { + private val mExposureEventSparseArray: SparseArray = SparseArray() + + private val positionAndPackageMap = HashMap() + + override fun setListData(updateData: MutableList?) { + if (updateData != null) { + for (i in 0 until updateData.size) { + var packages = "" + for (apkEntity in updateData[i].getApk()) { + packages += apkEntity.packageName + } + positionAndPackageMap[packages + i] = i + } + } + super.setListData(updateData) + } + + override fun areItemsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean { + return oldItem?.id == newItem?.id + } + + override fun getItemViewType(position: Int): Int { + if (position == itemCount - 1) { + return ItemViewType.ITEM_FOOTER + } + if (position == 0 && mEntityList != null && mEntityList.size > 0 + && !TextUtils.isEmpty(mEntityList[0].image)) { + return ItemViewType.GAME_IMAGE + } + return ItemViewType.GAME_NORMAL + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + ItemViewType.GAME_NORMAL -> { + GameItemViewHolder(GameItemBinding.bind(mLayoutInflater.inflate(R.layout.game_item, parent, false))) + } + ItemViewType.GAME_IMAGE -> { + GameImageViewHolder(mLayoutInflater.inflate(R.layout.game_image_item, parent, false)) + } + else -> { + FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)) + } + } + } + + override fun getItemCount(): Int { + return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1 + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is GameItemViewHolder) { + val gameEntity = mEntityList[position] + + holder.binding.game = gameEntity + holder.binding.subjectTag = subjectData.tagType + holder.initServerType(gameEntity, mContext) + holder.binding.executePendingBindings() + + if (subjectData.isOrder!!) { + var index = 1 + if (!TextUtils.isEmpty(mEntityList[0].image)) index = 0 + holder.binding.gameOrder.visibility = View.VISIBLE + holder.binding.gameOrder.text = (position + index).toString() + } else { + holder.binding.gameOrder.visibility = View.GONE + } + + val exposureSources = ArrayList() + exposureSources.add(ExposureSource("专题", subjectData.subjectName.toString())) + exposureSources.add(ExposureSource("专题详情", subjectData.mTileType + "+" + + if ("-1" == subjectData.listOrder) "最新" else "最热")) + gameEntity.sequence = position + 1 + val event = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE) + mExposureEventSparseArray.put(position, event) + + holder.itemView.setOnClickListener { v -> + DataCollectionUtils.uploadClick(mContext, "列表", subjectData.subjectName, gameEntity.name) + GameDetailActivity.startGameDetailActivity(mContext, gameEntity, + StringUtils.buildString(mEntrance, + "+(", subjectData.subjectName, ":列表[", subjectData.mTileType, "=", + if ("-1" == subjectData.listOrder) "最新" + else "最热", "=", (position + 1).toString(), "])"), event) + } + DownloadItemUtils.setOnClickListener(mContext, holder.binding.downloadBtn, + gameEntity, position, this, + StringUtils.buildString(mEntrance, "+(", subjectData.subjectName, + ":列表[", subjectData.mTileType, "=", + if ("-1" == subjectData.subjectName) "最新" + else "最热", "=", (position + 1).toString(), "])"), + StringUtils.buildString(subjectData.subjectName, ":", gameEntity.name), event) + DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding), true) + } else if (holder is GameImageViewHolder) { + holder.line.visibility = View.GONE + val widthPixels = mContext.resources.displayMetrics.widthPixels + val gameEntity = mEntityList[position] + ImageUtils.getInstance().display(holder.image, gameEntity.image, widthPixels) + + if (!TextUtils.isEmpty(gameEntity.des)) { + holder.gameDes.visibility = View.VISIBLE + holder.gameDes.text = gameEntity.des + } + holder.itemView.setOnClickListener { + DataCollectionUtils.uploadClick(mContext, "头图", subjectData.subjectName) + when (gameEntity.type) { + "game" -> GameDetailActivity.startGameDetailActivity(mContext, gameEntity.link, + mEntrance + "(" + subjectData.subjectName + ":大图)") + "news" -> { + // 统计阅读量 + NewsUtils.statNewsViews(mContext, gameEntity.link) + val intent = NewsDetailActivity.getIntentById(mContext, gameEntity.link, + mEntrance + "(" + subjectData.subjectName + ":大图)") + mContext.startActivity(intent) + } + "column" -> SubjectActivity.startSubjectActivity(mContext, gameEntity.link + , gameEntity.name, false, mEntrance + "(" + subjectData.subjectName + ":大图)") + } + } + } else if (holder is FooterViewHolder) { + holder.initItemPadding() + holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint) + } + } + + + override fun getEventByPosition(pos: Int): ExposureEvent? { + return mExposureEventSparseArray.get(pos) + } + + override fun getEventListByPosition(pos: Int): List? { + return null + } + + fun notifyItemByDownload(download: DownloadEntity) { + for (key in positionAndPackageMap.keys) { + if (key.contains(download.packageName)) { + val position = positionAndPackageMap[key] + if (position != null) { + mEntityList[position].getEntryMap()[download.platform] = download + notifyItemChanged(position) + } + } + } + } + + fun notifyItemAndRemoveDownload(status: EBDownloadStatus) { + for (key in positionAndPackageMap.keys) { + if (key.contains(status.packageName)) { + val position = positionAndPackageMap[key] + if (position != null) { + mEntityList[position].getEntryMap().remove(status.platform) + notifyItemChanged(position) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectListFragment.kt b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectListFragment.kt new file mode 100644 index 0000000000..16afb15371 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectListFragment.kt @@ -0,0 +1,106 @@ +package com.gh.gamecenter.subject.refactor + +import android.arch.lifecycle.ViewModelProviders +import android.os.Bundle +import android.support.v7.widget.RecyclerView +import android.view.View +import com.gh.common.util.EntranceUtils +import com.gh.download.DownloadManager +import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.eventbus.EBDownloadStatus +import com.gh.gamecenter.eventbus.EBPackage +import com.gh.gamecenter.eventbus.EBReuse +import com.gh.gamecenter.subject.SubjectTileFragment +import com.halo.assistant.HaloApp +import com.lightgame.OnTitleClickListener +import com.lightgame.download.DataWatcher +import com.lightgame.download.DownloadEntity +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class SubjectListFragment : ListFragment(), OnTitleClickListener { + + private var mAdapter: SubjectAdapter? = null + private var mScrollTop = false + + private val dataWatcher = object : DataWatcher() { + override fun onDataChanged(downloadEntity: DownloadEntity) { + mAdapter?.notifyItemByDownload(downloadEntity) + } + } + + override fun provideListAdapter(): SubjectAdapter { + if (mAdapter == null) { + mAdapter = SubjectAdapter(context!!, + arguments?.getParcelable(EntranceUtils.KEY_SUBJECT_DATA)!!, + arguments?.getString(EntranceUtils.KEY_ENTRANCE)) + } + return mAdapter as SubjectAdapter + } + + override fun provideListViewModel(): SubjectListViewModel { + val factory = SubjectListViewModel.Factory(HaloApp.getInstance().application + , arguments?.getParcelable(EntranceUtils.KEY_SUBJECT_DATA)!!) + return ViewModelProviders.of(this, factory).get(SubjectListViewModel::class.java) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mListRv.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + val position = mLayoutManager.findFirstCompletelyVisibleItemPosition() + if (mScrollTop && position == 0 && newState == RecyclerView.SCROLL_STATE_IDLE) { + mScrollTop = false + EventBus.getDefault().post(EBReuse(SubjectTileFragment.OPEN_APPBAR)) + } + } + + override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + val position = mLayoutManager.findFirstCompletelyVisibleItemPosition() + if (position == 0 && Math.abs(dy) > 10) { + EventBus.getDefault().post(EBReuse(SubjectTileFragment.OPEN_APPBAR)) + } + } + }) + } + + override fun onTitleClick() { + if (mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0 || provideListAdapter().itemCount == 0) { + EventBus.getDefault().post(EBReuse(SubjectTileFragment.OPEN_APPBAR)) + } else { + mLayoutManager.smoothScrollToPosition(mListRv, null, 0) + mScrollTop = true + } + } + + override fun onResume() { + if (isEverPause && mAdapter != null) mAdapter?.notifyDataSetChanged() + super.onResume() + DownloadManager.getInstance(context).addObserver(dataWatcher) + } + + override fun onPause() { + super.onPause() + DownloadManager.getInstance(context).removeObserver(dataWatcher) + } + + // 下载被删除事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(status: EBDownloadStatus) { + if ("delete" == status.status) { + mAdapter?.notifyItemAndRemoveDownload(status) + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(busFour: EBPackage) { + if ("安装" == busFour.type || "卸载" == busFour.type) { + mAdapter?.notifyDataSetChanged() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectListViewModel.kt b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectListViewModel.kt new file mode 100644 index 0000000000..1b3aa308a0 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectListViewModel.kt @@ -0,0 +1,34 @@ +package com.gh.gamecenter.subject.refactor + +import android.app.Application +import android.arch.lifecycle.ViewModel +import android.arch.lifecycle.ViewModelProvider +import com.gh.common.util.UrlFilterUtils +import com.gh.gamecenter.baselist.ListViewModel +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.entity.SubjectData +import com.gh.gamecenter.retrofit.RetrofitManager +import io.reactivex.Observable + +class SubjectListViewModel(application: Application, + private val subjectData: SubjectData) : ListViewModel(application) { + + + override fun provideDataObservable(page: Int): Observable> { + return RetrofitManager.getInstance(getApplication()).api.getColumn(subjectData.subjectId + , UrlFilterUtils.getFilterQuery("publish", subjectData.listOrder) + , UrlFilterUtils.getFilterQuery("type", subjectData.mTileType), page) + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData, { mResultLiveData.postValue(it) }) + } + + + class Factory(private val mApplication: Application, private val subjectData: SubjectData) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return SubjectListViewModel(mApplication, subjectData) as T + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectViewModel.kt b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectViewModel.kt new file mode 100644 index 0000000000..c9aec129e9 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/subject/refactor/SubjectViewModel.kt @@ -0,0 +1,95 @@ +package com.gh.gamecenter.subject.refactor + +import android.app.Application +import android.arch.lifecycle.AndroidViewModel +import android.arch.lifecycle.MutableLiveData +import android.arch.lifecycle.ViewModel +import android.arch.lifecycle.ViewModelProvider +import android.text.TextUtils +import com.gh.common.constant.Config +import com.gh.gamecenter.entity.SubjectData +import com.gh.gamecenter.entity.SubjectSettingEntity +import com.gh.gamecenter.retrofit.JSONObjectResponse +import com.gh.gamecenter.retrofit.Response +import com.gh.gamecenter.retrofit.RetrofitManager +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import org.json.JSONObject +import retrofit2.HttpException + +class SubjectViewModel(application: Application, var subjectData: SubjectData?) : AndroidViewModel(application) { + + val subjectNameLD = MutableLiveData() + val subjectSettingLD = MutableLiveData() + + init { + initData() + } + + fun initData() { + if (subjectData != null) { + if (subjectData?.subjectName.isNullOrEmpty()) { + loadSubjectName() + } else { + subjectNameLD.postValue(subjectData?.subjectName) + loadSubjectType() + } + } else { + subjectSettingLD.postValue(null) + } + } + + private fun loadSubjectName() { + RetrofitManager.getInstance(getApplication()).api + .getSubjectName(subjectData?.subjectId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : JSONObjectResponse() { + override fun onResponse(response: JSONObject) { + var name = response.getString("name") + if (!TextUtils.isEmpty(name) && !Config.isShowPlugin()) { + name = name.replace("插件", "游戏") + } + subjectData?.subjectName = name + subjectNameLD.postValue(name) + loadSubjectType() + } + + override fun onFailure(e: HttpException?) { + super.onFailure(e) + subjectNameLD.postValue("专题") + subjectData?.subjectName = "专题" + loadSubjectType() + } + }) + } + + private fun loadSubjectType() { + RetrofitManager.getInstance(getApplication()).api + .getColumnSettings(subjectData?.subjectId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: SubjectSettingEntity?) { + super.onResponse(response) + val content = response!!.typeEntity.content + content.add(0, "全部") + subjectData?.typeList = content + subjectData?.tagType = response.tag + subjectSettingLD.postValue(response) + } + + override fun onFailure(e: HttpException?) { + super.onFailure(e) + subjectSettingLD.postValue(null) + } + }) + } + + + class Factory(private val mApplication: Application, private val subjectData: SubjectData?) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return SubjectViewModel(mApplication, subjectData) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/subject/refactor/tab/SubjectTabFragment.kt b/app/src/main/java/com/gh/gamecenter/subject/refactor/tab/SubjectTabFragment.kt new file mode 100644 index 0000000000..8a64c24fb8 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/subject/refactor/tab/SubjectTabFragment.kt @@ -0,0 +1,47 @@ +package com.gh.gamecenter.subject.refactor.tab + +import android.os.Bundle +import android.support.design.widget.TabLayout +import android.support.v4.app.Fragment +import android.support.v4.view.ViewPager +import android.view.View +import com.gh.base.fragment.BaseFragment +import com.gh.common.util.EntranceUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.SubjectData +import com.gh.gamecenter.subject.refactor.SubjectListFragment +import com.lightgame.adapter.BaseFragmentPagerAdapter +import kotterknife.bindView +import java.util.* + +class SubjectTabFragment : BaseFragment() { + + private val mTabLayout by bindView(R.id.subject_tab) + private val mViewPager by bindView(R.id.subject_viewpager) + + + override fun getLayoutId(): Int { + return R.layout.fragment_subject_tab + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val subjectData = arguments?.getParcelable(EntranceUtils.KEY_SUBJECT_DATA) + val tagList = subjectData?.typeList ?: return + + if (tagList.size > 1) { + mTabLayout.visibility = View.VISIBLE + } + val fragments = ArrayList() + for (tag in tagList) { + mTabLayout.addTab(mTabLayout.newTab().setText(tag)) + val element = SubjectListFragment() + element.arguments = arguments?.clone() as Bundle? + fragments.add(element) + } + + val adapter = BaseFragmentPagerAdapter.newInstance(childFragmentManager, fragments, tagList) + mViewPager.adapter = adapter + mTabLayout.setupWithViewPager(mViewPager) + } +} diff --git a/app/src/main/java/com/gh/gamecenter/subject/refactor/tile/SubjectTileFragment.kt b/app/src/main/java/com/gh/gamecenter/subject/refactor/tile/SubjectTileFragment.kt new file mode 100644 index 0000000000..041cc75280 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/subject/refactor/tile/SubjectTileFragment.kt @@ -0,0 +1,145 @@ +package com.gh.gamecenter.subject.refactor.tile + +import android.os.Bundle +import android.support.design.widget.AppBarLayout +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentTransaction +import android.support.v7.widget.GridLayoutManager +import android.support.v7.widget.RecyclerView +import android.text.TextUtils +import android.view.MotionEvent +import android.view.View +import android.widget.CheckedTextView +import butterknife.OnClick +import com.gh.base.fragment.BaseFragment +import com.gh.common.util.EntranceUtils +import com.gh.common.util.StringUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.SubjectData +import com.gh.gamecenter.eventbus.EBReuse +import com.gh.gamecenter.normal.ToolbarController +import com.gh.gamecenter.subject.SubjectTileFragment +import com.gh.gamecenter.subject.refactor.SubjectListFragment +import kotterknife.bindView +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class SubjectTileFragment : BaseFragment() { + + private val mAppbar by bindView(R.id.subject_appbar) + private val mTypeList by bindView(R.id.subject_type_list) + private val mBarHottest by bindView(R.id.subject_tabbar_hottest) + private val mBarNewest by bindView(R.id.subject_tabbar_newest) + + private var mSubjectData: SubjectData? = null + +// private val OPEN_APPBAR = "openAppBar" + + private var mIsTouchScreen: Boolean = false + + + override fun getLayoutId(): Int { + return R.layout.fragment_subject_tiled + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mSubjectData = arguments?.getParcelable(EntranceUtils.KEY_SUBJECT_DATA) + mSubjectData?.mTileType = "全部" + mSubjectData?.listOrder = "" + + // 初始化顶部类型列表 + val layoutManager = object : GridLayoutManager(context, 4) { + override fun canScrollVertically(): Boolean { + return false + } + } + mTypeList.isNestedScrollingEnabled = false + mTypeList.layoutManager = layoutManager + if (mSubjectData?.typeList != null && mSubjectData?.typeList!!.size > 1) { + val adapter = SubjectTypeListAdapter(context!!, mItemClickListener = { + mSubjectData?.mTileType = it + loadData() + }, mGameType = mSubjectData?.typeList!!) + mTypeList.adapter = adapter + } + + // Appbar 交互 + mAppbar.addOnOffsetChangedListener { appBarLayout, verticalOffset -> + if (!TextUtils.isEmpty(mSubjectData?.subjectName)) { + val totalScrollRange = appBarLayout.totalScrollRange + if (Math.abs(verticalOffset) < totalScrollRange / 2) { + if (activity is ToolbarController) { + (activity as ToolbarController).setNavigationTitle(mSubjectData?.subjectName) + } + } else if (Math.abs(verticalOffset) == totalScrollRange && totalScrollRange != 0) { + if (activity is ToolbarController) { + (activity as ToolbarController).setNavigationTitle(StringUtils.buildString(mSubjectData?.subjectName, "-", mSubjectData?.mTileType, "↑")) + } + } + } + } + + loadData() + } + + fun onTouchEvent(motionEvent: MotionEvent) { + when (motionEvent.action) { + MotionEvent.ACTION_DOWN -> mIsTouchScreen = true + MotionEvent.ACTION_UP -> mIsTouchScreen = false + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(reuse: EBReuse) { + if (SubjectTileFragment.OPEN_APPBAR == reuse.type && !mIsTouchScreen) { + mAppbar.setExpanded(true, true) + } + } + + @OnClick(R.id.subject_tabbar_hottest, R.id.subject_tabbar_newest) + override fun onClick(view: View) { + when (view.id) { + R.id.subject_tabbar_hottest -> { + mBarHottest.isChecked = true + mBarNewest.isChecked = false + mSubjectData?.listOrder = "" + loadData() + } + R.id.subject_tabbar_newest -> { + mBarHottest.isChecked = false + mBarNewest.isChecked = true + mSubjectData?.listOrder = "-1" + loadData() + } + } + + } + + fun loadData() { + val transaction = childFragmentManager.beginTransaction() + hideFragments(transaction) + alterFragment(transaction, mSubjectData?.mTileType + mSubjectData?.listOrder) + transaction.commitAllowingStateLoss() + } + + private fun alterFragment(transaction: FragmentTransaction, fmTag: String) { + var fragmentByTag: Fragment? = childFragmentManager.findFragmentByTag(fmTag) + try { + if (fragmentByTag != null) { + transaction.show(fragmentByTag) + } else { + fragmentByTag = SubjectListFragment() + val bundle = Bundle() + bundle.putParcelable(EntranceUtils.KEY_SUBJECT_DATA, mSubjectData) + fragmentByTag.arguments = bundle + transaction.add(R.id.subject_content_rl, fragmentByTag, fmTag) + } + } catch (e: Exception) { + e.printStackTrace() + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/subject/refactor/tile/SubjectTypeListAdapter.kt b/app/src/main/java/com/gh/gamecenter/subject/refactor/tile/SubjectTypeListAdapter.kt new file mode 100644 index 0000000000..54f64848da --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/subject/refactor/tile/SubjectTypeListAdapter.kt @@ -0,0 +1,67 @@ +package com.gh.gamecenter.subject.refactor.tile + +import android.content.Context +import android.graphics.Color +import android.support.v4.content.ContextCompat +import android.support.v7.widget.RecyclerView +import android.text.TextUtils +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.RelativeLayout +import android.widget.TextView +import com.gh.common.util.DisplayUtils +import com.gh.gamecenter.R +import com.lightgame.adapter.BaseRecyclerAdapter + +class SubjectTypeListAdapter(context: Context, + private val mItemClickListener: (type: String) -> Unit, + private val mGameType: List) : BaseRecyclerAdapter(context) { + + private var mCurType = "全部" + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubjectTypeViewHolder { + val relativeLayout = RelativeLayout(mContext) + relativeLayout.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(mContext, 35f)) + relativeLayout.gravity = Gravity.CENTER + val textView = TextView(mContext) + textView.textSize = 14f + textView.setBackgroundResource(R.drawable.subject_tab_style) + textView.setTextColor(ContextCompat.getColor(mContext, R.color.title)) + textView.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, DisplayUtils.dip2px(mContext, 25f)) + textView.gravity = Gravity.CENTER + textView.setPadding(DisplayUtils.dip2px(mContext, 10f), 0, DisplayUtils.dip2px(mContext, 10f), 0) + relativeLayout.addView(textView) + return SubjectTypeViewHolder(relativeLayout) + } + + + override fun onBindViewHolder(holder: SubjectTypeViewHolder, position: Int) { + holder.type.text = mGameType[position] + + if (!TextUtils.isEmpty(mCurType) && mCurType == mGameType[position]) { + holder.type.isSelected = true + holder.type.setTextColor(Color.WHITE) + + } else { + holder.type.isSelected = false + holder.type.setTextColor(ContextCompat.getColor(mContext, R.color.title)) + } + + holder.type.setOnClickListener { + holder.type.isSelected = true + mCurType = mGameType[holder.adapterPosition] + mItemClickListener.invoke(mGameType[holder.adapterPosition]) + notifyDataSetChanged() + } + } + + override fun getItemCount(): Int { + return mGameType.size + } + + inner class SubjectTypeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val type: TextView = (itemView as RelativeLayout).getChildAt(0) as TextView + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_subject.xml b/app/src/main/res/layout/activity_subject.xml new file mode 100644 index 0000000000..ea6efe6198 --- /dev/null +++ b/app/src/main/res/layout/activity_subject.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_subject_tab.xml b/app/src/main/res/layout/fragment_subject_tab.xml new file mode 100644 index 0000000000..77b29518eb --- /dev/null +++ b/app/src/main/res/layout/fragment_subject_tab.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_subject_tiled.xml b/app/src/main/res/layout/fragment_subject_tiled.xml index 50a3dfb768..a8c8bfb1f1 100644 --- a/app/src/main/res/layout/fragment_subject_tiled.xml +++ b/app/src/main/res/layout/fragment_subject_tiled.xml @@ -26,23 +26,27 @@ android:layout_marginTop = "15dp" android:background = "@drawable/border_black_bg" > - - diff --git a/channel.txt b/channel.txt index 203ea282cb..ce5f615085 100644 --- a/channel.txt +++ b/channel.txt @@ -53,6 +53,16 @@ GH_617 GH_618 GH_619 GH_620 +GH_621 +GH_622 +GH_623 +GH_624 +GH_625 +GH_626 +GH_627 +GH_628 +GH_629 +GH_630 GH_666 GH_777 GH_888