Compare commits

...

13 Commits

Author SHA1 Message Date
65577ad938 fix:游戏预约功能(第五期)-0912测试-客户端 https://jira.shanqu.cc/browse/GHZSCY-6675 2024-09-23 09:48:10 +08:00
bd049064ac fix:游戏预约功能(第五期)-0912测试-客户端 https://jira.shanqu.cc/browse/GHZSCY-6675 2024-09-23 09:41:18 +08:00
18e964df3c feat:游戏预约功能(第五期)-0912测试-客户端 https://jira.shanqu.cc/browse/GHZSCY-6675 2024-09-12 17:49:06 +08:00
501f70d530 feat:游戏预约功能(第五期)-前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5915 2024-09-12 16:31:39 +08:00
e24186025a feat:游戏预约功能(第五期)-前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5915 2024-09-12 15:57:14 +08:00
c531fc9390 feat:游戏预约功能(第五期)-前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5915 2024-09-12 14:55:38 +08:00
cb5abb13db feat:游戏预约功能(第五期)-前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5915 2024-09-11 10:04:39 +08:00
dd3cdd10a1 feat:游戏预约功能(第五期)-前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5915 2024-09-10 18:07:54 +08:00
77a21a4cee feat:游戏预约功能(第五期)-前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5915 2024-09-10 15:00:56 +08:00
4739ad4ade feat:游戏预约功能(第五期)-前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5915 2024-09-07 11:17:17 +08:00
316de820ae feat:游戏预约功能(第五期)-前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5915 2024-09-05 09:50:56 +08:00
f2151cbe4f fix:游戏预约功能(第五期)-前端部分-0827UI测试—客户端 https://jira.shanqu.cc/browse/GHZSCY-6586 2024-08-29 16:12:34 +08:00
b412be135b feat:游戏预约功能(第五期)-前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5915
feat:https://jira.shanqu.cc/browse/GHZSCY-5915 游戏预约功能(第五期)-前端部分—客户端

ci
2024-08-26 17:19:07 +08:00
103 changed files with 5298 additions and 399 deletions

View File

@ -72,6 +72,7 @@ android_build:
only:
- dev
- release
- feat/GHZSCY-5915
# 代码检查
sonarqube_analysis:
@ -103,6 +104,7 @@ sonarqube_analysis:
only:
- dev
- release
- feat/GHZSCY-5915
## 发送简易检测结果报告
send_sonar_report:
@ -121,6 +123,7 @@ send_sonar_report:
only:
- dev
- release
- feat/GHZSCY-5915
oss-upload&send-email:
tags:
@ -156,4 +159,5 @@ oss-upload&send-email:
- /usr/local/bin/python /ci-android-mail-jira-comment.py
only:
- dev
- release
- release
- feat/GHZSCY-5915

View File

@ -296,7 +296,7 @@ public class BindingAdapters {
});
});
} else {
ReservationHelper.showCancelReservationDialog(progressBar.getContext(), () -> {
ReservationHelper.showCancelReservationDialog(progressBar.getContext(),gameEntity, () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
});

View File

@ -1,27 +1,42 @@
package com.gh.common.dialog
import android.content.Context
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.IExposable
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.fromHtml
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.FixLinearLayoutManager
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils.getBoolean
import com.gh.gamecenter.databinding.DialogReserveBinding
import com.gh.gamecenter.databinding.DialogReserveItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.ReserveOnlineEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.mygame.MyGameActivity
import com.halo.assistant.HaloApp
import com.lightgame.adapter.BaseRecyclerAdapter
class ReserveDialog : BaseDialogFragment() {
private lateinit var mReserveList: List<SimpleGameEntity>
private lateinit var reserveOnlineEntity: ReserveOnlineEntity
val games: List<GameEntity>
get() = reserveOnlineEntity.games
private var mDismissListener: (() -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) {
@ -36,66 +51,162 @@ class ReserveDialog : BaseDialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val binding: DialogReserveBinding = DialogReserveBinding.inflate(layoutInflater, null, false)
mReserveList = arguments?.getParcelableArrayList(RESERVE_LIST) ?: arrayListOf()
reserveOnlineEntity = arguments?.getParcelable(RESERVE_ONLINE) ?: ReserveOnlineEntity()
binding.title.text = resources.getString(R.string.dialog_reserve_title, mReserveList.size).fromHtml()
binding.more.visibility = if (mReserveList.size > 4) {
View.VISIBLE
} else View.GONE
binding.more.setOnClickListener {
binding.tvTitle.text =
resources.getString(R.string.dialog_reserve_title, reserveOnlineEntity.gamesTotal).fromHtml()
binding.tvViewAllAppointment.setOnClickListener {
SensorsBridge.trackAppointmentGameOnlineDialogClick(buttonName = "查看全部预约")
val intent = MyGameActivity.getIntentWithConfig(requireContext(), MyGameActivity.RESERVATION_INDEX)
startActivity(intent)
}
val adapter = ReserveDialogAdapter(requireContext(), games)
binding.rvGames.layoutManager = FixLinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
binding.rvGames.adapter = adapter
val exposureListener = ExposureListener(this, adapter)
binding.rvGames.addOnScrollListener(exposureListener)
binding.ivClose.setOnClickListener {
dismissAllowingStateLoss()
}
binding.recyclerView.layoutManager = if (mReserveList.size > 4) {
GridLayoutManager(context, 4)
} else {
FixLinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
}
binding.recyclerView.adapter = object : BaseRecyclerAdapter<ReserveDialogItemViewHolder>(context) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReserveDialogItemViewHolder {
val inflate = mLayoutInflater.inflate(R.layout.dialog_reserve_item, parent, false)
return ReserveDialogItemViewHolder(DialogReserveItemBinding.bind(inflate))
}
override fun getItemCount(): Int {
return if (mReserveList.size > 4) 4 else mReserveList.size
}
override fun onBindViewHolder(holder: ReserveDialogItemViewHolder, position: Int) {
val entity = mReserveList[position]
ImageUtils.display(holder.binding.icon, entity.icon)
holder.binding.gameNameTv.text = entity.name
holder.itemView.setOnClickListener {
GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(预约弹窗)")
dismissAllowingStateLoss()
}
}
}
checkHasAutoDownload(binding)
dialog?.setCanceledOnTouchOutside(true)
return binding.root
}
private fun checkHasAutoDownload(binding: DialogReserveBinding) {
if (reserveOnlineEntity.wifiAutoDownloadTotal > 0) {
// 开启自动下载
binding.tvAutoDownloadTips.goneIf(false)
var firstAutoDownloadGameName =
reserveOnlineEntity.games.find { it.wifiAutoDownload && !it.isLandPageAddressDialog() }?.name
if(!firstAutoDownloadGameName.isNullOrBlank() && firstAutoDownloadGameName.length > GAME_NAME_SHOW_MAX_LENGTH){
firstAutoDownloadGameName = "${firstAutoDownloadGameName.take(GAME_NAME_SHOW_MAX_LENGTH-1)}..."
}
val isWifiOpen = NetworkUtils.isWifiConnected(HaloApp.getInstance())
binding.tvAutoDownloadTips.text =
if (isWifiOpen) {
if (firstAutoDownloadGameName.isNullOrBlank()) {
getString(
R.string.reserve_reminder_auto_download,
"${reserveOnlineEntity.wifiAutoDownloadTotal}"
)
} else {
getString(
R.string.reserve_reminder_auto_download_with_name,
firstAutoDownloadGameName,
"${reserveOnlineEntity.wifiAutoDownloadTotal}"
)
}
} else {
if (firstAutoDownloadGameName.isNullOrBlank()) {
getString(
R.string.reserve_reminder_wait_for_wifi_to_auto_download,
"${reserveOnlineEntity.wifiAutoDownloadTotal}"
)
} else {
getString(
R.string.reserve_reminder_wait_for_wifi_to_auto_download_with_name,
firstAutoDownloadGameName,
"${reserveOnlineEntity.wifiAutoDownloadTotal}"
)
}
}
binding.tvAutoDownloadTips.setOnClickListener {
SensorsBridge.trackAppointmentGameOnlineDialogClick(buttonName = "查看进度")
val intent = DownloadManagerActivity.getDownloadMangerIntent(requireContext(), "")
startActivity(intent)
}
} else {
binding.tvAutoDownloadTips.goneIf(true)
}
}
fun setOnDismissListener(dismissListener: () -> Unit) {
mDismissListener = dismissListener
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
SensorsBridge.trackAppointmentGameOnlineDialogClick(buttonName = "关闭弹窗")
}
override fun onStart() {
super.onStart()
dialog?.window?.let {
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val params = it.attributes
params.width = DisplayUtils.dip2px(300F)
it.attributes = params
}
}
override fun onDestroy() {
super.onDestroy()
mDismissListener?.invoke()
}
companion object {
const val RESERVE_LIST = "reserve_list"
const val RESERVE_ONLINE = "reserve_online"
private const val GAME_NAME_SHOW_MAX_LENGTH = 8
@JvmStatic
fun getInstance(reserveList: List<SimpleGameEntity>) = ReserveDialog().apply {
arguments = Bundle()
arguments?.putParcelableArrayList(RESERVE_LIST, ArrayList(reserveList))
fun getInstance(reserveOnlineEntity: ReserveOnlineEntity?) = ReserveDialog().apply {
arguments = Bundle().apply {
putParcelable(RESERVE_ONLINE, reserveOnlineEntity)
}
}
}
}
class ReserveDialogAdapter(
context: Context,
private val games: List<GameEntity>
) :
BaseRecyclerAdapter<ReserveDialogItemViewHolder>(context), IExposable {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReserveDialogItemViewHolder {
return ReserveDialogItemViewHolder(parent.toBinding())
}
override fun getItemCount(): Int {
return if (games.size > 8) 8 else games.size
}
override fun onBindViewHolder(holder: ReserveDialogItemViewHolder, position: Int) {
val entity = games[position]
holder.binding.icon.displayGameIcon(entity)
holder.binding.gameNameTv.text = entity.name
holder.itemView.setOnClickListener {
SensorsBridge.trackAppointmentGameOnlineDialogClick(
"游戏",
entity.id,
entity.name ?: "",
entity.categoryChinese,
)
GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(预约弹窗)", entity.exposureEvent)
}
entity.exposureEvent = ExposureEvent.createEvent(
entity,
listOf(ExposureSource("预约上线弹窗", ""))
)
}
override fun getEventByPosition(pos: Int): ExposureEvent? {
return games.getOrNull(pos)?.exposureEvent
}
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? {
return null
}
}
class ReserveDialogItemViewHolder(val binding: DialogReserveItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)

View File

@ -0,0 +1,278 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.text.InputFilter
import android.view.LayoutInflater
import androidx.core.widget.addTextChangedListener
import com.gh.gamecenter.R
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.toResString
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DialogReserveReminderPhoneNumberBinding
import com.gh.gamecenter.entity.ReserveModifyEntity
import com.gh.gamecenter.entity.ValidateCodeResponse
import com.halo.assistant.fragment.reserve.OnReserveReminderListener
import com.halo.assistant.fragment.reserve.ReserveReminderRepository
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
import java.util.concurrent.TimeUnit
class ReserveReminderPhoneNumberDialog(
context: Context,
themeResId: Int,
private val dialogType: Int,
private val phoneNumber: String,
private var serviceId: String,
private val gameId: String,
private val repository: ReserveReminderRepository,
private val listener: OnReserveReminderListener
) :
Dialog(context, themeResId) {
private val compositeDisposable = CompositeDisposable()
private lateinit var binding: DialogReserveReminderPhoneNumberBinding
private var hasValidated = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DialogReserveReminderPhoneNumberBinding.inflate(LayoutInflater.from(context))
setContentView(binding.root)
initView()
}
private fun initView() {
binding.vClose.setOnClickListener {
dismiss()
}
setSubmitState(phoneNumber)
binding.etInput.addTextChangedListener {
val content = binding.etInput.text?.toString() ?: ""
if (dialogType == DIALOG_TYPE_BIND_PHONE || dialogType == DIALOG_TYPE_CHANGE_PHONE) {
setSubmitState(content)
} else {
val length = content.length
if (length == VALIDATE_CODE_LENGTH) {
verifyPhoneNumber(content)
}
}
}
when (dialogType) {
DIALOG_TYPE_BIND_PHONE -> {
binding.tvTitle.setText(R.string.enable_sms_reminder)
binding.tvDescription.setText(R.string.enable_sms_reminder_description)
binding.etInput.setText(phoneNumber)
binding.etInput.setHint(R.string.input_phone_hint)
}
DIALOG_TYPE_CHANGE_PHONE -> {
binding.tvTitle.setText(R.string.change_phone_number_2)
binding.tvDescription.setText(R.string.enable_sms_reminder_description)
binding.etInput.setText(phoneNumber)
binding.etInput.setHint(R.string.input_phone_hint)
}
DIALOG_TYPE_VERIFY_PHONE -> {
startCountDown()
binding.tvTitle.setText(R.string.please_input_sms_verify_code)
if (phoneNumber.length == PHONE_NUMBER_LENGTH) {
val phoneNumberWithMask = phoneNumber.substring(0, 3) + MASK + phoneNumber.substring(7)
binding.tvDescription.text =
context.getString(R.string.verify_code_send_with_phone_number, phoneNumberWithMask)
}
binding.tvSubmit.alpha = 1.0F
binding.etInput.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(VALIDATE_CODE_LENGTH))
binding.etInput.setHint(R.string.please_input_verify_code)
}
}
binding.tvSubmit.setOnClickListener {
val text = binding.etInput.text?.toString() ?: ""
if (dialogType == DIALOG_TYPE_VERIFY_PHONE) {
resendValidateCode()
} else {
if (isEnableSubmit(text)) {
when (dialogType) {
DIALOG_TYPE_BIND_PHONE -> bindPhoneNumber(text)
DIALOG_TYPE_CHANGE_PHONE -> bindPhoneNumber(text)
}
} else {
if (text != phoneNumber) {
ToastUtils.toast(R.string.invalid_phone_number_format.toResString())
}
}
}
}
}
private fun resendValidateCode() {
repository.sendVerifyCode(phoneNumber)
.compose(singleToMain())
.subscribe(object : BiResponse<ValidateCodeResponse>() {
override fun onSuccess(data: ValidateCodeResponse) {
serviceId = data.serviceId
startCountDown()
}
}).let(compositeDisposable::add)
}
private fun verifyPhoneNumber(content: String) {
repository.verifyPhoneNumber(phoneNumber, content, serviceId)
.compose(singleToMain())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
hasValidated = true
listener.phoneNumberValidateSuccessfully()
ToastUtils.toast(R.string.phone_number_validate_successfully.toResString())
dismiss()
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
binding.etInput.text = null
ToastUtils.toast(R.string.phone_number_validate_failure.toResString())
}
}).let(compositeDisposable::add)
}
private fun bindPhoneNumber(phone: String) {
repository.bindPhone(gameId, phone)
.compose(singleToMain())
.subscribe(object : BiResponse<ReserveModifyEntity>() {
override fun onSuccess(data: ReserveModifyEntity) {
listener.bindPhoneSuccessfully(data.smsConfig.mobileValidated, phone)
dismiss()
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
if (exception is HttpException) {
try {
val string = exception.response().errorBody()?.string()
if (!string.isNullOrBlank()) {
val json = JSONObject(string)
val message = json.getJSONObject("toast").getString("sms_config.mobile")
ToastUtils.showToast(message)
}
} catch (e: Exception) {
// no implement
}
}
}
}).let(compositeDisposable::add)
}
private fun startCountDown() {
binding.tvSubmit.isEnabled = false
binding.tvSubmit.setBackgroundResource(R.drawable.bg_common_button_light_fill_gray)
binding.tvSubmit.setTextColor(R.color.text_tertiary.toColor(context))
Observable.interval(0, 1, TimeUnit.SECONDS)
.take(COUNT_DOWN_DURATION)
.map {
COUNT_DOWN_DURATION - it
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<Long>() {
override fun onSubscribe(d: Disposable) {
compositeDisposable.add(d)
}
override fun onNext(time: Long) {
binding.tvSubmit.text = context.getString(R.string.resend_with_time, "$time")
}
override fun onComplete() {
binding.tvSubmit.isEnabled = true
binding.tvSubmit.setBackgroundResource(R.drawable.bg_common_button_fill_blue)
binding.tvSubmit.setTextColor(R.color.text_aw_primary.toColor(context))
binding.tvSubmit.setText(R.string.resend)
}
})
}
override fun dismiss() {
compositeDisposable.clear()
if (dialogType == DIALOG_TYPE_VERIFY_PHONE && !hasValidated) {
ToastUtils.toast(R.string.phone_number_validate_cancel.toResString())
}
super.dismiss()
}
private fun isEnableSubmit(phone: String) =
PHONE_NUMBER_PATTERN.toRegex().matches(phone)
&& if (dialogType == DIALOG_TYPE_CHANGE_PHONE) phone != phoneNumber else true
private fun setSubmitState(phone: String) {
val isEnable = isEnableSubmit(phone)
binding.tvSubmit.alpha = if (isEnable) {
TV_SUBMIT_ENABLE_ALPHA
} else {
TV_SUBMIT_UNABLE_ALPHA
}
}
companion object {
private const val PHONE_NUMBER_PATTERN = "^1\\d{10}$"
private const val MASK = "****"
private const val PHONE_NUMBER_LENGTH = 11
private const val VALIDATE_CODE_LENGTH = 6
const val DIALOG_TYPE_BIND_PHONE = 0
const val DIALOG_TYPE_CHANGE_PHONE = 1
const val DIALOG_TYPE_VERIFY_PHONE = 2
private const val COUNT_DOWN_DURATION = 60L
private const val TV_SUBMIT_ENABLE_ALPHA = 1F
private const val TV_SUBMIT_UNABLE_ALPHA = 0.4F
fun create(
context: Context,
dialogType: Int,
phoneNumber: String,
serviceId: String,
gameId: String,
repository: ReserveReminderRepository,
listener: OnReserveReminderListener
) =
ReserveReminderPhoneNumberDialog(
context,
R.style.DialogWindowTransparent,
dialogType,
phoneNumber,
serviceId,
gameId,
repository,
listener
)
}
}

View File

@ -0,0 +1,428 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.view.*
import android.view.ViewGroup.MarginLayoutParams
import androidx.core.view.updateLayoutParams
import com.gh.common.pop.EditBindPhoneInfoPop
import com.gh.common.pop.EditBindWechatPop
import com.gh.common.pop.RealNameTipsPop
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.entity.ReserveReminderEntity
import com.gh.gamecenter.login.entity.UserInfoEntity
import com.gh.gamecenter.login.user.UserManager
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.reserve.OnReserveReminderListener
class ReserveSuccessReminderDialog(
context: Context,
themeResId: Int,
private val listener: OnReserveReminderListener
) :
Dialog(context, themeResId), OnReserveSuccessListener {
private var reserveReminder = ReserveReminderEntity()
private val handler = Handler(Looper.getMainLooper())
private val handlers = arrayListOf<ReminderContentHandler>()
private lateinit var binding: DialogReserveSuccessWithSmsBinding
private val realNameQuestionPop by lazy {
RealNameTipsPop.create(context, listener)
}
private var hasAutoPopped = false
private var isInit = true
override fun onTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_UP) {
if (realNameQuestionPop.isShowing) {
realNameQuestionPop.dismiss()
return true
} else if (handlers.any { it.hasPopShowing }) {
handlers.forEach {
it.dismissPop()
}
return true
}
}
return super.onTouchEvent(event)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DialogReserveSuccessWithSmsBinding.inflate(LayoutInflater.from(context))
setContentView(binding.root)
binding.ivClose.setOnClickListener {
dismiss()
}
binding.ivQuestion.setOnClickListener {
realNameQuestionPop.showAtLocation(binding.cbAutoDownload, Gravity.BOTTOM, 0, 4F.dip2px())
}
}
private fun initView() {
handlers.clear()
binding.flContentContainer.removeAllViews()
val smsConfig = reserveReminder.smsConfig
val wechatConfig = reserveReminder.wechatConfig
when {
reserveReminder.onlyShowWechatReminder && !wechatConfig.isReminderEnable -> { // 只显示微信:未开启
binding.tvContent.setText(R.string.reverse_success_without_reminder_tips)
arrayListOf(OnlyWechatReminderUnableHandler(16.dp, binding.flContentContainer, this))
}
reserveReminder.onlyShowWechatReminder && wechatConfig.isReminderEnable -> { // 只显示微信:已开
binding.tvContent.setText(R.string.reverse_success_with_reminder_tips)
arrayListOf(
WechatReminderEnableHandler(
reserveReminder.wechatConfig.nickName,
8.dp,
binding.flContentContainer,
this
)
)
}
!smsConfig.notice && !wechatConfig.isReminderEnable -> { // 短信,微信未开启
binding.tvContent.setText(R.string.reverse_success_without_reminder_tips)
arrayListOf(
SmsReminderUnableHandler(16.dp, binding.flContentContainer, this),
WechatReminderUnableHandler(8.dp, binding.flContentContainer, this)
)
}
smsConfig.notice && wechatConfig.isReminderEnable -> {// 短信,微信已开启
binding.tvContent.setText(R.string.reverse_success_with_reminder_tips)
arrayListOf(
SmsReminderEnableHandler(reserveReminder.smsConfig, 8.dp, binding.flContentContainer, this),
WechatReminderEnableHandler(
reserveReminder.wechatConfig.nickName,
8.dp,
binding.flContentContainer,
this
)
)
}
smsConfig.notice && !wechatConfig.isReminderEnable -> { // 短信开启,微信未开启
binding.tvContent.setText(R.string.reverse_success_with_reminder_tips)
arrayListOf(
SmsReminderEnableHandler(smsConfig, 8.dp, binding.flContentContainer, this),
WechatReminderUnableHandler(16.dp, binding.flContentContainer, this)
)
}
!smsConfig.notice && wechatConfig.isReminderEnable -> { // 微信开启,短信未开启
binding.tvContent.setText(R.string.reverse_success_with_reminder_tips)
arrayListOf(
WechatReminderEnableHandler(
wechatConfig.nickName,
8.dp,
binding.flContentContainer,
this
),
SmsReminderUnableHandler(16.dp, binding.flContentContainer, this)
)
}
else -> {
binding.tvContent.setText(R.string.reverse_success_without_reminder_tips)
arrayListOf()
}
}.let {
handlers.clear()
handlers.addAll(it)
}
handlers.forEach {
binding.flContentContainer.addView(it.init())
}
if (isInit) {
isInit = false
binding.gAutoDownload.goneIf(!reserveReminder.isEnableAutoDownload)
if (reserveReminder.isEnableAutoDownload) {
binding.cbAutoDownload.isChecked = reserveReminder.wifiAutoDownload
checkIfShowRealNamePop()
}
binding.cbAutoDownload.setOnCheckedChangeListener { _, isChecked ->
listener.enableAutoDownload(isChecked)
checkIfShowRealNamePop()
}
}
}
private fun checkIfShowRealNamePop() {
if (hasAutoPopped) {
return
}
hasAutoPopped = true
handler.postDelayed({
val idCard = UserManager.getInstance().userInfoEntity?.idCard
if (idCard != null && idCard.status != 1 && idCard.minor != true) {
// 账号已实名
return@postDelayed
}
val deviceCertificationInfoString =
SPUtils.getString(Constants.SP_DEVICE_CERTIFICATION_PREFIX + HaloApp.getInstance().gid)
if (!TextUtils.isEmpty(deviceCertificationInfoString)) {
val deviceIdCard = deviceCertificationInfoString.toObject<UserInfoEntity>()?.idCard
if (deviceIdCard != null && deviceIdCard.status != 1 && deviceIdCard.minor != true) {
// 设备已实名
return@postDelayed
}
}
realNameQuestionPop.showAtLocation(binding.cbAutoDownload, Gravity.BOTTOM, 0, 0)
}, 16)
}
override fun updateSmsReminder(isEnable: Boolean) {
listener.updateSmsReminder(isEnable)
}
override fun updateWechatReminder() {
listener.updateWechatReminder()
}
override fun changePhoneNumber() {
listener.changedPhoneNumber()
}
override fun verifyPhoneNumber() {
listener.verifyPhoneNumber()
}
override fun changeWechatBinding() {
listener.changeWechatBinding()
}
override fun onStart() {
super.onStart()
window?.let {
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val params = it.attributes
params.width = DisplayUtils.dip2px(300F)
it.attributes = params
}
}
fun updateReserveReminder(reserveReminder: ReserveReminderEntity) {
this.reserveReminder = reserveReminder
initView()
}
override fun dismiss() {
handler.removeCallbacksAndMessages(null)
super.dismiss()
}
companion object {
private val Int.dp: Int
get() = DisplayUtils.dip2px(this.toFloat())
fun create(context: Context, listener: OnReserveReminderListener) =
ReserveSuccessReminderDialog(
context,
com.gh.gamecenter.common.R.style.DialogWindowTransparent,
listener
).apply {
}
}
abstract class ReminderContentHandler(
val topMargin: Int,
val parent: ViewGroup,
val listener: OnReserveSuccessListener
) {
open val hasPopShowing: Boolean = false
fun init(): View {
val root = createView(LayoutInflater.from(parent.context))
root.updateLayoutParams<MarginLayoutParams> {
this.topMargin = this@ReminderContentHandler.topMargin
}
initView()
return root
}
protected abstract fun createView(inflater: LayoutInflater): View
protected abstract fun initView()
open fun dismissPop() = Unit
}
class SmsReminderUnableHandler(topMargin: Int, parent: ViewGroup, listener: OnReserveSuccessListener) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveSmsReminderUnableBinding
override fun createView(inflater: LayoutInflater): View {
return LayoutReserveSmsReminderUnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
}
override fun initView() {
binding.vSmsAdd.setOnClickListener {
listener.updateSmsReminder(true)
}
}
}
class WechatReminderUnableHandler(topMargin: Int, parent: ViewGroup, listener: OnReserveSuccessListener) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveWechatReminderUnableBinding
override fun createView(inflater: LayoutInflater): View {
return LayoutReserveWechatReminderUnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
}
override fun initView() {
binding.vWechatAdd.setOnClickListener {
listener.updateWechatReminder()
}
}
}
class SmsReminderEnableHandler(
private val smsConfig: ReserveReminderEntity.SmsConfig,
topMargin: Int,
parent: ViewGroup, listener:
OnReserveSuccessListener
) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveSmsReminderEnableBinding
override val hasPopShowing: Boolean
get() = editBindPhoneInfoPop.isShowing
override fun dismissPop() {
if (hasPopShowing) {
editBindPhoneInfoPop.dismiss()
}
}
private val editBindPhoneInfoPop by lazy {
EditBindPhoneInfoPop.create(parent.context, smsConfig.mobileValidated, listener)
}
override fun createView(inflater: LayoutInflater) =
LayoutReserveSmsReminderEnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
override fun initView() {
binding.tvPhone.text = smsConfig.mobile
binding.vSmsEdit.setOnClickListener {
editBindPhoneInfoPop.showAsDropDown(
binding.ivSmsEdit,
(-104).dp,
0,
)
}
}
}
class WechatReminderEnableHandler(
private val nickName: String,
topMargin: Int,
parent: ViewGroup,
listener: OnReserveSuccessListener
) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveWechatReminderEnableBinding
private val editWechatPop by lazy {
EditBindWechatPop.create(parent.context, listener)
}
override fun createView(inflater: LayoutInflater) =
LayoutReserveWechatReminderEnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
override fun initView() {
binding.tvWechat.text = nickName
binding.vModifyWechat.setOnClickListener {
editWechatPop.showAsDropDown(
binding.ivModifyWechat,
(-104).dp,
0
)
}
}
}
class OnlyWechatReminderUnableHandler(topMargin: Int, parent: ViewGroup, listener: OnReserveSuccessListener) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveOnlyWechatUnableBinding
override fun createView(inflater: LayoutInflater) =
LayoutReserveOnlyWechatUnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
override fun initView() {
binding.vSubmitBackground.setOnClickListener {
listener.updateWechatReminder()
}
}
}
}
interface OnReserveSuccessListener {
fun updateSmsReminder(isEnable: Boolean)
fun updateWechatReminder()
fun changePhoneNumber()
fun verifyPhoneNumber()
fun changeWechatBinding()
}

