diff --git a/app/src/main/java/com/gh/common/PushManager.kt b/app/src/main/java/com/gh/common/PushManager.kt index 158ca81432..8e252dc3e1 100644 --- a/app/src/main/java/com/gh/common/PushManager.kt +++ b/app/src/main/java/com/gh/common/PushManager.kt @@ -53,7 +53,7 @@ object PushManager { registerDevice() val aliasInSp = PreferenceManager.getDefaultSharedPreferences(application).getString(SP_PUSH_ALIAS, "") - previousAlias = aliasInSp.toObject() + previousAlias = aliasInSp?.toObject() if (previousAlias == null) { getAndSetAlias() diff --git a/app/src/main/java/com/gh/common/dialog/ReserveDialogFragment.kt b/app/src/main/java/com/gh/common/dialog/ReserveDialogFragment.kt index 933d1a60a9..1ab3c9c125 100644 --- a/app/src/main/java/com/gh/common/dialog/ReserveDialogFragment.kt +++ b/app/src/main/java/com/gh/common/dialog/ReserveDialogFragment.kt @@ -1,6 +1,7 @@ package com.gh.common.dialog import android.annotation.SuppressLint +import android.app.Application import android.os.Bundle import android.text.Html import android.view.LayoutInflater @@ -8,16 +9,24 @@ import android.view.View import android.view.ViewGroup import android.widget.EditText import android.widget.TextView +import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel import butterknife.BindView import butterknife.ButterKnife import butterknife.OnClick +import com.gh.common.constant.Config +import com.gh.common.util.DirectUtils +import com.gh.common.util.createRequestBody import com.gh.common.util.observeNonNull import com.gh.common.util.viewModelProvider import com.gh.gamecenter.R +import com.gh.gamecenter.manager.UserManager +import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.RetrofitManager import com.lightgame.dialog.BaseDialogFragment import com.lightgame.utils.Utils +import io.reactivex.schedulers.Schedulers +import okhttp3.ResponseBody class ReserveDialogFragment : BaseDialogFragment() { @@ -33,9 +42,14 @@ class ReserveDialogFragment : BaseDialogFragment() { lateinit var reserveContainer: View @BindView(R.id.reserve_completed_container) lateinit var reserveCompletedContainer: View + @BindView(R.id.customizable_btn) + lateinit var customizableBtn: TextView lateinit var mViewModel: ReserveViewModel + var userId: String = "" + var gameId: String = "" + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -55,22 +69,36 @@ class ReserveDialogFragment : BaseDialogFragment() { val reserveContent = "游戏上线,您将免费收到短信提醒" reserveContentTv.text = Html.fromHtml(reserveContent) + mobileEt.setText(UserManager.getInstance().userInfoEntity.mobile) mViewModel.reservation.observeNonNull(this) { - if (it) { - showSuccessDialog() + if (it.success) { + showSuccessDialog(it.withMobile) } } dialog.setCanceledOnTouchOutside(true) } - private fun showSuccessDialog() { + private fun showSuccessDialog(withMobile: Boolean) { reserveHintTv.text = "游戏预约成功" - reserveCompletedContentTv.text = Html.fromHtml("游戏上线,将通过免费短信提醒您建议你设置微信提醒,多渠道提醒,不会错过任何预约的游戏。" + - "一个帐号仅需设置一次,即可永久有效。") - reserveContainer.visibility = View.GONE reserveCompletedContainer.visibility = View.VISIBLE + + val reservation = Config.getSettings()?.appointment + val dialogConfig = if (withMobile) reservation?.withMobile else reservation?.withoutMobile + if (dialogConfig?.text.isNullOrEmpty()) { + customizableBtn.visibility = View.GONE + } else { + reserveCompletedContentTv.text = Html.fromHtml(dialogConfig?.htmlContent) + customizableBtn.text = dialogConfig?.text + customizableBtn.setOnClickListener { + DirectUtils.directToLinkPage( + requireContext(), + dialogConfig!!.toLinkEntity(), + "(游戏预约)", + "") + } + } } @OnClick(R.id.reserve_with_mobile_btn, @@ -80,7 +108,7 @@ class ReserveDialogFragment : BaseDialogFragment() { fun onClick(view: View) { when (view.id) { R.id.reserve_without_mobile_btn -> { - mViewModel.reserve() + mViewModel.reserve(userId = userId, gameId = gameId) } R.id.reserve_with_mobile_btn -> { @@ -90,29 +118,51 @@ class ReserveDialogFragment : BaseDialogFragment() { return } - mViewModel.reserve(mobile = mobile) + mViewModel.reserve(userId = userId, gameId = gameId, mobile = mobile) } R.id.close_btn -> { - dismiss() + dismissAllowingStateLoss() } + } + } - R.id.customizable_btn -> { - dismiss() - } + companion object { + @JvmStatic + fun getInstance(userId: String, gameId: String) = ReserveDialogFragment().apply { + this.userId = userId + this.gameId = gameId } } } -class ReserveViewModel : ViewModel() { - val reservation = MutableLiveData() +class ReserveViewModel(application: Application) : AndroidViewModel(application) { + val reservation = MutableLiveData() - fun reserve(mobile: String = "") { + @SuppressLint("CheckResult") + fun reserve(userId: String, gameId: String, mobile: String = "") { + + val requestMap = hashMapOf() + requestMap["user_id"] = userId + requestMap["game_id"] = gameId if (mobile.isNotEmpty()) { - reservation.postValue(true) - } else { - reservation.postValue(true) + requestMap["mobile"] = mobile } + + RetrofitManager.getInstance(getApplication()).api + .createNewGameReservation(requestMap.createRequestBody()) + .subscribeOn(Schedulers.io()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ResponseBody) { + reservation.postValue(Reservation(success = true, withMobile = mobile.isNotEmpty())) + } + + override fun onFailure(exception: Exception) { + Utils.toast(getApplication(), exception.message) + } + }) } + class Reservation(var success: Boolean = false, var withMobile: Boolean = false) + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java index 3e1345f6eb..5f29e06dfb 100644 --- a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java +++ b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java @@ -30,6 +30,12 @@ public class DetailDownloadUtils { return; } + if (viewHolder.gameEntity.isReservable()) { + viewHolder.mDownloadPb.setText("预约"); + viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.RESERVABLE); + return; + } + if (viewHolder.gameEntity.getApk().isEmpty()) { viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.downloadOffText) ? "暂无下载" : viewHolder.downloadOffText); viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NONE); diff --git a/app/src/main/java/com/gh/common/util/DownloadItemUtils.java b/app/src/main/java/com/gh/common/util/DownloadItemUtils.java index 06738ef428..51456c8143 100644 --- a/app/src/main/java/com/gh/common/util/DownloadItemUtils.java +++ b/app/src/main/java/com/gh/common/util/DownloadItemUtils.java @@ -26,6 +26,7 @@ import com.gh.gamecenter.entity.ApkEntity; import com.gh.gamecenter.entity.GameEntity; import com.gh.gamecenter.entity.PluginLocation; import com.gh.gamecenter.manager.PackagesManager; +import com.gh.gamecenter.manager.UserManager; import com.lightgame.download.DownloadConfig; import com.lightgame.download.DownloadEntity; import com.lightgame.download.DownloadStatus; @@ -128,7 +129,7 @@ public class DownloadItemUtils { } // 显示预约 - if (gameEntity.getCanReserve()) { + if (gameEntity.isReservable()) { holder.gameDes.setVisibility(View.VISIBLE); holder.gameProgressbar.setVisibility(View.GONE); holder.gameInfo.setVisibility(View.GONE); @@ -311,10 +312,10 @@ public class DownloadItemUtils { final String location, final ExposureEvent traceEvent) { - if (gameEntity.getCanReserve()) { + if (gameEntity.isReservable()) { downloadBtn.setOnClickListener(v -> { CheckLoginUtils.checkLogin(context, entrance, () -> { - ReserveDialogFragment dialogFragment = new ReserveDialogFragment(); + ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(UserManager.getInstance().getUserId(), gameEntity.getId()); dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve"); }); }); diff --git a/app/src/main/java/com/gh/common/util/Extensions.kt b/app/src/main/java/com/gh/common/util/Extensions.kt index c068bd4baa..159c47ab70 100644 --- a/app/src/main/java/com/gh/common/util/Extensions.kt +++ b/app/src/main/java/com/gh/common/util/Extensions.kt @@ -1,14 +1,14 @@ package com.gh.common.util -import androidx.lifecycle.* import android.content.ClipboardManager import android.content.Context -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity -import androidx.viewpager.widget.ViewPager import android.text.Html import android.text.Spanned import android.view.View +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.* +import androidx.viewpager.widget.ViewPager import com.google.gson.reflect.TypeToken import com.halo.assistant.HaloApp import com.lightgame.utils.Utils @@ -19,7 +19,7 @@ import java.net.URI /** * 创建以 activity 为观察者上下文的 viewModel */ -inline fun androidx.fragment.app.FragmentActivity.viewModelProvider( +inline fun FragmentActivity.viewModelProvider( provider: ViewModelProvider.Factory? = null ) = ViewModelProviders.of(this, provider).get(VM::class.java) @@ -27,7 +27,7 @@ inline fun androidx.fragment.app.FragmentActivity.viewM /** * 创建以 activity 为观察者上下文的 viewModel */ -inline fun androidx.fragment.app.Fragment.viewModelProviderFromParent( +inline fun Fragment.viewModelProviderFromParent( provider: ViewModelProvider.Factory? = null ) = ViewModelProviders.of(requireActivity(), provider).get(VM::class.java) @@ -35,7 +35,7 @@ inline fun androidx.fragment.app.Fragment.viewModelProv /** * 创建以 fragment 为观察者上下文的 viewModel */ -inline fun androidx.fragment.app.Fragment.viewModelProvider( +inline fun Fragment.viewModelProvider( provider: ViewModelProvider.Factory? = null ) = ViewModelProviders.of(this, provider).get(VM::class.java) @@ -45,10 +45,10 @@ inline fun androidx.fragment.app.Fragment.viewModelProv * ViewPager Extensions * */ -fun androidx.viewpager.widget.ViewPager.doOnPageSelected(action: (position: Int) -> Unit) = addOnPageChangeListener(onSelected = action) +fun ViewPager.doOnPageSelected(action: (position: Int) -> Unit) = addOnPageChangeListener(onSelected = action) -fun androidx.viewpager.widget.ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = null) { - val listener = object : androidx.viewpager.widget.ViewPager.OnPageChangeListener { +fun ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = null) { + val listener = object : ViewPager.OnPageChangeListener { override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { // Do nothing. } @@ -78,7 +78,7 @@ fun LiveData.observeNonNull(owner: LifecycleOwner, callback: (T) -> Unit /** * Login related extensions */ -fun androidx.fragment.app.Fragment.ifLogin(entrance: String, action: (() -> Unit)? = null) { +fun Fragment.ifLogin(entrance: String, action: (() -> Unit)? = null) { requireContext().ifLogin(entrance, action) } diff --git a/app/src/main/java/com/gh/common/view/DownloadProgressBar.java b/app/src/main/java/com/gh/common/view/DownloadProgressBar.java index cb36fbfc54..58e1e5390e 100644 --- a/app/src/main/java/com/gh/common/view/DownloadProgressBar.java +++ b/app/src/main/java/com/gh/common/view/DownloadProgressBar.java @@ -10,13 +10,14 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; -import androidx.annotation.StringRes; -import androidx.core.content.ContextCompat; import android.text.TextPaint; import android.text.TextUtils; import android.util.AttributeSet; import android.widget.ProgressBar; +import androidx.annotation.StringRes; +import androidx.core.content.ContextCompat; + import com.gh.common.util.DisplayUtils; import com.gh.gamecenter.R; @@ -35,6 +36,7 @@ public class DownloadProgressBar extends ProgressBar { INSTALL_PLUGIN, DOWNLOADING_NORMAL, DOWNLOADING_PLUGIN, + RESERVABLE } private PorterDuffXfermode mDuffXFerMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); @@ -194,6 +196,10 @@ public class DownloadProgressBar extends ProgressBar { ? R.drawable.detail_downloading_plugin_rect_style : R.drawable.detail_downloading_plugin_style)); mDefaultColor = ContextCompat.getColor(getContext(), R.color.btn_plugin); break; + case RESERVABLE: + setProgressDrawable(getResources().getDrawable(R.drawable.button_reserve)); + mDefaultColor = ContextCompat.getColor(getContext(), R.color.all_white); + break; } mDownloadType = downloadType; diff --git a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java index 2ae70a7d32..612deb87b2 100644 --- a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java +++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java @@ -2,14 +2,19 @@ package com.gh.gamecenter.adapter.viewholder; import android.content.Context; import android.content.Intent; -import androidx.annotation.Nullable; import android.text.TextUtils; import android.view.View; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.gh.common.dialog.ReserveDialogFragment; import com.gh.common.exposure.ExposureEvent; import com.gh.common.exposure.ExposureUtils; +import com.gh.common.util.CheckLoginUtils; import com.gh.common.util.DataUtils; import com.gh.common.util.DialogUtils; +import com.gh.common.util.MtaHelper; import com.gh.common.util.PackageUtils; import com.gh.common.util.StringUtils; import com.gh.common.view.DownloadDialog; @@ -19,7 +24,7 @@ import com.gh.gamecenter.DownloadManagerActivity; import com.gh.gamecenter.R; import com.gh.gamecenter.entity.ApkEntity; import com.gh.gamecenter.entity.GameEntity; -import com.halo.assistant.HaloApp; +import com.gh.gamecenter.manager.UserManager; import com.lightgame.download.DownloadEntity; import com.lightgame.download.FileUtils; import com.lightgame.utils.Utils; @@ -86,35 +91,38 @@ public class DetailViewHolder { // 这个 switch 纯粹是为了 MTA 统计用的 switch (mViewHolder.mDownloadPb.getDownloadType()) { case DOWNLOADING_PLUGIN: - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "插件化中", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "插件化中", mGameEntity.getName()); break; case DOWNLOADING_NORMAL: - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "下载中", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "下载中", mGameEntity.getName()); break; case NONE: - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "关闭下载", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "关闭下载", mGameEntity.getName()); break; case NORMAL: - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "下载", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "下载", mGameEntity.getName()); break; case PLUGIN: - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "插件化", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "插件化", mGameEntity.getName()); break; case INSTALL_PLUGIN: - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "安装插件化", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "安装插件化", mGameEntity.getName()); break; case INSTALL_NORMAL: - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "安装", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "安装", mGameEntity.getName()); + break; + case RESERVABLE: + MtaHelper.onEvent("游戏详情_新", "预约", mGameEntity.getName()); break; } // 由于部分状态不包含在 downloadType 里,所以还是需要手动获取下载按钮文字判断点击时的状态 String downloadText = mViewHolder.mDownloadPb.getText(); if (downloadText.contains("打开")) { - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "打开", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "打开", mGameEntity.getName()); } else if (downloadText.contains("启动")) { - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "启动", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "启动", mGameEntity.getName()); } else if (downloadText.contains("更新")) { - DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "游戏详情_新", "更新", mGameEntity.getName()); + MtaHelper.onEvent("游戏详情_新", "更新", mGameEntity.getName()); } String autoDownloadPlatform = v.getTag() instanceof String ? (String) v.getTag() : ""; @@ -164,6 +172,12 @@ public class DetailViewHolder { PackageUtils.launchSetup(mViewHolder.context, mDownloadEntity.getPath()); } break; + case RESERVABLE: + CheckLoginUtils.checkLogin(mViewHolder.context, mEntrance, () -> { + ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(UserManager.getInstance().getUserId(), mGameEntity.getId()); + dialogFragment.show(((AppCompatActivity) mViewHolder.context).getSupportFragmentManager(), "reserve"); + }); + break; } } diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt index a4ef65b29e..50b1cdff02 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt @@ -19,7 +19,8 @@ data class GameEntity( var nameSuffix: String = "", var brief: String? = null, - var canReserve: Boolean = false, + @SerializedName("appointment") + var isReservable: Boolean = true, // 此游戏是否处于可预约状态 private var tag: ArrayList? = null, private var apk: ArrayList? = null, 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 d7dacc704c..98d84cfa68 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt @@ -89,6 +89,9 @@ class MeEntity(@SerializedName("is_community_voted") @SerializedName("is_moderator") val isModerator: Boolean = false, + @SerializedName("is_appointment") + var isGameReserved: Boolean = false, // 是否已预约了游戏 + @SerializedName("permissions") val moderatorPermissions: Permissions = Permissions()) : Parcelable diff --git a/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt index 5eaeae71a3..326c930545 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt @@ -22,6 +22,8 @@ data class SettingsEntity( var gamePackageMatch: List? = listOf(), @SerializedName("ad") var adList: List? = listOf(), + @SerializedName("appointment_success") + var appointment: Appointment? = Appointment(), @SerializedName("article_entrance") private var articleEntrance: String = "") { @@ -61,7 +63,6 @@ data class SettingsEntity( return false } - data class Support( @SerializedName("qq-group") var qQun: String? = "", @@ -136,4 +137,22 @@ data class SettingsEntity( var name: String, val icon: String) + data class Appointment( + @SerializedName("with_mobile") + var withMobile: DialogConfig = DialogConfig(), + @SerializedName("without_mobile") + var withoutMobile: DialogConfig = DialogConfig()) { + class DialogConfig { + @SerializedName("html_content") + var htmlContent: String = "" + var text: String = "" + var type: String = "" + var link: String = "" + + fun toLinkEntity(): LinkEntity { + return LinkEntity(title = "", image = "", link = link, type = type, text = "") + } + } + } + } \ 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 ac6753d111..2071927d4b 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 @@ -1713,4 +1713,29 @@ public interface ApiService { */ @PUT("devices/{device_id}/applications") Single putInstalledApps(@Path("device_id") String deviceId, @Body RequestBody body); + + /** + * 新建游戏预约 + */ + @POST("./appointment:apply") + Single createNewGameReservation(@Body RequestBody body); + + /** + * 取消游戏预约 + */ + @POST("./appointment:cancel") + Single cancelGameReservation(@Body RequestBody body); + + /** + * 删除游戏预约 + */ + @POST("./appointment:delete") + Single deleteGameReservation(@Body RequestBody body); + + /** + * 获取用户游戏预约列表 + */ + @GET("users/{user_id}/appointment") + Single getGameReservations(@Path("user_id") String userId); + } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_reserve_game.xml b/app/src/main/res/layout/dialog_reserve_game.xml index c3a8dff29c..87c1ba6daa 100644 --- a/app/src/main/res/layout/dialog_reserve_game.xml +++ b/app/src/main/res/layout/dialog_reserve_game.xml @@ -73,7 +73,6 @@ android:layout_marginTop="15dp" android:background="@drawable/round_grey_stroke" android:gravity="center" - android:text="13710110010" android:textColor="@color/black" android:textSize="15sp" />