View File

@ -0,0 +1,63 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.DialogWechatBindingConflictBinding
class WechatBindingConflictDialogFragment : BaseDialogFragment() {
private lateinit var binding: DialogWechatBindingConflictBinding
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
setCanceledOnTouchOutside(true)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return DialogWechatBindingConflictBinding.inflate(inflater, container, false)
.also {
binding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.tvIKnow.setOnClickListener {
dismiss()
}
}
override fun onStart() {
super.onStart()
dialog?.window?.let {
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val params = it.attributes
params.width = DisplayUtils.dip2px(300F)
it.attributes = params
}
}
companion object {
fun show(context: Context) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
WechatBindingConflictDialogFragment().show(it, WechatBindingConflictDialogFragment::class.java.name)
}
}
}
}

View File

@ -0,0 +1,125 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.entity.ErrorEntity
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.DialogWechatBindingFailedBinding
import com.gh.gamecenter.login.user.UserRepository
import com.lightgame.utils.Utils
class WechatBindingFailedDialogFragment : BaseDialogFragment() {
private lateinit var binding: DialogWechatBindingFailedBinding
private var currentUserId: String? = null
private lateinit var userConflict: ErrorEntity.Data.UserConflict
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
userConflict = arguments?.getParcelable(KEY_USER_CONFLICT) ?: ErrorEntity.Data.UserConflict()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
setCanceledOnTouchOutside(true)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return DialogWechatBindingFailedBinding.inflate(inflater, container, false)
.also {
binding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
UserRepository.getInstance().loginUserInfo.observe(viewLifecycleOwner) {
currentUserId = it.data.getShortUserId()
binding.tvCurrentName.text = it.data.name
binding.ivCurrentAvatar.displayAvatar(it.data.icon)
binding.tvUserId.text = getString(R.string.user_id, currentUserId)
}
binding.tvConflictName.text = userConflict.name
binding.ivConflictAvatar.displayAvatar(userConflict.icon)
binding.tvConflictUserId.text = getString(R.string.user_id, userConflict.seq)
binding.tvConflictProblem.setOnClickListener {
dismiss()
WechatBindingConflictDialogFragment.show(requireContext())
}
binding.tvIKnow.setOnClickListener {
dismiss()
}
binding.tvUserId.setOnLongClickListener {
currentUserId?.let {
copyTextToClipboard(it)
true
} ?: false
}
binding.tvConflictUserId.setOnLongClickListener {
copyTextToClipboard(userConflict.id)
true
}
}
private fun copyTextToClipboard(text: String) {
val clipboardManager = context?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
if (clipboardManager != null) {
val clip = ClipData.newPlainText(COPY_ID_TEXT, text)
clipboardManager.setPrimaryClip(clip)
Utils.toast(requireContext(), R.string.copy_user_id_successfully)
}
}
override fun onStart() {
super.onStart()
dialog?.window?.let {
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val params = it.attributes
params.width = DisplayUtils.dip2px(300F)
it.attributes = params
}
}
companion object {
private const val COPY_ID_TEXT = "user_id"
private const val KEY_USER_CONFLICT = "key_user_conflict"
fun show(context: Context, userConflict: ErrorEntity.Data.UserConflict?) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
val fragment = WechatBindingFailedDialogFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_USER_CONFLICT, userConflict)
}
}
fragment.show(it, WechatBindingFailedDialogFragment::class.java.name)
}
}
}
}

View File

@ -0,0 +1,44 @@
package com.gh.common.pop
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.updateLayoutParams
import com.gh.gamecenter.R
import com.gh.gamecenter.common.databinding.LayoutPopupContainerBinding
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.LayoutAddKaifuPopupItemBinding
class BatchManagementPop(
binding: LayoutPopupContainerBinding,
private val listener: OnBatchManagementListener
) :
CommonPopupWindow(binding) {
override val viewDataList: List<ViewData>
get() = listOf(
ViewData(R.string.enable_automatic_downloading_in_batches) {
listener.enableAutoDownload()
},
ViewData(R.string.batch_management) {
listener.batchManage()
}
)
companion object {
fun create(context: Context, listener: OnBatchManagementListener): BatchManagementPop {
val binding = LayoutPopupContainerBinding.inflate(LayoutInflater.from(context))
return BatchManagementPop(binding, listener).apply {
initView()
}
}
}
interface OnBatchManagementListener {
fun enableAutoDownload()
fun batchManage()
}
}

View File

@ -0,0 +1,49 @@
package com.gh.common.pop
import android.content.Context
import android.view.LayoutInflater
import com.gh.gamecenter.R
import com.gh.gamecenter.common.databinding.LayoutPopupContainerBinding
import com.gh.gamecenter.feature.entity.GameEntity
class CancelReservePop(
private val game: GameEntity,
binding: LayoutPopupContainerBinding,
private val listener: OnCancelReserveListener
) : CommonPopupWindow(binding) {
override val viewDataList: List<ViewData>
get() {
val list = arrayListOf<ViewData>()
if (game.wifiAutoDownloadEnable) {
list.add(ViewData(if (game.wifiAutoDownload) R.string.cancel_auto_download_with_wifi else R.string.enable_automatic_downloading_with_wifi) {
listener.enableAutoDownload(!game.wifiAutoDownload)
})
}
list.add(ViewData(R.string.cancel_reserve, listener::cancelReserve))
return list
}
companion object {
fun create(
game: GameEntity,
context: Context,
listener: OnCancelReserveListener
): CancelReservePop {
val inflater = LayoutInflater.from(context)
val binding = LayoutPopupContainerBinding.inflate(inflater)
return CancelReservePop(game, binding, listener).apply {
initView()
}
}
}
interface OnCancelReserveListener {
fun enableAutoDownload(isEnable: Boolean)
fun cancelReserve()
}
}

View File

@ -0,0 +1,47 @@
package com.gh.common.pop
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.updateLayoutParams
import com.gh.gamecenter.common.databinding.LayoutPopupContainerBinding
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.LayoutAddKaifuPopupBinding
import com.gh.gamecenter.databinding.LayoutAddKaifuPopupItemBinding
import com.gh.gamecenter.databinding.LayoutPopupOptionItemBinding
import com.gh.gamecenter.databinding.LayoutPopupReserveReminderOptionItemBinding
abstract class CommonPopupWindow(
private val binding: LayoutPopupContainerBinding,
) : BugFixedPopupWindow(binding.root, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) {
private val inflater = LayoutInflater.from(binding.root.context)
abstract val viewDataList: List<ViewData>
fun initView() {
isFocusable = true
binding.container.updateLayoutParams<ViewGroup.LayoutParams> {
width = DisplayUtils.dip2px(128F)
}
viewDataList.forEach {
addItemView(it.textResId, it.click)
}
}
private fun addItemView(textResId: Int, click: () -> Unit) =
LayoutPopupReserveReminderOptionItemBinding.inflate(inflater, binding.container, false)
.also {
it.hintText.setText(textResId)
binding.container.addView(it.root)
it.root.setOnClickListener {
dismiss()
click()
}
}.root
data class ViewData(
val textResId: Int,
val click: () -> Unit
)
}

View File

@ -0,0 +1,70 @@
package com.gh.common.pop
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.updateLayoutParams
import com.gh.common.dialog.OnReserveSuccessListener
import com.gh.gamecenter.R
import com.gh.gamecenter.common.databinding.LayoutPopupContainerBinding
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.LayoutAddKaifuPopupItemBinding
class EditBindPhoneInfoPop(
private val hasValidated: Boolean,
private val binding: LayoutPopupContainerBinding,
private val listener: OnReserveSuccessListener
) : BugFixedPopupWindow(binding.root, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) {
private val context
get() = binding.root.context
init {
initView()
}
private fun initView() {
isOutsideTouchable = false
isFocusable = true
binding.container.updateLayoutParams<ViewGroup.LayoutParams> {
width = DisplayUtils.dip2px(128F)
}
val inflater = LayoutInflater.from(context)
fun createItemView(textResId: Int) =
LayoutAddKaifuPopupItemBinding.inflate(inflater, binding.container, false)
.also {
it.hintText.setText(textResId)
binding.container.addView(it.root)
}.root
val tvChangePhoneNumber = createItemView(R.string.change_phone_number)
if(!hasValidated){
val tvVerifyPhoneNumber = createItemView(R.string.verify_phone_number)
tvVerifyPhoneNumber.setOnClickListener {
dismiss()
listener.verifyPhoneNumber()
}
}
val tvTurnOffSmsReminder = createItemView(R.string.turn_off_sms_reminders)
tvChangePhoneNumber.setOnClickListener {
dismiss()
listener.changePhoneNumber()
}
tvTurnOffSmsReminder.setOnClickListener {
dismiss()
listener.updateSmsReminder(false)
}
}
companion object {
fun create(context: Context, hasValidated: Boolean, listener: OnReserveSuccessListener): EditBindPhoneInfoPop {
val binding = LayoutPopupContainerBinding.inflate(LayoutInflater.from(context))
return EditBindPhoneInfoPop(hasValidated, binding, listener)
}
}
}

View File

@ -0,0 +1,26 @@
package com.gh.common.pop
import android.content.Context
import android.view.LayoutInflater
import com.gh.common.dialog.OnReserveSuccessListener
import com.gh.gamecenter.R
import com.gh.gamecenter.common.databinding.LayoutPopupContainerBinding
class EditBindWechatPop(
binding: LayoutPopupContainerBinding,
private val listener: OnReserveSuccessListener
) : CommonPopupWindow(binding) {
override val viewDataList: List<ViewData>
get() = listOf(
ViewData(R.string.change_the_wechat_binding, listener::changeWechatBinding)
)
companion object {
fun create(context: Context, listener: OnReserveSuccessListener): EditBindWechatPop {
val inflater = LayoutInflater.from(context)
return EditBindWechatPop(LayoutPopupContainerBinding.inflate(inflater), listener).apply { initView() }
}
}
}

View File

@ -0,0 +1,69 @@
package com.gh.common.pop
import android.content.Context
import android.graphics.Color
import android.text.SpannableString
import android.text.TextPaint
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.core.text.set
import com.gh.common.dialog.OnReserveSuccessListener
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.toResString
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.PopRealNameTipsBinding
import com.halo.assistant.fragment.reserve.OnReserveReminderListener
class RealNameTipsPop(
private val binding: PopRealNameTipsBinding,
private val listener: OnReserveReminderListener
) :
BugFixedPopupWindow(binding.root, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) {
private val context: Context
get() = binding.root.context
init {
initView()
}
private fun initView() {
val text = R.string.reserve_real_name_description.toResString()
val spannableString = SpannableString(text)
val clickSpan = object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
ds.bgColor = Color.TRANSPARENT
ds.setColor(R.color.text_theme.toColor(context))
}
override fun onClick(widget: View) {
dismiss()
listener.realName()
}
}
spannableString.set(start = text.length - 6, end = text.length, span = clickSpan)
binding.tvRealNameDescription.text = spannableString
binding.tvRealNameDescription.movementMethod = LinkMovementMethod.getInstance()
binding.tvRealNameDescription.setHighlightColor(Color.TRANSPARENT)
}
companion object {
@JvmStatic
fun create(context: Context, listener: OnReserveReminderListener): RealNameTipsPop {
val pop = RealNameTipsPop(PopRealNameTipsBinding.inflate(LayoutInflater.from(context)), listener)
pop.isFocusable = true
pop.isOutsideTouchable = false
return pop
}
}
}

View File

@ -0,0 +1,95 @@
package com.gh.common.pop
import android.content.Context
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.CompoundButton
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.databinding.PopReserveAllSelectBinding
import com.gh.gamecenter.mygame.MyReservationFragment
class ReserveAllSelectPop(
val binding: PopReserveAllSelectBinding,
private val listener: OnReserveAllSelectListener
) : BugFixedPopupWindow(binding.root, ViewGroup.LayoutParams.MATCH_PARENT, 56F.dip2px()) {
private var pageStatus: MyReservationFragment.ReservePageState =
MyReservationFragment.ReservePageState.EnableAutoDownload
private val onCheckedChangeListener = { _: CompoundButton, isChecked: Boolean ->
val count = listener.selectAll(isChecked)
updateSelectedCount(count)
}
init {
isOutsideTouchable = false
binding.cbAll.setOnCheckedChangeListener(onCheckedChangeListener)
binding.tvSubmit.setOnClickListener {
listener.submit()
}
}
fun show(state: MyReservationFragment.ReservePageState, context: Context) {
enableSubmit(false)
binding.tvSubmit.setText(
if (state == MyReservationFragment.ReservePageState.EnableAutoDownload) {
R.string.enable_automatic_downloading_with_wifi
} else {
R.string.cancel_reserve
}
)
// 清空上一次的状态
pageStatus = state
updateSelectedCount(0)
if (!isShowing) {
showAtLocation((context as AppCompatActivity).window.decorView, Gravity.BOTTOM, 0, 0)
}
}
fun updateSelectedCount(count: Int) {
if (count == 0) {
enableSubmit(false)
binding.cbAll.setOnCheckedChangeListener(null)
binding.cbAll.isChecked = false
binding.cbAll.setOnCheckedChangeListener(onCheckedChangeListener)
} else {
enableSubmit(true)
binding.tvNumber.text = binding.root.context.getString(R.string.count_with_parentheses, "$count")
}
}
private fun enableSubmit(isEnable: Boolean) {
binding.tvSubmit.isEnabled = isEnable
if (isEnable) {
binding.tvSubmit.alpha = 1F
} else {
binding.tvSubmit.alpha = 0.4F
binding.tvNumber.setText(null)
}
}
companion object {
fun create(context: Context, listener: OnReserveAllSelectListener): ReserveAllSelectPop {
val inflater = LayoutInflater.from(context)
return ReserveAllSelectPop(PopReserveAllSelectBinding.inflate(inflater), listener)
}
}
interface OnReserveAllSelectListener {
fun selectAll(isChecked: Boolean): Int
fun submit()
}
}

View File

@ -5,25 +5,33 @@ import android.app.Activity
import android.app.Application.ActivityLifecycleCallbacks
import android.os.Bundle
import android.preference.PreferenceManager
import android.text.TextUtils
import androidx.fragment.app.FragmentActivity
import com.gh.common.iinterface.ISuperiorChain
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.SplashAdActivity
import com.gh.gamecenter.SplashScreenActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.SPUtils.getBoolean
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.DialogEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.ReserveOnlineEntity
import com.gh.gamecenter.feature.entity.WelcomeDialogEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.hud.PendingInstallHUDHandler
import com.gh.gamecenter.hud.ResumeDownloadHudHandler
import com.gh.gamecenter.login.entity.UserInfoEntity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
/**
@ -35,6 +43,7 @@ import io.reactivex.schedulers.Schedulers
object GlobalPriorityChainHelper : ISuperiorChain {
private val api = RetrofitManager.getInstance().api
private val newApi = RetrofitManager.getInstance().newApi
private var inferiorChain: PriorityChain? = null
private val mainChain: PriorityChain by lazy { PriorityChain { inferiorChain?.start() } }
@ -223,7 +232,7 @@ object GlobalPriorityChainHelper : ISuperiorChain {
/**
* 请求预约弹窗相关的数据
*/
@SuppressLint("CheckResult")
private fun requestReserveDialogData(reserveDialogHandler: ReserveDialogHandler) {
// debugOnly {
// reserveDialogHandler.doPreProcess(arrayListOf(SimpleGameEntity(
@ -236,23 +245,144 @@ object GlobalPriorityChainHelper : ISuperiorChain {
// }
if (CheckLoginUtils.isLogin()) {
api.getReserveDialog(UserManager.getInstance().userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<List<SimpleGameEntity>>() {
override fun onSuccess(data: List<SimpleGameEntity>) {
reserveDialogHandler.doPreProcess(data)
}
override fun onFailure(exception: Exception) {
reserveDialogHandler.doPreProcess(null)
}
})
val isTeenagerMode = getBoolean(Constants.SP_TEENAGER_MODE)
loadReserveDialogOnlineData(isTeenagerMode, reserveDialogHandler)
} else {
reserveDialogHandler.doPreProcess(null)
}
}
/**
* 由于用户预约的游戏个数没有限制为避免一次加载游戏过多这里采用先加载第一页显示出dialog,后续数据在第二页返回
* 注意:当page = 2 时,后台会将后续所有数据一次性返回,所以递归到第三层时,就会结束
* 当拉取第一页数据时,后台会将当前接口的数据全部标记为已读,这个时候在请求第一页数据会返回空(避免弹窗重复显示),但是第二页永远有数据(方便将后续自动下载的任务加入到下载队列)
* @param isTeenagerMode 青少年模式关闭时才需要启动自动下载,所以当 isTeenagerMode == true 时,不需要加载后续数据,也不需要启动自动下载
*/
@SuppressLint("CheckResult")
private fun loadReserveDialogOnlineData(isTeenagerMode: Boolean, handler: ReserveDialogHandler? = null) {
newApi.getReserveDialog()
.compose(singleToMain())
.subscribe(object : BiResponse<ReserveOnlineEntity>() {
override fun onSuccess(data: ReserveOnlineEntity) {
handler?.doPreProcess(data)
// 继续获取后续需要自动下载的游戏
loadGamesWithAutoDownload(1, 20, isTeenagerMode)
}
override fun onFailure(exception: Exception) {
handler?.doPreProcess(null)
}
})
}
/**
* 由于这个方法本身就是在子线程调用的,这里不需要另外在做线程切换
*/
@SuppressLint("CheckResult")
private fun loadGamesWithAutoDownload(page: Int, pageSize: Int, isTeenagerMode: Boolean) {
if (page >= 5) {
// 为防止死循环这里设置最多请求到第5页(正常情况下,第一页就是全部数据)
return
}
val filter = "wifi_auto_download:true"
newApi.loadGamesWithAutoDownload(page, pageSize, filter)
.subscribeOn(Schedulers.io())
.doOnSuccess(::trackAppointmentGameOnlineDialogShow)
.subscribe(object : BiResponse<List<GameEntity>>() {
override fun onSuccess(data: List<GameEntity>) {
// 请注意,这是在子线程中
if (data.isNotEmpty()) {
loadGamesWithAutoDownload(page + 1, pageSize, isTeenagerMode)
startAutoDownloadIfNeed(data, isTeenagerMode)
}
}
})
}
@SuppressLint("CheckResult")
private fun startAutoDownloadIfNeed(games: List<GameEntity>, isTeenagerMode: Boolean) {
val autoDownloadGameIds = mutableSetOf<String>()
games.forEach {
autoDownloadGameIds.add(it.id)
if (it.wifiAutoDownload && !it.isLandPageAddressDialog() && !isTeenagerMode) {
// 开启了 wifi 自动下载,并且不能为第三方落地页跳转
val apk = when (it.getApk().size) {
0 -> null
1 -> it.getApk().first()
else -> {
// 自动下载,多版本默认:九游版
it.getApk().find { apk -> "9u" == apk.getPlatform() && apk.isActive }
}
}
if (apk != null) {
val updateEntities = PackageUtils.getUpdateData(it, false)
val isCanUpdate = if (updateEntities.size == 1) {
true
} else {
// 多版本只需要判断九游版是否需要更新
updateEntities.any { update -> "9u" == update.platform }
}
val isCanPluggable = PackageUtils.isCanPluggable(apk)
if ((!PackageUtils.isInstalled(HaloApp.getInstance(), apk.packageName)
|| isCanUpdate
|| isCanPluggable)
&& DownloadManager.getInstance().getDownloadEntityByUrl(apk.url) == null
) {
// 未下载/可更新/可插件化 且 之前没有下载记录
val msg = FileUtils.isCanDownload(HaloApp.getInstance(), apk.size ?: "")
if (msg.isNullOrBlank()) {
val isWifiOpen = NetworkUtils.isWifiConnected(HaloApp.getInstance())
val isSubscribe = !isWifiOpen
DownloadManager.createDownload(
HaloApp.getInstance(),
apk,
it,
false,
false,
"",
"",
isSubscribe,
ExposureEvent.createEvent(it, listOf(ExposureSource("预约上线弹窗-自动下载", "")))
)
} else {
// 存储空间不足,直接跳出循环,放弃后续的所有游戏
ToastUtils.showToast(msg)
return@forEach
}
}
}
}
}
if (autoDownloadGameIds.isNotEmpty()) {
val body = hashMapOf(
"game_ids" to autoDownloadGameIds,
"type" to "wifi_auto_download"
)
newApi.logAutoDownload(body)
.subscribe({}, {})
}
}
private fun trackAppointmentGameOnlineDialogShow(games: List<GameEntity>) {
if (games.isNotEmpty()) {
val gameIds = arrayListOf<String>()
val gameNames = arrayListOf<String>()
val gameTypes = arrayListOf<String>()
games.forEach { game ->
gameIds.add(game.id)
gameNames.add(game.name ?: "")
gameTypes.add(game.categoryChinese)
}
val gameId = gameIds.joinToString()
val gameName = gameNames.joinToString()
val gameType = gameTypes.joinToString()
SensorsBridge.trackAppointmentGameOnlineDialogShow(gameId, gameName, gameType)
}
}
override fun registerInferiorChain(chain: PriorityChain) {
inferiorChain = chain
if (mainChain.isHandlerQueueEmpty()) {

View File

@ -2,28 +2,28 @@ package com.gh.common.prioritychain
import androidx.fragment.app.FragmentActivity
import com.gh.common.dialog.ReserveDialog
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.feature.entity.ReserveOnlineEntity
class ReserveDialogHandler(priority: Int) : PriorityChainHandler(priority) {
private var mReserveData: List<SimpleGameEntity>? = null
private var mReserveData: ReserveOnlineEntity? = null
/**
* 提前预处理显示弹窗的内容
*/
fun doPreProcess(reserveData: List<SimpleGameEntity>?) {
fun doPreProcess(reserveData: ReserveOnlineEntity?) {
mReserveData = reserveData
if (getStatus() == STATUS_PENDING) {
if (reserveData.isNullOrEmpty()) {
if (reserveData?.games.isNullOrEmpty()) {
processNext()
} else {
updateStatus(STATUS_VALID)
process()
}
} else {
if (reserveData.isNullOrEmpty()) {
if (reserveData?.games.isNullOrEmpty()) {
updateStatus(STATUS_INVALID)
} else {
updateStatus(STATUS_VALID)
@ -37,7 +37,7 @@ class ReserveDialogHandler(priority: Int) : PriorityChainHandler(priority) {
if (GlobalPriorityChainHelper.isThisActivityValid(currentActivity)) {
when (getStatus()) {
STATUS_VALID -> {
val reserveDialog = ReserveDialog.getInstance(mReserveData!!)
val reserveDialog = ReserveDialog.getInstance(mReserveData ?:ReserveOnlineEntity())
reserveDialog.setOnDismissListener {
processNext()
}

View File

@ -4,16 +4,19 @@ import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.WechatBindHelper
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.WechatConfigEntity
import com.gh.gamecenter.core.provider.IWechatBindHelperProvider
@Route(path = RouteConsts.provider.wechatHelper, name = "WechatHelper暴露服务")
class WechatHelperProviderImpl : IWechatBindHelperProvider {
override fun getWechatConfig(callback: (() -> Unit)?) {
class WechatHelperProviderImpl : IWechatBindHelperProvider<WechatConfigEntity> {
override fun getWechatConfig(callback: ((WechatConfigEntity) -> Unit)?) {
WechatBindHelper.getWechatConfig {
callback?.invoke()
callback?.invoke(it)
}
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -2,6 +2,7 @@ package com.gh.common.util;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
@ -66,6 +67,7 @@ import com.gh.gamecenter.databinding.DialogReportReasonBinding;
import com.gh.gamecenter.databinding.DialogWechatReserveSuccessBinding;
import com.gh.gamecenter.databinding.ImprintContentItemBinding;
import com.gh.gamecenter.entity.BadgeEntity;
import com.gh.gamecenter.entity.ReserveReminderEntity;
import com.gh.gamecenter.entity.TrackableEntity;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.Badge;
@ -73,6 +75,7 @@ import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.SettingsEntity;
import com.gh.gamecenter.help.HelpAndFeedbackBridge;
import com.gh.gamecenter.setting.SettingBridge;
import com.halo.assistant.fragment.reserve.ReserveReminderContainerFragment;
import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.Util_System_Keyboard;
@ -148,6 +151,7 @@ public class DialogUtils {
}
return false;
}
public static void showNoConnectionDownloadDialog(Context context, ConfirmListener listener, CancelListener cancelListener) {
DialogHelper.showDialog(context, "下载提示", "网络异常,请检查手机网络状态", "知道了", "WiFi自动下载", listener::onConfirm, cancelListener::onCancel, false, "", "");
}
@ -1224,7 +1228,7 @@ public class DialogUtils {
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
DialogWechatReserveSuccessBinding binding = DialogWechatReserveSuccessBinding.inflate(LayoutInflater.from(context));
binding.titleIv.setImageResource(isReserve ? R.drawable.bg_reserve_success : R.drawable.bg_vote_success);
binding.contentTv.setText(isReserve ? "游戏上线时,您将在消息中心收到通知。为了避免错过通知,建议您开启微信公众号提醒": "版本上线时,您将在消息中心收到通知。为了避免错过通知,亦建议您开启微信公众号提醒");
binding.contentTv.setText(isReserve ? "游戏上线时,您将在消息中心收到通知。为了避免错过通知,建议您开启微信公众号提醒" : "版本上线时,您将在消息中心收到通知。为了避免错过通知,亦建议您开启微信公众号提醒");
binding.closeBtn.setOnClickListener(v -> {
cancelListener.onCancel();
dialog.dismiss();
@ -1269,6 +1273,10 @@ public class DialogUtils {
}
}
public static void showReserveReminderDialog(Context context, GameEntity gameEntity, ReserveReminderEntity reserveReminder) {
ReserveReminderContainerFragment.show(context, gameEntity, reserveReminder);
}
public static void showRelievePhoneDialog(Context context) {
context = checkDialogContext(context);

View File

@ -27,6 +27,8 @@ import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.base.GlobalActivityManager.getCurrentPageEntity
import com.gh.gamecenter.common.base.GlobalActivityManager.getLastPageEntity
import com.gh.gamecenter.common.callback.CancelListener
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
@ -128,6 +130,7 @@ object DownloadItemUtils {
holder.gameDownloadBtn.text = "已预约"
holder.gameDownloadBtn.visibility = View.VISIBLE
holder.gameDownloadBtn.buttonStyle = DownloadButton.ButtonStyle.RESERVED
holder.multiVersionDownloadTv.visibility = View.GONE
updateItemViewStatus(holder, null, null)
}
}
@ -297,11 +300,13 @@ object DownloadItemUtils {
// 来自于下载管理的实体快照
val entityFromDownloadManager = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
// 是否正在下载中
val isDownloading = entityFromDownloadManager != null && entityFromDownloadManager.status != DownloadStatus.done
val isDownloading =
entityFromDownloadManager != null && entityFromDownloadManager.status != DownloadStatus.done
// 是否已安装至本地
val isInstalledLocally = PackagesManager.isInstalled(gameEntity.getUniquePackageName())
// 来自于畅玩安装列表的实体快照,若存在,代表游戏已下载并成功安装
val entityFromInstalledVGame = VHelper.getVDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
val entityFromInstalledVGame =
VHelper.getVDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
// 是否已安装至畅玩
val isInstalledToVSpace = entityFromInstalledVGame != null
// 是否处于待安装状态 (仅本地安装有这个状态)
@ -318,19 +323,20 @@ object DownloadItemUtils {
// 3. 存在待安装任务时,待安装任务优先
// 4. 存在一个已安装,已安装的显示优先
// 5. 都已安装,按后台配置显示的状态优先
val isVGamePreferred = if (!isInstalledLocally && !isInstalledToVSpace && entityFromDownloadManager == null) {
gameEntity.isVGamePreferred()
} else if (isDownloading || isPendingToInstall) {
entityFromDownloadManager?.isVGameDownloadInDualDownloadMode() == true
} else if (isInstalledLocally && isInstalledToVSpace) {
gameEntity.isVGamePreferred()
} else if (isInstalledLocally) {
false
} else if (isInstalledToVSpace) {
true
} else {
gameEntity.isVGamePreferred()
}
val isVGamePreferred =
if (!isInstalledLocally && !isInstalledToVSpace && entityFromDownloadManager == null) {
gameEntity.isVGamePreferred()
} else if (isDownloading || isPendingToInstall) {
entityFromDownloadManager?.isVGameDownloadInDualDownloadMode() == true
} else if (isInstalledLocally && isInstalledToVSpace) {
gameEntity.isVGamePreferred()
} else if (isInstalledLocally) {
false
} else if (isInstalledToVSpace) {
true
} else {
gameEntity.isVGamePreferred()
}
val downloadEntity: DownloadEntity? = if (isDownloading) {
entityFromDownloadManager
@ -386,7 +392,11 @@ object DownloadItemUtils {
if (PackagesManager.isInstalled(downloadEntity.packageName) && !downloadEntity.isUpdate) {
// 双下载按钮快速安装时存在已下载的安装包过时,需要重新下载的情况
if (PackagesManager.isCanUpdate(downloadEntity.gameId, downloadEntity.packageName)) {
if (PackagesManager.isCanUpdate(
downloadEntity.gameId,
downloadEntity.packageName
)
) {
buttonStyle = DownloadButton.ButtonStyle.NORMAL
setText(R.string.update)
} else {
@ -626,7 +636,17 @@ object DownloadItemUtils {
location: String,
sourceEntrance: String = "其他"
) {
setOnClickListener(context, downloadBtn, gameEntity, position, adapter, entrance, sourceEntrance, location, null)
setOnClickListener(
context,
downloadBtn,
gameEntity,
position,
adapter,
entrance,
sourceEntrance,
location,
null
)
}
@JvmStatic
@ -641,7 +661,18 @@ object DownloadItemUtils {
location: String,
traceEvent: ExposureEvent?,
) {
setOnClickListener(context, downloadBtn, gameEntity, position, adapter, entrance, sourceEntrance, location, traceEvent, null)
setOnClickListener(
context,
downloadBtn,
gameEntity,
position,
adapter,
entrance,
sourceEntrance,
location,
traceEvent,
null
)
}
/**
@ -779,14 +810,18 @@ object DownloadItemUtils {
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.id)) {
SensorsBridge.trackEvent(
"AppointmentGame",
"game_name",
gameEntity.name ?: "",
"game_id",
gameEntity.id,
"game_type",
gameEntity.categoryChinese,
"source_entrance",
sourceEntrance
"game_name", gameEntity.name ?: "",
"game_id", gameEntity.id,
"game_type", gameEntity.categoryChinese,
"source_entrance", sourceEntrance,
"page_name", getCurrentPageEntity().pageName,
"page_id", getCurrentPageEntity().pageId,
"page_business_id", getCurrentPageEntity().pageBusinessId,
"last_page_name", getLastPageEntity().pageName,
"last_page_id", getLastPageEntity().pageId,
"last_page_business_id", getLastPageEntity().pageBusinessId,
"source", gameEntity.exposureEvent?.source?.toString() ?: "",
*gameEntity.customPageTrackData?.toKV() ?: arrayOf()
)
allStateClickCallback?.onCallback()
CheckLoginUtils.checkLogin(context, entrance) {
@ -812,7 +847,7 @@ object DownloadItemUtils {
}
}
} else {
ReservationHelper.showCancelReservationDialog(context, {
ReservationHelper.showCancelReservationDialog(context, gameEntity,{
NewFlatLogUtils.logMyGameCancelReserveDialogClick(
"确定取消",
gameEntity.id,
@ -954,7 +989,16 @@ object DownloadItemUtils {
addHandler(CheckDownloadHandler())
}
.setProcessEndCallback { asVGame, isSubscribe ->
download(context, gameEntity, downloadBtn, entrance, location, asVGame, isSubscribe as Boolean, traceEvent)
download(
context,
gameEntity,
downloadBtn,
entrance,
location,
asVGame,
isSubscribe as Boolean,
traceEvent
)
}
.buildHandlerChain()
?.handleRequest(context, gameEntity, shouldPerformAsVGame)
@ -973,7 +1017,16 @@ object DownloadItemUtils {
addHandler(CheckDownloadHandler())
}
.setProcessEndCallback { asVGame, isSubscribe ->
download(context, gameEntity, downloadBtn, entrance, location, asVGame, isSubscribe as Boolean, traceEvent)
download(
context,
gameEntity,
downloadBtn,
entrance,
location,
asVGame,
isSubscribe as Boolean,
traceEvent
)
}
.buildHandlerChain()
?.handleRequest(context, gameEntity, shouldPerformAsVGame)
@ -992,7 +1045,16 @@ object DownloadItemUtils {
addHandler(CheckDownloadHandler())
}
.setProcessEndCallback { asVGame, isSubscribe ->
download(context, gameEntity, downloadBtn, entrance, location, asVGame, isSubscribe as Boolean, traceEvent)
download(
context,
gameEntity,
downloadBtn,
entrance,
location,
asVGame,
isSubscribe as Boolean,
traceEvent
)
}
.buildHandlerChain()
?.handleRequest(context, gameEntity, shouldPerformAsVGame)
@ -1057,7 +1119,8 @@ object DownloadItemUtils {
NewSimulatorGameManager.showUpdateNewsSimulator(context, gameEntity, null)
return
}
val downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().firstOrNull()?.url)
val downloadEntity =
SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().firstOrNull()?.url)
if (downloadEntity != null) {
val file = File(downloadEntity.path)
if (!file.exists()) {

View File

@ -53,6 +53,12 @@ object DownloadObserver {
private val mRetryableHashMap = hashMapOf<String, Boolean>()
/**
* 当下载任务是 预约上线提醒 触发的,则所有弹窗均不显示
*/
private val DownloadEntity.isDownloadByReserveOnlineReminder: Boolean
get() = !meta?.get(Constants.IS_RESERVE_ONLINE_REMINDER).isNullOrBlank()
// 如果在WIFI状态下,下载自动暂停,则再重试一遍
@JvmStatic
fun initObserver() {
@ -71,6 +77,9 @@ object DownloadObserver {
if (DownloadStatus.hijack == downloadEntity.status) {
// 链接被劫持
if(downloadEntity.isDownloadByReserveOnlineReminder){
return
}
processHijack(downloadEntity)
return
} else if (DownloadStatus.notfound == downloadEntity.status) {
@ -87,7 +96,9 @@ object DownloadObserver {
gameName = downloadEntity.name,
gameType = downloadEntity.categoryChinese
)
if(downloadEntity.isDownloadByReserveOnlineReminder){
return
}
DialogHelper.showDialog(
currentActivity,
"下载失败",
@ -155,7 +166,9 @@ object DownloadObserver {
DownloadDataHelper.uploadRedirectEvent(downloadEntity)
} else if (DownloadStatus.unqualified == downloadEntity.status) {
// 未成年
RealNameHelper.showRealNameUnqualifiedDialog(downloadEntity)
if(!downloadEntity.isDownloadByReserveOnlineReminder){
RealNameHelper.showRealNameUnqualifiedDialog(downloadEntity)
}
// 删除任务
downloadEntity.status = DownloadStatus.cancel
@ -164,7 +177,7 @@ object DownloadObserver {
// 未接入防沉迷系统
val currentActivity = AppManager.getInstance().currentActivity()
if (currentActivity != null) {
if (currentActivity != null && !downloadEntity.isDownloadByReserveOnlineReminder) {
DialogHelper.showDialog(
context = currentActivity,
title = "温馨提示",
@ -183,7 +196,7 @@ object DownloadObserver {
// 未接入防沉迷系统
val currentActivity = AppManager.getInstance().currentActivity()
if (currentActivity != null) {
if (currentActivity != null && !downloadEntity.isDownloadByReserveOnlineReminder) {
DialogHelper.showDialog(
context = currentActivity,
title = "实名提示",
@ -209,7 +222,9 @@ object DownloadObserver {
downloadManager.cancel(downloadEntity.url)
} else if (DownloadStatus.uncertificated == downloadEntity.status) {
// 未实名
RealNameHelper.showRealNameUncertificatedDialog(downloadEntity)
if(!downloadEntity.isDownloadByReserveOnlineReminder){
RealNameHelper.showRealNameUncertificatedDialog(downloadEntity)
}
// 删除任务
downloadEntity.status = DownloadStatus.cancel
@ -224,11 +239,15 @@ object DownloadObserver {
if (DownloadStatus.done == downloadEntity.status) {
if (mDoneDebouncePair?.first != downloadEntity.url) {
mDoneDebouncePair = Pair(downloadEntity.url, System.currentTimeMillis())
// 清理临时变量
downloadEntity.addMetaExtra(Constants.IS_RESERVE_ONLINE_REMINDER, "")
performDownloadCompleteAction(downloadEntity, downloadManager)
} else {
if (mDoneDebouncePair?.second == 0L
|| System.currentTimeMillis() - (mDoneDebouncePair?.second ?: 0) > 500
) {
// 清理临时变量
downloadEntity.addMetaExtra(Constants.IS_RESERVE_ONLINE_REMINDER, "")
performDownloadCompleteAction(downloadEntity, downloadManager)
}
}
@ -508,7 +527,7 @@ object DownloadObserver {
"space_schema_type",
if (downloadEntity.packageName == VHelper.VSPACE_32BIT_PACKAGENAME) "32位" else "64位"
)
} else if(downloadEntity.gameId == Constants.HALO_FUN_NEW_32_GAME_ID) {
} else if (downloadEntity.gameId == Constants.HALO_FUN_NEW_32_GAME_ID) {
SensorsBridge.trackEvent(
"HaloFunDownloadDone",
"space_schema_type",

View File

@ -7,13 +7,13 @@ import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.constant.Config
import com.gh.common.dialog.WechatBindingFailedDialogFragment
import com.gh.gamecenter.R
import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.VerifyPhoneActivity
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.avoidcallback.AvoidOnResultManager
import com.gh.gamecenter.common.avoidcallback.Callback
import com.gh.gamecenter.common.callback.CancelListener
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
@ -191,7 +191,7 @@ object ErrorHelper {
403018 -> Utils.toast(context, R.string.comment_failed_unable)
403070 -> Utils.toast(context, "请勿重复提交~")
403073 -> Utils.toast(context, "标题违规,请重新编辑")
403074 -> Utils.toast(context, "该微信号(${errorEntity.data?.nickname})已绑定")
403074 -> handleErrorWithRepeatWechatBinding(context, errorEntity)
403078 -> Utils.toast(context, "已点赞")
403072 -> Utils.toast(context, R.string.comment_failed_userblocked)
403082 -> Utils.toast(context, "作者已关闭评论")
@ -234,6 +234,10 @@ object ErrorHelper {
}
}
private fun handleErrorWithRepeatWechatBinding(context: Context, errorEntity: ErrorEntity) {
WechatBindingFailedDialogFragment.show(context, errorEntity.data?.userConflict)
}
private fun handleAskFrequentlyError(context: Context, showHighPriorityHint: Boolean) {
if (showHighPriorityHint) {
DialogHelper.showDialog(
@ -261,7 +265,7 @@ object ErrorHelper {
SensorsBridge.trackVerificationDialogShow(
gameId = gameEntity?.id ?: "",
gameName = gameEntity?.name ?: "",
gameType = gameEntity?.categoryChinese ?:"",
gameType = gameEntity?.categoryChinese ?: "",
articleType = articleType,
verificationType = verificationType
)

View File

@ -1815,60 +1815,6 @@ object NewLogUtils {
log(json, LOG_STORE_EVENT)
}
//成功预约游戏
@JvmStatic
fun logReserveGameSuccess(wechatConfigEntity: WechatConfigEntity) {
val json = json {
KEY_EVENT to "appointment_wechat_appointment_game"
"wechat_is_bind" to wechatConfigEntity.bind
"wechat_is_follow" to wechatConfigEntity.follow
"wechat_is_remind" to wechatConfigEntity.notice
KEY_TIMESTAMP to System.currentTimeMillis() / 1000
parseAndPutMeta().invoke(this)
}
log(json, "appointment", false)
}
//引导设置微信提醒弹窗事件
@JvmStatic
fun logReserveWechatRemindPopShow(wechatConfigEntity: WechatConfigEntity) {
val json = json {
KEY_EVENT to "appointment_wechat_remind_pop_show"
"wechat_is_bind" to wechatConfigEntity.bind
"wechat_is_follow" to wechatConfigEntity.follow
"wechat_is_remind" to wechatConfigEntity.notice
KEY_TIMESTAMP to System.currentTimeMillis() / 1000
parseAndPutMeta().invoke(this)
}
log(json, "appointment", false)
}
//引导设置微信提醒弹窗点击事件
@JvmStatic
fun logReserveWechatRemindPopClick(wechatConfigEntity: WechatConfigEntity, operationType: String) {
val json = json {
KEY_EVENT to "appointment_wechat_remind_pop_click"
"wechat_is_bind" to wechatConfigEntity.bind
"wechat_is_follow" to wechatConfigEntity.follow
"wechat_is_remind" to wechatConfigEntity.notice
"operation_type" to operationType
KEY_TIMESTAMP to System.currentTimeMillis() / 1000
parseAndPutMeta().invoke(this)
}
log(json, "appointment", false)
}
//预约成功弹窗事件
@JvmStatic
fun logReserveWechatSuccessPopShow() {
val json = json {
KEY_EVENT to "appointment_wechat_success_pop_show"
KEY_TIMESTAMP to System.currentTimeMillis() / 1000
parseAndPutMeta().invoke(this)
}
log(json, "appointment", false)
}
//选择图片上传方式
@JvmStatic
fun logShowGameCollectionCoverTypeDialog() {

View File

@ -2,22 +2,29 @@ package com.gh.common.util
import android.annotation.SuppressLint
import android.content.Context
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.gamecenter.common.constant.Constants
import com.gh.common.repository.ReservationRepository
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.base.GlobalActivityManager.getCurrentPageEntity
import com.gh.gamecenter.common.base.GlobalActivityManager.getLastPageEntity
import com.gh.gamecenter.common.callback.CancelListener
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.WechatConfigEntity
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.entity.ReserveReminderEntity
import com.gh.gamecenter.jg.push.service.HaloJPushMessageReceiver
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.RequestBody
import okhttp3.ResponseBody
object ReservationHelper {
@ -38,18 +45,22 @@ object ReservationHelper {
deleteReservation: Boolean,
refreshCallback: EmptyCallback
) {
val retrofit = RetrofitManager.getInstance()
val requestMap = hashMapOf<String, String>()
requestMap["game_id"] = game.id
val retrofit = RetrofitManager.getInstance()
val single = if (deleteReservation) {
retrofit.api
.deleteGameReservation(requestMap.createRequestBody())
retrofit.newApi
.deleteGameReservation(
game.id,
getReserveRequestBody(game, context = HaloApp.getInstance().application)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
} else {
retrofit.api
.cancelGameReservation(requestMap.createRequestBody())
retrofit.newApi
.cancelGameReservation(
game.id,
getReserveRequestBody(game, context = HaloApp.getInstance().application)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
@ -70,71 +81,65 @@ object ReservationHelper {
@JvmStatic
@SuppressLint("CheckResult")
fun reserve(context: Context, game: GameEntity?, sourceEntrance: String = "其他", callback: EmptyCallback) {
val requestMap = hashMapOf<String, String>()
requestMap["game_id"] = game?.id ?: ""
RetrofitManager.getInstance().api
.createNewGameReservation(requestMap.createRequestBody())
.compose(singleToMain())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
RetrofitManager.getInstance().newApi
.createNewGameReservation(game?.id ?: "", getReserveRequestBody(game, context))
.compose(singleToMain())
.subscribe(object : BiResponse<ReserveReminderEntity>() {
override fun onSuccess(data: ReserveReminderEntity) {
SensorsBridge.trackEvent(
"AppointmentGameResult",
"game_name",
game?.name ?: "",
"game_id",
game?.id ?: "",
"game_type",
game?.categoryChinese ?: "",
"result",
"成功",
"source_entrance",
sourceEntrance
"game_name", game?.name ?: "",
"game_id", game?.id ?: "",
"game_type", game?.categoryChinese ?: "",
"result", "成功",
"source_entrance", sourceEntrance,
"page_name", getCurrentPageEntity().pageName,
"page_id", getCurrentPageEntity().pageId,
"page_business_id", getCurrentPageEntity().pageBusinessId,
"last_page_name", getLastPageEntity().pageName,
"last_page_id", getLastPageEntity().pageId,
"last_page_business_id", getLastPageEntity().pageBusinessId,
"source", game?.exposureEvent?.source?.toString() ?: "",
*game?.customPageTrackData?.toKV() ?: arrayOf()
)
ReservationRepository.addReservationToMemoryAndRefresh(game?.id ?: "")
callback.onCallback()
val wechatConfig = SPUtils.getString(Constants.SP_WECHAT_CONFIG).toObject<WechatConfigEntity>()
wechatConfig?.run {
NewLogUtils.logReserveGameSuccess(wechatConfig)
if (bind && follow && notice) {
NewLogUtils.logReserveWechatSuccessPopShow()
DialogUtils.showReserveOrVoteSuccessDialog(context, true)
} else {
NewLogUtils.logReserveWechatRemindPopShow(wechatConfig)
SensorsBridge.trackEvent("AppointmenWechatRemindDialogShow")
DialogUtils.showReserveOrVoteSuccess2WechatBindDialog(context, true, {
NewLogUtils.logReserveWechatRemindPopClick(wechatConfig, "开启微信提醒")
SensorsBridge.trackEvent("AppointmenWechatRemindDialogClick")
context.startActivity(WebActivity.getBindWechatIntent(context))
SensorsBridge.trackEvent(
"AppointmenWechatRemindConfigPageShow",
"source_entrance",
"设置微信提醒弹窗"
)
}, object : CancelListener {
override fun onCancel() {
NewLogUtils.logReserveWechatRemindPopClick(wechatConfig, "关闭弹窗")
SensorsBridge.trackEvent("AppointmenWechatRemindDialogClick")
}
})
}
checkWechatConfigEntityUpdated(data.wechatConfig)
game?.let {
SensorsBridge.trackAppointmentSuccessDialogShow(
it.id,
it.name ?: "",
it.categoryChinese,
data.wechatConfig.isReminderEnable,
if (data.hasSmsConfig) data.smsConfig.notice else null,
if (data.isEnableAutoDownload) data.wifiAutoDownload else null
)
}
DialogUtils.showReserveReminderDialog(context, game, data)
}
override fun onFailure(exception: Exception) {
SensorsBridge.trackEvent(
"AppointmentGameResult",
"game_name",
game?.name ?: "",
"game_id",
game?.id ?: "",
"game_type",
game?.categoryChinese ?: "",
"result",
"失败",
"source_entrance",
sourceEntrance
"game_name", game?.name ?: "",
"game_id", game?.id ?: "",
"game_type", game?.categoryChinese ?: "",
"result", "失败",
"source_entrance", sourceEntrance,
"page_name", getCurrentPageEntity().pageName,
"page_id", getCurrentPageEntity().pageId,
"page_business_id", getCurrentPageEntity().pageBusinessId,
"last_page_name", getLastPageEntity().pageName,
"last_page_id", getLastPageEntity().pageId,
"last_page_business_id", getLastPageEntity().pageBusinessId,
"source", game?.exposureEvent?.source?.toString() ?: "",
*game?.customPageTrackData?.toKV() ?: arrayOf()
)
ToastUtils.showToast(exception.message ?: "")
}
@ -157,24 +162,81 @@ object ReservationHelper {
}
@JvmStatic
fun showCancelReservationDialog(context: Context, emptyCallback: EmptyCallback) {
showCancelReservationDialog(context, emptyCallback, null)
fun showCancelReservationDialog(context: Context, game: GameEntity?, emptyCallback: EmptyCallback) {
showCancelReservationDialog(context, game, emptyCallback, null)
}
@JvmStatic
fun showCancelReservationDialog(context: Context, emptyCallback: EmptyCallback, cancelListener: CancelListener?) {
fun showCancelReservationDialog(
context: Context,
game: GameEntity?,
emptyCallback: EmptyCallback,
cancelListener: CancelListener?,
dialogCancelCallback: (() -> Unit)? = null
) {
if (game != null) {
SensorsBridge.trackCancelAppointmentDialogShow(game.id, game.name ?: "", game.categoryChinese)
}
DialogHelper.showDialog(context, "取消预约",
"取消之后你将无法收到游戏上线的通知,确定取消预约吗?",
"确定取消",
"暂不取消", confirmClickCallback = {
if (game != null) {
SensorsBridge.trackCancelAppointmentDialogClick(
game.id,
game.name ?: "",
game.categoryChinese,
"确定取消"
)
}
emptyCallback.onCallback()
}, cancelClickCallback = {
if (game != null) {
SensorsBridge.trackCancelAppointmentDialogClick(
game.id,
game.name ?: "",
game.categoryChinese,
"暂不取消"
)
}
cancelListener?.onCancel()
}, uiModificationCallback = {
it.confirmTv.setTextColor(R.color.secondary_red.toColor(context))
}, extraConfig = DialogHelper.Config(centerContent = true, centerTitle = true)
}, extraConfig = DialogHelper.Config(centerContent = true, centerTitle = true),
dialogCancelCallback = {
if (game != null) {
SensorsBridge.trackCancelAppointmentDialogClick(
game.id,
game.name ?: "",
game.categoryChinese,
"关闭弹窗"
)
}
dialogCancelCallback?.invoke()
}
)
}
private fun checkWechatConfigEntityUpdated(newWechatConfig: WechatConfigEntity) {
val wechatConfig = SPUtils.getString(Constants.SP_WECHAT_CONFIG).toObject<WechatConfigEntity>()
if (wechatConfig != newWechatConfig) {
SPUtils.setString(Constants.SP_WECHAT_CONFIG, newWechatConfig.toJson())
}
}
@JvmStatic
fun getReserveRequestBody(game: GameEntity?, context: Context): RequestBody {
val jPushId =
(ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider)
?.getRegistrationId(context) ?: ""
var mirrorPosition = game?.getMirrorPosition() ?: 0
if (mirrorPosition == -1) {
mirrorPosition = 0
}
val body = hashMapOf(
"jpush_id" to jPushId,
"mirror_type" to mirrorPosition
).toRequestBody()
return body
}
}

View File

@ -22,7 +22,7 @@ object WechatBindHelper {
fun getWechatConfig(callback: ((WechatConfigEntity) -> Unit)? = null) {
if (!UserManager.getInstance().isLoggedIn) return
RetrofitManager.getInstance()
.api
.newApi
.wechatConfig
.compose(singleToMain())
.subscribe(object : BiResponse<WechatConfigEntity>() {
@ -36,7 +36,7 @@ object WechatBindHelper {
@SuppressLint("CheckResult")
fun bindWechat(wechatLoginInfoMap: Map<String, String>, callback: BiCallback<Boolean, Boolean>) {
RetrofitManager.getInstance()
.api
.newApi
.postBindWechat(wechatLoginInfoMap.createRequestBody())
.compose(singleToMain())
.subscribe(object : BiResponse<ResponseBody>() {

View File

@ -1,5 +1,7 @@
package com.gh.download;
import static com.gh.gamecenter.common.constant.Constants.IS_RESERVE_ONLINE_REMINDER;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
@ -413,6 +415,12 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setCustomPageTrackData(trackJson);
}
// 是否时预约上线提醒时,开启的自动下载(如果是这种情况开启的自动下载,则下载过程中的验证弹窗全部不显示)
boolean wifiAutoDownload = gameEntity.getWifiAutoDownload();
if (wifiAutoDownload) {
// 注意,这只是临时变量,用户在下载过程中,判断当前任务是否是预约上线触发的下载,下载完成后,请及时清理此字段
ExtensionsKt.addMetaExtra(downloadEntity, IS_RESERVE_ONLINE_REMINDER, IS_RESERVE_ONLINE_REMINDER);
}
if (isSubscribe) {
DownloadManager.getInstance().subscribe(downloadEntity);
} else {

View File

@ -27,6 +27,8 @@ import com.gh.download.dialog.DownloadDialog
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.base.GlobalActivityManager.getCurrentPageEntity
import com.gh.gamecenter.common.base.GlobalActivityManager.getLastPageEntity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.eventbus.EBReuse
@ -210,7 +212,8 @@ class DetailViewHolder(
&& downloadButton.buttonStyle !== ButtonStyle.INSTALL_PLUGIN
&& downloadButton.buttonStyle !== ButtonStyle.LAUNCH_OR_OPEN
&& downloadButton.buttonStyle !== ButtonStyle.NONE
&& downloadButton.buttonStyle !== ButtonStyle.NONE_WITH_HINT) {
&& downloadButton.buttonStyle !== ButtonStyle.NONE_WITH_HINT
) {
// 畅玩游戏的非真实点击下载按钮下载不需要滚动到特定地方
if (!mAsVGame || VHelper.shouldLaunchGameAfterInstallation()) {
EventBus.getDefault().post(EBScroll(Constants.EB_GAME_DETAIL, mGameEntity.id))
@ -304,7 +307,8 @@ class DetailViewHolder(
NewSimulatorGameManager.showUpdateNewsSimulator(mViewHolder.context, mGameEntity, null)
return
}
val downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(mGameEntity.getApk().firstOrNull()?.url)
val downloadEntity =
SimulatorGameManager.findDownloadEntityByUrl(mGameEntity.getApk().firstOrNull()?.url)
if (downloadEntity != null) {
val file = File(downloadEntity.path)
if (!file.exists()) {
@ -429,8 +433,15 @@ class DetailViewHolder(
mGameEntity.id,
"game_type",
mGameEntity.categoryChinese,
"source_entrance",
"其他"
"source_entrance", "其他",
"page_name", getCurrentPageEntity().pageName,
"page_id", getCurrentPageEntity().pageId,
"page_business_id", getCurrentPageEntity().pageBusinessId,
"last_page_name", getLastPageEntity().pageName,
"last_page_id", getLastPageEntity().pageId,
"last_page_business_id", getLastPageEntity().pageBusinessId,
"source", mGameEntity.exposureEvent?.source?.toString() ?: "",
*mGameEntity.customPageTrackData?.toKV() ?: arrayOf()
)
CheckLoginUtils.checkLogin(mViewHolder.context, mEntrance) {
ReservationHelper.reserve(mViewHolder.context, mGameEntity) {
@ -449,7 +460,7 @@ class DetailViewHolder(
}
}
} else {
ReservationHelper.showCancelReservationDialog(mViewHolder.context) {
ReservationHelper.showCancelReservationDialog(mViewHolder.context, mGameEntity) {
ReservationHelper.cancelReservation(mGameEntity) {
DetailDownloadUtils.updateViewHolder(mViewHolder)
}
@ -483,6 +494,7 @@ class DetailViewHolder(
ToastUtils.toast("正在加急更新版本,敬请后续留意")
showLandPageAddressDialogIfNeeded()
}
ButtonStyle.TEENAGER_MODE -> {
SensorsBridge.trackAdolescentModeDialogShow(
mGameEntity.id,
@ -506,11 +518,11 @@ class DetailViewHolder(
},
negativeClickCallback = {
SensorsBridge.trackAdolescentModeDialogClick(
"关闭弹窗",
mGameEntity.id,
(if (mGameEntity.name != null) mGameEntity.name else "")!!,
mGameEntity.categoryChinese
)
"关闭弹窗",
mGameEntity.id,
(if (mGameEntity.name != null) mGameEntity.name else "")!!,
mGameEntity.categoryChinese
)
}
) {
SensorsBridge.trackAdolescentModeDialogClick(
@ -544,7 +556,8 @@ class DetailViewHolder(
DownloadManager.getInstance().resume(mDownloadEntity, false)
} else {
DownloadManager.getInstance().pause(mDownloadEntity!!.url)
downloadButton.text = "${DetailDownloadUtils.getValidProgress(mDownloadEntity)}% $mPausedText"
downloadButton.text =
"${DetailDownloadUtils.getValidProgress(mDownloadEntity)}% $mPausedText"
}
}
}
@ -618,7 +631,8 @@ class DetailViewHolder(
if (mShowDualDownloadButton
&& downloadEntity != null
&& downloadEntity.status == DownloadStatus.done
&& !FileUtils.isEmptyFile(downloadEntity.path)) {
&& !FileUtils.isEmptyFile(downloadEntity.path)
) {
if (downloadEntity.getMetaExtra(Constants.APK_MD5) != mGameEntity.getApk().firstOrNull()?.md5) {
// 已下载的 md5 与接口返回的不一样,不使用快速安装功能,重新下载安装

View File

@ -0,0 +1,12 @@
package com.gh.gamecenter.entity
import com.google.gson.annotations.SerializedName
data class ReserveModifyEntity(
@SerializedName("sms_config")
private val _smsConfig: ReserveReminderEntity.SmsConfig? = null
) {
val smsConfig: ReserveReminderEntity.SmsConfig
get() = _smsConfig ?: ReserveReminderEntity.SmsConfig()
}

View File

@ -0,0 +1,84 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.gh.gamecenter.common.entity.WechatConfigEntity
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
data class ReserveReminderEntity(
@SerializedName("sms_config")
private var _smsConfig: SmsConfig? = null,
@SerializedName("wechat_config")
private var _wechatConfig: WechatConfigEntity? = null,
@SerializedName("mirror_type")
private val _mirrorType: String? = null,
@SerializedName("wifi_auto_download")
private val _wifiAutoDownload: Boolean? = null,
@SerializedName("jpush_id")
private val _jpushId: String? = null
) : Parcelable {
val hasSmsConfig: Boolean
get() = _smsConfig != null
var smsConfig: SmsConfig
get() = _smsConfig ?: SmsConfig()
set(value) {
_smsConfig = value
}
var wechatConfig: WechatConfigEntity
get() = _wechatConfig ?: WechatConfigEntity()
set(value) {
_wechatConfig = value
}
val onlyShowWechatReminder: Boolean
get() = _smsConfig == null
val mirrorType: String
get() = _mirrorType ?: ""
val wifiAutoDownload: Boolean
get() = _wifiAutoDownload ?: true
val isEnableAutoDownload: Boolean
get() = _wifiAutoDownload != null
val jpushId: String
get() = _jpushId ?: ""
companion object {
private const val ON = "on"
}
@Parcelize
data class SmsConfig(
@SerializedName("notice")
private var _notice: Boolean? = null,
@SerializedName("mobile")
private val _mobile: String? = null,
@SerializedName("mobile_validated")
private var _mobileValidated: Boolean? = null
) : Parcelable {
var notice: Boolean
get() = _notice ?: false
set(value) {
_notice = value
}
val mobile: String
get() = _mobile ?: ""
var mobileValidated: Boolean
get() = _mobileValidated ?: false
set(value) {
_mobileValidated = value
}
}
}

View File

@ -0,0 +1,12 @@
package com.gh.gamecenter.entity
import com.google.gson.annotations.SerializedName
data class ValidateCodeRequest(
@SerializedName("mobile")
val mobile: String,
@SerializedName("service_id")
val serviceId: String,
@SerializedName("code")
val code: String
)

View File

@ -0,0 +1,15 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
data class ValidateCodeResponse(
@SerializedName("service_id")
private val _serviceId: String? = null
) : Parcelable {
val serviceId: String
get() = _serviceId ?: ""
}

View File

@ -869,7 +869,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
showConcernIconAtBottomBarIfAvailable()
if (isSpecialDownloadDialogAvailable()
&& DownloadManager.getInstance().getDownloadEntitySnapshot(mGameEntity) != null) {
&& DownloadManager.getInstance().getDownloadEntitySnapshot(mGameEntity) != null
) {
updateSpecialDownloadDialogIcon(true)
}
@ -1823,7 +1824,7 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
mGameEntity,
callback = getCallback(),
)
)
} else {
if ("download" == mGameEntity?.reserveStatus) {
ReservationHelper.showDeleteReservationDialog(requireContext()) {
@ -1833,7 +1834,7 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
}
}
} else {
ReservationHelper.showCancelReservationDialog(requireContext()) {
ReservationHelper.showCancelReservationDialog(requireContext(), mGameEntity) {
ReservationHelper.cancelReservation(mGameEntity!!) {
DetailDownloadUtils.updateViewHolder(detailViewHolder)
showReserveBtn(isShowReserveBtn())

View File

@ -122,6 +122,9 @@ class MyFollowedGameAdapter(context: Context, var mViewModel: MyFollowedGameView
)
GameDetailActivity.startGameDetailActivity(mContext, gameEntity.id, mEntrance, exposureEvent)
}
binding.gameItemIncluded.tvAutoDownloadTips.goneIf(true)
binding.gameItemIncluded.ivEdit.goneIf(true)
}
}
is FooterViewHolder -> {

View File

@ -4,64 +4,175 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Gravity
import android.view.MenuItem
import android.view.View
import android.widget.LinearLayout
import androidx.fragment.app.Fragment
import android.widget.TextView
import androidx.activity.viewModels
import androidx.constraintlayout.widget.Group
import androidx.lifecycle.Observer
import androidx.viewpager.widget.ViewPager
import com.gh.common.pop.BatchManagementPop
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout.PAGE_INDEX
import com.gh.gamecenter.common.base.adapter.FragmentAdapter
import com.gh.gamecenter.common.base.fragment.BaseFragment_TabLayout
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.showRegulationTestDialogIfNeeded
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.common.view.TabIndicatorView
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.PopupMyGameGuideBinding
import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
import com.google.android.material.tabs.TabLayout
/**
* 我的游戏
*/
class MyGameActivity : BaseActivity_TabLayout() {
class MyGameActivity : BaseActivity() {
private val viewModel by viewModels<MyGameActivityViewModel>()
private var checkedIndex = 0
private val titles by lazy {
listOf(R.string.played.toResString(), R.string.follow.toResString(), R.string.reserve.toResString())
}
private val batchManagePop by lazy {
BatchManagementPop.create(
this,
object : BatchManagementPop.OnBatchManagementListener {
override fun enableAutoDownload() {
viewModel.changePageStatus(MyReservationFragment.ReservePageState.EnableAutoDownload)
}
override fun batchManage() {
viewModel.changePageStatus(MyReservationFragment.ReservePageState.CancelReserve)
}
})
}
private lateinit var vBack: View
private lateinit var vGameCollection: View
private lateinit var gGameCollection: Group
private lateinit var vMore: View
private lateinit var tvCancel: TextView
private lateinit var gMore: Group
private lateinit var viewPager: ViewPager
override fun getLayoutId(): Int = R.layout.activity_my_game
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNavigationTitle("我的游戏")
setToolbarMenu(R.menu.menu_my_game)
mDividerLineView?.visibility = View.VISIBLE
showGuide()
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
checkedIndex = intent.getIntExtra(PAGE_INDEX, 0)
override fun initFragmentList(fragments: MutableList<Fragment>?) {
fragments?.add(MyPlayedGameFragment())
fragments?.add(MyFollowedGameFragment())
fragments?.add(MyReservationFragment())
}
vBack = findViewById(R.id.v_back)
vGameCollection = findViewById(R.id.v_game_collection)
gGameCollection = findViewById(R.id.g_game_collection)
vMore = findViewById(R.id.v_more)
tvCancel = findViewById(R.id.tv_cancel)
gMore = findViewById(R.id.g_more)
viewPager = findViewById(R.id.activity_view_pager)
override fun initTabTitleList(tabTitleList: MutableList<String>?) {
tabTitleList?.add("玩过")
tabTitleList?.add("关注")
tabTitleList?.add("预约")
}
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
MtaHelper.onEvent("我的光环", "我的游戏", "${mTabTitleList[position]}Tab")
MtaHelper.onEvent("我的光环_新", "我的游戏", "${mTabTitleList[position]}Tab")
NewFlatLogUtils.logMyGameTabClick(mTabTitleList[position])
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
if (item?.itemId == R.id.menu_create_game_collection) {
vBack.setOnClickListener { finish() }
vGameCollection.setOnClickListener {
showRegulationTestDialogIfNeeded {
startActivity(GameCollectionEditActivity.getCreateIntent(this, mEntrance, "我的游戏"))
}
}
return super.onMenuItemClick(item)
vMore.setOnClickListener {
showBatchManagementPop()
}
tvCancel.setOnClickListener {
viewModel.changePageStatus(MyReservationFragment.ReservePageState.Normal)
}
initFragmentList()
with(viewModel) {
reservePageStatus.observe(this@MyGameActivity, Observer {
val tabPosition = viewPager.currentItem
if (tabPosition == RESERVATION_INDEX) {
if (it is MyReservationFragment.ReservePageState.Normal) {
setViewsVisible(true, gGameCollection, gMore)
setViewsVisible(false, tvCancel)
} else {
setViewsVisible(false, gGameCollection, gMore)
setViewsVisible(true, tvCancel)
}
} else {
setViewsVisible(true, gGameCollection)
setViewsVisible(false, gMore, tvCancel)
}
})
}
}
private fun setViewsVisible(isVisible: Boolean, vararg views: View) {
views.forEach {
it.goneIf(!isVisible)
}
}
fun initFragmentList() {
val tabLayout = findViewById<TabLayout>(R.id.activity_tab_layout)
val tabIndicatorView = findViewById<TabIndicatorView>(R.id.activity_tab_indicator)
val fragments = listOf(MyPlayedGameFragment(), MyFollowedGameFragment(), MyReservationFragment())
val pageAdapter = FragmentAdapter(supportFragmentManager, fragments, titles)
viewPager.offscreenPageLimit = fragments.size
viewPager.adapter = pageAdapter
viewPager.setCurrentItem(checkedIndex)
tabLayout.setupWithViewPager(viewPager)
tabIndicatorView.setupWithTabLayout(tabLayout)
tabIndicatorView.setupWithViewPager(viewPager)
tabIndicatorView.setIndicatorWidth(20)
for (i in 0 until tabLayout.tabCount) {
val tab: TabLayout.Tab = tabLayout.getTabAt(i) ?: continue
val tabTitle = if (tab.text != null) tab.text.toString() else ""
val tabView = BaseFragment_TabLayout.createDefaultTabCustomView(this, tabTitle)
tab.setCustomView(tabView)
}
BaseFragment_TabLayout.initTabStyle(tabLayout, checkedIndex)
viewPager.addOnPageChangeListener(::onPageSelected)
onPageSelected(checkedIndex)
showGuide(checkedIndex)
}
fun onPageSelected(position: Int) {
MtaHelper.onEvent("我的光环", "我的游戏", "${titles[position]}Tab")
MtaHelper.onEvent("我的光环_新", "我的游戏", "${titles[position]}Tab")
NewFlatLogUtils.logMyGameTabClick(titles[position])
if (position == RESERVATION_INDEX) {
gMore.goneIf(false)
} else {
gMore.goneIf(true)
}
// 用户切换了tab:退出编辑模式
viewModel.changePageStatus(MyReservationFragment.ReservePageState.Normal)
}
private fun showBatchManagementPop() {
if (!batchManagePop.isShowing) {
batchManagePop.showAsDropDown(vMore, 0, (-4F).dip2px())
}
}
override fun isAutoResetViewBackgroundEnabled() = true
@ -69,10 +180,9 @@ class MyGameActivity : BaseActivity_TabLayout() {
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
getMenuItem(R.id.menu_create_game_collection).setIcon(R.drawable.ic_create_game_collection)
}
private fun showGuide() {
private fun showGuide(position: Int) {
AppExecutor.uiExecutor.executeWithDelay({
tryCatchInRelease {
if (!SPUtils.getBoolean(Constants.SP_MY_GAME_GUIDE)) {
@ -86,11 +196,18 @@ class MyGameActivity : BaseActivity_TabLayout() {
SPUtils.setBoolean(Constants.SP_MY_GAME_GUIDE, true)
popupWindow.dismiss()
}
val paddingEnd = if (position == RESERVATION_INDEX) {
48F.dip2px()
} else {
0
}
binding.guideContainer.setPadding(0, 0, paddingEnd, 0)
popupWindow.run {
isTouchable = true
isFocusable = true
if (!isFinishing) {
showAtLocation(window.decorView, Gravity.TOP, 0, 0)
showAtLocation(vGameCollection, Gravity.TOP, 0, 0)
}
}
}
@ -98,6 +215,15 @@ class MyGameActivity : BaseActivity_TabLayout() {
}, 500)
}
override fun handleBackPressed(): Boolean {
if (viewModel.reservePageStatus.value == MyReservationFragment.ReservePageState.Normal) {
return super.handleBackPressed()
} else {
viewModel.changePageStatus(MyReservationFragment.ReservePageState.Normal)
return true
}
}
companion object {
const val PLAYED_INDEX = 0
const val FOLLOWED_INDEX = 1

View File

@ -0,0 +1,17 @@
package com.gh.gamecenter.mygame
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.gh.gamecenter.livedata.Event
class MyGameActivityViewModel : ViewModel() {
private val _reservePageStatus = MutableLiveData<MyReservationFragment.ReservePageState>()
val reservePageStatus: LiveData<MyReservationFragment.ReservePageState> = _reservePageStatus
fun changePageStatus(state: MyReservationFragment.ReservePageState) {
if (state != reservePageStatus.value) {
_reservePageStatus.value = state
}
}
}

View File

@ -3,9 +3,13 @@ package com.gh.gamecenter.mygame
import android.content.Context
import android.util.SparseArray
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.databind.BindingAdapters
import com.gh.common.exposure.IExposable
import com.gh.common.pop.CancelReservePop
import com.gh.common.pop.ReserveAllSelectPop
import com.gh.common.util.DownloadItemUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.ReservationHelper
@ -17,23 +21,64 @@ import com.gh.gamecenter.common.callback.CancelListener
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.DrawableView
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.ItemFollowedGameBinding
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.game.GameItemViewHolder
import com.gh.gamecenter.game.GameAndPosition
import com.lightgame.view.CheckableImageView
class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewModel) : ListAdapter<GameEntity>(context),
IExposable {
private var pageState: MyReservationFragment.ReservePageState = MyReservationFragment.ReservePageState.Normal
private val isEditing: Boolean
get() = pageState != MyReservationFragment.ReservePageState.Normal
private val mEntrance = "(我的预约)"
private val mExposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
private val selectedGames = mutableSetOf<GameEntity>()
private val allSelectPop by lazy {
ReserveAllSelectPop.create(mContext, object : ReserveAllSelectPop.OnReserveAllSelectListener {
override fun selectAll(isChecked: Boolean): Int {
selectedGames.clear()
if (isChecked) {
if (pageState == MyReservationFragment.ReservePageState.EnableAutoDownload) {
mEntityList
.filter {
it.wifiAutoDownloadEnable && !it.wifiAutoDownload
}
.let(selectedGames::addAll)
} else {
mEntityList.let(selectedGames::addAll)
}
}
notifyItemRangeChanged(0, mEntityList.size)
return selectedGames.size
}
override fun submit() {
doSubmit()
}
})
}
private fun doSubmit() {
if (pageState == MyReservationFragment.ReservePageState.EnableAutoDownload) {
allSelectPop.dismiss()
mViewModel.enableAutoDownload(true, selectedGames.toSet())
mViewModel.changeReserveStatus(MyReservationFragment.ReservePageState.Normal)
} else {
showCancelReservationInBatchDialog(selectedGames.toSet())
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
@ -48,6 +93,7 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo
)
)
}
else -> {
FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
}
@ -73,7 +119,8 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo
val newPath = "预约Tab_新"
holder.binding.run {
root.background = R.drawable.reuse_listview_item_style.toDrawable(root.context)
root.setBackgroundColor(R.color.ui_surface.toColor(mContext))
listOf(forumTv, trendsTv, commentsTv).forEach {
it.setTextColor(R.color.text_secondary.toColor(mContext))
}
@ -103,6 +150,24 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo
gameDes.text = gameEntity.decoratedDes
recommendStar.rating = gameEntity.recommendStar.toFloat()
GameItemViewHolder.initGameSubtitleAndAdLabel(gameEntity, gameSubtitleTv)
tvAutoDownloadTips.goneIf(!gameEntity.wifiAutoDownload)
ivEdit.goneIf(isEditing)
if (isEditing) {
selectIv.goneIf(false)
updateSelectedStatus(selectIv, gameEntity)
cardContainer.updateLayoutParams {
if (this is MarginLayoutParams) {
marginStart = 120F.dip2px()
}
}
} else {
selectIv.goneIf(true)
cardContainer.updateLayoutParams {
if (this is MarginLayoutParams) {
marginStart = 92F.dip2px()
}
}
}
}
}
@ -115,8 +180,19 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo
)
mExposureEventSparseArray.append(position, exposureEvent)
val gameItemBinding = holder.binding.gameItemIncluded
DownloadItemUtils.updateItemWithReserveStatus(
GameViewHolder(holder.binding.gameItemIncluded),
GameViewHolder(holder.binding.gameItemIncluded.root).apply {
gameDownloadBtn = gameItemBinding.downloadBtn
gameDes = gameItemBinding.gameDes
gameDownloadTips = gameItemBinding.downloadTipsLottie
multiVersionDownloadTv = gameItemBinding.multiVersionDownloadTv
gameRating = gameItemBinding.gameRating
recommendContainer = gameItemBinding.recommendContainer
recommendIv = gameItemBinding.recommendIv
recommendTv = gameItemBinding.recommendTv
recommendStarInfo = gameItemBinding.recommendStarInfo
},
gameEntity
)
@ -129,7 +205,35 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo
gameEntity.id,
gameEntity.name ?: ""
)
GameDetailActivity.startGameDetailActivity(mContext, gameEntity.id, mEntrance, exposureEvent)
if (pageState == MyReservationFragment.ReservePageState.Normal) {
GameDetailActivity.startGameDetailActivity(mContext, gameEntity.id, mEntrance, exposureEvent)
} else {
val isEnableSelect = pageState == MyReservationFragment.ReservePageState.CancelReserve
|| (gameEntity.wifiAutoDownloadEnable && !gameEntity.wifiAutoDownload)
if (isEnableSelect) { // 可勾选状态
val ivSelect = holder.binding.gameItemIncluded.selectIv
if (ivSelect.isEnabled) {
ivSelect.toggle()
if (ivSelect.isChecked) {
selectedGames.add(gameEntity)
} else {
selectedGames.remove(gameEntity)
}
updateSelectedStatus(ivSelect, gameEntity)
allSelectPop.updateSelectedCount(selectedGames.size)
}
} else { // 不可勾选状态,弹出相应的提示
val toastResId = if (gameEntity.wifiAutoDownload) {
// 已经开启wifi自动下载
R.string.has_enabled_for_auto_download_in_wifi
} else {
R.string.not_support_auto_download_in_wifi
}
ToastUtils.showToast(toastResId.toResString())
}
}
}
if ("appointment" == gameEntity.reserveStatus) {
@ -149,11 +253,24 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo
)
}
initDownloadButtonOffset(holder.binding)
holder.binding.root.setOnLongClickListener {
showCancelReservationDialog(gameEntity)
true
holder.binding.gameItemIncluded.ivEdit.setOnClickListener {
CancelReservePop.create(
gameEntity,
mContext,
object : CancelReservePop.OnCancelReserveListener {
override fun enableAutoDownload(isEnable: Boolean) {
mViewModel.enableAutoDownload(isEnable, setOf(gameEntity))
}
override fun cancelReserve() {
showCancelReservationDialog(gameEntity)
}
}).showAsDropDown(holder.binding.gameItemIncluded.ivEdit)
}
}
is FooterViewHolder -> {
holder.initItemPadding()
holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
@ -161,6 +278,34 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo
}
}
private fun updateSelectedStatus(selectIv: CheckableImageView, gameEntity: GameEntity) {
if (pageState == MyReservationFragment.ReservePageState.CancelReserve) {
selectIv.isChecked = selectedGames.any { gameEntity.id == it.id }
val isChecked = selectedGames.any { gameEntity.id == it.id }
if (isChecked) {
selectIv.setImageResource(R.drawable.ic_selector_selected)
} else {
selectIv.setImageResource(R.drawable.ic_selector_default)
}
} else { // 批量开启wifi自动下载
when {
!gameEntity.wifiAutoDownloadEnable -> { // 此游戏不支持wifi自动下载不可勾选状态
selectIv.setImageResource(R.drawable.ic_selector_unable)
}
gameEntity.wifiAutoDownload -> {// 已经开启了wifi自动下载勾选-不可编辑状态
selectIv.setImageResource(R.drawable.ic_selector_selected_unable)
}
else -> { // 默认状态,可勾选
selectIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(mContext))
selectIv.isChecked = selectedGames.any { gameEntity.id == it.id }
}
}
}
}
fun notifyItemAndRemoveDownload(status: EBDownloadStatus) {
val data = getGameEntityByPackage(status.packageName)
for (gameAndPosition in data) {
@ -192,17 +337,9 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo
}
}
private fun showDeleteReservationDialog(game: GameEntity) {
ReservationHelper.showDeleteReservationDialog(mContext, object : EmptyCallback {
override fun onCallback() {
mViewModel.deleteReservation(game)
}
})
}
private fun showCancelReservationDialog(game: GameEntity) {
NewFlatLogUtils.logMyGameReserveTabGameCardClick("按钮", game.id, game.name ?: "")
ReservationHelper.showCancelReservationDialog(mContext, {
ReservationHelper.showCancelReservationDialog(mContext, game, {
NewFlatLogUtils.logMyGameCancelReserveDialogClick("确定取消", game.id, game.name ?: "")
mViewModel.cancelReservation(game)
}, object : CancelListener {
@ -212,8 +349,67 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo
})
}
private fun showCancelReservationInBatchDialog(games: Set<GameEntity>) {
// 批量删除,埋点在外部上报
games.forEach {
SensorsBridge.trackCancelAppointmentDialogShow(it.id, it.name ?: "", it.categoryChinese)
}
ReservationHelper.showCancelReservationDialog(mContext, null, {
games.forEach {
SensorsBridge.trackCancelAppointmentDialogClick(it.id, it.name ?: "", it.categoryChinese, "确定取消")
}
mViewModel.cancelReserveInBatch(games)
if (allSelectPop.isShowing) {
allSelectPop.dismiss()
}
mViewModel.changeReserveStatus(MyReservationFragment.ReservePageState.Normal)
}, object : CancelListener {
override fun onCancel() {
games.forEach {
SensorsBridge.trackCancelAppointmentDialogClick(
it.id,
it.name ?: "",
it.categoryChinese,
"暂不取消"
)
}
}
}, dialogCancelCallback = {
games.forEach {
SensorsBridge.trackCancelAppointmentDialogClick(it.id, it.name ?: "", it.categoryChinese, "关闭弹窗")
}
})
}
override fun getEventByPosition(pos: Int): ExposureEvent = mExposureEventSparseArray.get(pos)
override fun getEventListByPosition(pos: Int) = null
fun changeStatus(status: MyReservationFragment.ReservePageState) {
if (pageState != status) {
selectedGames.clear()
pageState = status
notifyItemRangeChanged(0, itemCount)
if (status == MyReservationFragment.ReservePageState.Normal) {
allSelectPop.dismiss()
} else {
allSelectPop.show(status, mContext)
}
}
}
fun updatePopupWindow() {
with(allSelectPop.binding) {
cbAll.setButtonDrawable(R.drawable.selector_kaifu_report)
cbAll.setTextColor(R.color.text_primary.toColor(mContext))
tvNumber.setTextColor(R.color.text_theme.toColor(mContext))
tvNumber.background = R.drawable.bg_common_button_fill_gradient_blue.toDrawable(mContext)
tvSubmit.setTextColor(R.color.text_aw_primary.toColor(mContext))
root.setBackgroundColor(R.color.ui_surface.toColor(mContext))
vLine.setBackgroundColor(R.color.ui_divider.toColor(mContext))
}
}
}

View File

@ -4,12 +4,9 @@ import android.os.Bundle
import android.text.TextUtils
import android.view.View
import androidx.core.content.ContextCompat
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureListener
import com.gh.gamecenter.common.utils.ifLogin
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.toDrawable
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.view.CustomDividerItemDecoration
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
@ -21,6 +18,9 @@ import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.livedata.EventObserver
import com.gh.gamecenter.login.user.UserManager
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
@ -34,6 +34,8 @@ class MyReservationFragment : ListFragment<GameEntity, MyReservationViewModel>()
private var mExposureListener: ExposureListener? = null
private val mBinding by lazy { FragmentListBaseBinding.inflate(layoutInflater) }
private val activityViewModel by activityViewModels<MyGameActivityViewModel>()
private val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
val data = mAdapter?.getGameEntityByPackage(downloadEntity.packageName) ?: arrayListOf()
@ -57,6 +59,27 @@ class MyReservationFragment : ListFragment<GameEntity, MyReservationViewModel>()
mBinding.reuseNoneData.reuseNoneDataTv.setOnClickListener(this)
mListRv.addOnScrollListener(mExposureListener!!)
mListRv.setBackgroundColor(R.color.ui_surface.toColor(requireContext()))
with(activityViewModel) {
reservePageStatus.observe(viewLifecycleOwner) {
mAdapter?.changeStatus(it)
}
}
with(mViewModel) {
enableAutoDownloadSuccessfully.observe(viewLifecycleOwner, EventObserver {
if (it) {
ToastUtils.showToast(R.string.has_enabled_for_auto_download_in_wifi.toResString())
} else {
ToastUtils.showToast(R.string.has_unable_for_auto_download_in_wifi.toResString())
}
})
changePageStateAction.observe(viewLifecycleOwner, EventObserver {
activityViewModel.changePageStatus(it)
})
}
}
override fun onStart() {
@ -153,5 +176,15 @@ class MyReservationFragment : ListFragment<GameEntity, MyReservationViewModel>()
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mListRv.setBackgroundColor(R.color.ui_surface.toColor(requireContext()))
mAdapter?.updatePopupWindow()
}
sealed class ReservePageState {
object Normal : ReservePageState() // 正常显示状态
object EnableAutoDownload : ReservePageState() // 批量启动自动下载状态
object CancelReserve : ReservePageState() // 批量管理-取消预约状态
}
}

View File

@ -2,20 +2,31 @@ package com.gh.gamecenter.mygame
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.repository.ReservationRepository
import com.gh.common.util.ReservationHelper.getReserveRequestBody
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.common.utils.createRequestBody
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.livedata.Event
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.reserve.ReserveReminderRepository
import com.lightgame.utils.Utils
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
@ -23,13 +34,16 @@ class MyReservationViewModel(application: Application) : ListViewModel<GameEntit
var positionAndPackageMap = HashMap<String, Int>() // key: packageName + position, value: position
private val repository = ReserveReminderRepository.newInstance()
private val compositeDisposable = CompositeDisposable()
override fun provideDataObservable(page: Int): Observable<List<GameEntity>>? {
return null
}
override fun provideDataSingle(page: Int): Single<MutableList<GameEntity>> {
return RetrofitManager.getInstance().api
.getGameReservations(UserManager.getInstance().userId, page, Utils.getTime(getApplication()))
return RetrofitManager.getInstance().newApi
.getGameReservations(page, Utils.getTime(getApplication()))
}
override fun mergeResultLiveData() {
@ -53,27 +67,19 @@ class MyReservationViewModel(application: Application) : ListViewModel<GameEntit
game.setEntryMap(DownloadManager.getInstance().getEntryMap(game.name))
}
@SuppressLint("CheckResult")
fun deleteReservation(game: GameEntity) {
deleteOrCancelReservation(game, true)
}
fun cancelReservation(game: GameEntity) {
deleteOrCancelReservation(game, false)
}
@SuppressLint("CheckResult")
private fun deleteOrCancelReservation(game: GameEntity, deleteReservation: Boolean) {
val requestMap = hashMapOf<String, String>()
requestMap["game_id"] = game.id
val single = if (deleteReservation) {
RetrofitManager.getInstance().api
.deleteGameReservation(requestMap.createRequestBody())
RetrofitManager.getInstance().newApi
.deleteGameReservation(game.id, getReserveRequestBody(game, HaloApp.getInstance().application))
.subscribeOn(Schedulers.io())
} else {
RetrofitManager.getInstance().api
.cancelGameReservation(requestMap.createRequestBody())
RetrofitManager.getInstance().newApi
.cancelGameReservation(game.id, getReserveRequestBody(game, HaloApp.getInstance().application))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
@ -105,4 +111,94 @@ class MyReservationViewModel(application: Application) : ListViewModel<GameEntit
})
}
private val _enableAutoDownloadSuccessfully = MutableLiveData<Event<Boolean>>()
val enableAutoDownloadSuccessfully: LiveData<Event<Boolean>> = _enableAutoDownloadSuccessfully
fun enableAutoDownload(enable: Boolean, games: Set<GameEntity>) {
if (enable) {
games.forEach {
SensorsBridge.trackOpenAppointmentAutomaticDownload(it.id, it.name ?: "", it.categoryChinese)
}
} else {
games.forEach {
SensorsBridge.trackCancelAppointmentAutomaticDownload(it.id, it.name ?: "", it.categoryChinese)
}
}
val params = createParamsInBatch(games).apply {
put("wifi_auto_download", enable)
}
repository.enableAutoDownloadInBatches(params.toRequestBody())
.map {
val oldList = mResultLiveData.value ?: emptyList()
val newList = oldList.map { item ->
if (games.any { it.id == item.id }) {
item.copy(_wifiAutoDownload = enable)
} else {
item
}
}
newList
}
.compose(singleToMain())
.subscribe(object : BiResponse<List<GameEntity>>() {
override fun onSuccess(data: List<GameEntity>) {
mResultLiveData.value = data
_enableAutoDownloadSuccessfully.value = Event(enable)
}
}).let(compositeDisposable::add)
}
fun cancelReserveInBatch(games: Set<GameEntity>) {
val params = createParamsInBatch(games).apply {
put("appointment", false)
}
repository.cancelReserveInBatch(params.toRequestBody())
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
ReservationRepository.refreshReservations()
val oldList = mResultLiveData.value ?: emptyList()
val newList = oldList.toMutableList()
newList.removeAll {
games.any { game -> game.id == it.id }
}
if (newList.isEmpty()) {
// 刷新页面
runOnUiThread { load(LoadType.REFRESH) }
} else {
mResultLiveData.postValue(newList)
}
}
}).let(compositeDisposable::add)
}
private fun createParamsInBatch(games: Set<GameEntity>): HashMap<String, Any> {
val jPushId =
(ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider)
?.getRegistrationId(HaloApp.getInstance().application) ?: ""
val idAndMirrorType = games.map {
var mirrorPosition = it.getMirrorPosition()
if (mirrorPosition == -1) {
mirrorPosition = 0
}
hashMapOf("_id" to it.id, "mirror_type" to mirrorPosition)
}
return hashMapOf("jpush_id" to jPushId, "games" to idAndMirrorType)
}
private val _changePageStateAction = MutableLiveData<Event<MyReservationFragment.ReservePageState>>()
val changePageStateAction: LiveData<Event<MyReservationFragment.ReservePageState>> = _changePageStateAction
fun changeReserveStatus(state: MyReservationFragment.ReservePageState) {
_changePageStateAction.value = Event(state)
}
override fun onCleared() {
super.onCleared()
compositeDisposable.clear()
}
}

View File

@ -5,7 +5,6 @@ import com.gh.gamecenter.common.entity.LaunchRedirectWrapper;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.entity.OssEntity;
import com.gh.gamecenter.common.entity.SignatureEntity;
import com.gh.gamecenter.common.entity.SimpleGameEntity;
import com.gh.gamecenter.common.entity.ToolBoxEntity;
import com.gh.gamecenter.common.entity.WechatConfigEntity;
import com.gh.gamecenter.entity.ActivityLabelEntity;
@ -73,6 +72,8 @@ import com.gh.gamecenter.entity.RatingComment;
import com.gh.gamecenter.entity.RatingDraftEntity;
import com.gh.gamecenter.entity.RatingReplyEntity;
import com.gh.gamecenter.entity.RecommendPopupEntity;
import com.gh.gamecenter.entity.ReserveModifyEntity;
import com.gh.gamecenter.entity.ReserveReminderEntity;
import com.gh.gamecenter.entity.SearchSubjectEntity;
import com.gh.gamecenter.entity.ServerPublishEntity;
import com.gh.gamecenter.entity.ServerSubscriptionEntity;
@ -91,6 +92,8 @@ import com.gh.gamecenter.entity.TimeEntity;
import com.gh.gamecenter.entity.ToolBoxBlockEntity;
import com.gh.gamecenter.entity.UnifiedUserTrendEntity;
import com.gh.gamecenter.entity.UserAuthEntity;
import com.gh.gamecenter.entity.ValidateCodeRequest;
import com.gh.gamecenter.entity.ValidateCodeResponse;
import com.gh.gamecenter.entity.VersionVoteEntity;
import com.gh.gamecenter.entity.VideoDataOverViewEntity;
import com.gh.gamecenter.entity.VideoDraftEntity;
@ -107,6 +110,7 @@ import com.gh.gamecenter.feature.entity.BackgroundImageEntity;
import com.gh.gamecenter.feature.entity.CommentEntity;
import com.gh.gamecenter.feature.entity.CommentnumEntity;
import com.gh.gamecenter.feature.entity.ConcernEntity;
import com.gh.gamecenter.feature.entity.FloatingWindowEntity;
import com.gh.gamecenter.feature.entity.ForumVideoEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.LibaoEntity;
@ -117,6 +121,7 @@ import com.gh.gamecenter.feature.entity.MessageUnreadEntity;
import com.gh.gamecenter.feature.entity.NewsEntity;
import com.gh.gamecenter.feature.entity.PersonalEntity;
import com.gh.gamecenter.feature.entity.QuestionDraftEntity;
import com.gh.gamecenter.feature.entity.ReserveOnlineEntity;
import com.gh.gamecenter.feature.entity.ServerCalendarEntity;
import com.gh.gamecenter.feature.entity.ServerCalendarFormEntity;
import com.gh.gamecenter.feature.entity.ServerCalendarGame;
@ -126,7 +131,6 @@ import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.feature.entity.UserEntity;
import com.gh.gamecenter.feature.entity.ViewsEntity;
import com.gh.gamecenter.feature.entity.WXSubscribeMsgConfig;
import com.gh.gamecenter.feature.entity.FloatingWindowEntity;
import com.gh.gamecenter.gamedetail.entity.BigEvent;
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity;
import com.gh.gamecenter.home.custom.model.CustomPageData;
@ -142,6 +146,7 @@ import com.gh.gamecenter.qa.entity.QuestionsIndexEntity;
import com.gh.gamecenter.qa.entity.TopCommunityCategory;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.protobuf.Any;
import java.util.ArrayList;
import java.util.HashMap;
@ -1433,26 +1438,26 @@ public interface ApiService {
/**
* 新建游戏预约
*/
@POST("./appointment:apply")
Single<ResponseBody> createNewGameReservation(@Body RequestBody body);
@POST("games/{game_id}/appointment")
Single<ReserveReminderEntity> createNewGameReservation(@Path("game_id") String gameId, @Body RequestBody body);
/**
* 取消游戏预约
*/
@POST("./appointment:cancel")
Single<ResponseBody> cancelGameReservation(@Body RequestBody body);
@POST("games/{game_id}/appointment/cancel")
Single<ResponseBody> cancelGameReservation(@Path("game_id") String gameId, @Body RequestBody body);
/**
* 删除游戏预约
*/
@POST("./appointment:delete")
Single<ResponseBody> deleteGameReservation(@Body RequestBody body);
@DELETE("games/{game_id}/appointment")
Single<ResponseBody> deleteGameReservation(@Path("game_id") String gameId, @Body RequestBody body);
/**
* 获取用户游戏预约列表
*/
@GET("users/{user_id}/appointment")
Single<List<GameEntity>> getGameReservations(@Path("user_id") String userId, @Query("page") int page, @Query("timestamp") long timestamp);
@GET("users/appointments")
Single<List<GameEntity>> getGameReservations(@Query("page") int page, @Query("timestamp") long timestamp);
/**
* 获取用户游戏预约列表
@ -1776,13 +1781,13 @@ public interface ApiService {
/**
* 绑定微信
*/
@POST("./wechat:bind")
@POST("users/wechat/bind")
Single<ResponseBody> postBindWechat(@Body RequestBody body);
/**
* 获取公众号配置信息
*/
@GET("wechat/config")
@GET("users/wechat/config")
Single<WechatConfigEntity> getWechatConfig();
/**
@ -1861,10 +1866,25 @@ public interface ApiService {
Observable<ResponseBody> deleteVideo(@Path("video_id") String videoId);
/**
* 获取预约弹窗
* 获取预约上线弹窗
*/
@GET("users/{user_id}/appointment_popup")
Single<List<SimpleGameEntity>> getReserveDialog(@Path("user_id") String userId);
@GET("users/appointment_popup")
Single<ReserveOnlineEntity> getReserveDialog();
/**
* 预约游戏上线弹窗-游戏列表(开启wifi自动下载)
*/
@GET("users/appointment_popup/games?filter=wifi_auto_download:true")
Single<List<GameEntity>> loadGamesWithAutoDownload(
@Query("page") int page,
@Query("page_size") int page_size,
@Query("filter") String filter);
/**
* 添加下载任务成功
*/
@POST("users/appointments/games/log_download")
Single<ResponseBody> logAutoDownload(@Body HashMap<String, Object> body);
/**
* 获取我的光环部分功能的未读数
@ -3390,4 +3410,28 @@ public interface ApiService {
*/
@GET("game_lists/hot_columns")
Single<List<SubjectEntity>> getHotColumns();
@PATCH("games/{game_id}/appointment")
Single<ReserveModifyEntity> reserveModify(@Path("game_id") String gameId, @Body RequestBody body);
/**
* 获取验证码
*/
@POST("mobile/validate/code")
Single<ValidateCodeResponse> getValidateCode(@Body HashMap<String, String> map);
/**
* 验证手机号
*/
@POST("mobile/validate")
Single<ResponseBody> mobileValidate(@Body ValidateCodeRequest request);
/**
* 批量操作:
* 1.是/否 开启wifi自动下载
* 2.取消预约
*/
@POST("users/appointments/settings")
Single<ResponseBody> reserveSetting(@Body RequestBody body);
}

View File

@ -0,0 +1,253 @@
package com.halo.assistant.fragment.reserve
import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.gh.common.dialog.ReserveReminderPhoneNumberDialog
import com.gh.common.dialog.ReserveReminderPhoneNumberDialog.Companion.DIALOG_TYPE_BIND_PHONE
import com.gh.common.dialog.ReserveReminderPhoneNumberDialog.Companion.DIALOG_TYPE_CHANGE_PHONE
import com.gh.common.dialog.ReserveReminderPhoneNumberDialog.Companion.DIALOG_TYPE_VERIFY_PHONE
import com.gh.common.dialog.ReserveSuccessReminderDialog
import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.ShellActivity.Companion.getIntent
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.WechatConfigEntity
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.ReserveReminderEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.livedata.EventObserver
class ReserveReminderContainerFragment : Fragment(), OnReserveReminderListener {
private var isWechatBinding = false
private var isCanDismissed = true
private val repository by lazy {
ReserveReminderRepository.newInstance()
}
private val viewModel by viewModels<ReserveReminderViewModel>()
private lateinit var reserveReminderEntity: ReserveReminderEntity
private var game: GameEntity? = null
private val reservesReminderDialog by lazy {
ReserveSuccessReminderDialog.create(requireContext(), this).apply {
setOnDismissListener {
if (isCanDismissed) {
onDismiss()
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
game = arguments?.getParcelable(KEY_GAME)
reserveReminderEntity =
arguments?.getParcelable(KEY_RESERVE_REMINDER) ?: ReserveReminderEntity()
viewModel.updateReserveReminder(reserveReminderEntity)
reservesReminderDialog.show()
with(viewModel) {
val lifeCycleOwner = this@ReserveReminderContainerFragment
reserveReminder.observe(lifeCycleOwner) {
reservesReminderDialog.updateReserveReminder(it)
}
sendVerifyCode.observe(lifeCycleOwner, EventObserver {
showPhoneNumberDialog(DIALOG_TYPE_VERIFY_PHONE, reserveReminderEntity.smsConfig.mobile, it)
})
unableSmsReminderSuccessfully.observe(lifeCycleOwner, EventObserver {
reserveReminderEntity.smsConfig.notice = false
reserveReminderEntity.smsConfig.mobileValidated = false
viewModel.updateReserveReminder(reserveReminderEntity)
})
}
}
override fun updateSmsReminder(isEnable: Boolean) {
if (isEnable) {
trackAppointmentSuccessDialogClick("开启短信提醒")
showPhoneNumberDialog(DIALOG_TYPE_BIND_PHONE, reserveReminderEntity.smsConfig.mobile)
} else {
trackAppointmentSuccessDialogClick("关闭短信提醒")
viewModel.unableSmsReminder(game?.id ?: "")
}
}
override fun updateWechatReminder() {
isWechatBinding = true
trackAppointmentSuccessDialogClick("开启微信提醒")
startActivity(WebActivity.getBindWechatIntent(requireContext()))
}
override fun changedPhoneNumber() {
trackAppointmentSuccessDialogClick("修改手机号")
showPhoneNumberDialog(DIALOG_TYPE_CHANGE_PHONE, reserveReminderEntity.smsConfig.mobile)
}
override fun verifyPhoneNumber() {
trackAppointmentSuccessDialogClick("验证手机号")
viewModel.sendVerifyCode(reserveReminderEntity.smsConfig.mobile)
}
override fun changeWechatBinding() {
isWechatBinding = true
trackAppointmentSuccessDialogClick("更换绑定微信")
startActivity(WebActivity.getBindWechatIntent(requireContext()))
}
override fun bindPhoneSuccessfully(hasValidated: Boolean, phone: String) {
reserveReminderEntity.smsConfig =
ReserveReminderEntity.SmsConfig(_notice = true, _mobile = phone, _mobileValidated = hasValidated)
viewModel.updateReserveReminder(reserveReminderEntity)
}
override fun phoneNumberValidateSuccessfully() {
reserveReminderEntity.smsConfig.mobileValidated = true
viewModel.updateReserveReminder(reserveReminderEntity)
}
override fun enableAutoDownload(isEnable: Boolean) {
viewModel.enableAutoDownload(game, isEnable)
}
override fun realName() {
trackAppointmentSuccessDialogClick("实名认证")
val intent = getIntent(requireContext(), ShellActivity.Type.REAL_NAME_INFO)
requireContext().startActivity(intent)
}
private fun showPhoneNumberDialog(dialogType: Int, phone: String, serviceId: String = "") {
isCanDismissed = false
reservesReminderDialog.dismiss()
ReserveReminderPhoneNumberDialog.create(
requireContext(),
dialogType,
phone,
serviceId,
game?.id ?: "",
repository,
this
)
.let {
it.show()
it.setOnDismissListener {
isCanDismissed = true
reservesReminderDialog.show()
}
}
}
override fun onResume() {
super.onResume()
if (isWechatBinding) {
isWechatBinding = false
val wechatConfig = SPUtils.getString(Constants.SP_WECHAT_CONFIG).toObject<WechatConfigEntity>()
if (reserveReminderEntity.wechatConfig != wechatConfig) {
reserveReminderEntity.wechatConfig = wechatConfig ?: WechatConfigEntity()
viewModel.updateReserveReminder(reserveReminderEntity)
}
}
}
private fun onDismiss() {
SensorsBridge.trackAppointmentSuccessDialogClick(
game?.id ?: "",
game?.name ?: "",
game?.categoryChinese ?: "",
"关闭弹窗"
)
val ft = parentFragmentManager.beginTransaction()
ft.remove(this)
ft.commitAllowingStateLoss()
}
private fun trackAppointmentSuccessDialogClick(
buttonName: String,
wechatRemind: Boolean? = null,
messageRemind: Boolean? = null,
autoDownloadEnable: Boolean? = null
) {
SensorsBridge.trackAppointmentSuccessDialogClick(
game?.id ?: "",
game?.name ?: "",
game?.categoryChinese ?: "",
buttonName,
wechatRemind,
messageRemind,
autoDownloadEnable
)
}
companion object {
private const val KEY_RESERVE_REMINDER = "key_reserve_reminder"
private const val KEY_GAME = "key_game"
@JvmStatic
fun show(context: Context, gameEntity: GameEntity?, reserveReminder: ReserveReminderEntity) {
(if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
})?.let {
val tag = ReserveReminderContainerFragment::class.java.name
val fragment = it.findFragmentByTag(tag) ?: newInstance(gameEntity, reserveReminder)
if (!fragment.isAdded) {
it.beginTransaction()
.add(fragment, tag)
.commitAllowingStateLoss()
}
}
}
private fun newInstance(
gameEntity: GameEntity?,
reserveReminder: ReserveReminderEntity
): ReserveReminderContainerFragment {
return ReserveReminderContainerFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_GAME, gameEntity)
putParcelable(KEY_RESERVE_REMINDER, reserveReminder)
}
}
}
}
}
interface OnReserveReminderListener {
fun updateSmsReminder(isEnable: Boolean)
fun updateWechatReminder()
fun bindPhoneSuccessfully(hasValidated: Boolean, phone: String)
fun changedPhoneNumber()
fun verifyPhoneNumber()
fun changeWechatBinding()
fun phoneNumberValidateSuccessfully()
fun enableAutoDownload(isEnable: Boolean)
fun realName()
}

View File

@ -0,0 +1,102 @@
package com.halo.assistant.fragment.reserve
import android.annotation.SuppressLint
import android.os.Handler
import android.os.Looper
import android.os.Message
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.entity.ReserveModifyEntity
import com.gh.gamecenter.entity.ReserveReminderEntity
import com.gh.gamecenter.entity.ValidateCodeRequest
import com.gh.gamecenter.entity.ValidateCodeResponse
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.retrofit.service.ApiService
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import okhttp3.RequestBody
import okhttp3.ResponseBody
class ReserveReminderRepository(
private val apiService: ApiService
) {
private val handler = object : Handler(Looper.getMainLooper()) {
@SuppressLint("CheckResult")
override fun handleMessage(msg: Message) {
if (msg.what == MESSAGE_WHAT_ENABLE_AUTO_DOWNLOAD) {
val content = msg.obj as? Pair<GameEntity?, Boolean> ?: return
val (game, isEnable) = content
val body = hashMapOf(
"wifi_auto_download" to isEnable
).toRequestBody()
val buttonName = if (isEnable) {
"勾选自动下载"
} else {
"取消勾选自动下载"
}
SensorsBridge.trackAppointmentSuccessDialogClick(
game?.id ?: "",
game?.name ?: "",
game?.categoryChinese ?: "",
buttonName
)
apiService.reserveModify(game?.id, body)
.subscribeOn(Schedulers.io())
.subscribe({}, {})
}
}
}
fun sendVerifyCode(mobile: String): Single<ValidateCodeResponse> =
apiService.getValidateCode(hashMapOf("mobile" to mobile))
fun bindPhone(gameId: String, phone: String): Single<ReserveModifyEntity> {
val body = hashMapOf<String, Any>(
"sms_config" to ReserveReminderEntity.SmsConfig(true, phone)
).toRequestBody()
return apiService.reserveModify(gameId, body)
}
fun verifyPhoneNumber(phoneNumber: String, code: String, serviceId: String): Single<ResponseBody> {
val request = ValidateCodeRequest(phoneNumber, serviceId, code)
return apiService.mobileValidate(request)
}
fun unableSmsReminder(gameId: String): Single<ReserveModifyEntity> {
val body = hashMapOf(
"sms_config" to hashMapOf("notice" to false)
).toRequestBody()
return apiService.reserveModify(gameId, body)
}
/**
* 为防止用户快速点击这里300ms之内只会请求一次接口
*/
fun enableAutoDownload(game: GameEntity?, enable: Boolean) {
val message = Message.obtain()
message.what = MESSAGE_WHAT_ENABLE_AUTO_DOWNLOAD
message.obj = game to enable
handler.removeMessages(MESSAGE_WHAT_ENABLE_AUTO_DOWNLOAD)
handler.sendMessageDelayed(message, 300)
}
fun enableAutoDownloadInBatches(requestBody: RequestBody): Single<ResponseBody> {
return apiService.reserveSetting(requestBody)
}
fun cancelReserveInBatch(requestBody: RequestBody): Single<ResponseBody> {
return apiService.reserveSetting(requestBody)
}
companion object {
private const val MESSAGE_WHAT_ENABLE_AUTO_DOWNLOAD = 1
fun newInstance() =
ReserveReminderRepository(RetrofitManager.getInstance().newApi)
}
}

View File

@ -0,0 +1,68 @@
package com.halo.assistant.fragment.reserve
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.entity.ReserveModifyEntity
import com.gh.gamecenter.entity.ReserveReminderEntity
import com.gh.gamecenter.entity.ValidateCodeResponse
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.livedata.Event
import io.reactivex.disposables.CompositeDisposable
class ReserveReminderViewModel : ViewModel() {
private val repository = ReserveReminderRepository.newInstance()
private val composeDisposable = CompositeDisposable()
private val _reserveReminder = MutableLiveData<ReserveReminderEntity>()
val reserveReminder: LiveData<ReserveReminderEntity> = _reserveReminder
fun updateReserveReminder(reserveReminder: ReserveReminderEntity) {
_reserveReminder.value = reserveReminder
}
private val _sendVerifyCode = MutableLiveData<Event<String>>()
val sendVerifyCode: LiveData<Event<String>> = _sendVerifyCode
fun sendVerifyCode(phone: String) {
repository.sendVerifyCode(phone)
.compose(singleToMain())
.subscribe(object : BiResponse<ValidateCodeResponse>() {
override fun onSuccess(data: ValidateCodeResponse) {
_sendVerifyCode.value = Event(data.serviceId)
}
}).let(composeDisposable::add)
}
private val _unableSmsReminderSuccessfully = MutableLiveData<Event<Unit>>()
val unableSmsReminderSuccessfully: LiveData<Event<Unit>> = _unableSmsReminderSuccessfully
fun unableSmsReminder(gameId: String) {
repository.unableSmsReminder(gameId)
.compose(singleToMain())
.subscribe(object : BiResponse<ReserveModifyEntity>() {
override fun onSuccess(data: ReserveModifyEntity) {
_unableSmsReminderSuccessfully.value = Event(Unit)
}
}).let(composeDisposable::add)
}
/**
* 由于可能存在用户点击了自动下载立马就退出dialog这个方法仍然需要执行完毕
* 所以这里当 预约提醒弹窗 退出时,仍然继续执行
*/
fun enableAutoDownload(game: GameEntity?, enable: Boolean) {
repository.enableAutoDownload(game, enable)
}
override fun onCleared() {
composeDisposable.clear()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="20dp"/>
<solid android:color="@color/ui_container_2"/>
</shape>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/ui_container_1" />
<corners android:radius="4dp" />
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="100dp"/>
<gradient android:startColor="#13C26A"
android:endColor="#16B867"
android:angle="270"/>
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="8dp" />
<stroke
android:width="1dp"
android:color="@color/reserve_reminder_border_color" />
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient android:startColor="#142496FF"
android:endColor="#0A2496FF"/>
<stroke android:color="#142496FF"
android:width="1dp"/>
<corners android:radius="4dp"/>
</shape>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M8.667,2C8.667,1.632 8.368,1.333 8,1.333C7.632,1.333 7.333,1.632 7.333,2V8.724L4.805,6.195C4.544,5.935 4.122,5.935 3.862,6.195C3.602,6.456 3.602,6.878 3.862,7.138L7.529,10.805C7.654,10.93 7.823,11 8,11C8.177,11 8.346,10.93 8.471,10.805L12.138,7.138C12.398,6.878 12.398,6.456 12.138,6.195C11.878,5.935 11.456,5.935 11.195,6.195L8.667,8.724V2ZM2.667,12.667C2.298,12.667 2,12.965 2,13.333C2,13.701 2.298,14 2.667,14H13.333C13.701,14 14,13.701 14,13.333C14,12.965 13.701,12.667 13.333,12.667H2.667Z"
android:fillColor="#333333"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M10.471,3.748C10.211,3.487 9.789,3.487 9.529,3.748L8.943,4.333L10.667,6.057L11.252,5.471C11.513,5.211 11.513,4.789 11.252,4.529L10.471,3.748ZM9.724,7L8,5.276L2.862,10.414C2.737,10.539 2.667,10.709 2.667,10.886V12C2.667,12.184 2.816,12.333 3,12.333H4.114C4.291,12.333 4.461,12.263 4.586,12.138L9.724,7ZM7.528,3.862L1.919,9.471C1.544,9.846 1.333,10.355 1.333,10.886V12C1.333,12.92 2.08,13.667 3,13.667H4.114C4.645,13.667 5.154,13.456 5.529,13.081L11.138,7.471L12.195,6.414C12.976,5.633 12.976,4.367 12.195,3.586L11.414,2.805C10.633,2.024 9.367,2.024 8.586,2.805L7.529,3.862C7.529,3.862 7.529,3.862 7.529,3.862C7.529,3.862 7.528,3.862 7.528,3.862ZM7.333,13C7.333,12.632 7.632,12.333 8,12.333H14C14.368,12.333 14.667,12.632 14.667,13C14.667,13.368 14.368,13.667 14,13.667L8,13.667C7.632,13.667 7.333,13.368 7.333,13Z"
android:fillColor="#B3B3B3"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="26dp"
android:height="14dp"
android:viewportWidth="26"
android:viewportHeight="14">
<path
android:pathData="M7,0C3.134,0 0,3.134 0,7C0,10.866 3.134,14 7,14H19C22.866,14 26,10.866 26,7C26,3.134 22.866,0 19,0H7ZM6.484,4.758V3.498H5.359V4.758H4.45V5.847H5.359V7.305C5.167,7.353 4.981,7.401 4.801,7.449C4.621,7.491 4.444,7.53 4.27,7.566L4.468,8.664L5.359,8.421V9.591C5.359,9.795 5.311,9.966 5.215,10.104C5.125,10.236 4.948,10.368 4.684,10.5L5.269,11.553C5.701,11.325 6.01,11.064 6.196,10.77C6.388,10.482 6.484,10.134 6.484,9.726V8.097C6.616,8.055 6.739,8.019 6.853,7.989C6.967,7.959 7.072,7.929 7.168,7.899L7.006,7.08H7.069H7.195C7.237,7.08 7.279,7.077 7.321,7.071V11.4H8.419V11.103H12.424V10.104H10.723V9.267H12.154V8.277H10.723V7.44H12.154V6.477H10.723V5.64H12.307V4.641H10.795L11.074,4.479C11.02,4.401 10.954,4.308 10.876,4.2C10.798,4.092 10.717,3.981 10.633,3.867C10.549,3.753 10.468,3.642 10.39,3.534C10.312,3.42 10.246,3.324 10.192,3.246L9.328,3.759L9.931,4.641H8.347V3.498H7.24V5.631C7.24,5.739 7.216,5.82 7.168,5.874C7.12,5.922 7.066,5.946 7.006,5.946H6.862V6.891L6.484,6.999V5.847H7.096V4.758H6.484ZM9.625,6.477H8.419V5.64H9.625V6.477ZM9.625,10.104H8.419V9.267H9.625V10.104ZM9.625,8.277H8.419V7.44H9.625V8.277ZM13.9,9.123C14.182,9.123 14.464,9.078 14.746,8.988V11.31H15.88V8.313C16.054,8.145 16.21,7.956 16.348,7.746C16.492,7.536 16.612,7.296 16.708,7.026V7.791H19.507L18.373,8.349V8.502H16.177V9.447H18.373V9.807C18.373,9.903 18.361,9.987 18.337,10.059C18.319,10.131 18.283,10.2 18.229,10.266C18.175,10.326 18.103,10.386 18.013,10.446C17.923,10.506 17.806,10.569 17.662,10.635L18.22,11.544C18.466,11.412 18.67,11.286 18.832,11.166C18.994,11.052 19.123,10.932 19.219,10.806C19.315,10.686 19.381,10.554 19.417,10.41C19.459,10.266 19.48,10.101 19.48,9.915V9.447H21.433V8.502H20.011L21.055,7.935C21.169,7.869 21.247,7.776 21.289,7.656C21.331,7.536 21.337,7.416 21.307,7.296C21.283,7.176 21.223,7.074 21.127,6.99C21.037,6.9 20.914,6.855 20.758,6.855H16.762L16.798,6.693C16.816,6.633 16.831,6.573 16.843,6.513H21.433V5.568H16.942V5.379H15.853V5.568H13.693V6.513H15.736C15.652,6.813 15.535,7.065 15.385,7.269C15.235,7.473 15.07,7.638 14.89,7.764C14.71,7.884 14.527,7.971 14.341,8.025C14.155,8.079 13.984,8.106 13.828,8.106H13.405V9.123H13.9ZM16.618,4.866H18.391V5.271H19.489V4.866H21.37V3.903H19.489V3.408H18.391V3.903H16.618V3.408H15.52V3.903H13.621V4.866H15.52V5.271H16.618V4.866Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="14dp"
android:viewportWidth="14"
android:viewportHeight="14">
<path
android:pathData="M6.759,4.883C6.759,4.883 6.1,4.619 6.084,4.252C6.066,3.866 6.347,3.561 6.728,3.553C7.111,3.545 7.406,3.837 7.405,4.222C7.403,4.59 6.759,4.883 6.759,4.883ZM3.357,4.883C2.993,4.877 2.705,4.589 2.699,4.227C2.693,3.865 2.975,3.57 3.34,3.557C3.725,3.543 4.029,3.83 4.034,4.21C4.038,4.589 3.736,4.889 3.357,4.883ZM9.952,4.496C9.756,3.906 9.449,3.384 9.014,2.942C7.926,1.836 6.58,1.372 5.181,1.346C3.729,1.357 2.52,1.724 1.489,2.579C0.518,3.385 -0.044,4.411 0.003,5.7C0.047,6.925 0.639,7.88 1.579,8.627C1.834,8.83 1.929,9.038 1.819,9.35C1.748,9.553 1.699,9.766 1.656,9.977C1.603,10.235 1.714,10.327 1.949,10.206C2.231,10.061 2.508,9.904 2.776,9.733C3.039,9.563 3.301,9.519 3.607,9.608C4.048,9.736 4.503,9.783 4.964,9.784C5.19,9.785 5.29,9.722 5.244,9.471C4.935,7.76 5.669,6.535 7.065,5.64C7.855,5.133 8.744,4.921 9.674,4.898C9.991,4.89 10.042,4.768 9.952,4.496Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M12.928,6.413C11.274,4.86 8.336,4.846 6.669,6.385C5.982,7.018 5.591,7.793 5.564,8.749C5.587,9.775 6.027,10.61 6.821,11.249C7.927,12.139 9.211,12.454 10.586,12.184C11.194,12.065 11.673,12.149 12.153,12.49C12.171,12.503 12.191,12.518 12.21,12.533C12.313,12.614 12.433,12.708 12.559,12.616C12.696,12.516 12.626,12.361 12.572,12.239C12.565,12.223 12.558,12.208 12.552,12.193C12.358,11.734 12.502,11.448 12.875,11.118C14.364,9.803 14.368,7.765 12.928,6.413ZM11.199,8.177C10.891,8.182 10.638,7.942 10.632,7.639C10.625,7.335 10.87,7.084 11.178,7.079C11.488,7.073 11.737,7.311 11.743,7.617C11.749,7.925 11.509,8.172 11.199,8.177ZM8.369,8.177C8.057,8.174 7.82,7.933 7.823,7.622C7.826,7.311 8.067,7.076 8.38,7.079C8.692,7.082 8.929,7.322 8.926,7.633C8.923,7.942 8.68,8.18 8.369,8.177Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="14dp"
android:viewportWidth="14"
android:viewportHeight="14">
<path
android:pathData="M7,2.625C4.584,2.625 2.625,4.584 2.625,7C2.625,9.416 4.584,11.375 7,11.375C9.416,11.375 11.375,9.416 11.375,7C11.375,4.584 9.416,2.625 7,2.625ZM1.458,7C1.458,3.939 3.939,1.458 7,1.458C10.061,1.458 12.542,3.939 12.542,7C12.542,10.061 10.061,12.542 7,12.542C3.939,12.542 1.458,10.061 1.458,7ZM7.729,9.479C7.729,9.882 7.403,10.208 7,10.208C6.597,10.208 6.271,9.882 6.271,9.479C6.271,9.076 6.597,8.75 7,8.75C7.403,8.75 7.729,9.076 7.729,9.479ZM6.125,5.542C6.125,5.362 6.36,4.958 7,4.958C7.64,4.958 7.875,5.362 7.875,5.542C7.875,5.693 7.835,5.755 7.793,5.803C7.727,5.878 7.627,5.944 7.429,6.062L7.406,6.076C7.239,6.176 6.988,6.326 6.79,6.55C6.559,6.813 6.417,7.151 6.417,7.583C6.417,7.906 6.678,8.167 7,8.167C7.322,8.167 7.583,7.906 7.583,7.583C7.583,7.433 7.623,7.37 7.665,7.322C7.732,7.247 7.832,7.181 8.029,7.063L8.052,7.049C8.22,6.949 8.47,6.799 8.668,6.575C8.899,6.312 9.042,5.974 9.042,5.542C9.042,4.555 8.11,3.792 7,3.792C5.89,3.792 4.958,4.555 4.958,5.542C4.958,5.864 5.219,6.125 5.542,6.125C5.864,6.125 6.125,5.864 6.125,5.542Z"
android:fillColor="#B3B3B3"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="26dp"
android:height="15dp"
android:viewportWidth="26"
android:viewportHeight="15">
<path
android:pathData="M7,0.5L19,0.5A7,7 0,0 1,26 7.5L26,7.5A7,7 0,0 1,19 14.5L7,14.5A7,7 0,0 1,0 7.5L0,7.5A7,7 0,0 1,7 0.5z"
android:fillColor="#06CEA8"/>
<path
android:pathData="M6.484,3.998V5.258H7.096V6.347H6.484V7.499L6.862,7.391V6.446H7.006C7.066,6.446 7.12,6.422 7.168,6.374C7.216,6.32 7.24,6.239 7.24,6.131V3.998H8.347V5.141H9.931L9.328,4.259L10.192,3.746C10.246,3.824 10.312,3.92 10.39,4.034C10.468,4.142 10.549,4.253 10.633,4.367C10.717,4.481 10.798,4.592 10.876,4.7C10.954,4.808 11.02,4.901 11.074,4.979L10.795,5.141H12.307V6.14H10.723V6.977H12.154V7.94H10.723V8.777H12.154V9.767H10.723V10.604H12.424V11.603H8.419V11.9H7.321V7.571C7.279,7.577 7.237,7.58 7.195,7.58C7.159,7.58 7.117,7.58 7.069,7.58H7.006L7.168,8.399C7.072,8.429 6.967,8.459 6.853,8.489C6.739,8.519 6.616,8.555 6.484,8.597V10.226C6.484,10.634 6.388,10.982 6.196,11.27C6.01,11.564 5.701,11.825 5.269,12.053L4.684,11C4.948,10.868 5.125,10.736 5.215,10.604C5.311,10.466 5.359,10.295 5.359,10.091V8.921L4.468,9.164L4.27,8.066C4.444,8.03 4.621,7.991 4.801,7.949C4.981,7.901 5.167,7.853 5.359,7.805V6.347H4.45V5.258H5.359V3.998H6.484ZM8.419,6.977H9.625V6.14H8.419V6.977ZM8.419,10.604H9.625V9.767H8.419V10.604ZM8.419,8.777H9.625V7.94H8.419V8.777ZM14.746,9.488C14.464,9.578 14.182,9.623 13.9,9.623H13.405V8.606H13.828C13.984,8.606 14.155,8.579 14.341,8.525C14.527,8.471 14.71,8.384 14.89,8.264C15.07,8.138 15.235,7.973 15.385,7.769C15.535,7.565 15.652,7.313 15.736,7.013H13.693V6.068H15.853V5.879H16.942V6.068H21.433V7.013H16.843C16.831,7.073 16.816,7.133 16.798,7.193C16.786,7.247 16.774,7.301 16.762,7.355H20.758C20.914,7.355 21.037,7.4 21.127,7.49C21.223,7.574 21.283,7.676 21.307,7.796C21.337,7.916 21.331,8.036 21.289,8.156C21.247,8.276 21.169,8.369 21.055,8.435L20.011,9.002H21.433V9.947H19.48V10.415C19.48,10.601 19.459,10.766 19.417,10.91C19.381,11.054 19.315,11.186 19.219,11.306C19.123,11.432 18.994,11.552 18.832,11.666C18.67,11.786 18.466,11.912 18.22,12.044L17.662,11.135C17.806,11.069 17.923,11.006 18.013,10.946C18.103,10.886 18.175,10.826 18.229,10.766C18.283,10.7 18.319,10.631 18.337,10.559C18.361,10.487 18.373,10.403 18.373,10.307V9.947H16.177V9.002H18.373V8.849L19.507,8.291H16.708V7.526C16.612,7.796 16.492,8.036 16.348,8.246C16.21,8.456 16.054,8.645 15.88,8.813V11.81H14.746V9.488ZM18.391,5.366H16.618V5.771H15.52V5.366H13.621V4.403H15.52V3.908H16.618V4.403H18.391V3.908H19.489V4.403H21.37V5.366H19.489V5.771H18.391V5.366Z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group>
<clip-path
android:pathData="M0,0h24v24h-24z"/>
<path
android:pathData="M12,12m-11.25,0a11.25,11.25 0,1 1,22.5 0a11.25,11.25 0,1 1,-22.5 0"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="@color/text_aw_primary"/>
<path
android:pathData="M8.47,8.47C8.763,8.177 9.237,8.177 9.53,8.47L12,10.939L14.47,8.47C14.763,8.177 15.237,8.177 15.53,8.47C15.823,8.763 15.823,9.237 15.53,9.53L13.061,12L15.53,14.47C15.823,14.762 15.823,15.237 15.53,15.53C15.237,15.823 14.763,15.823 14.47,15.53L12,13.061L9.53,15.53C9.237,15.823 8.763,15.823 8.47,15.53C8.177,15.237 8.177,14.762 8.47,14.47L10.939,12L8.47,9.53C8.177,9.237 8.177,8.763 8.47,8.47Z"
android:fillColor="@color/text_aw_primary"
android:fillType="evenOdd"/>
</group>
</vector>

View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/v_toolbar_background"
android:layout_width="0dp"
android:layout_height="48dp"
android:background="@color/ui_surface"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/v_back"
android:layout_width="48dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@id/v_toolbar_background"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/v_toolbar_background" />
<ImageView
android:id="@+id/iv_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_bar_back"
app:layout_constraintBottom_toBottomOf="@id/v_back"
app:layout_constraintEnd_toEndOf="@id/v_back"
app:layout_constraintStart_toStartOf="@id/v_back"
app:layout_constraintTop_toTopOf="@id/v_back" />
<TextView
style="@style/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/my_game"
android:textColor="@color/text_primary"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@id/v_toolbar_background"
app:layout_constraintEnd_toEndOf="@id/v_toolbar_background"
app:layout_constraintStart_toStartOf="@id/v_toolbar_background"
app:layout_constraintTop_toTopOf="@id/v_toolbar_background" />
<View
android:id="@+id/v_more"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintBottom_toBottomOf="@id/v_toolbar_background"
app:layout_constraintEnd_toEndOf="@id/v_toolbar_background"
app:layout_constraintTop_toTopOf="@id/v_toolbar_background" />
<ImageView
android:id="@+id/iv_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@id/v_more"
app:layout_constraintEnd_toEndOf="@id/v_more"
app:layout_constraintStart_toStartOf="@id/v_more"
app:layout_constraintTop_toTopOf="@id/v_more"
app:srcCompat="@drawable/ic_menu_more" />
<androidx.constraintlayout.widget.Group
android:id="@+id/g_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="v_more,iv_more" />
<View
android:id="@+id/v_game_collection"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintBottom_toBottomOf="@id/v_toolbar_background"
app:layout_constraintEnd_toStartOf="@id/v_more"
app:layout_constraintTop_toTopOf="@id/v_toolbar_background" />
<ImageView
android:id="@+id/iv_game_collection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_create_game_collection"
app:layout_constraintBottom_toBottomOf="@id/v_game_collection"
app:layout_constraintEnd_toEndOf="@id/v_game_collection"
app:layout_constraintStart_toStartOf="@id/v_game_collection"
app:layout_constraintTop_toTopOf="@id/v_game_collection" />
<androidx.constraintlayout.widget.Group
android:id="@+id/g_game_collection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="iv_game_collection,iv_game_collection" />
<TextView
android:id="@+id/tv_cancel"
android:layout_width="60dp"
android:layout_height="0dp"
android:gravity="center"
android:text="@string/cancel"
android:textColor="@color/text_theme"
android:textSize="14sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/v_toolbar_background"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/v_toolbar_background" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/activity_tab_layout"
android:layout_width="0dp"
android:layout_height="45dp"
android:background="@color/ui_surface"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/v_toolbar_background"
app:tabIndicator="@null"
app:tabTextAppearance="@style/TabLayoutTextAppearance" />
<com.gh.gamecenter.common.view.TabIndicatorView
android:id="@+id/activity_tab_indicator"
android:layout_width="0dp"
android:layout_height="@dimen/default_tab_indicator_height"
app:layout_constraintBottom_toBottomOf="@id/activity_tab_layout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<View
android:id="@+id/v_line"
android:layout_width="0dp"
android:layout_height="0.5dp"
android:background="@color/ui_divider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/activity_tab_layout" />
<com.lightgame.view.NoScrollableViewPager
android:id="@+id/activity_view_pager"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/v_line" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,40 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/dialog_reserve_background"
android:gravity="center_horizontal"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="300dp"
android:layout_height="match_parent">
<View
android:id="@+id/v_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="12dp"
android:background="@drawable/background_shape_white_radius_12"
app:layout_constraintBottom_toTopOf="@id/space_bottom"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/dialog_reserve_head_background" />
android:src="@drawable/bg_reserve_online_reminder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/title"
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:includeFontPadding="false"
android:textColor="@color/text_primary"
android:textSize="16sp"
android:textStyle="bold" />
android:layout_marginStart="24dp"
android:layout_marginTop="80dp"
android:textColor="@color/text_secondary"
android:textSize="13sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="您预约的4款游戏上线了~" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="wrap_content"
android:id="@+id/rv_games"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp" />
android:paddingHorizontal="20dp"
android:clipToPadding="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title"
tools:itemCount="1"
tools:listitem="@layout/dialog_reserve_item" />
<TextView
android:id="@+id/more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:text="查看全部 >"
android:textColor="@color/text_theme"
android:textSize="14sp" />
android:id="@+id/tv_auto_download_tips"
style="@style/TextCaption1"
android:layout_width="0dp"
android:layout_height="52dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:background="@drawable/bg_shape_f8_radius_12"
android:drawablePadding="12dp"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="2"
android:paddingHorizontal="12dp"
android:textColor="@color/text_secondary"
app:drawableEndCompat="@drawable/ic_forum_arrow_right"
app:drawableStartCompat="@drawable/ic_download"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv_games"
tools:text="@string/reserve_reminder_auto_download_with_name" />
</LinearLayout>
<TextView
android:id="@+id/tv_view_all_appointment"
style="@style/BtnRegularStyle"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:background="@drawable/bg_common_button_light_fill_blue"
android:text="@string/view_all_appointments"
android:textColor="@color/primary_theme"
android:textStyle="bold"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_auto_download_tips" />
<Space
android:id="@+id/space_bottom"
android:layout_width="wrap_content"
android:layout_height="1dp"
android:layout_marginTop="24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_view_all_appointment" />
<ImageView
android:id="@+id/iv_close"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/v_background"
app:srcCompat="@drawable/ic_reserve_reminder_close" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -6,23 +6,25 @@
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp">
android:paddingHorizontal="4dp">
<com.facebook.drawee.view.SimpleDraweeView
<com.gh.gamecenter.feature.view.GameIconView
android:id="@+id/icon"
style="@style/frescoStyle"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_width="52dp"
android:layout_height="52dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
fresco:roundedCornerRadius="10dp" />
fresco:roundedCornerRadius="12dp" />
<TextView
android:id="@+id/gameNameTv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:gravity="center_horizontal"
android:singleLine="true"
android:textColor="@color/text_primary"
android:textSize="12sp"

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="300dp"
android:layout_height="wrap_content"
android:background="@drawable/background_shape_white_radius_12"
android:paddingBottom="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/tv_title"
style="@style/TextHeadline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:textColor="@color/text_primary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/v_close"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_close"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:src="@drawable/icon_close"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_description"
style="@style/TextBody2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="12dp"
android:textColor="@color/text_secondary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<EditText
android:id="@+id/et_input"
style="@style/TextBody2"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:background="@drawable/bg_enable_sms_reminder_et"
android:inputType="number"
android:maxLength="11"
android:paddingHorizontal="20dp"
android:textColor="@color/text_primary"
android:textColorHint="@color/text_instance"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_description" />
<TextView
android:id="@+id/tv_submit"
style="@style/BtnRegularStyle"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:alpha="0.4"
android:background="@drawable/bg_common_button_fill_blue"
android:text="@string/servers_subscribed_game_unsubscribe_dialog_confirm"
android:textColor="@color/text_aw_primary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/et_input" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="300dp"
android:layout_height="wrap_content">
<View
android:id="@+id/v_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="12dp"
android:background="@drawable/background_shape_white_radius_12"
app:layout_constraintBottom_toBottomOf="@id/space_bottom"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_title"
android:layout_width="0dp"
android:layout_height="112dp"
android:scaleType="centerCrop"
android:src="@drawable/bg_reserve_success_top"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="80dp"
android:layout_marginRight="24dp"
android:lineSpacingExtra="4dp"
android:text="@string/reverse_success_without_reminder_tips"
android:textColor="@color/text_secondary"
android:textSize="13sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/fl_content_container"
android:layout_width="252dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content" />
<CheckBox
android:id="@+id/cb_auto_download"
style="@style/TextCaption1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:button="@drawable/selector_kaifu_report"
android:gravity="center_vertical"
android:paddingStart="4dp"
android:checked="false"
android:text="@string/reserve_auto_download"
android:textColor="@color/text_secondary"
app:layout_constraintEnd_toStartOf="@id/iv_question"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/fl_content_container" />
<ImageView
android:id="@+id/iv_question"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_marginStart="4dp"
android:src="@drawable/ic_explain"
app:layout_constraintBottom_toBottomOf="@id/cb_auto_download"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/cb_auto_download"
app:layout_constraintTop_toTopOf="@id/cb_auto_download"
app:tint="@color/text_neutral" />
<androidx.constraintlayout.widget.Group
android:id="@+id/g_auto_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="cb_auto_download,iv_question" />
<Space
android:id="@+id/space_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cb_auto_download" />
<ImageView
android:id="@+id/iv_close"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/space_bottom"
app:srcCompat="@drawable/ic_reserve_reminder_close" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/background_shape_white_radius_8"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:id="@+id/tv_title"
style="@style/TextHeadline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/wechat_binding_conflict_title"
android:textColor="@color/text_primary" />
<TextView
android:id="@+id/tv_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/wechat_binding_conflict_description"
android:textColor="@color/text_secondary"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_i_know"
style="@style/BtnRegularStyle"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="24dp"
android:background="@drawable/bg_common_button_fill_blue"
android:text="@string/know"
android:textColor="@color/text_aw_primary" />
</LinearLayout>
</FrameLayout>

View File

@ -0,0 +1,214 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/background_shape_white_radius_8"
android:padding="24dp">
<TextView
android:id="@+id/tv_title"
style="@style/TextHeadline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/binding_failed"
android:textColor="@color/text_primary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_description"
style="@style/TextCaption1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/binding_failed_description"
android:textColor="@color/text_secondary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<androidx.cardview.widget.CardView
android:id="@+id/v_current_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:cardBackgroundColor="@color/ui_container_1"
app:cardCornerRadius="8dp"
app:cardElevation="0dp"
app:layout_constraintBottom_toBottomOf="@id/space_current_bottom"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_description" />
<TextView
android:id="@+id/tv_current_title"
style="@style/TextBody2B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:text="@string/current_number"
android:textColor="@color/text_primary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/v_current_background" />
<com.gh.gamecenter.common.view.AvatarBorderView
android:id="@+id/iv_current_avatar"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
app:border_color="@color/resource_border"
app:border_width="1dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_current_title" />
<TextView
android:id="@+id/tv_current_name"
style="@style/TextBody2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="12dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="1"
android:textColor="@color/text_primary"
app:layout_constraintBottom_toTopOf="@id/tv_user_id"
app:layout_constraintStart_toEndOf="@id/iv_current_avatar"
app:layout_constraintTop_toTopOf="@id/iv_current_avatar"
tools:text="用户名称" />
<TextView
android:id="@+id/tv_user_id"
style="@style/TextCaption1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginEnd="12dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="1"
android:textColor="@color/text_tertiary"
app:layout_constraintBottom_toBottomOf="@id/iv_current_avatar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tv_current_name"
app:layout_constraintTop_toBottomOf="@id/tv_current_name"
tools:text="ID:02000200" />
<Space
android:id="@+id/space_current_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_current_avatar" />
<androidx.cardview.widget.CardView
android:id="@+id/v_conflict_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
app:cardBackgroundColor="@color/ui_container_1"
app:cardCornerRadius="8dp"
app:cardElevation="0dp"
app:layout_constraintBottom_toBottomOf="@id/space_conflict_bottom"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/v_current_background" />
<TextView
android:id="@+id/tv_conflict_title"
style="@style/TextBody2B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:text="@string/conflict_number"
android:textColor="@color/text_primary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/v_conflict_background" />
<com.gh.gamecenter.common.view.AvatarBorderView
android:id="@+id/iv_conflict_avatar"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
app:border_color="@color/resource_border"
app:border_width="1dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_conflict_title" />
<TextView
android:id="@+id/tv_conflict_name"
style="@style/TextBody2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="12dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="1"
android:textColor="@color/text_primary"
app:layout_constraintBottom_toTopOf="@id/tv_conflict_user_id"
app:layout_constraintStart_toEndOf="@id/iv_conflict_avatar"
app:layout_constraintTop_toTopOf="@id/iv_conflict_avatar"
tools:text="用户名称" />
<TextView
android:id="@+id/tv_conflict_user_id"
style="@style/TextCaption1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="1"
android:textColor="@color/text_tertiary"
app:layout_constraintBottom_toBottomOf="@id/iv_conflict_avatar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tv_conflict_name"
app:layout_constraintTop_toBottomOf="@id/tv_conflict_name"
tools:text="ID:02000200" />
<Space
android:id="@+id/space_conflict_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_conflict_avatar" />
<TextView
android:id="@+id/tv_conflict_problem"
style="@style/TextCaption1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/change_binding_tips_with_conflict"
android:textColor="@color/text_theme"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/v_conflict_background" />
<TextView
android:id="@+id/tv_i_know"
style="@style/BtnRegularStyle"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="16dp"
android:background="@drawable/bg_common_button_fill_blue"
android:text="@string/know"
android:textColor="@color/text_aw_primary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_conflict_problem" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@ -9,14 +9,22 @@
<include
android:id="@+id/game_item_included"
layout="@layout/game_item" />
layout="@layout/recycler_my_reserve"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="-4dp"
android:layout_marginTop="12dp"
android:orientation="horizontal"
android:paddingBottom="16dp">
android:paddingBottom="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/game_item_included">
<LinearLayout
android:id="@+id/cardContainer"
@ -111,4 +119,4 @@
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/reuse_listview_item_style"
android:orientation="vertical">
<include
android:id="@+id/game_item_included"
layout="@layout/recycler_my_reserve"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal"
android:paddingBottom="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/game_item_included">
<LinearLayout
android:id="@+id/cardContainer"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginStart="92dp"
android:layout_marginEnd="16dp"
android:background="@drawable/bg_shape_space_radius_8"
android:orientation="horizontal"
android:showDividers="middle"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:id="@+id/comments_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
app:srcCompat="@drawable/ic_my_follow_comment" />
<TextView
android:id="@+id/commentsTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:text="评价"
android:textColor="@color/text_secondary"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/trends_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
app:srcCompat="@drawable/ic_my_follow_zone" />
<TextView
android:id="@+id/trendsTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:text="专区"
android:textColor="@color/text_secondary"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/forum_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
app:srcCompat="@drawable/ic_my_follow_forum" />
<TextView
android:id="@+id/forumTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:text="论坛"
android:textColor="@color/text_secondary"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/hint_text"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="?selectableItemBackground"
android:gravity="center"
android:orientation="vertical"
android:paddingHorizontal="16dp"
android:text="修改"
android:textColor="@color/text_secondary"
android:textSize="12sp" />

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="252dp"
android:layout_height="92dp">
<View
android:id="@+id/v_description_background"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="@drawable/bg_shape_f8_radius_8"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_description"
style="@style/TextCaption1"
android:layout_width="0dp"
android:layout_height="52dp"
android:paddingHorizontal="12dp"
android:paddingVertical="10dp"
android:textColor="@color/text_secondary"
android:text="@string/reserve_only_wechat_unable_tips"
app:layout_constraintEnd_toEndOf="@id/v_description_background"
app:layout_constraintStart_toStartOf="@id/v_description_background"
app:layout_constraintTop_toTopOf="@id/v_description_background" />
<View
android:id="@+id/v_submit_background"
android:layout_width="0dp"
android:layout_height="40dp"
android:background="@drawable/bg_reserve_only_wechat_unable_submit"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_description" />
<ImageView
android:id="@+id/iv_wechat"
android:layout_width="14dp"
android:layout_height="14dp"
app:layout_constraintBottom_toBottomOf="@id/v_submit_background"
app:layout_constraintEnd_toStartOf="@id/tv_open_wechat_reminder"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="@id/v_submit_background"
app:layout_constraintTop_toTopOf="@id/v_submit_background"
app:srcCompat="@drawable/ic_reserve_open_wechat_reminder" />
<TextView
android:id="@+id/tv_open_wechat_reminder"
style="@style/TextBody2B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:text="@string/enable_wechat_reminder"
android:textColor="@color/text_aw_primary"
app:layout_constraintBottom_toBottomOf="@id/iv_wechat"
app:layout_constraintEnd_toEndOf="@id/iv_wechat"
app:layout_constraintEnd_toStartOf="@id/iv_recommend"
app:layout_constraintStart_toEndOf="@id/iv_wechat"
app:layout_constraintTop_toTopOf="@id/iv_wechat" />
<ImageView
android:id="@+id/iv_recommend"
android:layout_width="26dp"
android:layout_height="14dp"
android:layout_marginStart="4dp"
app:layout_constraintBottom_toBottomOf="@id/tv_open_wechat_reminder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_open_wechat_reminder"
app:layout_constraintTop_toTopOf="@id/tv_open_wechat_reminder"
app:srcCompat="@drawable/ic_reserve_only_wechat_recommend" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="252dp"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/bg_sms_reminders_enable">
<TextView
android:id="@+id/tv_sms_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:gravity="center"
android:text="@string/sms_reminder"
android:textColor="@color/text_tertiary"
android:textSize="13dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textColor="@color/text_secondary"
android:textSize="13sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_sms_title"
app:layout_constraintTop_toTopOf="parent"
tools:text="12666666666" />
<View
android:id="@+id/v_sms_edit"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_sms_edit"
android:layout_width="16dp"
android:layout_height="16dp"
app:srcCompat="@drawable/ic_edit_bind_info"
app:layout_constraintBottom_toBottomOf="@id/v_sms_edit"
app:layout_constraintEnd_toEndOf="@id/v_sms_edit"
app:layout_constraintStart_toStartOf="@id/v_sms_edit"
app:layout_constraintTop_toTopOf="@id/v_sms_edit" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="252dp"
android:layout_height="56dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/bg_sms_reminders_unable">
<TextView
android:id="@+id/tv_sms_reminder_title"
style="@style/TextBody2B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:drawablePadding="2dp"
android:gravity="center"
android:text="@string/sms_reminder"
android:textColor="@color/text_primary"
app:drawableEndCompat="@drawable/ic_reserve_remind_recommend"
app:layout_constraintBottom_toTopOf="@id/tv_sms_reminder_description"
app:layout_constraintStart_toEndOf="@id/tv_sms_reminder_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/tv_sms_reminder_description"
style="@style/TextCaption2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/sms_reminder_description"
android:textColor="@color/text_tertiary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@id/tv_sms_reminder_title"
app:layout_constraintTop_toBottomOf="@id/tv_sms_reminder_title" />
<TextView
android:id="@+id/tv_sms_reminder_open"
style="@style/TextCaption1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:includeFontPadding="false"
android:text="@string/open"
android:textColor="@color/text_theme"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_sms_add"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginEnd="2dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_follow_question"
app:layout_constraintBottom_toBottomOf="@id/tv_sms_reminder_open"
app:layout_constraintEnd_toStartOf="@id/tv_sms_reminder_open"
app:layout_constraintTop_toTopOf="@id/tv_sms_reminder_open" />
<View
android:id="@+id/v_sms_add"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@id/tv_sms_reminder_open"
app:layout_constraintEnd_toEndOf="@id/tv_sms_reminder_open"
app:layout_constraintStart_toStartOf="@id/iv_sms_add"
app:layout_constraintTop_toTopOf="@id/tv_sms_reminder_open" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="252dp"
android:layout_height="40dp"
android:background="@drawable/bg_sms_reminders_enable">
<TextView
android:id="@+id/tv_wechat_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:gravity="center"
android:text="@string/wechat_reminder"
android:textColor="@color/text_tertiary"
android:textSize="13dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_wechat"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="48dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/text_secondary"
android:textSize="13sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_wechat_title"
app:layout_constraintTop_toTopOf="parent"
tools:text="你看起来好像很好吃" />
<View
android:id="@+id/v_modify_wechat"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_modify_wechat"
android:layout_width="16dp"
android:layout_height="16dp"
app:srcCompat="@drawable/ic_edit_bind_info"
app:layout_constraintBottom_toBottomOf="@id/v_modify_wechat"
app:layout_constraintEnd_toEndOf="@id/v_modify_wechat"
app:layout_constraintStart_toStartOf="@id/v_modify_wechat"
app:layout_constraintTop_toTopOf="@id/v_modify_wechat" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="252dp"
android:layout_height="56dp"
android:background="@drawable/bg_enable_wechat_reminders">
<TextView
android:id="@+id/tv_wechat_reminder_title"
style="@style/TextBody2B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/wechat_reminder"
android:textColor="@color/text_primary"
app:layout_constraintBottom_toTopOf="@id/tv_wechat_reminder_description"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/tv_wechat_reminder_description"
style="@style/TextCaption2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/wechat_reminder_description"
android:textColor="@color/text_tertiary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@id/tv_wechat_reminder_title"
app:layout_constraintTop_toBottomOf="@id/tv_wechat_reminder_title" />
<TextView
android:id="@+id/tv_wechat_reminder_open"
style="@style/TextCaption1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:includeFontPadding="false"
android:text="@string/open"
android:textColor="@color/text_theme"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_wechat_add"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginEnd="2dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_follow_question"
app:layout_constraintBottom_toBottomOf="@id/tv_wechat_reminder_open"
app:layout_constraintEnd_toStartOf="@id/tv_wechat_reminder_open"
app:layout_constraintTop_toTopOf="@id/tv_wechat_reminder_open" />
<View
android:id="@+id/v_wechat_add"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@id/tv_wechat_reminder_open"
app:layout_constraintEnd_toEndOf="@id/tv_wechat_reminder_open"
app:layout_constraintStart_toStartOf="@id/iv_wechat_add"
app:layout_constraintTop_toTopOf="@id/tv_wechat_reminder_open" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:id="@+id/v_real_name_background"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginHorizontal="24dp"
android:background="@drawable/bg_reserve_reminder_real_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_real_name_description"
style="@style/TextCaption2"
android:layout_width="252dp"
android:layout_height="50dp"
android:layout_marginBottom="4dp"
android:gravity="center_vertical"
android:paddingHorizontal="12dp"
android:text="@string/reserve_real_name_description"
android:textColor="@color/text_secondary"
app:layout_constraintBottom_toBottomOf="@id/v_real_name_background"
app:layout_constraintEnd_toEndOf="@id/v_real_name_background"
app:layout_constraintStart_toStartOf="@id/v_real_name_background" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@color/ui_surface">
<View
android:id="@+id/v_line"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="@color/ui_divider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/cb_all"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_marginStart="16dp"
android:button="@drawable/selector_kaifu_report"
android:paddingStart="6dp"
android:text="@string/all_select"
android:textColor="@color/text_primary"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/tv_number"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="6dp"
android:gravity="center"
android:textColor="@color/text_theme"
android:textSize="@dimen/primary_text_size"
app:layout_constraintStart_toEndOf="@id/cb_all"
tools:text="(10)" />
<TextView
android:id="@+id/tv_submit"
style="@style/BtnSmallStyle"
android:layout_marginEnd="16dp"
android:background="@drawable/bg_common_button_fill_gradient_blue"
android:textColor="@color/text_aw_primary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="取消预约" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,373 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/reuse_listview_item_style"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/game_order"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:gravity="center"
android:minWidth="24dp"
android:minHeight="24dp"
android:textColor="@color/title"
android:textSize="12sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/selectIv"
app:layout_constraintTop_toTopOf="parent" />
<com.lightgame.view.CheckableImageView
android:id="@+id/selectIv"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_gravity="center"
android:layout_marginStart="16dp"
android:layout_marginRight="12dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/game_order"
app:layout_constraintRight_toLeftOf="@+id/gameIconView"
app:layout_constraintTop_toTopOf="parent" />
<com.gh.gamecenter.feature.view.GameIconView
android:id="@+id/gameIconView"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginTop="16dp"
android:layout_marginRight="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/selectIv"
app:layout_constraintRight_toLeftOf="@+id/gameDesSpace"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginLeft="16dp" />
<LinearLayout
android:id="@+id/gameNameContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@+id/gameDesSpace"
app:layout_constraintEnd_toStartOf="@+id/barrier"
app:layout_constraintStart_toStartOf="@id/gameDesSpace"
app:layout_constraintTop_toTopOf="@+id/gameIconView"
app:layout_constraintVertical_chainStyle="packed">
<TextView
android:id="@+id/game_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:singleLine="true"
android:textColor="@color/text_primary"
android:textSize="14sp"
android:textStyle="bold"
tools:text="地海争霸:巫妖王再怒" />
<TextView
android:id="@+id/gameSubtitleTv"
android:layout_width="wrap_content"
android:layout_height="14dp"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:background="@drawable/bg_advance_download_game_subtitle"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:singleLine="true"
android:textColor="@color/text_secondary"
android:textSize="@dimen/tag_text_size"
android:visibility="gone"
tools:text="副标题副标题副标题"
tools:visibility="visible" />
<TextView
android:id="@+id/recent_played_tag"
android:layout_width="48dp"
android:layout_height="14dp"
android:layout_marginLeft="4dp"
android:background="@drawable/button_round_1affa142"
android:gravity="center"
android:text="近期玩过"
android:textColor="@color/text_F8A142"
android:textSize="10sp"
android:visibility="gone" />
<TextView
android:id="@+id/game_kaifu_type"
android:layout_width="wrap_content"
android:layout_height="14dp"
android:layout_marginLeft="4dp"
android:background="@color/primary_theme"
android:gravity="center"
android:includeFontPadding="false"
android:maxLines="1"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:textColor="@color/white"
android:textSize="10sp"
android:visibility="gone" />
<TextView
android:id="@+id/adLabelTv"
android:layout_width="21dp"
android:layout_height="14dp"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:background="@drawable/bg_ad_label"
android:gravity="center"
android:text="AD"
android:textColor="@color/white"
android:textSize="@dimen/tag_text_size"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
<Space
android:id="@+id/space_end"
android:layout_width="0dp"
android:layout_height="24dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_edit"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="8dp"
android:src="@drawable/ic_reserve_more"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="left"
app:constraint_referenced_ids="space_end,iv_edit"/>
<TextView
android:id="@+id/tv_auto_download_tips"
style="@style/TextLabel2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_shape_ui_container_2_radius_2"
android:gravity="center"
android:paddingHorizontal="4dp"
android:paddingVertical="2dp"
android:text="@string/automatic_downloading_is_enabled"
android:textColor="@color/text_tertiary"
app:layout_constraintBottom_toBottomOf="@id/space_end"
app:layout_constraintEnd_toStartOf="@id/barrier_edit"
app:layout_constraintTop_toTopOf="@id/space_end" />
<Space
android:id="@+id/space_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
app:layout_constraintBottom_toBottomOf="@id/iv_edit"
app:layout_constraintEnd_toStartOf="@id/tv_auto_download_tips"
app:layout_constraintTop_toTopOf="@id/iv_edit" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="start"
app:constraint_referenced_ids="tv_auto_download_tips,iv_edit,space_left,download_btn" />
<Space
android:id="@+id/gameDesSpace"
android:layout_width="0dp"
android:layout_height="28dp"
android:background="@color/black"
app:layout_constraintBottom_toTopOf="@+id/label_list"
app:layout_constraintLeft_toRightOf="@+id/gameIconView"
app:layout_constraintRight_toLeftOf="@+id/download_btn"
app:layout_constraintTop_toBottomOf="@+id/gameNameContainer" />
<TextView
android:id="@+id/game_rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="4dp"
android:includeFontPadding="false"
android:textStyle="bold"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/gameDesSpace"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="@+id/gameDesSpace"
app:layout_constraintRight_toLeftOf="@+id/game_des"
app:layout_constraintTop_toTopOf="@+id/gameDesSpace" />
<TextView
android:id="@+id/game_des"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:includeFontPadding="false"
android:singleLine="true"
android:textColor="@color/text_tertiary"
android:textSize="10sp"
app:layout_constraintBottom_toBottomOf="@id/gameDesSpace"
app:layout_constraintLeft_toRightOf="@+id/game_rating"
app:layout_constraintRight_toRightOf="@+id/gameDesSpace"
app:layout_constraintTop_toTopOf="@+id/gameDesSpace"
tools:text="巫妖王再怒霜之哀殤又飢渴" />
<LinearLayout
android:id="@+id/recommendContainer"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_marginTop="3dp"
android:background="@drawable/bg_game_item_recommend"
android:gravity="center"
android:orientation="horizontal"
android:paddingStart="4dp"
android:paddingEnd="8dp"
android:visibility="gone"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintLeft_toLeftOf="@+id/gameDesSpace"
app:layout_constraintRight_toRightOf="@+id/gameDesSpace"
app:layout_constraintTop_toTopOf="@+id/gameDesSpace">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/recommendIv"
android:layout_width="12dp"
android:layout_height="12dp" />
<TextView
android:id="@+id/recommendTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:ellipsize="end"
android:gravity="center|start"
android:includeFontPadding="false"
android:maxLines="1"
android:textColor="@color/game_recommend_text"
android:textSize="10sp"
android:textStyle="bold"
tools:text="最新活动火爆来袭" />
</LinearLayout>
<TextView
android:id="@+id/recommendStarPref"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:text="推荐指数:"
android:textColor="@color/text_tertiary"
android:textSize="10sp"
app:layout_constraintBottom_toBottomOf="@+id/gameDesSpace"
app:layout_constraintLeft_toLeftOf="@+id/gameDesSpace"
app:layout_constraintTop_toTopOf="@+id/gameDesSpace" />
<com.gh.gamecenter.common.view.materialratingbar.MaterialRatingBar
android:id="@+id/recommendStar"
style="@style/Widget.MaterialRatingBar.RatingBar"
android:layout_width="84dp"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:isIndicator="true"
android:minWidth="12dp"
android:minHeight="12dp"
android:numStars="5"
app:layout_constraintBottom_toBottomOf="@+id/recommendStarPref"
app:layout_constraintLeft_toRightOf="@+id/recommendStarPref"
app:layout_constraintTop_toTopOf="@+id/recommendStarPref"
app:mrb_progressTint="@color/primary_theme"
tools:rating="3" />
<androidx.constraintlayout.widget.Group
android:id="@+id/recommendStarInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="recommendStarPref,recommendStar" />
<com.gh.gamecenter.common.view.GameTagContainerView
android:id="@+id/label_list"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="fill_vertical"
android:orientation="horizontal"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/gameIconView"
app:layout_constraintLeft_toRightOf="@+id/game_play_count"
app:layout_constraintRight_toRightOf="@+id/gameDesSpace"
app:layout_constraintTop_toBottomOf="@+id/gameDesSpace" />
<TextView
android:id="@+id/game_play_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="@color/text_tertiary"
android:textSize="11sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/gameIconView"
app:layout_constraintLeft_toLeftOf="@+id/gameDesSpace"
app:layout_constraintRight_toLeftOf="@+id/label_list"
app:layout_constraintTop_toBottomOf="@+id/gameDesSpace"
tools:text="999.9万人玩过" />
<com.gh.gamecenter.feature.view.DownloadButton
android:id="@+id/download_btn"
android:layout_width="56dp"
android:layout_height="28dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="16dp"
app:download_button_show_progress="true"
app:download_button_text_size="12sp"
app:layout_constraintBottom_toBottomOf="@id/gameIconView"
app:layout_constraintLeft_toRightOf="@+id/gameDesSpace"
app:layout_constraintRight_toRightOf="parent" />
<TextView
android:id="@+id/multiVersionDownloadTv"
android:layout_width="wrap_content"
android:layout_height="28dp"
android:drawablePadding="2dp"
android:gravity="center"
android:text="展开"
android:textSize="@dimen/secondary_size"
android:visibility="gone"
android:textColor="@color/white"
app:drawableEndCompat="@drawable/ic_jump_universal"
app:layout_constraintBottom_toBottomOf="@id/download_btn"
app:layout_constraintEnd_toEndOf="@id/download_btn"
app:layout_constraintStart_toStartOf="@id/download_btn"
app:layout_constraintTop_toTopOf="@id/download_btn" />
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/downloadTipsLottie"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginTop="-8dp"
android:visibility="gone"
app:layout_constraintRight_toRightOf="@+id/download_btn"
app:layout_constraintTop_toTopOf="@+id/download_btn"
app:lottie_autoPlay="false"
app:lottie_loop="true"
app:lottie_repeatMode="restart" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_create_game_collection"
android:icon="@drawable/ic_create_game_collection"
android:title="创建游戏单"
app:showAsAction="always" />
<item
android:id="@+id/menu_more"
android:icon="@drawable/ic_menu_more"
android:orderInCategory="1"
android:title="@string/menu_more"
app:showAsAction="always" />
</menu>

View File

@ -589,5 +589,61 @@
<string name="hud_wifi_download_resumed">WI-FI网络继续下载中...</string>
<string name="download_suspend_draw_overlay_permission_confirm">去開啟懸浮窗</string>
<string name="download_suspend_draw_overlay_permission_title">開啟懸浮窗\n系統下載不限速</string>
<string name="reverse_success_without_reminder_tips">遊戲上線後,您將在訊息中心收到通知</string>
<string name="reverse_success_with_reminder_tips">遊戲上線後,您將在訊息中心收到通知,及以下方式提醒</string>
<string name="sms_reminder">簡訊提醒</string>
<string name="sms_reminder_description">開啟後將收到免費簡訊提醒</string>
<string name="open">開啟</string>
<string name="wechat_reminder">微信提醒</string>
<string name="wechat_reminder_description">只需一次設置,即可永久有效</string>
<string name="reserve_auto_download">遊戲上線後WiFi環境自動下載</string>
<string name="reserve_real_name_description">根據相關政策要求,遊戲自動下載需通過實名認證,馬上實名 ></string>
<string name="change_phone_number">修改手機號</string>
<string name="change_phone_number_2">修改手機號碼</string>
<string name="verify_phone_number">驗證手機號</string>
<string name="turn_off_sms_reminders">關閉簡訊提醒</string>
<string name="reserve_only_wechat_unable_tips">建議開啟微信提醒,不錯過任何預約的遊戲,只需一次設置,即可永久有效</string>
<string name="enable_wechat_reminder">開啟微信提醒</string>
<string name="enable_sms_reminder">開啟簡訊提醒</string>
<string name="enable_sms_reminder_description">遊戲上線後,將透過免費簡訊提醒您;手機號僅用於預約提醒</string>
<string name="invalid_phone_number_format">手機號碼格式錯誤,請檢查並重新輸入</string>
<string name="please_input_sms_verify_code">請輸入簡訊驗證碼</string>
<string name="please_input_verify_code">請輸入驗證碼</string>
<string name="verify_code_send_with_phone_number">已經發送至%1$s</string>
<string name="change_the_wechat_binding">更換綁定微信</string>
<string name="binding_failed">綁定失敗</string>
<string name="binding_failed_description">該微訊號(微信暱稱)已經綁定在另一個衝突號碼上,衝突號碼可能是你先前登入的</string>
<string name="current_number">目前號</string>
<string name="conflict_number">衝突號</string>
<string name="change_binding_tips_with_conflict">遇到衝突如何換綁?</string>
<string name="user_id">ID%1$s</string>
<string name="wechat_binding_conflict_title">遇到衝突如何換綁?</string>
<string name="wechat_binding_conflict_description">1.請先退出目前號【我的光環--設定--退出帳號】\n2.再重新登入衝突號,在【我的光環-微信提醒】的「第一步:綁定微信」點選解除綁定\n3.微信解除綁定成功後,再退出衝突號,並重新登入目前號,進入【我的光環-微信提醒】進行綁定</string>
<string name="copy_user_id_successfully">用戶ID複製成功</string>
<string name="resend">重新發送</string>
<string name="resend_with_time">重新發送(%1$ss)</string>
<string name="reserve_reminder_online">您預約的%1$s款遊戲上線囉~</string>
<string name="reserve_reminder_auto_download">共%1$s款遊戲已經開始WiFi環境自動下載</string>
<string name="reserve_reminder_auto_download_with_name">%1$s 共%2$s款遊戲已經開始WiFi環境自動下載</string>
<string name="reserve_reminder_wait_for_wifi_to_auto_download">共%1$s款遊戲已加入下載隊列連接WiFi後自動下載</string>
<string name="reserve_reminder_wait_for_wifi_to_auto_download_with_name">%1$s 共%2$s款遊戲已加入下載隊列連接WiFi後自動下載</string>
<string name="view_all_appointments">查看全部預約</string>
<string name="automatic_downloading_is_enabled">已開啟自動下載</string>
<string name="enable_automatic_downloading_in_batches">批次開啟自動下載</string>
<string name="enable_automatic_downloading_with_wifi">開啟WiFi自動下載</string>
<string name="batch_management">大量管理</string>
<string name="cancel_auto_download_with_wifi">取消WiFi自動下載</string>
<string name="cancel_reserve">取消預約</string>
<string name="all_select">全選</string>
<string name="count_with_parentheses">(%1$s)</string>
<string name="phone_number_validate_successfully">簡訊驗證透過</string>
<string name="phone_number_validate_failure">簡訊驗證失敗,請重新輸入驗證碼</string>
<string name="phone_number_validate_cancel">驗證已取消</string>
<string name="has_enabled_for_auto_download_in_wifi">遊戲已開啟WiFi環境自動下載</string>
<string name="has_unable_for_auto_download_in_wifi">遊戲已取消WiFi環境自動下載”</string>
<string name="not_support_auto_download_in_wifi">遊戲暫不支援WiFi環境自動下載</string>
<string name="my_game">我的遊戲</string>
<string name="played">玩過</string>
<string name="reserve">預約</string>
</resources>

View File

@ -425,7 +425,7 @@
<item>完美,太棒了</item>
</string-array>
<string name="title_installed_game">将已安装游戏标记为玩过的游戏</string>
<string name="dialog_reserve_title"><Data><![CDATA[<font color="#1383EB">%1$d</font>]]></Data>预约的游戏上线啦</string>
<string name="dialog_reserve_title">你预约的%1$d款游戏上线啦</string>
<string name="dialog_privacy_policy_content">欢迎您使用光环助手!\n在您使用光环助手之前请您认真阅读《用户协议》和《隐私政策》的全部内容以了解用户权利义务和个人信息处理规则。主要内容向您说明如下\n1.为了正常地提供优质的产品服务,基于您的授权我们会获取必要的个人信息,您有权拒绝或取消授权\n2.我们会采取合理的安全措施保护您的个人信息,防止数据被不当使用或未经授权的情况下被访问、公开披露、使用、修改、损坏、丢失或泄漏。\n3.未经您同意,我们不会从第三方处获取、共享或向其提供您的信息\n4.您可以查询、更正、删除您的个人信息,我们也提供账户注销的渠道</string>
<string name="oversea_hint">此游戏下载资源由第三方提供。若该资源侵犯了您的合法权益或违反了当地法规,请点击页面右上角-版权申诉,按指引发起申诉,我们会尽快联系您并解决。</string>
<string name="rating_protection">游戏停服更新维护中,为避免情绪化内容对游戏评分带来的影响,因此开启停服保护功能。在停服保护状态期间,所新增及修改发布的评分将不计入总分,所评分评论内容在展示上也会有文字提示告知其他玩家。\n\n感谢您的配合及谅解祝您游戏愉快\n\n光环助手会持续关注产品建议及反馈如您在使用过程中有任何问题欢迎向我们反馈。</string>
@ -589,4 +589,60 @@
<string name="special_download_tips_click_to_enable">点击开启</string>
<string name="download_suspend_draw_overlay_permission_confirm">去开启悬浮窗</string>
<string name="download_suspend_draw_overlay_permission_title">开启悬浮窗\n系统下载不限速</string>
<string name="reverse_success_without_reminder_tips">游戏上线后,您将在消息中心收到通知</string>
<string name="reverse_success_with_reminder_tips">游戏上线后,您将在消息中心收到通知,及以下方式提醒</string>
<string name="sms_reminder">短信提醒</string>
<string name="sms_reminder_description">开启后将收到免费短信提醒</string>
<string name="open">开启</string>
<string name="wechat_reminder">微信提醒</string>
<string name="wechat_reminder_description">只需一次设置,即可永久有效</string>
<string name="reserve_auto_download">游戏上线后WiFi环境自动下载</string>
<string name="reserve_real_name_description">根据相关政策要求,游戏自动下载需要通过实名认证,马上实名 ></string>
<string name="change_phone_number">修改手机号</string>
<string name="change_phone_number_2">修改手机号码</string>
<string name="verify_phone_number">验证手机号</string>
<string name="turn_off_sms_reminders">关闭短信提醒</string>
<string name="reserve_only_wechat_unable_tips">建议开启微信提醒,不错过任何预约的游戏,只需一次设置,即可永久有效</string>
<string name="enable_wechat_reminder">开启微信提醒</string>
<string name="enable_sms_reminder">开启短信提醒</string>
<string name="enable_sms_reminder_description">游戏上线后,将通过免费短信提醒您;手机号仅用于预约提醒</string>
<string name="invalid_phone_number_format">手机号格式错误,请检查并重新输入</string>
<string name="please_input_sms_verify_code">请输入短信验证码</string>
<string name="please_input_verify_code">请输入验证码</string>
<string name="verify_code_send_with_phone_number">已经发送至%1$s</string>
<string name="change_the_wechat_binding">更换绑定微信</string>
<string name="binding_failed">绑定失败</string>
<string name="binding_failed_description">该微信号(微信昵称)已经绑定在另外一个冲突号上,冲突号可能是你之前登录的</string>
<string name="current_number">当前号</string>
<string name="conflict_number">冲突号</string>
<string name="change_binding_tips_with_conflict">遇到冲突如何换绑?</string>
<string name="user_id">ID%1$s</string>
<string name="wechat_binding_conflict_title">遇到冲突如何换绑?</string>
<string name="wechat_binding_conflict_description">1.请先退出当前号【我的光环--设置--退出账号】\n2.再重新登录冲突号,在【我的光环-微信提醒】的“第一步:绑定微信”点击解除绑定\n3.微信解除绑定成功后,再退出冲突号,并重新登录当前号,进入【我的光环-微信提醒】进行绑定</string>
<string name="copy_user_id_successfully">用户ID复制成功</string>
<string name="resend">重新发送</string>
<string name="resend_with_time">重新发送(%1$ss)</string>
<string name="reserve_reminder_online">您预约的%1$s款游戏上线啦~</string>
<string name="reserve_reminder_auto_download">共%1$s款游戏已经开始WiFi环境自动下载</string>
<string name="reserve_reminder_auto_download_with_name">%1$s 共%2$s款游戏已经开始WiFi环境自动下载</string>
<string name="reserve_reminder_wait_for_wifi_to_auto_download">共%1$s款游戏已加入下载队列连接WiFi后自动下载</string>
<string name="reserve_reminder_wait_for_wifi_to_auto_download_with_name">%1$s 共%2$s款游戏已加入下载队列连接WiFi后自动下载</string>
<string name="view_all_appointments">查看全部预约</string>
<string name="automatic_downloading_is_enabled">已开启自动下载</string>
<string name="enable_automatic_downloading_in_batches">批量开启自动下载</string>
<string name="enable_automatic_downloading_with_wifi">开启WiFi自动下载</string>
<string name="batch_management">批量管理</string>
<string name="cancel_auto_download_with_wifi">取消WiFi自动下载</string>
<string name="cancel_reserve">取消预约</string>
<string name="all_select">全选</string>
<string name="count_with_parentheses">(%1$s)</string>
<string name="phone_number_validate_successfully">短信验证通过</string>
<string name="phone_number_validate_failure">短信验证失败,请重新输入验证码</string>
<string name="phone_number_validate_cancel">验证已取消</string>
<string name="has_enabled_for_auto_download_in_wifi">游戏已开启WiFi环境自动下载</string>
<string name="has_unable_for_auto_download_in_wifi">游戏已取消WiFi环境自动下载”</string>
<string name="not_support_auto_download_in_wifi">游戏暂不支持WiFi环境自动下载</string>
<string name="my_game">我的游戏</string>
<string name="played">玩过</string>
<string name="reserve">预约</string>
</resources>

View File

@ -406,6 +406,7 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements IBus
showDialog.setUsed(true);
IPackageInstallerProvider packageInstallerConfig = (IPackageInstallerProvider) ARouter.getInstance().build(RouteConsts.provider.packageInstaller).navigation();
if (DOWNLOAD_HIJACK.equals(showDialog.getType())) {
DownloadEntity downloadEntity = showDialog.getDownloadEntity();
DialogHelper.showQqSessionDialog(this);// 建议用户联系客服
} else if (PLUGGABLE.equals(showDialog.getType())) {
DownloadEntity downloadEntity = showDialog.getDownloadEntity();

View File

@ -466,4 +466,6 @@ public class Constants {
public static final String SP_BOTTOM_TAB_GUIDE_SET = "bottom_tab_guide_id_set";
public static final String SP_MULTI_TAB_NAV_GUIDE_SET = "multi_tab_nav_guide_id_set";
public static final String IS_RESERVE_ONLINE_REMINDER = "is_reserve_online_reminder";
}

View File

@ -1,6 +1,8 @@
package com.gh.gamecenter.common.entity
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
class ErrorEntity(
var code: Int? = 0,
@ -32,7 +34,11 @@ class ErrorEntity(
val link: String = "",
val text: String = "",
@SerializedName("link_community", alternate = ["community"])
var community: CommunityEntity? = CommunityEntity()
var community: CommunityEntity? = CommunityEntity(),
@SerializedName("bind")
private val _bind: Boolean? = null,
@SerializedName("user_conflict")
private val _userConflict: UserConflict? = null
) {
// 问题关注数默认是1
fun getFollowCount(): Int {
@ -49,5 +55,33 @@ class ErrorEntity(
community = community
)
}
val userConflict: UserConflict
get() = _userConflict ?: UserConflict()
@Parcelize
data class UserConflict(
@SerializedName("_id")
private val _id: String? = null,
@SerializedName("name")
private val _name: String? = null,
@SerializedName("icon")
private val _icon: String? = null,
@SerializedName("_seq")
private val _seq: String? = null
) : Parcelable {
val id: String
get() = _id ?: ""
val name: String
get() = _name ?: ""
val icon: String
get() = _icon ?: ""
val seq: String
get() = _seq ?: ""
}
}
}

View File

@ -1,11 +1,18 @@
package com.gh.gamecenter.common.entity
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
class WechatConfigEntity(
@Parcelize
data class WechatConfigEntity(
var bind: Boolean = false,//用户是否绑定微信
var follow: Boolean = false,//绑定的微信是否关注光环助手
var notice: Boolean = false,//是否打开微信通知开关
@SerializedName("nickname")
var nickName: String = "",
)
) : Parcelable {
val isReminderEnable: Boolean
get() = bind && follow && notice
}

View File

@ -118,6 +118,9 @@ object SensorsBridge {
private const val KEY_BBS_NAME = "bbs_name"
private const val KEY_CONTENT_TYPE = "content_type"
private const val KEY_DOWNLOAD_TASK_STATUS = "download_task_status"
private const val KEY_WECHAT_REMIND = "wechat_remind"
private const val KEY_MESSAGE_REMIND = "message_remind"
private const val KEY_AUTOMATIC_DOWNLOAD = "automatic_download"
private const val EVENT_GAME_DETAIL_PAGE_TAB_SELECT = "GameDetailPageTabSelect"
private const val EVENT_GAME_DETAIL_PAGE_TAG_CLICK = "GameDetailPageGameTagClick"
@ -273,6 +276,15 @@ object SensorsBridge {
private const val EVENT_COLUMN_TEST_CLICK = "ColumnTestClick"
private const val EVENT_CANCEL_APPOINTMENT_DIALOG_SHOW = "CancelAppointmentDialogShow"
private const val EVENT_CANCEL_APPOINTMENT_DIALOG_CLICK = "CancelAppointmentDialogClick"
private const val EVENT_APPOINTMENT_SUCCESS_DIALOG_SHOW = "AppointmentSuccessDialogShow"
private const val EVENT_APPOINTMENT_SUCCESS_DIALOG_CLICK = "AppointmentSuccessDialogClick"
private const val EVENT_OPEN_APPOINTMENT_AUTOMATIC_DOWNLOAD = "OpenAppointmentAutomaticDownload"
private const val EVENT_CANCEL_APPOINTMENT_AUTOMATIC_DOWNLOAD = "CancelAppointmentAutomaticDownload"
private const val EVENT_APPOINTMENT_GAME_ONLINE_DIALOG_SHOW = "AppointmentGameOnlineDialogShow"
private const val EVENT_APPOINTMENT_GAME_ONLINE_DIALOG_CLICK = "AppointmentGameOnlineDialogClick"
private var mIsSensorsEnabled = false
private val mSensor by lazy {
@ -4119,6 +4131,7 @@ object SensorsBridge {
}
trackEvent(EVENT_DOWNLOAD_SUSPENDED_WINDOW_RESULT_RETURN, json)
}
/**
* 事件IDInstallationPromptBarShow
* 事件名称:安装提示条展示事件
@ -4356,4 +4369,166 @@ object SensorsBridge {
trackEvent(EVENT_COLUMN_TEST_CLICK, json)
}
/**
* 事件IDCancelAppointmentDialogShow
* 事件名称:游戏取消预约弹窗展示事件
* 触发时机:触发游戏取消弹窗时上报
*/
fun trackCancelAppointmentDialogShow(
gameId: String,
gameName: String,
gameType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_GAME_TYPE to gameType
}
trackEvent(EVENT_CANCEL_APPOINTMENT_DIALOG_SHOW, json)
}
/**
* 事件IDCancelAppointmentDialogClick
* 事件名称:游戏取消预约弹窗点击事件
* 触发时机:点击游戏取消弹窗时上报
*/
fun trackCancelAppointmentDialogClick(
gameId: String,
gameName: String,
gameType: String,
buttonName: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_GAME_TYPE to gameType
KEY_BUTTON_NAME to buttonName
}
trackEvent(EVENT_CANCEL_APPOINTMENT_DIALOG_CLICK, json)
}
/**
* 事件IDAppointmentSuccessDialogShow
* 事件名称:预约成功弹窗展示事件
* 触发时机:触发游戏预约成功提示弹窗时上报
*/
fun trackAppointmentSuccessDialogShow(
gameId: String,
gameName: String,
gameType: String,
wechatRemind: Boolean,
messageRemind: Boolean?,
automaticDownload: Boolean?
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_GAME_TYPE to gameType
KEY_WECHAT_REMIND to wechatRemind
KEY_MESSAGE_REMIND to messageRemind
KEY_AUTOMATIC_DOWNLOAD to automaticDownload
}
trackEvent(EVENT_APPOINTMENT_SUCCESS_DIALOG_SHOW, json)
}
/**
* 事件IDAppointmentSuccessDialogClick
* 事件名称:预约成功弹窗点击事件
* 触发时机:游戏预约成功提示弹窗点击时上报
*/
fun trackAppointmentSuccessDialogClick(
gameId: String,
gameName: String,
gameType: String,
buttonName: String,
wechatRemind: Boolean? = null,
messageRemind: Boolean? = null,
automaticDownload: Boolean? = null
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_GAME_TYPE to gameType
KEY_BUTTON_NAME to buttonName
KEY_WECHAT_REMIND to wechatRemind
KEY_MESSAGE_REMIND to messageRemind
KEY_AUTOMATIC_DOWNLOAD to automaticDownload
}
trackEvent(EVENT_APPOINTMENT_SUCCESS_DIALOG_CLICK, json)
}
/**
* 事件IDOpenAppointmentAutomaticDownload
* 事件名称:预约开启自动下载事件
* 触发时机:我的游戏-预约tab 开启自动下载时上报
*/
fun trackOpenAppointmentAutomaticDownload(
gameId: String,
gameName: String,
gameType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_GAME_TYPE to gameType
}
trackEvent(EVENT_OPEN_APPOINTMENT_AUTOMATIC_DOWNLOAD, json)
}
/**
* 事件IDCancelAppointmentAutomaticDownload
* 事件名称:预约取消自动下载事件
* 触发时机:我的游戏-预约tab 取消自动下载时上报
*/
fun trackCancelAppointmentAutomaticDownload(
gameId: String,
gameName: String,
gameType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_GAME_TYPE to gameType
}
trackEvent(EVENT_CANCEL_APPOINTMENT_AUTOMATIC_DOWNLOAD, json)
}
/**
* 事件IDAppointmentGameOnlineDialogShow
* 事件名称:预约游戏上线弹窗展示事件
* 触发时机:触发预约游戏上线提示弹窗时上报
*/
fun trackAppointmentGameOnlineDialogShow(
gameId: String,
gameName: String,
gameType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_GAME_TYPE to gameType
}
trackEvent(EVENT_APPOINTMENT_GAME_ONLINE_DIALOG_SHOW, json)
}
/**
* 事件IDAppointmentGameOnlineDialogClick
* 事件名称:预约游戏上线弹窗点击事件
* 触发时机:触发预约游戏上线提示弹窗点击时上报
*/
fun trackAppointmentGameOnlineDialogClick(
buttonName: String,
gameId: String? = null,
gameName: String? = null,
gameType: String? = null,
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_GAME_TYPE to gameType
KEY_BUTTON_NAME to buttonName
}
trackEvent(EVENT_APPOINTMENT_GAME_ONLINE_DIALOG_CLICK, json)
}
}

View File

@ -7,5 +7,5 @@
android:pathData="M8,8m-7.25,0a7.25,7.25 0,1 1,14.5 0a7.25,7.25 0,1 1,-14.5 0"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#EEEEEE" />
android:strokeColor="@color/ui_divider_2" />
</vector>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="12dp"/>
<solid android:color="@color/ui_surface" />
</shape>

View File

@ -2,5 +2,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="8dp" />
<solid android:color="@color/ui_surface" />
<solid android:color="@color/ui_surface"/>
</shape>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="@color/ui_container_2" />
</shape>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,4.5C7.858,4.5 4.5,7.858 4.5,12C4.5,16.142 7.858,19.5 12,19.5C16.142,19.5 19.5,16.142 19.5,12C19.5,7.858 16.142,4.5 12,4.5ZM2.5,12C2.5,6.753 6.753,2.5 12,2.5C17.247,2.5 21.5,6.753 21.5,12C21.5,17.247 17.247,21.5 12,21.5C6.753,21.5 2.5,17.247 2.5,12ZM13.25,16.25C13.25,16.94 12.69,17.5 12,17.5C11.31,17.5 10.75,16.94 10.75,16.25C10.75,15.56 11.31,15 12,15C12.69,15 13.25,15.56 13.25,16.25ZM10.5,9.5C10.5,9.191 10.902,8.5 12,8.5C13.098,8.5 13.5,9.191 13.5,9.5C13.5,9.759 13.431,9.866 13.359,9.948C13.245,10.077 13.074,10.189 12.736,10.392L12.696,10.416C12.409,10.588 11.98,10.845 11.641,11.229C11.244,11.679 11,12.259 11,13C11,13.552 11.448,14 12,14C12.552,14 13,13.552 13,13C13,12.741 13.069,12.634 13.141,12.552C13.255,12.423 13.426,12.311 13.764,12.108L13.804,12.084L13.804,12.084C14.091,11.912 14.52,11.655 14.859,11.271C15.256,10.821 15.5,10.241 15.5,9.5C15.5,7.809 13.902,6.5 12,6.5C10.098,6.5 8.5,7.809 8.5,9.5C8.5,10.052 8.948,10.5 9.5,10.5C10.052,10.5 10.5,10.052 10.5,9.5Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
</vector>

View File

@ -7,5 +7,5 @@
android:pathData="M8,8m-7.25,0a7.25,7.25 0,1 1,14.5 0a7.25,7.25 0,1 1,-14.5 0"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#EEEEEE" />
android:strokeColor="@color/ui_divider_2" />
</vector>

View File

@ -0,0 +1,32 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M8,8m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"
android:strokeAlpha="0.4"
android:fillAlpha="0.4">
<aapt:attr name="android:fillColor">
<gradient
android:startX="0"
android:startY="8"
android:endX="16"
android:endY="8"
android:type="linear">
<item android:offset="0" android:color="#FF4BC7FF"/>
<item android:offset="1" android:color="#FF2496FF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M4,8.222L6.857,11L12,6"
android:strokeAlpha="0.4"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:fillAlpha="0.4"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M8,8m-7.25,0a7.25,7.25 0,1 1,14.5 0a7.25,7.25 0,1 1,-14.5 0"
android:strokeAlpha="0.1"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#000000"/>
<path
android:pathData="M8,8m-6.5,0a6.5,6.5 0,1 1,13 0a6.5,6.5 0,1 1,-13 0"
android:fillColor="#000000"
android:fillAlpha="0.07"/>
</vector>

View File

@ -55,6 +55,8 @@
<color name="ui_container_2">#0AFFFFFF</color>
<!-- 分隔线 -->
<color name="ui_divider">#333333</color>
<color name="ui_divider_2">#1EFFFFFF</color>
<color name="ui_divider_3">#33FFFFFF</color>
<!-- 高亮 -->
<color name="ui_highlight">#0A2888E0</color>
<!-- 骨架-框架 -->
@ -386,4 +388,6 @@
<color name="button_gradient_green_end">#14A3A3</color>
<color name="button_gradient_yellow_start">#E5A82E</color>
<color name="button_gradient_yellow_end">#E58627</color>
<color name="reserve_reminder_border_color">#0Dffffff</color>
</resources>

View File

@ -55,6 +55,9 @@
<color name="ui_container_2">#F5F5F5</color>
<!-- 分隔线 -->
<color name="ui_divider">#EEEEEE</color>
<color name="ui_divider_2">#12000000</color>
<color name="ui_divider_3">#1A000000</color>
<!-- 高亮 -->
<color name="ui_highlight">#0A2496FF</color>
<!-- 骨架-框架 -->
@ -434,4 +437,6 @@
<color name="button_gradient_yellow_end">#FF9933</color>
<color name="text_price">#FF5447</color>
<color name="text_price_alpha_10">#1AFF5447</color>
<color name="reserve_reminder_border_color">#0D000000</color>
</resources>

View File

@ -2,6 +2,6 @@ package com.gh.gamecenter.core.provider
import com.alibaba.android.arouter.facade.template.IProvider
interface IWechatBindHelperProvider : IProvider {
fun getWechatConfig(callback: (() -> Unit)? = null)
interface IWechatBindHelperProvider<T> : IProvider {
fun getWechatConfig(callback: ((T) -> Unit)? = null)
}

View File

@ -321,6 +321,8 @@ data class GameEntity(
// 资讯数据
@SerializedName("article_data")
var articleData: CommunityTopEntity? = null,
@SerializedName("wifi_auto_download")
private val _wifiAutoDownload: Boolean? = null, // 只有预约上线弹窗/我的预约接口接口会返回这个字段
// 本地字段
// 用来标记在专题中的序号,仅用于曝光记录
@ -652,6 +654,14 @@ data class GameEntity(
val abbreviation: String
get() = _abbreviation ?: ""
@IgnoredOnParcel
val wifiAutoDownload
get() = _wifiAutoDownload ?: false
// 游戏是否有 wifi自动下载功能
val wifiAutoDownloadEnable: Boolean
get() = _wifiAutoDownload != null
//是否需要弹出试玩弹窗
fun isShowVersionNumber(): Boolean {
return versionNumber == "无版号无内购有弹窗"

View File

@ -0,0 +1,25 @@
package com.gh.gamecenter.feature.entity
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
data class ReserveOnlineEntity(
@SerializedName("games")
private val _games: List<GameEntity>? = null,
@SerializedName("wifi_auto_download_total")
private val _wifiAutoDownloadTotal: Int? = null,
@SerializedName("games_total")
private val _gamesTotal: Int? = null
) : Parcelable {
val games: List<GameEntity>
get() = _games ?: emptyList()
val wifiAutoDownloadTotal: Int
get() = _wifiAutoDownloadTotal ?: 0
val gamesTotal: Int
get() = _gamesTotal ?: 0
}

Some files were not shown because too many files have changed in this diff Show More