feat: 游戏开服/开测消息通知—客户端 https://jira.shanqu.cc/browse/GHZS-3350

This commit is contained in:
曾祥俊
2023-10-26 14:06:22 +08:00
parent 95beddc194
commit d697bc7b8a
119 changed files with 5587 additions and 328 deletions

View File

@ -63,6 +63,8 @@ import com.gh.gamecenter.gamecollection.hotlist.GameCollectionListDetailActivity
import com.gh.gamecenter.gamecollection.square.GameCollectionSquareActivity
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarManagementActivity
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersSubscribedGameListActivity
import com.gh.gamecenter.gamedetail.history.HistoryApkListActivity
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.help.HelpAndFeedbackBridge
@ -192,6 +194,8 @@ object DirectUtils {
}
}
"game_server_calendar" -> directToGameServerCalendar(context, linkEntity.link)
"column", "游戏专题" -> directToSubject(
context, linkEntity.link
?: "", linkEntity.text, BaseActivity.mergeEntranceAndPath(entrance, path), exposureEvent
@ -543,12 +547,13 @@ object DirectUtils {
* 跳转至游戏日历表
*/
@JvmStatic
fun directToGameServerCalendar(context: Context, gameId: String?) {
fun directToGameServerCalendar(context: Context, gameId: String?, kaifuTime: Long = 0) {
val bundle = Bundle()
bundle.putString(KEY_TO, ServersCalendarActivity::class.java.name)
bundle.putParcelable(GameEntity::class.java.simpleName, GameEntity().apply {
id = gameId ?: ""
})
bundle.putLong(KEY_KAIFU_TIME, kaifuTime)
bundle.putParcelable(GameDetailServer::class.java.simpleName, GameDetailServer())
bundle.putParcelable(MeEntity::class.java.simpleName, MeEntity())
jumpActivity(context, bundle)
@ -2117,4 +2122,24 @@ object DirectUtils {
)
)
}
/**
* 跳转到游戏订阅页面
* @param context 上下文
*/
@JvmStatic
fun directToServersSubscribedGameList(context: Context) {
context.startActivity(ServersSubscribedGameListActivity.getIntent(context))
}
/**
* 跳转到开服订阅页面
* @param context 上下文
*/
@JvmStatic
fun directToServersCalendarManagement(context: Context, entrance: String) {
CheckLoginUtils.checkLogin(context, entrance) {
context.startActivity(ServersCalendarManagementActivity.getIntent(context))
}
}
}

View File

@ -2487,4 +2487,209 @@ object NewLogUtils {
}
log(json, LOG_STORE_EVENT)
}
/**
* 埋点序号117
* 事件IDmessage_inform_push
* 事件名称:消息推送事件
* 触发时机:系统触发消息推送
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param sessionMessageType 会话类型
* @param messageType 消息类型
*/
@JvmStatic
fun logMessageInformPush(
gameId: String,
gameName: String,
sessionMessageType: String,
messageType: String
) {
val json = json {
KEY_EVENT to "message_inform_push"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
"session_message_type" to sessionMessageType
"message_type" to messageType
parseAndPutMeta().invoke(this)
}
log(json, LOG_STORE_EVENT)
}
/**
* 埋点序号118
* 事件IDlaunch_server_subscribe_add
* 事件名称:加入开服订阅事件
* 触发时机:点击开服表加入订阅
* @param gameId 游戏ID
* @param gameName 游戏名称
*/
@JvmStatic
fun logLaunchServerSubscribeAdd(
gameId: String,
gameName: String
) {
val json = json {
KEY_EVENT to "launch_server_subscribe_add"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
parseAndPutMeta().invoke(this)
}
log(json, LOG_STORE_EVENT)
}
/**
* 埋点序号119
* 事件IDlaunch_server_subscribe_cancel
* 事件名称:取消开服订阅事件
* 触发时机:点击开服表取消订阅
* @param gameId 游戏ID
* @param gameName 游戏名称
*/
@JvmStatic
fun logLaunchServerSubscribeCancel(
gameId: String,
gameName: String
) {
val json = json {
KEY_EVENT to "launch_server_subscribe_cancel"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
parseAndPutMeta().invoke(this)
}
log(json, LOG_STORE_EVENT)
}
/**
* 埋点序号120
* 事件IDlaunch_server_subscribe_click
* 事件名称:点击开服订阅事件
* 触发时机:点击开服管理的开服记录
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param launchServerTime 以秒为单位的时间戳,若为日期则是当天0点的时间戳
*/
@JvmStatic
fun logLaunchServerSubscribeClick(
gameId: String,
gameName: String,
launchServerTime: Int
) {
val json = json {
KEY_EVENT to "launch_server_subscribe_click"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
"launch_server_time" to launchServerTime
parseAndPutMeta().invoke(this)
}
log(json, LOG_STORE_EVENT)
}
/**
* 埋点序号121
* 事件IDlaunch_server_reminder_add
* 事件名称:添加开服提醒事件
* 触发时机:点击开服表的添加提醒
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param reminderTime 设置提醒时间: 已知服是上传以秒为单位的时间戳未知服则是当天0点的时间戳
* @param reminderType 提醒类型: 已知服/未知服
* @param launchServerTime 设置开服时间: 已知服是上传以秒为单位的时间戳未知服则是当天0点的时间戳
* @param serverName 服务器名字
* @param isWechat 是否微信提醒
* @param isApp 是否APP提醒
*/
@JvmStatic
fun logLaunchServerReminderAdd(
gameId: String,
gameName: String,
reminderTime: Int,
reminderType: String,
launchServerTime: Int,
serverName: String,
isWechat: Boolean,
isApp: Boolean
) {
val json = json {
KEY_EVENT to "launch_server_reminder_add"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
"reminder_time" to reminderTime
"reminder_type" to reminderType
"launch_server_time" to launchServerTime
"server_name" to serverName
"is_wechat" to isWechat
"is_app" to isApp
parseAndPutMeta().invoke(this)
}
log(json, LOG_STORE_EVENT)
}
/**
* 埋点序号122
* 事件IDlaunch_server_reminder_cancel
* 事件名称:取消开服提醒事件
* 触发时机:点击开服表的取消提醒
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param reminderTime 设置提醒时间: 已知服是上传以秒为单位的时间戳未知服则是当天0点的时间戳
* @param reminderType 提醒类型: 已知服/未知服
* @param launchServerTime 设置开服时间: 已知服是上传以秒为单位的时间戳未知服则是当天0点的时间戳
* @param serverName 服务器名字
* @param isWechat 是否微信提醒
* @param isApp 是否APP提醒
*/
@JvmStatic
fun logLaunchServerReminderCancel(
gameId: String,
gameName: String,
reminderTime: Int,
reminderType: String,
launchServerTime: Int,
serverName: String,
isWechat: Boolean,
isApp: Boolean
) {
val json = json {
KEY_EVENT to "launch_server_reminder_cancel"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
"reminder_time" to reminderTime
"reminder_type" to reminderType
"launch_server_time" to launchServerTime
"server_name" to serverName
"is_wechat" to isWechat
"is_app" to isApp
parseAndPutMeta().invoke(this)
}
log(json, LOG_STORE_EVENT)
}
/**
* 埋点序号123
* 事件IDlaunch_server_reminder_click
* 事件名称:点击开服提醒事件
* 触发时机:点击开服管理的提醒记录
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param reminderTime 设置提醒时间: 已知服是上传以秒为单位的时间戳未知服则是当天0点的时间戳
* @param status 记录状态: todo 待提醒 coming 即将开服 opened 已开服 has_new 有新服 expired 已过期
*/
@JvmStatic
fun logLaunchServerReminderClick(
gameId: String,
gameName: String,
reminderTime: Int,
status: String,
) {
val json = json {
KEY_EVENT to "launch_server_reminder_click"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
"reminder_time" to reminderTime
"status" to status
parseAndPutMeta().invoke(this)
}
log(json, LOG_STORE_EVENT)
}
}

View File

@ -385,7 +385,7 @@ public class SkipActivity extends BaseActivity {
EntranceConsts.ENTRANCE_BROWSER);
break;
case EntranceConsts.HOST_GAME_CALENDAR:
DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID));
DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID), 0);
break;
case EntranceConsts.HOST_HISTORY_APK:
DirectUtils.directToHistoryApk(this, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID));

View File

@ -1,15 +1,16 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import kotlinx.parcelize.Parcelize
/**
* Created by khy on 2017/3/28.
*/
class CalendarEntity {
var day: Int = 0
var month: Int = 0
var year: Int = 0
@Parcelize
class CalendarEntity(
var day: Int = 0,
var month: Int = 0,
var year: Int = 0,
var server: MutableList<ServerCalendarEntity> = ArrayList()
}
) : Parcelable

View File

@ -0,0 +1,10 @@
package com.gh.gamecenter.entity
import com.google.gson.annotations.SerializedName
class ServerSubscriptionEntity(
@SerializedName("by_app")
val byApp: Boolean = false,
@SerializedName("by_wechat")
val byWeChat: Boolean = false
)

View File

@ -37,6 +37,7 @@ import com.gh.gamecenter.common.base.fragment.BaseLazyFragment;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.iinterface.SearchBarHint;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
@ -326,7 +327,7 @@ public class SearchToolbarFragment extends BaseLazyFragment implements View.OnCl
CheckLoginUtils.checkLogin(requireContext(), "(工具栏)", () -> {
NewLogUtils.logMessageInformBellClick(mMessageUnread.getVisibility() == View.VISIBLE, mLocation);
SensorsBridge.trackMessageCenterClick();
// 优先进入有数字提醒的消息tab其次是有红点提醒的游戏动态最后是没有提醒的消息tab
int defaultTabIndex = 1;
MessageUnreadCount messageUnreadCount = mUnreadViewModel.getMessageUnreadCountLiveData().getValue();

View File

@ -1648,7 +1648,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
true
)
updateConcernMenuIcon(mNewGameDetailEntity?.me?.isGameConcerned ?: false)
mMoreMenuItem?.setIcon(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.ic_menu_gamedetail_more else R.drawable.ic_menu_gamedetail_more_light)
mMoreMenuItem?.setIcon(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.ic_menu_more else R.drawable.ic_menu_more_light)
mSearchMenuItem?.setIcon(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.ic_column_search else R.drawable.ic_column_search_light)
mDownloadMenuIcon?.setImageResource(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.toolbar_download else R.drawable.toolbar_download_light)
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn && isToolbarWhite)

View File

@ -5,36 +5,33 @@ import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Paint
import android.os.Bundle
import android.text.TextUtils
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.entity.SuggestType
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.ActivityServersCalendarBinding
import com.gh.gamecenter.databinding.DialogServersCalendearDetailItemBinding
import com.gh.gamecenter.entity.CalendarEntity
import com.gh.gamecenter.feature.entity.GameDetailServer
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.MeEntity
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import com.gh.gamecenter.help.HelpAndFeedbackBridge
import com.gh.gamecenter.servers.add.AddKaiFuActivity
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.halo.assistant.HaloApp
import com.lightgame.adapter.BaseRecyclerAdapter
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.text.SimpleDateFormat
import java.util.*
@ -46,6 +43,13 @@ class ServersCalendarActivity : ToolBarActivity() {
NewLogUtils.logGameDetailOpenCalendarView(mViewModel.game.name ?: "", mViewModel.game.id)
}
private val mMoreDialog by lazy { ServersCalendarMoreDialog() }
private val mWeChatSubscriptionSuccessDialog by lazy { ServersCalendarWeChatSubscriptionSuccessDialog() }
private val mSubscriptionSuccessDialog by lazy { ServersCalendarSubscriptionSuccessDialog() }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val serverCalendars = mViewModel.serverCalendarLiveData.value ?: return
@ -85,6 +89,20 @@ class ServersCalendarActivity : ToolBarActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
val game = intent?.getParcelableExtra<GameEntity>(GameEntity::class.java.simpleName)
val serverList = intent?.getParcelableExtra<GameDetailServer>(GameDetailServer::class.java.simpleName)
val meEntity = intent?.getParcelableExtra<MeEntity>(MeEntity::class.java.simpleName)
if (game == null || serverList == null) {
throwExceptionInDebug()
return
}
// 必须放在super.onCreate前面因为子Fragment的onCreate方法也是在super.onCreate回调的时候调用
// 如果放在super.onCreate之后那么在页面重构时子Fragment在onCreate方法引用通过viewModels方法获取parentViewModel将触发崩溃
val factory = ServersCalendarViewModel.Factory(HaloApp.getInstance().application, game, serverList, meEntity)
mViewModel = ViewModelProviders.of(this, factory).get(ServersCalendarViewModel::class.java)
mViewModel.setKaifuTime(intent.getLongExtra(EntranceConsts.KEY_KAIFU_TIME, 0))
super.onCreate(savedInstanceState)
updateStatusBarColor(R.color.background_white, R.color.background_white)
setNavigationTitle("开服日历表")
@ -96,16 +114,6 @@ class ServersCalendarActivity : ToolBarActivity() {
mViewModel.loadServerData()
}
val game = intent?.getParcelableExtra<GameEntity>(GameEntity::class.java.simpleName)
val serverList = intent?.getParcelableExtra<GameDetailServer>(GameDetailServer::class.java.simpleName)
val meEntity = intent?.getParcelableExtra<MeEntity>(MeEntity::class.java.simpleName)
if (game == null || serverList == null) {
throwExceptionInDebug()
return
}
val factory = ServersCalendarViewModel.Factory(HaloApp.getInstance().application, game, serverList, meEntity)
mViewModel = ViewModelProviders.of(this, factory).get(ServersCalendarViewModel::class.java)
mViewModel.calendarLiveData.observeNonNull(this, callback = {
val adapter = ServersCalendarAdapter(this, mViewModel, it)
mBinding.recyclerView.isNestedScrollingEnabled = false
@ -113,7 +121,7 @@ class ServersCalendarActivity : ToolBarActivity() {
mBinding.recyclerView.adapter = adapter
})
mViewModel.serversDetailLiveData.observeNonNull(this, callback = {
showServersDetailDialog(it)
showServersCalendarDetailDialog(it)
NewLogUtils.logGameDetailOpenCalendarClick(mViewModel.game.name ?: "", mViewModel.game.id)
})
mViewModel.serverCalendarLiveData.observe(this) {
@ -125,6 +133,52 @@ class ServersCalendarActivity : ToolBarActivity() {
mBinding.includeNoConnection.root.visibility = View.VISIBLE
}
}
mViewModel.serverSubscriptionLiveData.observe(this) {
// 用户订阅状态
if (it?.byApp == true) {// 用户已登录并处于已订阅状态
clearMenu()
setToolbarMenu(R.menu.menu_server_calendar_more)
mBinding.subscribe.visibility = View.GONE
mBinding.subscribeHint1.visibility = View.GONE
mBinding.subscribeHint2.visibility = View.GONE
mBinding.subscribe.setOnClickListener(null)
} else {// 用户已登录并处于未订阅状态
clearMenu()
mBinding.subscribe.visibility = View.VISIBLE
mBinding.subscribeHint1.visibility = View.VISIBLE
mBinding.subscribeHint2.visibility = View.VISIBLE
mBinding.subscribe.setOnClickListener {
CheckLoginUtils.checkLogin(this, "游戏详情-开服日历表-开启订阅") {
mViewModel.subscribeServer()
NewLogUtils.logLaunchServerSubscribeAdd(
gameId = mViewModel.game.id,
gameName = mViewModel.game.name ?: ""
)
SensorsBridge.trackLaunchServerSubscribeClick(
gameId = mViewModel.game.id,
gameName = mViewModel.game.name ?: ""
)
}
}
}
}
mViewModel.subscribeServerSuccessEvent.observe(this) {
val serverSubscription = mViewModel.serverSubscriptionLiveData.value
if (serverSubscription?.byWeChat != true && !mWeChatSubscriptionSuccessDialog.isAdded) {// 开启微信提醒弹窗
mWeChatSubscriptionSuccessDialog.showNow(
supportFragmentManager,
SERVERS_CALENDAR_WECHAT_SUBSCRIPTION_DIALOG_TAG
)
} else if (!mSubscriptionSuccessDialog.isAdded) {// 开启订阅成功提醒弹窗
mSubscriptionSuccessDialog.showNow(
supportFragmentManager,
SERVERS_CALENDAR_SUBSCRIPTION_DIALOG_TAG
)
}
}
mViewModel.error.observe(this) {
ToastUtils.showToast(getString(R.string.network_error_hint))
}
mBaseHandler.postDelayed(mDelayLogRunnable, 3000)
}
@ -133,6 +187,15 @@ class ServersCalendarActivity : ToolBarActivity() {
mBaseHandler.removeCallbacks(mDelayLogRunnable)
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
if (item?.itemId == R.id.menu_more) {
if (!mMoreDialog.isAdded) {
mMoreDialog.showNow(supportFragmentManager, SERVERS_CALENDAR_MORE_DIALOG_TAG)
}
}
return super.onMenuItemClick(item)
}
fun initView() {
mBinding.contentContainer.visibility = View.VISIBLE
mBinding.includeLoading.root.visibility = View.GONE
@ -184,7 +247,7 @@ class ServersCalendarActivity : ToolBarActivity() {
}
if (!mViewModel.isExistCurServer) {
if (!mViewModel.isExistCurServer) {// 这里已经不执行了,估计是遗留下的旧代码...
mViewModel.selectedMonth = MonthType.NEXT_MONTH
mBinding.curMonth.visibility = View.GONE
@ -193,13 +256,41 @@ class ServersCalendarActivity : ToolBarActivity() {
mBinding.nextMonth.setTextColor(Color.WHITE)
mBinding.year.text = formatYearText.format(previousTime)
} else {
mViewModel.selectedMonth = MonthType.CUR_MONTH
mBinding.curMonth.visibility = View.VISIBLE
mBinding.curMonth.setBackgroundResource(R.drawable.download_oval_hint_up)
mBinding.curMonth.text = formatMonthText.format(curTime)
mBinding.year.text = formatYearText.format(curTime)
when (mViewModel.selectedMonth) {
MonthType.CUR_MONTH -> {
mBinding.curMonth.setBackgroundResource(R.drawable.download_oval_hint_up)
mBinding.curMonth.setTextColor(Color.WHITE)
mBinding.previousMonth.setBackgroundColor(0)
mBinding.previousMonth.setTextColor(R.color.text_title.toColor(this))
mBinding.nextMonth.setBackgroundColor(0)
mBinding.nextMonth.setTextColor(R.color.text_title.toColor(this))
}
MonthType.NEXT_MONTH -> {
mBinding.nextMonth.setBackgroundResource(R.drawable.download_oval_hint_up)
mBinding.nextMonth.setTextColor(Color.WHITE)
mBinding.curMonth.setBackgroundColor(0)
mBinding.curMonth.setTextColor(R.color.text_title.toColor(this))
mBinding.previousMonth.setBackgroundColor(0)
mBinding.previousMonth.setTextColor(R.color.text_title.toColor(this))
}
else -> {
mBinding.previousMonth.setBackgroundResource(R.drawable.download_oval_hint_up)
mBinding.previousMonth.setTextColor(Color.WHITE)
mBinding.nextMonth.setBackgroundColor(0)
mBinding.nextMonth.setTextColor(R.color.text_title.toColor(this))
mBinding.curMonth.setBackgroundColor(0)
mBinding.curMonth.setTextColor(R.color.text_title.toColor(this))
}
}
}
mBinding.nextMonth.setOnClickListener { v ->
@ -276,129 +367,51 @@ class ServersCalendarActivity : ToolBarActivity() {
}
private fun showServersDetailDialog(calendarEntity: CalendarEntity) {
val contentView = LayoutInflater.from(this).inflate(R.layout.dialog_servers_calendear_detail, null)
val params = ViewGroup.LayoutParams(resources.displayMetrics.widthPixels, ViewGroup.LayoutParams.WRAP_CONTENT)
val dialog = Dialog(this, R.style.DialogWindowTransparent)
val window = dialog.window
window?.setGravity(Gravity.BOTTOM)
window?.setWindowAnimations(R.style.community_publication_animation)
dialog.setContentView(contentView, params)
dialog.show()
private fun showServersCalendarDetailDialog(calendarEntity: CalendarEntity) {
val currentCalendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
val serverCalendar = Calendar.getInstance().apply {
set(calendarEntity.year, calendarEntity.month - 1, calendarEntity.day, 0, 0, 0)
}
val calendarHint = contentView.findViewById<TextView>(R.id.calendar_hint)
calendarHint.text = (calendarEntity.server.first().getFormatTime("MM-dd") + "详细开服")
// 开服表详情是否显示提醒按钮,条件如下:
// 2. 当前开服表日期大于当天日期
val isRemindFeatureSupported = serverCalendar >= currentCalendar
val addBtn = contentView.findViewById<View>(R.id.add)
if (mViewModel.meEntity?.isPartTime == true) {
addBtn.visibility = View.INVISIBLE
if (!isRemindFeatureSupported && calendarEntity.server.isEmpty()) {
// 小于当前时间的未知服不显示弹窗
return
}
val dialog = if (calendarEntity.server.isEmpty()) {
ServersCalendarDetailNoDataDialog().apply {
arguments = Bundle().apply {
putInt(EntranceConsts.KEY_CALENDAR_YEAR, calendarEntity.year)
putInt(EntranceConsts.KEY_CALENDAR_MONTH, calendarEntity.month)
putInt(EntranceConsts.KEY_CALENDAR_DAY, calendarEntity.day)
}
}
} else {
addBtn.visibility = View.GONE
}
val feedback = contentView.findViewById<TextView>(R.id.feedback)
feedback.paint.flags = Paint.UNDERLINE_TEXT_FLAG
feedback.paint.isAntiAlias = true
if (mViewModel.meEntity?.isPartTime == true) {
feedback.text = "新增"
} else {
feedback.text = "意见反馈"
}
feedback.setOnClickListener {
if (mViewModel.meEntity?.isPartTime == true) {
startActivityForResult(
AddKaiFuActivity.getIntent(
this,
mViewModel.serverCalendarLiveData.value!!.last(),
mViewModel.serverCalendarLiveData.value as ArrayList<ServerCalendarEntity>,
mViewModel.game.id, calendarEntity.server.first().getTime() * 1000
), GAME_DETAIL_ADD_KAIFU_REQUEST
)
} else {
dialog.dismiss()
showServersDetailReportDialog(calendarEntity)
}
}
contentView.findViewById<View>(R.id.close).setOnClickListener {
dialog.dismiss()
}
val recyclerView = contentView.findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = object : BaseRecyclerAdapter<ServersDetailViewHolder>(this) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ServersDetailViewHolder {
val view = mLayoutInflater.inflate(R.layout.dialog_servers_calendear_detail_item, parent, false)
return ServersDetailViewHolder(DialogServersCalendearDetailItemBinding.bind(view))
}
override fun getItemCount(): Int {
return calendarEntity.server.size
}
override fun onBindViewHolder(holder: ServersDetailViewHolder, position: Int) {
val data = calendarEntity.server[position]
holder.bindItem(data, mViewModel.meEntity, mViewModel.game)
if (mViewModel.meEntity?.isPartTime == true) {
holder.binding.add.visibility = View.VISIBLE
} else {
holder.binding.add.visibility = View.GONE
}
holder.binding.add.setOnClickListener {
startActivityForResult(
AddKaiFuActivity.getIntent(
this@ServersCalendarActivity,
data,
mViewModel.serverCalendarLiveData.value as ArrayList<ServerCalendarEntity>,
mViewModel.game.id,
mViewModel.getSelectTime(calendarEntity.day, calendarEntity.month, calendarEntity.year)
), ServersCalendarActivity.GAME_DETAIL_ADD_KAIFU_REQUEST
)
}
if (itemCount == position + 1) {
holder.itemView.setPadding(0, 10F.dip2px(), 0, 19F.dip2px())
} else {
holder.itemView.setPadding(0, 10F.dip2px(), 0, 10F.dip2px())
ServersCalendarDetailDialog().apply {
arguments = Bundle().apply {
putInt(EntranceConsts.KEY_CALENDAR_YEAR, calendarEntity.year)
putInt(EntranceConsts.KEY_CALENDAR_MONTH, calendarEntity.month)
putInt(EntranceConsts.KEY_CALENDAR_DAY, calendarEntity.day)
putBoolean(EntranceConsts.KEY_SHOW_REMIND, isRemindFeatureSupported)
}
}
}
dialog.showNow(supportFragmentManager, null)
}
private fun showServersDetailReportDialog(calendarEntity: CalendarEntity) {
val contentView = LayoutInflater.from(this).inflate(R.layout.dialog_servers_calendear_detail_report, null)
val params = ViewGroup.LayoutParams(resources.displayMetrics.widthPixels, ViewGroup.LayoutParams.WRAP_CONTENT)
val dialog = BottomSheetDialog(this, R.style.DialogWindowTransparent)
val window = dialog.window
window?.setGravity(Gravity.BOTTOM)
window?.setWindowAnimations(R.style.community_publication_animation)
dialog.setContentView(contentView, params)
dialog.show()
val recyclerView = contentView.findViewById<RecyclerView>(R.id.recycler_view)
val adapter = ServersDetailReportAdapter(this, calendarEntity.server)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
contentView.findViewById<TextView>(R.id.submit).setOnClickListener {
val builder = StringBuilder()
val serverCalendarList = adapter.selectedServerCalendarList
serverCalendarList.forEachIndexed { index, entity ->
if (index != 0) builder.append("")
builder.append("${entity.getFormatTime("YYYY年MM月dd日")}开服信息有误:${entity.getNote()}")
}
HelpAndFeedbackBridge.startSuggestionActivity(
this,
SuggestType.GAME,
"service",
builder.toString()
)
dialog.dismiss()
}
contentView.findViewById<View>(R.id.close).setOnClickListener {
dialog.dismiss()
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(reuse: EBReuse) {
if (reuse.type == Constants.LOGIN_TAG || reuse.type == Constants.LOGOUT_TAG) {
mViewModel.loadServerData()
}
}
@ -423,6 +436,10 @@ class ServersCalendarActivity : ToolBarActivity() {
const val GAME_DETAIL_ADD_KAIFU_KEY = "GAME_DETAIL_ADD_KAIFU_KEY"
const val GAME_DETAIL_PATCH_KAIFU_KEY = "GAME_DETAIL_PATCH_KAIFU_KEY"
const val SERVERS_CALENDAR_MORE_DIALOG_TAG = "ServersCalendarMoreDialog"
const val SERVERS_CALENDAR_WECHAT_SUBSCRIPTION_DIALOG_TAG = "ServersCalendarWeChatSubscriptionDialog"
const val SERVERS_CALENDAR_SUBSCRIPTION_DIALOG_TAG = "ServersCalendarSubscriptionDialog"
fun getIntent(context: Context, game: GameEntity, gameServer: GameDetailServer, me: MeEntity?): Intent {
val intent = Intent(context, ServersCalendarActivity::class.java)
intent.putExtra(GameEntity::class.java.simpleName, game)

View File

@ -119,6 +119,8 @@ class ServersCalendarAdapter(
),
ServersCalendarActivity.GAME_DETAIL_ADD_KAIFU_REQUEST
)
} else {
viewModel.serversDetailLiveData.postValue(entity)
}
} else {
MtaHelper.onEvent("开服日历表", "详情", "${viewModel.game.name}+${holder.binding.calendarKaifu.text}")

View File

@ -0,0 +1,18 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
enum class ServersCalendarAdvancedTime(val value: Int, val text: String) {
IN_TIME(0, "准时提醒"),
FIVE_MINUTES_IN_ADVANCE(300, "提前5分钟"),
FIFTEEN_MINUTES_IN_ADVANCE(900, "提前15分钟"),
THIRTY_MINUTES_IN_ADVANCE(1800, "提前30分钟");
companion object {
fun valueOf(value: Int?): ServersCalendarAdvancedTime {
if (value == null) return IN_TIME
return ServersCalendarAdvancedTime.values().firstOrNull {
it.value == value
} ?: IN_TIME
}
}
}

View File

@ -0,0 +1,151 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Activity
import android.graphics.Paint
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import com.gh.common.util.CheckLoginUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.layoutInflater
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DialogServersCalendearDetailItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.MeEntity
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import com.gh.gamecenter.servers.add.AddKaiFuActivity
import com.gh.gamecenter.servers.patch.PatchKaifuActivity
import com.lightgame.utils.Utils
import java.util.*
class ServersCalendarDetailAdapter(
private val fragment: Fragment,
private val viewModel: ServersCalendarDetailViewModel,
private val parentViewModel: ServersCalendarViewModel
) : ListAdapter<ServerCalendarEntity, ServersCalendarDetailAdapter.ServersCalendarDetailViewHolder>(
object : DiffUtil.ItemCallback<ServerCalendarEntity>() {
override fun areItemsTheSame(oldItem: ServerCalendarEntity, newItem: ServerCalendarEntity): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: ServerCalendarEntity, newItem: ServerCalendarEntity): Boolean {
return oldItem.id == newItem.id
&& oldItem.getFirstName() == newItem.getFirstName()
&& oldItem.getServerName() == newItem.getServerName()
&& oldItem.getNote() == newItem.getNote()
&& oldItem.getTime() == newItem.getTime()
&& oldItem.remark == newItem.remark
&& oldItem.type == newItem.type
&& oldItem.notifySetting?.notifyTime == newItem.notifySetting?.notifyTime
&& oldItem.notifySetting?.secondsAdvance == newItem.notifySetting?.secondsAdvance
&& oldItem.notifySetting?.byApp == newItem.notifySetting?.byApp
&& oldItem.notifySetting?.byWechat == newItem.notifySetting?.byWechat
}
}
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ServersCalendarDetailViewHolder {
return ServersCalendarDetailViewHolder(
DialogServersCalendearDetailItemBinding.inflate(
parent.layoutInflater,
parent,
false
)
)
}
override fun onBindViewHolder(holder: ServersCalendarDetailViewHolder, position: Int) {
val data = getItem(position)
holder.bindItem(data, parentViewModel.meEntity, parentViewModel.game)
if (parentViewModel.meEntity?.isPartTime == true) {
holder.binding.add.visibility = View.VISIBLE
} else {
holder.binding.add.visibility = View.GONE
}
holder.binding.add.setOnClickListener {
fragment.startActivityForResult(
AddKaiFuActivity.getIntent(
it.context,
data,
parentViewModel.serverCalendarLiveData.value as ArrayList<ServerCalendarEntity>,
parentViewModel.game.id,
parentViewModel.getSelectTime(
viewModel.year,
viewModel.month,
viewModel.day
)
), ServersCalendarActivity.GAME_DETAIL_ADD_KAIFU_REQUEST
)
}
holder.itemView.layoutParams = (holder.itemView.layoutParams as ViewGroup.MarginLayoutParams).apply {
bottomMargin = if (itemCount == position + 1) 7F.dip2px() else 0
}
holder.binding.remindTitle.visibility = View.GONE
holder.binding.remind.visibility = if (viewModel.showRemind) View.VISIBLE else View.GONE
holder.binding.remind.isSelected = data.notifySetting != null
holder.binding.remind.setOnClickListener {
CheckLoginUtils.checkLogin(it.context, "游戏详情-开服日历表-开服详情-开服提醒") {
if ((System.currentTimeMillis() - (data.getTime() * 1000)) > 0) {
ToastUtils.showToast(it.context.getString(R.string.servers_calendar_time_out_of_date))
return@checkLogin
}
ServersCalendarDetailsRemindDialog().apply {
arguments = Bundle().apply {
putString(EntranceConsts.KEY_SERVER_CALENDAR_ID, data.id)
}
showNow(fragment.childFragmentManager, null)
}
}
}
}
class ServersCalendarDetailViewHolder(val binding: DialogServersCalendearDetailItemBinding) :
BaseRecyclerViewHolder<Any>(binding.root) {
fun bindItem(data: ServerCalendarEntity, meEntity: MeEntity?, gameEntity: GameEntity) {
binding.name.text = data.getNote()
binding.time.text = data.getFormatTime("HH:mm")
binding.remark.text = data.remark
binding.name.setTextColor(R.color.text_title.toColor(binding.root.context))
binding.time.setTextColor(R.color.text_title.toColor(binding.root.context))
binding.remark.setTextColor(R.color.text_title.toColor(binding.root.context))
if (meEntity?.isPartTime == true) {
binding.name.paint.flags = Paint.UNDERLINE_TEXT_FLAG
binding.name.paint.isAntiAlias = true
binding.name.setOnClickListener {
val context = binding.root.context
if ("删档内测" == data.type || "不删档内测" == data.type || "公测" == data.type) {
Utils.toast(context, "开测信息不可编辑");
} else {
(context as Activity).startActivityForResult(
PatchKaifuActivity.getIntent(
context,
data,
gameEntity.id
),
ServersCalendarActivity.GAME_DETAIL_PATCH_KAIFU_REQUEST
)
}
}
}
}
}
}

View File

@ -0,0 +1,164 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Dialog
import android.graphics.Paint
import android.os.Bundle
import android.view.*
import android.widget.TextView
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.entity.SuggestType
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.databinding.DialogServersCalendearDetailBinding
import com.gh.gamecenter.databinding.LayoutServersCalendarDetailListBinding
import com.gh.gamecenter.entity.CalendarEntity
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import com.gh.gamecenter.help.HelpAndFeedbackBridge
import com.gh.gamecenter.servers.add.AddKaiFuActivity
import com.google.android.material.bottomsheet.BottomSheetDialog
import java.text.SimpleDateFormat
import java.util.*
/**
* 游戏开服-开服表详情弹窗
*/
class ServersCalendarDetailDialog : DialogFragment() {
private lateinit var detailViewBinding: DialogServersCalendearDetailBinding
private lateinit var listViewBinding: LayoutServersCalendarDetailListBinding
private val titleFormat = SimpleDateFormat("MM-dd", Locale.CHINA)
private val parentViewModel by activityViewModels<ServersCalendarViewModel>()
private lateinit var viewModel: ServersCalendarDetailViewModel
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
window?.setWindowAnimations(R.style.community_publication_animation)
window?.setGravity(Gravity.BOTTOM)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
// 必须放在super.onCreate前面因为子Fragment的onCreate方法也是在super.onCreate回调的时候调用
// 如果放在super.onCreate之后那么在页面重构时子Fragment在onCreate方法引用通过viewModels方法获取parentViewModel将触发崩溃
viewModel = viewModelProvider(
ServersCalendarDetailViewModel.Factory(
source = parentViewModel.calendarLiveData,
year = requireArguments().getInt(EntranceConsts.KEY_CALENDAR_YEAR, 0),
month = requireArguments().getInt(EntranceConsts.KEY_CALENDAR_MONTH, 0),
day = requireArguments().getInt(EntranceConsts.KEY_CALENDAR_DAY, 0),
showRemind = requireArguments().getBoolean(EntranceConsts.KEY_SHOW_REMIND, false)
)
)
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, R.style.DialogWindowTransparent)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogServersCalendearDetailBinding.inflate(inflater, container, false)
.also {
detailViewBinding = it.apply {
content.layoutResource = R.layout.layout_servers_calendar_detail_list
listViewBinding = LayoutServersCalendarDetailListBinding.bind(content.inflate())
}
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 在这里加这句代码,才能保证弹窗宽度占满屏幕
// 如果在弹窗的Theme里面加<item name="android:windowIsFloating">false</item>,那么这句代码可以去掉
dialog?.window?.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
val isPartTime = parentViewModel.meEntity?.isPartTime == true
listViewBinding.titleInclude.add.visibility = if (isPartTime) View.VISIBLE else View.GONE
listViewBinding.titleInclude.remindTitle.visibility = if (viewModel.showRemind) View.VISIBLE else View.GONE
detailViewBinding.close.setOnClickListener { dismissAllowingStateLoss() }
detailViewBinding.feedback.paint.flags = Paint.UNDERLINE_TEXT_FLAG
detailViewBinding.feedback.paint.isAntiAlias = true
detailViewBinding.feedback.text = if (isPartTime) "新增" else "意见反馈"
detailViewBinding.feedback.setOnClickListener {
val calendarEntity = viewModel.calendarEntityLiveData.value ?: return@setOnClickListener
if (isPartTime) {
startActivityForResult(
AddKaiFuActivity.getIntent(
it.context,
parentViewModel.serverCalendarLiveData.value!!.last(),
parentViewModel.serverCalendarLiveData.value as ArrayList<ServerCalendarEntity>,
parentViewModel.game.id, calendarEntity.server.first().getTime() * 1000
), ServersCalendarActivity.GAME_DETAIL_ADD_KAIFU_REQUEST
)
} else {
showServersDetailReportDialog(calendarEntity)
dismissAllowingStateLoss()
}
}
val adapter = ServersCalendarDetailAdapter(this@ServersCalendarDetailDialog, viewModel, parentViewModel)
listViewBinding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
listViewBinding.recyclerView.adapter = adapter
viewModel.calendarEntityLiveData.observe(viewLifecycleOwner) { calendarEntity ->
calendarEntity?.let {
val calendar = Calendar.getInstance().apply {
set(it.year, it.month - 1, it.day)
}
detailViewBinding.calendarHint.text = "${titleFormat.format(calendar.time)}详细开服"
adapter.submitList(calendarEntity.server)
}
}
}
private fun showServersDetailReportDialog(calendarEntity: CalendarEntity) {
val contentView =
LayoutInflater.from(requireContext()).inflate(R.layout.dialog_servers_calendear_detail_report, null)
val params = ViewGroup.LayoutParams(resources.displayMetrics.widthPixels, ViewGroup.LayoutParams.WRAP_CONTENT)
val dialog = BottomSheetDialog(requireContext(), R.style.DialogWindowTransparent)
val window = dialog.window
window?.setGravity(Gravity.BOTTOM)
window?.setWindowAnimations(R.style.community_publication_animation)
dialog.setContentView(contentView, params)
dialog.show()
val recyclerView = contentView.findViewById<RecyclerView>(R.id.recycler_view)
val adapter = ServersCalendarDetailReportAdapter(requireContext(), calendarEntity.server)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
recyclerView.adapter = adapter
contentView.findViewById<TextView>(R.id.submit).setOnClickListener {
val builder = StringBuilder()
val serverCalendarList = adapter.selectedServerCalendarList
serverCalendarList.forEachIndexed { index, entity ->
if (index != 0) builder.append("")
builder.append("${entity.getFormatTime("YYYY年MM月dd日")}开服信息有误:${entity.getNote()}")
}
HelpAndFeedbackBridge.startSuggestionActivity(
it.context,
SuggestType.GAME,
"service",
builder.toString()
)
dialog.dismiss()
}
contentView.findViewById<View>(R.id.close).setOnClickListener {
dialog.dismiss()
}
}
}

View File

@ -0,0 +1,281 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Dialog
import android.graphics.Paint
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
import androidx.core.content.ContextCompat
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import com.gh.common.constant.Config
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.entity.SuggestType
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.WXAPIProxyFactory
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.view.DrawableView
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DialogServersCalendearDetailBinding
import com.gh.gamecenter.databinding.LayoutServersCalendarDetailNoDataBinding
import com.gh.gamecenter.feature.entity.ServerCalendarNotifySetting
import com.gh.gamecenter.help.HelpAndFeedbackBridge
import com.gh.gamecenter.login.user.UserManager
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.tencent.mm.opensdk.modelbase.BaseResp
import com.tencent.mm.opensdk.modelbiz.SubscribeMessage
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.text.SimpleDateFormat
import java.util.*
/**
* 游戏开服-未知服详情弹窗
*/
class ServersCalendarDetailNoDataDialog : BottomSheetDialogFragment() {
private val titleFormat = SimpleDateFormat("MM-dd", Locale.CHINA)
private lateinit var detailViewBinding: DialogServersCalendearDetailBinding
private lateinit var noDataViewBinding: LayoutServersCalendarDetailNoDataBinding
private val parentViewModel by activityViewModels<ServersCalendarViewModel>()
private lateinit var viewModel: ServersCalendarDetailNoDataViewModel
private lateinit var wxApi: WXAPIProxyFactory.WXAPIProxy<SubscribeMessage.Req, SubscribeMessage.Resp>
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
window?.setWindowAnimations(R.style.community_publication_animation)
window?.setGravity(Gravity.BOTTOM)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EventBus.getDefault().register(this)
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.DialogWindowTransparent)
Calendar.getInstance().apply {
set(
requireArguments().getInt(EntranceConsts.KEY_CALENDAR_YEAR, 0),
requireArguments().getInt(EntranceConsts.KEY_CALENDAR_MONTH, 0) - 1,
requireArguments().getInt(EntranceConsts.KEY_CALENDAR_DAY, 0),
0, 0, 0
)
set(Calendar.MILLISECOND, 0)
viewModel = viewModelProvider(ServersCalendarDetailNoDataViewModel.Factory(timeInMillis))
}
wxApi = WXAPIProxyFactory.createWXAPI(
requireContext(),
Config.WECHAT_APPID,
object: WXAPIProxyFactory.WXHandler<SubscribeMessage.Req, SubscribeMessage.Resp> {
private val reserved = System.currentTimeMillis().toString()
override fun handleOnReq(req: SubscribeMessage.Req) {
req.reserved = reserved
}
override fun handleOnResp(resp: BaseResp): SubscribeMessage.Resp? {
if (resp is SubscribeMessage.Resp && reserved == resp.reserved) {
return resp
}
return null
}
}
)
}
override fun onDestroy() {
super.onDestroy()
EventBus.getDefault().unregister(this)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogServersCalendearDetailBinding.inflate(inflater, container, false)
.also {
detailViewBinding = it.apply {
content.layoutResource = R.layout.layout_servers_calendar_detail_no_data
noDataViewBinding = LayoutServersCalendarDetailNoDataBinding.bind(content.inflate())
content.layoutParams = content.layoutParams.apply {
height = LayoutParams.WRAP_CONTENT
}
}
it.container.layoutParams = it.container.layoutParams.apply {
height = LayoutParams.WRAP_CONTENT
}
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
detailViewBinding.calendarHint.text = "${titleFormat.format(viewModel.serverTimeInMills)}详细开服"
detailViewBinding.feedback.paint.flags = Paint.UNDERLINE_TEXT_FLAG
detailViewBinding.feedback.paint.isAntiAlias = true
detailViewBinding.feedback.text = "意见反馈"
detailViewBinding.feedback.setOnClickListener {
HelpAndFeedbackBridge.startSuggestionActivity(
it.context,
SuggestType.GAME,
"service"
)
}
detailViewBinding.close.setOnClickListener {
dismissAllowingStateLoss()
}
noDataViewBinding.appRemindCheckIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(requireContext()))
noDataViewBinding.wechatRemindCheckIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(requireContext()))
viewModel.getServerCalenderRemind(parentViewModel.game.id)
viewModel.serverCalendarRemindLiveData.observe(viewLifecycleOwner) {
bindNoDataView(it)
}
viewModel.wxSubscribeMsgConfigLiveData.observe(viewLifecycleOwner) {
wxApi.sendReq(
SubscribeMessage.Req().apply {
scene = it.scene
templateID = it.templateId
reserved = it.reserved
}
)
}
viewModel.error.observe(viewLifecycleOwner) {
ToastUtils.showToast(getString(R.string.network_error_hint))
}
wxApi.liveData.observe(viewLifecycleOwner) {
if (it.action == "confirm") {
viewModel.addServerCalendarRemindWithWechat(
gameId = parentViewModel.game.id,
openId = it.openId,
templateId = it.templateID,
action = it.action,
reserved = UserManager.getInstance().userId,
scene = it.scene
)
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(reuse: EBReuse) {
if (reuse.type == Constants.LOGIN_TAG || reuse.type == Constants.LOGOUT_TAG) {
viewModel.getServerCalenderRemind(parentViewModel.game.id)
}
}
private fun bindNoDataView(notifySetting: ServerCalendarNotifySetting?) {
viewModel.initData(notifySetting)
noDataViewBinding.run {
appRemindCheckIv.isChecked = viewModel.appRemind
wechatRemindCheckIv.isChecked = viewModel.wechatRemind
if (notifySetting != null) {
appRemind.isEnabled = false
appRemindCheckIv.alpha = 0.4F
appRemind.setOnClickListener(null)
wechatRemind.isEnabled = false
wechatRemindCheckIv.alpha = 0.4F
wechatRemind.setOnClickListener(null)
addOrCancelRemind.text = getString(R.string.servers_detail_cancel_remind)
addOrCancelRemind.background =
ContextCompat.getDrawable(requireContext(), R.drawable.bg_servers_detail_cancel_no_data)
addOrCancelRemind.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.text_subtitle
)
)
addOrCancelRemind.setOnClickListener {
CheckLoginUtils.checkLogin(it.context, "游戏详情-开服日历表-未知服详情") {
viewModel.removeServerCalendarRemind(parentViewModel.game.id)
NewLogUtils.logLaunchServerReminderCancel(
gameId = parentViewModel.game.id,
gameName = parentViewModel.game.name ?: "",
reminderTime = viewModel.timeInSeconds,
reminderType = "未知服",
serverName = "",
launchServerTime = viewModel.timeInSeconds,
isApp = viewModel.appRemind,
isWechat = viewModel.wechatRemind
)
SensorsBridge.trackLaunchServerReminderCancelClick(
gameId = parentViewModel.game.id,
gameName = parentViewModel.game.name ?: "",
reminderType = "未知服",
)
}
}
} else {
appRemind.isEnabled = true
appRemindCheckIv.alpha = 1.0F
appRemind.setOnClickListener {
appRemindCheckIv.isChecked = !appRemindCheckIv.isChecked
viewModel.appRemind = appRemindCheckIv.isChecked
SPUtils.setBoolean(Constants.SP_SERVERS_CALENDAR_BY_APP, appRemindCheckIv.isChecked)
}
wechatRemind.isEnabled = true
wechatRemindCheckIv.alpha = 1.0F
wechatRemind.setOnClickListener {
wechatRemindCheckIv.isChecked = !wechatRemindCheckIv.isChecked
viewModel.wechatRemind = wechatRemindCheckIv.isChecked
SPUtils.setBoolean(Constants.SP_SERVERS_CALENDAR_BY_WECHAT, wechatRemindCheckIv.isChecked)
}
addOrCancelRemind.text = getString(R.string.servers_detail_add_remind)
addOrCancelRemind.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
addOrCancelRemind.background =
ContextCompat.getDrawable(requireContext(), R.drawable.download_button_normal_style)
addOrCancelRemind.setOnClickListener {
CheckLoginUtils.checkLogin(it.context, "游戏详情-开服日历表-未知服详情") {
if (!viewModel.wechatRemind && !viewModel.appRemind) {
ToastUtils.showToast(getString(R.string.servers_calendar_no_remind_checked_hint))
return@checkLogin
}
NewLogUtils.logLaunchServerReminderAdd(
gameId = parentViewModel.game.id,
gameName = parentViewModel.game.name ?: "",
reminderTime = viewModel.timeInSeconds,
reminderType = "未知服",
serverName = "",
launchServerTime = viewModel.timeInSeconds,
isApp = viewModel.appRemind,
isWechat = viewModel.wechatRemind
)
SensorsBridge.trackLaunchServerReminderClick(
gameId = parentViewModel.game.id,
gameName = parentViewModel.game.name ?: "",
reminderType = "未知服",
)
if (viewModel.wechatRemind) {// 勾选微信订阅后需要微信授权一次性订阅消息
viewModel.getWXSubscribeMsgConfig()
} else {
viewModel.addServerCalendarRemind(parentViewModel.game.id)
}
}
}
}
}
}
}

View File

@ -0,0 +1,140 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.annotation.SuppressLint
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.util.CheckLoginUtils
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.feature.entity.ServerCalendarNotifySetting
import com.gh.gamecenter.feature.entity.WXSubscribeMsgConfig
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class ServersCalendarDetailNoDataViewModel(
val serverTimeInMills: Long
) : ViewModel() {
val error = NonStickyMutableLiveData<Throwable>()
val wxSubscribeMsgConfigLiveData = MutableLiveData<WXSubscribeMsgConfig>()
val serverCalendarRemindLiveData: MutableLiveData<ServerCalendarNotifySetting?> = MutableLiveData()
private var isDataInit = false
var appRemind: Boolean = false
var wechatRemind: Boolean = false
val timeInSeconds: Int = (serverTimeInMills / 1000).toInt()
fun initData(notifySetting: ServerCalendarNotifySetting?) {
if (isDataInit) return
appRemind = notifySetting?.byApp ?: SPUtils.getBoolean(Constants.SP_SERVERS_CALENDAR_BY_APP, true)
wechatRemind = notifySetting?.byWechat ?: SPUtils.getBoolean(Constants.SP_SERVERS_CALENDAR_BY_WECHAT, true)
isDataInit = true
}
@SuppressLint("CheckResult")
fun getServerCalenderRemind(gameId: String) {
if (!CheckLoginUtils.isLogin()) {
serverCalendarRemindLiveData.postValue(null)
return
}
RetrofitManager.getInstance().newApi
.getServerCalendarRemind(gameId, timeInSeconds.toString())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
serverCalendarRemindLiveData.postValue(it)
}, {
serverCalendarRemindLiveData.postValue(null)
})
}
@SuppressLint("CheckResult")
fun addServerCalendarRemind(gameId: String) {
val requestBody = mapOf(
"by_app" to appRemind,
"by_wechat" to wechatRemind
).toRequestBody()
RetrofitManager.getInstance().newApi
.addServerCalendarRemind(gameId, timeInSeconds.toString(), requestBody)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
getServerCalenderRemind(gameId)
}, {
error.postValue(it)
})
}
@SuppressLint("CheckResult")
fun removeServerCalendarRemind(gameId: String) {
RetrofitManager.getInstance().newApi
.removeServerCalendarRemind(gameId, timeInSeconds.toString())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
getServerCalenderRemind(gameId)
}, {
error.postValue(it)
})
}
@SuppressLint("CheckResult")
fun getWXSubscribeMsgConfig() {
RetrofitManager.getInstance().newApi
.getWxSubscribeMsgConfig(UrlFilterUtils.getFilterQuery("type", "server_new"))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
wxSubscribeMsgConfigLiveData.postValue(it)
}, {
error.postValue(it)
})
}
@SuppressLint("CheckResult")
fun addServerCalendarRemindWithWechat(
gameId: String,
openId: String?,
templateId: String?,
action: String,
reserved: String,
scene: Int,
) {
val requestBody = mapOf(
"openid" to openId,
"template_id" to templateId,
"action" to action,
"scene" to scene,
"user_id" to reserved
).toRequestBody()
RetrofitManager.getInstance().newApi
.postWxSubscribeMsgCallback(UrlFilterUtils.getFilterQuery("type", "server_new"), requestBody)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
addServerCalendarRemind(gameId)
}, {
error.postValue(it)
})
}
class Factory(
private val serverTimeInMills: Long
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ServersCalendarDetailNoDataViewModel(serverTimeInMills) as T
}
}
}

View File

@ -3,17 +3,18 @@ package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.databinding.DialogServersCalendearDetailReportItemBinding
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class ServersDetailReportAdapter(
class ServersCalendarDetailReportAdapter(
context: Context,
private val serverList: MutableList<ServerCalendarEntity>
) : BaseRecyclerAdapter<ServersDetailReportViewHolder>(context) {
private val serverList: List<ServerCalendarEntity>
) : BaseRecyclerAdapter<ServersCalendarDetailReportAdapter.ServersCalendarDetailReportViewHolder>(context) {
private val selectedPositions = mutableListOf<Int>()
@ -21,14 +22,14 @@ class ServersDetailReportAdapter(
selectedPositions.contains(index)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ServersDetailReportViewHolder {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ServersCalendarDetailReportViewHolder {
val view = mLayoutInflater.inflate(R.layout.dialog_servers_calendear_detail_report_item, parent, false)
return ServersDetailReportViewHolder(DialogServersCalendearDetailReportItemBinding.bind(view))
return ServersCalendarDetailReportViewHolder(DialogServersCalendearDetailReportItemBinding.bind(view))
}
override fun getItemCount(): Int = serverList.size
override fun onBindViewHolder(holder: ServersDetailReportViewHolder, position: Int) {
override fun onBindViewHolder(holder: ServersCalendarDetailReportViewHolder, position: Int) {
val serverCalendarEntity = serverList[position]
holder.bindItem(serverCalendarEntity)
@ -50,4 +51,18 @@ class ServersDetailReportAdapter(
notifyItemChanged(position)
}
}
class ServersCalendarDetailReportViewHolder(val binding: DialogServersCalendearDetailReportItemBinding) :
BaseRecyclerViewHolder<Any>(binding.root) {
fun bindItem(data: ServerCalendarEntity) {
binding.name.text = data.getNote()
binding.time.text = data.getFormatTime("HH:mm")
binding.remark.text = data.remark
binding.name.setTextColor(R.color.text_title.toColor(binding.root.context))
binding.time.setTextColor(R.color.text_title.toColor(binding.root.context))
binding.remark.setTextColor(R.color.text_title.toColor(binding.root.context))
}
}
}

View File

@ -0,0 +1,38 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import androidx.lifecycle.*
import com.gh.gamecenter.entity.CalendarEntity
class ServersCalendarDetailViewModel(
source: LiveData<List<CalendarEntity>>,
val year: Int,
val month: Int,
val day: Int,
val showRemind: Boolean
) : ViewModel() {
var calendarEntityLiveData = Transformations.switchMap(source) {
Transformations.distinctUntilChanged(
MutableLiveData(
it.find { calendar ->
calendar.year == year
&& calendar.month == month
&& calendar.day == day
}
)
)
}
class Factory(
private val source: LiveData<List<CalendarEntity>>,
private val year: Int,
private val month: Int,
private val day: Int,
private val showRemind: Boolean
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ServersCalendarDetailViewModel(source, year, month, day, showRemind) as T
}
}
}

View File

@ -0,0 +1,320 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Dialog
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import com.gh.common.constant.Config
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.WXAPIProxyFactory
import com.gh.gamecenter.common.utils.WXAPIProxyFactory.WXAPIProxy
import com.gh.gamecenter.common.utils.WXAPIProxyFactory.WXHandler
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.setDrawableEnd
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.view.DrawableView
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DialogServersDetailRemindBinding
import com.gh.gamecenter.login.user.UserManager
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.tencent.mm.opensdk.modelbase.BaseResp
import com.tencent.mm.opensdk.modelbiz.SubscribeMessage
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import java.text.SimpleDateFormat
import java.util.*
/**
* 游戏开服-开服表详情-提醒详情弹窗
*/
class ServersCalendarDetailsRemindDialog : BottomSheetDialogFragment() {
private lateinit var viewBinding: DialogServersDetailRemindBinding
private lateinit var viewModel: ServersCalendarDetailsRemindViewModel
private lateinit var wxApi: WXAPIProxy<SubscribeMessage.Req, SubscribeMessage.Resp>
private val parentViewModel by viewModels<ServersCalendarDetailViewModel>({
parentFragment ?: this
})
private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault())
private val activityViewModel by activityViewModels<ServersCalendarViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.DialogWindowTransparent)
wxApi = WXAPIProxyFactory.createWXAPI(
requireContext(),
Config.WECHAT_APPID,
object: WXHandler<SubscribeMessage.Req, SubscribeMessage.Resp> {
private val reserved = System.currentTimeMillis().toString()
override fun handleOnReq(req: SubscribeMessage.Req) {
req.reserved = reserved
}
override fun handleOnResp(resp: BaseResp): SubscribeMessage.Resp? {
if (resp is SubscribeMessage.Resp && reserved == resp.reserved) {
return resp
}
return null
}
}
)
viewModel = viewModelProvider(
ServersCalendarDetailsRemindViewModel.Factory(
arguments?.getString(EntranceConsts.KEY_SERVER_CALENDAR_ID, "") ?: ""
)
)
viewModel.initCalendarLiveData(parentViewModel.calendarEntityLiveData)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
window?.setWindowAnimations(R.style.community_publication_animation)
window?.setGravity(Gravity.BOTTOM)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogServersDetailRemindBinding.inflate(inflater, container, false).also {
viewBinding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.appRemindCheckIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(requireContext()))
viewBinding.wechatRemindCheckIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(requireContext()))
viewModel.serverCalendarEntityLiveData.observe(viewLifecycleOwner) { entity ->
entity?.let {
val serverName = if (it.getNote().isNullOrEmpty()) it.remark else it.getNote()
viewModel.initData(it)
viewBinding.serverName.text = serverName
viewBinding.serverTime.text = dateFormat.format(viewModel.selectedNotifyTime)
viewBinding.serverRemindTime.text = viewModel.selectedAdvancedTime.text
viewBinding.appRemindCheckIv.isChecked = viewModel.appRemind
viewBinding.wechatRemindCheckIv.isChecked = viewModel.wechatRemind
val notifySetting = it.notifySetting
if (notifySetting != null) {
viewBinding.serverTime.isEnabled = false
viewBinding.serverTime.setPadding(12F.dip2px(), 0, 0, 0)
viewBinding.serverTime.setDrawableEnd(null)
viewBinding.serverTime.background =
ContextCompat.getDrawable(requireContext(), R.drawable.bg_server_detail_remind_time_disabled)
viewBinding.serverTime.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.text_subtitleDesc
)
)
viewBinding.serverRemindTime.isEnabled = false
viewBinding.serverRemindTime.setPadding(12F.dip2px(), 0, 0, 0)
viewBinding.serverRemindTime.setDrawableEnd(null)
viewBinding.serverRemindTime.background =
ContextCompat.getDrawable(requireContext(), R.drawable.bg_server_detail_remind_time_disabled)
viewBinding.serverRemindTime.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.text_subtitleDesc
)
)
viewBinding.appRemindCheckIv.alpha = 0.4F
viewBinding.appRemind.isEnabled = false
viewBinding.wechatRemindCheckIv.alpha = 0.4F
viewBinding.wechatRemind.isEnabled = false
viewBinding.addOrCancelRemind.text = getString(R.string.servers_detail_cancel_remind)
viewBinding.addOrCancelRemind.background =
ContextCompat.getDrawable(requireContext(), R.drawable.bg_servers_detail_cancel_remind)
viewBinding.addOrCancelRemind.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.text_subtitle
)
)
viewBinding.addOrCancelRemind.setOnClickListener {
CheckLoginUtils.checkLogin(view.context, "游戏详情-开服日历表-已知服详情") {
NewLogUtils.logLaunchServerReminderCancel(
gameId = activityViewModel.game.id,
gameName = activityViewModel.game.name ?: "",
reminderTime = viewModel.selectedNotifySeconds - viewModel.selectedAdvancedTime.value,
reminderType = "已知服",
serverName = serverName ?: "",
launchServerTime = viewModel.selectedNotifySeconds,
isApp = viewModel.appRemind,
isWechat = viewModel.wechatRemind
)
SensorsBridge.trackLaunchServerReminderCancelClick(
gameId = activityViewModel.game.id,
gameName = activityViewModel.game.name ?: "",
reminderType = "已知服"
)
viewModel.removeServerCalendarRemind(activityViewModel.game.id)
}
}
} else {
viewBinding.serverTime.isEnabled = true
viewBinding.serverTime.setPadding(12F.dip2px(), 0, 12F.dip2px(), 0)
viewBinding.serverTime.background =
ContextCompat.getDrawable(requireContext(), R.drawable.bg_server_detail_remind_time)
viewBinding.serverTime.setDrawableEnd(R.drawable.ic_arrow_gray)
viewBinding.serverTime.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_subtitle))
viewBinding.serverRemindTime.isEnabled = true
viewBinding.serverRemindTime.setPadding(12F.dip2px(), 0, 12F.dip2px(), 0)
viewBinding.serverRemindTime.background =
ContextCompat.getDrawable(requireContext(), R.drawable.bg_server_detail_remind_time)
viewBinding.serverRemindTime.setDrawableEnd(R.drawable.ic_arrow_gray)
viewBinding.serverRemindTime.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.text_subtitle
)
)
viewBinding.appRemindCheckIv.alpha = 1.0F
viewBinding.appRemind.isEnabled = true
viewBinding.wechatRemindCheckIv.alpha = 1.0F
viewBinding.wechatRemind.isEnabled = true
viewBinding.addOrCancelRemind.text = getString(R.string.servers_detail_add_remind)
viewBinding.addOrCancelRemind.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
viewBinding.addOrCancelRemind.background =
ContextCompat.getDrawable(requireContext(), R.drawable.download_button_normal_style)
viewBinding.addOrCancelRemind.setOnClickListener { view ->
CheckLoginUtils.checkLogin(view.context, "游戏详情-开服日历表-已知服详情") {
if (!viewModel.wechatRemind && !viewModel.appRemind) {
ToastUtils.showToast(getString(R.string.servers_calendar_no_remind_checked_hint))
return@checkLogin
}
val selectedNotifyTime = viewModel.selectedNotifyTime
val selectedAdvancedTime = viewModel.selectedAdvancedTime.value
if (selectedNotifyTime - selectedAdvancedTime * 1000 < System.currentTimeMillis()) {
ToastUtils.showToast(getString(R.string.servers_calendar_remind_time_out_of_date))
return@checkLogin
}
NewLogUtils.logLaunchServerReminderAdd(
gameId = activityViewModel.game.id,
gameName = activityViewModel.game.name ?: "",
reminderTime = viewModel.selectedNotifySeconds - viewModel.selectedAdvancedTime.value,
reminderType = "已知服",
serverName = serverName ?: "",
launchServerTime = viewModel.selectedNotifySeconds,
isApp = viewModel.appRemind,
isWechat = viewModel.wechatRemind
)
SensorsBridge.trackLaunchServerReminderClick(
gameId = activityViewModel.game.id,
gameName = activityViewModel.game.name ?: "",
reminderType = "已知服"
)
if (viewModel.wechatRemind) {// 勾选微信订阅后需要微信授权一次性订阅消息
viewModel.getWXSubscribeMsgConfig()
} else {
viewModel.addServerCalendarRemind(activityViewModel.game.id)
}
}
}
}
}
}
viewModel.wxSubscribeMsgConfigLiveData.observe(viewLifecycleOwner) {
wxApi.sendReq(
SubscribeMessage.Req().apply {
scene = it.scene
templateID = it.templateId
reserved = it.reserved
}
)
}
viewModel.error.observe(viewLifecycleOwner) {
ToastUtils.showToast(getString(R.string.network_error_hint))
}
wxApi.liveData.observe(viewLifecycleOwner) {
if (it.action == "confirm") {
viewModel.addServerCalendarRemindWithWechat(
gameId = activityViewModel.game.id,
openId = it.openId,
templateId = it.templateID,
action = it.action,
reserved = UserManager.getInstance().userId,
scene = it.scene
)
}
}
viewBinding.close.setOnClickListener {
dismissAllowingStateLoss()
}
viewBinding.serverTime.setOnClickListener {
val entity = viewModel.serverCalendarEntityLiveData.value ?: return@setOnClickListener
ServersCalendarTimeSettingDialog
.create(viewModel.selectedNotifyTime, entity.getTime() * 1000) {
viewModel.selectedNotifyTime = it
viewBinding.serverTime.text = dateFormat.format(it)
}
.showNow(childFragmentManager, null)
}
viewBinding.serverRemindTime.setOnClickListener {
ServersCalendarRemindTimeSettingDialog().also {
it.setSelectCallback { time ->
viewModel.selectedAdvancedTime = time
viewBinding.serverRemindTime.text = time.text
}
it.showNow(childFragmentManager, null)
}
}
viewBinding.appRemind.setOnClickListener {
viewBinding.appRemindCheckIv.isChecked = !viewBinding.appRemindCheckIv.isChecked
viewModel.appRemind = viewBinding.appRemindCheckIv.isChecked
SPUtils.setBoolean(Constants.SP_SERVERS_CALENDAR_BY_APP, viewBinding.appRemindCheckIv.isChecked)
}
viewBinding.wechatRemind.setOnClickListener {
viewBinding.wechatRemindCheckIv.isChecked = !viewBinding.wechatRemindCheckIv.isChecked
viewModel.wechatRemind = viewBinding.wechatRemindCheckIv.isChecked
SPUtils.setBoolean(Constants.SP_SERVERS_CALENDAR_BY_WECHAT, viewBinding.wechatRemindCheckIv.isChecked)
}
viewModel.notifySettingChangeLiveData.observe(viewLifecycleOwner) {
activityViewModel.dispatchNotifySettingChange(it.first, it.second)
}
}
}

View File

@ -0,0 +1,160 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.annotation.SuppressLint
import androidx.lifecycle.*
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.CalendarEntity
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import com.gh.gamecenter.feature.entity.ServerCalendarNotifySetting
import com.gh.gamecenter.feature.entity.WXSubscribeMsgConfig
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class ServersCalendarDetailsRemindViewModel(
val id: String
) : ViewModel() {
val error = NonStickyMutableLiveData<Throwable>()
lateinit var serverCalendarEntityLiveData: LiveData<ServerCalendarEntity?>
private set
val notifySettingChangeLiveData = MutableLiveData<Pair<String, ServerCalendarNotifySetting?>>()
val wxSubscribeMsgConfigLiveData = MutableLiveData<WXSubscribeMsgConfig>()
private var isDataInit = false
var selectedNotifyTime: Long = 0L
var selectedAdvancedTime: ServersCalendarAdvancedTime = ServersCalendarAdvancedTime.IN_TIME
var appRemind: Boolean = false
var wechatRemind: Boolean = false
val selectedNotifySeconds: Int get() = (selectedNotifyTime / 1000).toInt()
fun initCalendarLiveData(source: LiveData<CalendarEntity?>) {
serverCalendarEntityLiveData = Transformations.switchMap(source) {
Transformations.distinctUntilChanged(
MutableLiveData(
it?.server?.find { calendar ->
calendar.id == id
}
)
)
}
}
fun initData(calendarEntity: ServerCalendarEntity) {
if (isDataInit) return
val notifySetting = calendarEntity.notifySetting
selectedAdvancedTime = ServersCalendarAdvancedTime.valueOf(notifySetting?.secondsAdvance)
selectedNotifyTime = (notifySetting?.notifyTime ?: calendarEntity.getTime()) * 1000
appRemind = notifySetting?.byApp ?: SPUtils.getBoolean(Constants.SP_SERVERS_CALENDAR_BY_APP, true)
wechatRemind = notifySetting?.byWechat ?: SPUtils.getBoolean(Constants.SP_SERVERS_CALENDAR_BY_WECHAT, true)
isDataInit = true
}
@SuppressLint("CheckResult")
fun getServerCalenderRemind(gameId: String) {
RetrofitManager.getInstance().newApi
.getServerCalendarRemind(gameId, id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
notifySettingChangeLiveData.postValue(id to it)
}, {
notifySettingChangeLiveData.postValue(id to null)
})
}
@SuppressLint("CheckResult")
fun getWXSubscribeMsgConfig() {
RetrofitManager.getInstance().newApi
.getWxSubscribeMsgConfig(UrlFilterUtils.getFilterQuery("type", "server_open"))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
wxSubscribeMsgConfigLiveData.postValue(it)
}, {
error.postValue(it)
})
}
@SuppressLint("CheckResult")
fun addServerCalendarRemind(gameId: String) {
val requestBody = mapOf(
"notify_time" to selectedNotifySeconds,
"seconds_advance" to selectedAdvancedTime.value,
"by_app" to appRemind,
"by_wechat" to wechatRemind
).toRequestBody()
RetrofitManager.getInstance().newApi
.addServerCalendarRemind(gameId, id, requestBody)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
getServerCalenderRemind(gameId)
}, {
error.postValue(it)
})
}
@SuppressLint("CheckResult")
fun addServerCalendarRemindWithWechat(
gameId: String,
openId: String?,
templateId: String?,
action: String,
reserved: String,
scene: Int,
) {
val requestBody = mapOf(
"openid" to openId,
"template_id" to templateId,
"action" to action,
"scene" to scene,
"user_id" to reserved
).toRequestBody()
RetrofitManager.getInstance().newApi
.postWxSubscribeMsgCallback(UrlFilterUtils.getFilterQuery("type", "server_open"), requestBody)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
addServerCalendarRemind(gameId)
}, {
error.postValue(it)
})
}
@SuppressLint("CheckResult")
fun removeServerCalendarRemind(gameId: String) {
RetrofitManager.getInstance().newApi
.removeServerCalendarRemind(gameId, id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
getServerCalenderRemind(gameId)
}, {
error.postValue(it)
})
}
class Factory(
private val id: String
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ServersCalendarDetailsRemindViewModel(id) as T
}
}
}

View File

@ -0,0 +1,176 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.util.Log
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.databinding.ItemGameServerTestTimeBinding
import com.gh.gamecenter.databinding.ItemServerCalendarServerBinding
import com.gh.gamecenter.databinding.ItemServersCalendarBinding
import com.gh.gamecenter.feature.game.GameItemViewHolder
import splitties.views.backgroundColor
class ServersCalendarListAdapter(
context: Context,
private val viewModel: ServersCalendarListViewModel
) : ListAdapter<ServersCalendarListViewModel.ItemData>(context) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return when (viewType) {
ITEM_TYPE_FOOTER -> FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
ITEM_TYPE_DATA_ITEM -> ServersCalendarViewHolder(parent.toBinding())
else -> ServersCalendarTimeViewHolder(parent.toBinding())
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (holder) {
is ServersCalendarViewHolder -> {
val game = mEntityList[position].game ?: return
holder.binding.root.backgroundColor = ContextCompat.getColor(mContext, R.color.background_white)
holder.binding.icon.displayGameIcon(game.toGameEntity())
holder.binding.gameName.text = game.name
holder.binding.gameName.setTextColor(ContextCompat.getColor(mContext, R.color.text_title))
// 副标题
GameItemViewHolder.initGameSubtitleAndAdLabel(
game.toGameEntity(),
holder.binding.subtitle
)
// 如果开服表总数超过3个显示开服表总数
if (game.serversTotal > MAX_DISPLAY_SERVER_LIST_SIZE) {
holder.binding.serverCount.visibility = View.VISIBLE
holder.binding.serverCount.text =
holder.binding.root.context.getString(
R.string.servers_calendar_list_server_count,
game.serversTotal
)
} else {
holder.binding.serverCount.visibility = View.GONE
}
// 最多显示3条开服列表数据
val serverList = if (game.servers.size > MAX_DISPLAY_SERVER_LIST_SIZE) {
game.servers.subList(0, MAX_DISPLAY_SERVER_LIST_SIZE)
} else {
game.servers
}
holder.binding.servers.removeAllViews()
holder.binding.serversContainer.background = ContextCompat.getDrawable(
mContext,
R.drawable.bg_shape_f8_radius_8
)
serverList.forEachIndexed { index, server ->
ItemServerCalendarServerBinding.inflate(
mLayoutInflater,
holder.binding.servers,
true
).apply {
// 优先展示服务器名字,若服务器名字为空则展示备注
val note = server.getNote()
val remark = server.remark
val name = if (note.isNullOrEmpty()) remark else note
this.name.text = name
this.time.text = server.getFormatTime("HH:mm")
root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
bottomMargin = if (index < serverList.size - 1) 8F.dip2px() else 0
}
}
}
holder.binding.root.setOnClickListener {
DirectUtils.directToGameServerCalendar(
context = it.context,
gameId = game.id,
kaifuTime = game.startMidnight
)
NewLogUtils.logLaunchServerSubscribeClick(
gameId = game.id,
gameName = game.name,
launchServerTime = game.startMidnight.toInt()
)
}
}
is ServersCalendarTimeViewHolder -> {
holder.binding.root.backgroundColor = ContextCompat.getColor(mContext, R.color.background_white)
holder.binding.timeTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_subtitle))
holder.binding.timeTv.text =
ServersCalendarListFragment.formatTime(mContext, (mEntityList[position].time ?: 0) * 1000)
}
is FooterViewHolder -> initFooterViewHolder(holder, mIsLoading, mIsNetworkError, mIsOver)
}
}
fun initFooterViewHolder(
viewHolder: FooterViewHolder,
isLoading: Boolean,
isNetworkError: Boolean,
isOver: Boolean
) {
viewHolder.run {
if (isNetworkError) {
loading.visibility = View.GONE
hint.setText(R.string.loading_failed_retry)
itemView.isClickable = true
itemView.setOnClickListener { viewModel.load(LoadType.RETRY) }
} else if (isOver) {
loading.visibility = View.GONE
hint.setText(R.string.load_over_hint)
itemView.isClickable = false
itemView.setOnClickListener(null)
} else if (isLoading) {
loading.visibility = View.VISIBLE
hint.setText(R.string.loading)
itemView.isClickable = false
itemView.setOnClickListener(null)
} else {
loading.visibility = View.GONE
hint.setText(R.string.loading_more_hint)
itemView.isClickable = false
itemView.setOnClickListener(null)
}
}
}
override fun getItemViewType(position: Int): Int {
return if (mEntityList[position].footer) {
ITEM_TYPE_FOOTER
} else if(mEntityList[position].time != null) {
ITEM_TYPE_DATE_HEADER
} else {
ITEM_TYPE_DATA_ITEM
}
}
override fun getItemCount(): Int = mEntityList.size
class ServersCalendarViewHolder(val binding: ItemServersCalendarBinding) : ViewHolder(binding.root)
class ServersCalendarTimeViewHolder(var binding: ItemGameServerTestTimeBinding) : ViewHolder(binding.root)
companion object {
private const val ITEM_TYPE_FOOTER = 100
private const val ITEM_TYPE_DATE_HEADER = 200
private const val ITEM_TYPE_DATA_ITEM = 300
private const val MAX_DISPLAY_SERVER_LIST_SIZE = 3
}
}

View File

@ -0,0 +1,143 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.view.View
import android.widget.FrameLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.LazyListFragment
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.databinding.FragmentServersCalendarListBinding
import java.text.SimpleDateFormat
import java.util.*
/**
* 开服订阅-开服表
*/
class ServersCalendarListFragment :
LazyListFragment<ServersCalendarListViewModel.ItemData, ServersCalendarListViewModel>() {
private var adapter: ServersCalendarListAdapter? = null
private lateinit var viewBinding: FragmentServersCalendarListBinding
override fun getRealLayoutId(): Int {
return R.layout.fragment_servers_calendar_list
}
override fun onRealLayoutInflated(inflatedView: View) {
super.onRealLayoutInflated(inflatedView)
viewBinding = FragmentServersCalendarListBinding.bind(inflatedView)
}
override fun onRefresh() {
super.onRefresh()
viewBinding.topDateContainer.root.visibility = View.GONE
}
override fun onLoadError() {
super.onLoadError()
viewBinding.topDateContainer.root.visibility = View.GONE
}
override fun onLoadEmpty() {
super.onLoadEmpty()
viewBinding.topDateContainer.root.visibility = View.GONE
}
override fun provideListViewModel(): ServersCalendarListViewModel {
return viewModelProvider()
}
override fun provideListAdapter(): ListAdapter<*> {
return adapter ?: ServersCalendarListAdapter(
requireContext(),
mListViewModel
).apply {
adapter = this
}
}
override fun getItemDecoration(): RecyclerView.ItemDecoration? = null
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
viewBinding.subscribedGameManagementLayout.setOnClickListener {
DirectUtils.directToServersSubscribedGameList(it.context)
}
mListRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager
if (layoutManager is LinearLayoutManager && !mListViewModel.obsListData.value.isNullOrEmpty()) {
val firstVisiblePosition = layoutManager.findFirstVisibleItemPosition()
// 悬挂的文案
viewBinding.topDateContainer.root.visibility = View.VISIBLE
viewBinding.topDateContainer.timeTv.text =
formatTime(recyclerView.context, mListViewModel.getTimeByPosition(firstVisiblePosition) * 1000)
// 悬挂界面移动
val lp = viewBinding.topDateContainer.root.layoutParams as FrameLayout.LayoutParams
if (firstVisiblePosition != 0
&& mListViewModel?.getItemAtPosition(firstVisiblePosition + 1)?.time != null
) {
val bottom = layoutManager.findViewByPosition(firstVisiblePosition)?.bottom ?: 0
if (bottom <= viewBinding.topDateContainer.root.height) {
lp.topMargin = bottom - viewBinding.topDateContainer.root.height
} else {
lp.topMargin = 0
}
} else {
lp.topMargin = 0
}
viewBinding.topDateContainer.root.layoutParams = lp
}
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {}
})
}
companion object {
/**
* 将时间戳转换成开服表时间
* 开服表时间显示规则:
* 明天:目标日期=当天的下一天日期
* 今天:目标日期=当天日期
* 月日:目标日期在当前自然年以内
* 年月日:目标日期在当前自然年以外
*/
fun formatTime(context: Context, time: Long): String {
val serverCalendar = Calendar.getInstance().apply {
timeInMillis = time
}
val todayCalendar = Calendar.getInstance()
val tomorrowCalendar = Calendar.getInstance().apply {
add(Calendar.DATE, 1)
}
return if (todayCalendar.get(Calendar.YEAR) == serverCalendar.get(Calendar.YEAR)
&& todayCalendar.get(Calendar.MONTH) == serverCalendar.get(Calendar.MONTH)
&& todayCalendar.get(Calendar.DATE) == serverCalendar.get(Calendar.DATE)
) {
context.getString(R.string.servers_calendar_list_date_today)
} else if (tomorrowCalendar.get(Calendar.YEAR) == serverCalendar.get(Calendar.YEAR)
&& tomorrowCalendar.get(Calendar.MONTH) == serverCalendar.get(Calendar.MONTH)
&& tomorrowCalendar.get(Calendar.DATE) == serverCalendar.get(Calendar.DATE)
) {
context.getString(R.string.servers_calendar_list_date_tomorrow)
} else if (todayCalendar.get(Calendar.YEAR) == serverCalendar.get(Calendar.YEAR)) {
SimpleDateFormat("MM月dd日", Locale.getDefault()).format(time)
} else {
SimpleDateFormat("yyyy年MM月dd日", Locale.getDefault()).format(time)
}
}
}
}

View File

@ -0,0 +1,77 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Application
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.entity.HaloAddonEntity
import com.gh.gamecenter.feature.entity.ServerCalendarFormEntity
import com.gh.gamecenter.feature.entity.ServerCalendarGame
import com.gh.gamecenter.retrofit.RetrofitManager
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import io.reactivex.Observable
import io.reactivex.Single
class ServersCalendarListViewModel(application: Application) :
ListViewModel<ServersCalendarListViewModel.ItemData, ServersCalendarListViewModel.ItemData>(
application
) {
override fun provideDataObservable(page: Int): Observable<List<ItemData>>? {
return null
}
override fun provideDataSingle(page: Int): Single<MutableList<ItemData>> {
return RetrofitManager.getInstance().newApi
.getServerCalendarList(page, 20)
.map { list ->
val dataList = mutableListOf<ItemData>()
for (formEntity in list) {
dataList.add(ItemData(time = formEntity.startMidnight))
dataList.addAll(formEntity.games.map { game ->
ItemData(game = game.apply {
startMidnight = formEntity.startMidnight
})
})
}
dataList
}
}
fun getTimeByPosition(position: Int): Long {
var time = 0L
val dataList = mResultLiveData.value
dataList?.let {
for ((index, value) in dataList.withIndex()) {
if (value.time != null) {
time = value.time
}
if (index == position) {
return time
}
}
}
return time
}
fun getItemAtPosition(position: Int): ItemData? {
if (position < (mResultLiveData?.value?.size ?: 0)) {
return mResultLiveData.value?.get(position)
}
return null
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { list ->
mResultLiveData.postValue(
mutableListOf<ItemData>()
.also {
it.addAll(list)
it.add(ItemData(footer = true))
}
)
}
}
data class ItemData(val game: ServerCalendarGame? = null, val time: Long? = null, val footer: Boolean = false)
}

View File

@ -0,0 +1,40 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.PersistableBundle
import androidx.fragment.app.Fragment
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout
import com.gh.gamecenter.common.utils.updateStatusBarColor
class ServersCalendarManagementActivity : BaseActivity_TabLayout() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNavigationTitle(R.string.servers_calendar_subscription_title)
updateStatusBarColor(R.color.background_white, R.color.background_white)
}
override fun initFragmentList(fragments: MutableList<Fragment>?) {
fragments?.add(ServersCalendarListFragment())
fragments?.add(ServersCalendarRemindListFragment())
}
override fun initTabTitleList(tabTitleList: MutableList<String>?) {
tabTitleList?.add(getString(R.string.servers_calendar_list_tab))
tabTitleList?.add(getString(R.string.servers_calendar_remind_list_tab))
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.background_white, R.color.background_white)
}
companion object {
fun getIntent(context: Context): Intent {
return Intent(context, ServersCalendarManagementActivity::class.java)
}
}
}

View File

@ -0,0 +1,63 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Dialog
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.databinding.DialogServersCalendarMoreBinding
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
/**
* 开服日历表-更多菜单
*/
class ServersCalendarMoreDialog : BottomSheetDialogFragment() {
private lateinit var viewBinding: DialogServersCalendarMoreBinding
private val viewModel by activityViewModels<ServersCalendarViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.DialogWindowTransparent)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
window?.setWindowAnimations(R.style.community_publication_animation)
window?.setGravity(Gravity.BOTTOM)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.unsubscribe.setOnClickListener {
viewModel.unsubscribeServer()
NewLogUtils.logLaunchServerSubscribeCancel(
gameId = viewModel.game.id,
gameName = viewModel.game.name ?: ""
)
SensorsBridge.trackLaunchServerSubscribeCancelClick(
gameId = viewModel.game.id,
gameName = viewModel.game.name ?: ""
)
dismissAllowingStateLoss()
}
viewBinding.cancel.setOnClickListener {
dismissAllowingStateLoss()
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogServersCalendarMoreBinding.inflate(inflater, container, false).also {
viewBinding = it
}.root
}
}

View File

@ -0,0 +1,186 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.databinding.ItemServersCalendarRemindBinding
import com.gh.gamecenter.feature.game.GameItemViewHolder
import java.text.SimpleDateFormat
import java.util.*
class ServersCalendarRemindListAdapter(
context: Context,
private val viewModel: ServersCalendarRemindListViewModel
) : ListAdapter<ServersCalendarRemindListViewModel.ItemData>(context) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return when (viewType) {
ITEM_TYPE_FOOTER -> FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
else -> ServersCalendarRemindViewHolder(parent.toBinding())
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (holder is ServersCalendarRemindViewHolder) {
val game = mEntityList[position].game ?: return
holder.binding.icon.displayGameIcon(game.toGameEntity())
holder.binding.gameName.text = game.name
// 副标题
GameItemViewHolder.initGameSubtitleAndAdLabel(
game.toGameEntity(),
holder.binding.subtitle
)
val context = holder.binding.root.context
// 已知服: 展示设置开服时间+服务器名字/备注
// 未知服: 展示关注开服日期
val server = game.servers.firstOrNull() ?: return
val notifySetting = server.notifySetting ?: return
// 提醒状态
val notifyStatus = game.notifyStatus ?: return
if ((server.getNote()
.isNullOrEmpty() && server.remark.isEmpty()) || notifyStatus == NOTIFY_STATUS_HAS_NEW || notifyStatus == NOTIFY_STATUS_EXPIRED
) {// 未知服或未知服相关状态,仅展示日期
val format = SimpleDateFormat("MM月dd日", Locale.getDefault())
holder.binding.time.text = format.format(notifySetting.notifyTime * 1000)
} else {// 已知服
val format = SimpleDateFormat("MM月dd日 HH:mm", Locale.getDefault())
// 优先展示服务器名字,若服务器名字为空则展示备注
val note = server.getNote()
val remark = server.remark
val name = if (note.isNullOrEmpty()) remark else note
holder.binding.time.text = context.getString(
R.string.servers_calendar_remind_list_server_name,
format.format(notifySetting.notifyTime * 1000),
name
)
}
// 设置提醒状态文字颜色
val statusTextColorId = if (notifyStatus == NOTIFY_STATUS_TODO || notifyStatus == NOTIFY_STATUS_COMING) {
R.color.theme_font
} else {
R.color.text_subtitleDesc
}
holder.binding.status.setTextColor(ContextCompat.getColor(context, statusTextColorId))
// 设置提醒状态文案
val statusTextId = when (notifyStatus) {
NOTIFY_STATUS_TODO -> R.string.servers_calendar_remind_status_todo
NOTIFY_STATUS_COMING -> R.string.servers_calendar_remind_status_coming
NOTIFY_STATUS_OPENED -> R.string.servers_calendar_remind_status_opened
NOTIFY_STATUS_HAS_NEW -> R.string.servers_calendar_remind_status_has_new
else -> R.string.servers_calendar_remind_status_expired
}
holder.binding.status.text = context.getString(statusTextId)
holder.binding.root.setOnClickListener {
DirectUtils.directToGameServerCalendar(
context = it.context,
gameId = game.id,
kaifuTime = server.getTime()
)
NewLogUtils.logLaunchServerReminderClick(
gameId = game.id,
gameName = game.name,
reminderTime = (notifySetting.notifyTime - notifySetting.secondsAdvance).toInt(),
status = notifyStatus
)
}
} else if (holder is FooterViewHolder) {
initFooterViewHolder(holder, mIsLoading, mIsNetworkError, mIsOver)
}
}
fun initFooterViewHolder(
viewHolder: FooterViewHolder,
isLoading: Boolean,
isNetworkError: Boolean,
isOver: Boolean
) {
viewHolder.run {
if (isNetworkError) {
loading.visibility = View.GONE
hint.setText(R.string.loading_failed_retry)
itemView.isClickable = true
itemView.setOnClickListener { viewModel.load(LoadType.RETRY) }
} else if (isOver) {
loading.visibility = View.GONE
hint.setText(R.string.load_over_hint)
itemView.isClickable = false
itemView.setOnClickListener(null)
} else if (isLoading) {
loading.visibility = View.VISIBLE
hint.setText(R.string.loading)
itemView.isClickable = false
itemView.setOnClickListener(null)
} else {
loading.visibility = View.GONE
hint.setText(R.string.loading_more_hint)
itemView.isClickable = false
itemView.setOnClickListener(null)
}
}
}
override fun getItemViewType(position: Int): Int {
return if (mEntityList[position].footer) {
ITEM_TYPE_FOOTER
} else {
ITEM_TYPE_DATA
}
}
override fun getItemCount(): Int = mEntityList.size
class ServersCalendarRemindViewHolder(val binding: ItemServersCalendarRemindBinding) : ViewHolder(binding.root)
companion object {
/**
* 待提醒
*/
private const val NOTIFY_STATUS_TODO = "todo"
/**
* 即将开服
*/
private const val NOTIFY_STATUS_COMING = "coming"
/**
* 已开服
*/
private const val NOTIFY_STATUS_OPENED = "opened"
/**
* 有新服
*/
private const val NOTIFY_STATUS_HAS_NEW = "has_new"
/**
* 已过期
*/
private const val NOTIFY_STATUS_EXPIRED = "expired"
/**
* 未知服
*/
private const val SERVER_TYPE_UNKNOWN = "未知服"
private const val ITEM_TYPE_FOOTER = 100
private const val ITEM_TYPE_DATA = 200
}
}

View File

@ -0,0 +1,37 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.LazyListFragment
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.feature.entity.ServerCalendarGame
/**
* 开服订阅-开服提醒
*/
class ServersCalendarRemindListFragment : LazyListFragment<ServerCalendarGame, ServersCalendarRemindListViewModel>() {
private var adapter: ServersCalendarRemindListAdapter? = null
override fun provideListAdapter(): ListAdapter<*> {
return adapter ?: ServersCalendarRemindListAdapter(
requireContext(),
mListViewModel
).apply {
adapter = this
}
}
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
mCachedView.background = ContextCompat.getDrawable(requireContext(), R.color.background_white)
}
override fun getItemDecoration(): RecyclerView.ItemDecoration? = null
override fun provideListViewModel(): ServersCalendarRemindListViewModel {
return viewModelProvider()
}
}

View File

@ -0,0 +1,44 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Application
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.feature.entity.ServerCalendarGame
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.Single
class ServersCalendarRemindListViewModel(application: Application) :
ListViewModel<ServersCalendarRemindListViewModel.ItemData, ServersCalendarRemindListViewModel.ItemData>(application) {
override fun provideDataObservable(page: Int): Observable<List<ItemData>>? {
return null
}
override fun provideDataSingle(page: Int): Single<List<ItemData>> {
return RetrofitManager.getInstance().newApi
.getServerCalendarRemindList(page, 20)
.map { list ->
val dataList = mutableListOf<ItemData>()
list.forEach { game ->
if (game.servers.isNotEmpty()) {
dataList.add(ItemData(game = game))
}
}
dataList
}
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { list ->
mResultLiveData.postValue(
mutableListOf<ItemData>()
.also {
it.addAll(list)
it.add(ItemData(footer = true))
}
)
}
}
data class ItemData(val game: ServerCalendarGame? = null, val footer: Boolean = false)
}

View File

@ -0,0 +1,32 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.view.ViewGroup
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.databinding.ItemServersCalendarRemindTimeSettingBinding
import com.lightgame.adapter.BaseRecyclerAdapter
class ServersCalendarRemindTimeSettingAdapter(
context: Context,
private val itemCallback: (ServersCalendarAdvancedTime) -> Unit
) : BaseRecyclerAdapter<ServersCalendarRemindTimeSettingAdapter.ServersCalendarRemindTimeSettingViewHolder>(context) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ServersCalendarRemindTimeSettingViewHolder {
val view = mLayoutInflater.inflate(R.layout.item_servers_calendar_remind_time_setting, parent, false)
return ServersCalendarRemindTimeSettingViewHolder(ItemServersCalendarRemindTimeSettingBinding.bind(view))
}
override fun getItemCount(): Int = ServersCalendarAdvancedTime.values().size
override fun onBindViewHolder(holder: ServersCalendarRemindTimeSettingViewHolder, position: Int) {
val data = ServersCalendarAdvancedTime.values()[position]
holder.binding.nameTv.text = data.text
holder.binding.root.setOnClickListener {
itemCallback.invoke(data)
}
}
class ServersCalendarRemindTimeSettingViewHolder(val binding: ItemServersCalendarRemindTimeSettingBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,59 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Dialog
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.view.VerticalItemDecoration
import com.gh.gamecenter.databinding.DialogServersCalendarRemindTimeSettingBinding
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
/**
* 设置提醒时间弹窗
*/
class ServersCalendarRemindTimeSettingDialog : BottomSheetDialogFragment() {
private lateinit var viewBinding: DialogServersCalendarRemindTimeSettingBinding
private var selectCallback: ((ServersCalendarAdvancedTime) -> Unit)? = null
fun setSelectCallback(callback: ((ServersCalendarAdvancedTime) -> Unit)?) {
this.selectCallback = callback
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.DialogWindowTransparent)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
window?.setWindowAnimations(R.style.community_publication_animation)
window?.setGravity(Gravity.BOTTOM)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.cancel.setOnClickListener {
dismissAllowingStateLoss()
}
viewBinding.rv.adapter = ServersCalendarRemindTimeSettingAdapter(requireContext()) {
this.selectCallback?.invoke(it)
dismissAllowingStateLoss()
}
viewBinding.rv.layoutManager = LinearLayoutManager(context)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogServersCalendarRemindTimeSettingBinding.inflate(inflater, container, false).also {
viewBinding = it
}.root
}
}

View File

@ -0,0 +1,43 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.gh.gamecenter.R
import com.gh.gamecenter.common.databinding.DialogAlertDefaultBinding
import com.gh.gamecenter.common.utils.setDrawableStart
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
/**
* 游戏订阅成功-已绑定微信弹窗
*/
class ServersCalendarSubscriptionSuccessDialog : DialogFragment() {
private lateinit var viewBinding: DialogAlertDefaultBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(BottomSheetDialogFragment.STYLE_NORMAL, R.style.DialogWindowTransparent)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogAlertDefaultBinding.inflate(inflater, container, false).also {
viewBinding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.titleTv.text = getString(R.string.servers_calendar_subscription_dialog_title)
viewBinding.contentTv.text = getString(R.string.servers_calendar_subscription_dialog_content)
viewBinding.confirmTv.text = getString(R.string.servers_calendar_subscription_dialog_confirm)
viewBinding.centerDivider.visibility = View.GONE
viewBinding.cancelTv.visibility = View.GONE
viewBinding.titleTv.setDrawableStart(R.drawable.ic_reserve_success, null, null)
viewBinding.confirmTv.setOnClickListener {
dismissAllowingStateLoss()
}
}
}

View File

@ -0,0 +1,229 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Dialog
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import com.bigkoo.pickerview.adapter.ArrayWheelAdapter
import com.contrarywind.adapter.WheelAdapter
import com.contrarywind.view.WheelView
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.databinding.DialogServersCalendarTimeSettingBinding
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import java.text.SimpleDateFormat
import java.util.*
/**
* 设置开服时间弹窗
*/
class ServersCalendarTimeSettingDialog private constructor() : BottomSheetDialogFragment() {
private lateinit var viewBinding: DialogServersCalendarTimeSettingBinding
private lateinit var kaifuCalendar: Calendar
private lateinit var selectKaifuCalendar: Calendar
private val currentCalendar = Calendar.getInstance()
private val dateFormat = SimpleDateFormat("yyyy-MM-dd hh时 mm分", Locale.getDefault())
private var selectCallback: ((Long) -> Unit)? = null
fun setSelectCallback(callback: ((Long) -> Unit)?) {
this.selectCallback = callback
}
private fun dispatchSelectCallback() {
val date = viewBinding.date.adapter.getItem(viewBinding.date.currentItem)
val hour = viewBinding.hour.adapter.getItem(viewBinding.hour.currentItem)
val minute = viewBinding.minute.adapter.getItem(viewBinding.minute.currentItem)
dateFormat.parse("$date $hour $minute")?.let {
selectCallback?.invoke(it.time)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.DialogWindowTransparent)
selectKaifuCalendar = Calendar.getInstance().apply {
timeInMillis = arguments?.getLong(EntranceConsts.KEY_KAIFU_SELECT_TIME) ?: 0L
}
kaifuCalendar = Calendar.getInstance().apply {
timeInMillis = arguments?.getLong(EntranceConsts.KEY_KAIFU_TIME) ?: 0L
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
window?.setWindowAnimations(R.style.community_publication_animation)
window?.setGravity(Gravity.BOTTOM)
if (this is BottomSheetDialog) {
behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_DRAGGING) {
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
}
})
}
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogServersCalendarTimeSettingBinding.inflate(inflater, container, false).also {
viewBinding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.cancel.setOnClickListener {
dismissAllowingStateLoss()
}
viewBinding.confirm.setOnClickListener {
dispatchSelectCallback()
dismissAllowingStateLoss()
}
val dateList = buildDates(currentCalendar, kaifuCalendar)
initWheelView(
viewBinding.date,
ArrayWheelAdapter(dateList),
calculateCurrentDateItem(currentCalendar, selectKaifuCalendar),
false
)
initWheelView(
viewBinding.hour,
ArrayWheelAdapter(buildHours()),
selectKaifuCalendar.get(Calendar.HOUR_OF_DAY)
)
initWheelView(
viewBinding.minute,
ArrayWheelAdapter(buildMinutes()),
selectKaifuCalendar.get(Calendar.MINUTE)
)
}
companion object {
fun create(
kaifuSelectTime: Long,
kaifuTime: Long,
selectCallback: (Long) -> Unit
): ServersCalendarTimeSettingDialog =
ServersCalendarTimeSettingDialog().apply {
arguments = Bundle().apply {
putLong(EntranceConsts.KEY_KAIFU_SELECT_TIME, kaifuSelectTime)
putLong(EntranceConsts.KEY_KAIFU_TIME, kaifuTime)
}
setSelectCallback(selectCallback)
}
private fun initWheelView(
wheelView: WheelView,
adapter: WheelAdapter<*>,
currentIndex: Int,
isLoop: Boolean = true
) {
wheelView.javaClass.getDeclaredField("itemsVisible").apply {
isAccessible = true
set(wheelView, 7)
}
wheelView.setLabel("")
wheelView.setCyclic(isLoop)
wheelView.setGravity(Gravity.CENTER)
wheelView.adapter = adapter
wheelView.currentItem = currentIndex
wheelView.setTextSize(14F)
wheelView.setLineSpacingMultiplier(3F)
wheelView.setTextXOffset(0)
wheelView.setDividerColor(ContextCompat.getColor(wheelView.context, R.color.transparent))
wheelView.setTextColorCenter(ContextCompat.getColor(wheelView.context, R.color.text_title))
wheelView.setTextColorCenter(ContextCompat.getColor(wheelView.context, R.color.text_title))
}
private fun calculateCurrentDateItem(
currentCalendar: Calendar,
selectKaifuCalendar: Calendar
): Int {
val selectKaifuTime = Calendar.getInstance().apply {
timeInMillis = selectKaifuCalendar.timeInMillis
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
val currentTime = Calendar.getInstance().apply {
timeInMillis = currentCalendar.timeInMillis
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
return ((selectKaifuTime - currentTime) / (24 * 60 * 60 * 1000)).toInt()
}
private fun buildDates(currentCalendar: Calendar, kaifuCalendar: Calendar): List<String> {
val dateList = mutableListOf<String>()
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val calendar = Calendar.getInstance().apply {
timeInMillis = currentCalendar.timeInMillis
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
val kaifuTime = Calendar.getInstance().apply {
timeInMillis = kaifuCalendar.timeInMillis
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
var dateTime = calendar.timeInMillis
var dateOffset = (kaifuTime - dateTime) / (24 * 60 * 60 * 1000)
while (dateOffset >= 0) {
dateList.add(dateFormat.format(dateTime))
dateTime = calendar.apply {
add(Calendar.DAY_OF_YEAR, 1)
}.timeInMillis
dateOffset = (kaifuTime - dateTime) / (24 * 60 * 60 * 1000)
}
return dateList
}
private fun buildHours(): List<String> {
val hourList = mutableListOf<String>()
for (hour in 0..23) {
hourList.add("${hour}")
}
return hourList
}
private fun buildMinutes(): List<String> {
val minuteList = mutableListOf<String>()
for (minute in 0..59) {
minuteList.add("${minute}")
}
return minuteList
}
}
}

View File

@ -7,14 +7,12 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.util.CheckLoginUtils
import com.gh.gamecenter.common.utils.throwExceptionInDebug
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.throwExceptionInDebug
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.feature.entity.GameDetailServer
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.MeEntity
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.feature.entity.*
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Single
@ -23,18 +21,21 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
class ServersCalendarViewModel(
application: Application,
val game: GameEntity,
val gameServer: GameDetailServer,
var meEntity: MeEntity?
var meEntity: MeEntity?,
) : AndroidViewModel(application) {
val error = NonStickyMutableLiveData<Throwable>()
val calendarLiveData: MutableLiveData<List<CalendarEntity>> = MutableLiveData()
val serversDetailLiveData: MutableLiveData<CalendarEntity> = MutableLiveData()
val serverCalendarLiveData: MutableLiveData<MutableList<ServerCalendarEntity>> = MutableLiveData()
val serverCalendarLiveData: MutableLiveData<MutableList<ServerCalendarEntity>?> = MutableLiveData()
val serverSubscriptionLiveData = MutableLiveData<ServerSubscriptionEntity?>()
val subscribeServerSuccessEvent = MutableLiveData<Any?>()
var monthCount = 0
var curWeek = 0
@ -44,6 +45,7 @@ class ServersCalendarViewModel(
var isExistCurServer = true// 当月是否存在开服
var kaifuCalendar: Calendar? = null
init {
// checkExistCurSerer()
@ -59,21 +61,149 @@ class ServersCalendarViewModel(
}
}
/**
* 设置选中的开服表日期
* @param kaifuTime 选中日期的时间戳
*/
fun setKaifuTime(kaifuTime: Long) {
if (kaifuTime == 0L) return
val currentCalendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
val kaifuCalendar = Calendar.getInstance().also {
this.kaifuCalendar = it
it.timeInMillis = kaifuTime * 1000
}
val kaifuYear = kaifuCalendar.get(Calendar.YEAR)
val kaifuMonth = kaifuCalendar.get(Calendar.MONTH)
val currentYear = currentCalendar.get(Calendar.YEAR)
val currentMonth = currentCalendar.get(Calendar.MONTH)
this.selectedMonth = if (kaifuYear == currentYear && kaifuMonth == currentMonth - 1) {
MonthType.PREVIOUS_MONTH
} else if (kaifuYear == currentYear && kaifuMonth == currentMonth + 1) {
MonthType.NEXT_MONTH
} else {
MonthType.CUR_MONTH
}
}
@SuppressLint("CheckResult")
fun loadServerData(isMirror: Boolean = false) {
RetrofitManager.getInstance().api
.getGameServerCalendar(game.id, if (isMirror) "mirror" else "")
var apiService = RetrofitManager.getInstance().api
.getGameServerCalendar(game.id, if (isMirror) "mirror" else "", true)
if (!CheckLoginUtils.isLogin()) {
serverSubscriptionLiveData.postValue(null)
} else {
apiService = RetrofitManager.getInstance().newApi
.getServerSubscription(game.id)
.onErrorReturnItem(ServerSubscriptionEntity())
.zipWith(apiService) { subscription, list ->
serverSubscriptionLiveData.postValue(subscription)
list
}
}
apiService
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<MutableList<ServerCalendarEntity>>() {
override fun onSuccess(data: MutableList<ServerCalendarEntity>) {
serverCalendarLiveData.postValue(data)
}
override fun onFailure(exception: Exception) {
.subscribe(
{
serverCalendarLiveData.postValue(it)
},
{
serverCalendarLiveData.postValue(null)
}
})
)
}
@SuppressLint("CheckResult")
fun getServerSubscription(notifySubscribeSuccess: Boolean = false) {
if (!CheckLoginUtils.isLogin()) {
serverSubscriptionLiveData.postValue(null)
return
}
// 已登录状态下检查开服表订阅状态
RetrofitManager.getInstance().newApi
.getServerSubscription(game.id)
.onErrorReturnItem(ServerSubscriptionEntity())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
serverSubscriptionLiveData.postValue(it)
if (notifySubscribeSuccess && it.byApp) {// 发送订阅成功通知
subscribeServerSuccessEvent.postValue(null)
}
},
{
serverSubscriptionLiveData.postValue(null)
}
)
}
@SuppressLint("CheckResult")
fun subscribeServer() {
RetrofitManager.getInstance().newApi
.subscribeServer(game.id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
getServerSubscription(true)
},
{
error.postValue(it)
}
)
}
@SuppressLint("CheckResult")
fun unsubscribeServer() {
RetrofitManager.getInstance().newApi
.unsubscribeServer(game.id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
getServerSubscription()
}, {
error.postValue(it)
}
)
}
fun dispatchNotifySettingChange(id: String, notifySetting: ServerCalendarNotifySetting?) {
val serverCalendarList = serverCalendarLiveData.value ?: return
val index = serverCalendarList.indexOfFirst {
it.id == id
}
if (index != -1) {
val oldServerCalendar = serverCalendarList[index]
val newServerCalendar = ServerCalendarEntity().apply {
this.id = oldServerCalendar.id
this.setTime(oldServerCalendar.getTime())
this.setNote(oldServerCalendar.getNote())
this.remark = oldServerCalendar.remark
this.setFirstName(oldServerCalendar.getFirstName())
this.setServerName(oldServerCalendar.getServerName())
this.type = oldServerCalendar.type
this.setDataMark(oldServerCalendar.getDataMark())
this.notifySetting = notifySetting
}
serverCalendarList[index] = newServerCalendar
serverCalendarLiveData.value = serverCalendarList
}
}
@SuppressLint("CheckResult")
@ -81,7 +211,10 @@ class ServersCalendarViewModel(
val requestMap = hashMapOf<String, List<String>>()
requestMap["game"] = arrayListOf(game.id)
RetrofitManager.getInstance().api.getUserRelatedInfoByPost(UserManager.getInstance().userId, requestMap.toRequestBody())
RetrofitManager.getInstance().api.getUserRelatedInfoByPost(
UserManager.getInstance().userId,
requestMap.toRequestBody()
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<UnifiedUserTrendEntity>() {
@ -189,6 +322,19 @@ class ServersCalendarViewModel(
emitter.onSuccess(curDayData)
}.subscribe(object : BiResponse<MutableList<CalendarEntity>>() {
override fun onSuccess(data: MutableList<CalendarEntity>) {
val kaifuCalendar = this@ServersCalendarViewModel.kaifuCalendar
if (kaifuCalendar != null) {// 如果指定了选中的开服表日期,则自动唤起开服详情弹窗
val index = data.indexOfFirst {
it.year == kaifuCalendar.get(Calendar.YEAR)
&& it.month == kaifuCalendar.get(Calendar.MONTH) + 1
&& it.day == kaifuCalendar.get(Calendar.DATE)
}
if (index != -1) {
serversDetailLiveData.postValue(data[index])
}
this@ServersCalendarViewModel.kaifuCalendar = null
}
calendarLiveData.postValue(data)
}

View File

@ -0,0 +1,58 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.fragment.app.activityViewModels
import androidx.viewpager.widget.ViewPager.LayoutParams
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.databinding.DialogWechatReserveSuccessBinding
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
/**
* 游戏订阅成功-未绑定微信弹窗
*/
class ServersCalendarWeChatSubscriptionSuccessDialog : AppCompatDialogFragment() {
private lateinit var viewBinding: DialogWechatReserveSuccessBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(BottomSheetDialogFragment.STYLE_NORMAL, R.style.DialogWindowTransparent)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val rootView = DialogWechatReserveSuccessBinding.inflate(inflater, container, false)
.also {
viewBinding = it
}.root
return rootView.apply {
layoutParams = ViewGroup.LayoutParams(300F.dip2px(), LayoutParams.WRAP_CONTENT)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.closeBtn.setOnClickListener {
dismissAllowingStateLoss()
}
viewBinding.closeBtn.setOnClickListener {
dismissAllowingStateLoss()
}
viewBinding.titleIv.setImageResource(R.drawable.bg_servers_calendar_reserve_success)
viewBinding.openBtn.setOnClickListener {
it.context.startActivity(WebActivity.getBindWechatIntent(context))
dismissAllowingStateLoss()
}
viewBinding.contentTv.text = getString(R.string.servers_calendar_subscription_dialog_wechat_content)
}
}

View File

@ -1,28 +0,0 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Activity
import android.graphics.Paint
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogServersCalendearDetailItemBinding
import com.gh.gamecenter.databinding.DialogServersCalendearDetailReportItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.MeEntity
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import com.gh.gamecenter.servers.patch.PatchKaifuActivity
import com.lightgame.utils.Utils
class ServersDetailReportViewHolder(val binding: DialogServersCalendearDetailReportItemBinding) :
BaseRecyclerViewHolder<Any>(binding.root) {
fun bindItem(data: ServerCalendarEntity) {
binding.name.text = data.getNote()
binding.time.text = data.getFormatTime("HH:mm")
binding.remark.text = data.remark
binding.name.setTextColor(R.color.text_title.toColor(binding.root.context))
binding.time.setTextColor(R.color.text_title.toColor(binding.root.context))
binding.remark.setTextColor(R.color.text_title.toColor(binding.root.context))
}
}

View File

@ -1,47 +0,0 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.app.Activity
import android.graphics.Paint
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogServersCalendearDetailItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.MeEntity
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import com.gh.gamecenter.servers.patch.PatchKaifuActivity
import com.lightgame.utils.Utils
class ServersDetailViewHolder(val binding: DialogServersCalendearDetailItemBinding) :
BaseRecyclerViewHolder<Any>(binding.root) {
fun bindItem(data: ServerCalendarEntity, meEntity: MeEntity?, gameEntity: GameEntity) {
binding.name.text = data.getNote()
binding.time.text = data.getFormatTime("HH:mm")
binding.remark.text = data.remark
binding.name.setTextColor(R.color.text_title.toColor(binding.root.context))
binding.time.setTextColor(R.color.text_title.toColor(binding.root.context))
binding.remark.setTextColor(R.color.text_title.toColor(binding.root.context))
if (meEntity?.isPartTime == true) {
binding.name.paint.flags = Paint.UNDERLINE_TEXT_FLAG
binding.name.paint.isAntiAlias = true
binding.name.setOnClickListener {
val context = binding.root.context
if ("删档内测" == data.type || "不删档内测" == data.type || "公测" == data.type) {
Utils.toast(context, "开测信息不可编辑");
} else {
(context as Activity).startActivityForResult(
PatchKaifuActivity.getIntent(
context,
data,
gameEntity.id
),
ServersCalendarActivity.GAME_DETAIL_PATCH_KAIFU_REQUEST
)
}
}
}
}
}

View File

@ -0,0 +1,36 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.PersistableBundle
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.utils.updateStatusBarColor
class ServersSubscribedGameListActivity : ToolBarActivity() {
override fun provideNormalIntent(): Intent {
return getTargetIntent(
this,
ServersSubscribedGameListActivity::class.java,
ServersSubscribedGameListFragment::class.java
)
}
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
updateStatusBarColor(R.color.background_white, R.color.background_white)
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.background_white, R.color.background_white)
}
companion object {
fun getIntent(context: Context): Intent {
return Intent(context, ServersSubscribedGameListActivity::class.java)
}
}
}

View File

@ -0,0 +1,64 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.layoutInflater
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.databinding.ItemServersSubscribedGameBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.game.GameItemViewHolder
class ServersSubscribedGameListAdapter(context: Context) : ListAdapter<GameEntity>(context) {
private var onUnsubscribeClickListener: OnUnsubscribeClickListener? = null
fun setOnUnsubscribeClickListener(onUnsubscribeClickListener: OnUnsubscribeClickListener) {
this.onUnsubscribeClickListener = onUnsubscribeClickListener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ServersCalendarSubscriptionViewHolder(
ItemServersSubscribedGameBinding.inflate(
parent.layoutInflater,
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (holder is ServersCalendarSubscriptionViewHolder) {
val game = mEntityList[position]
holder.binding.icon.displayGameIcon(game)
holder.binding.gameName.text = game.name
GameItemViewHolder.initGameSubtitleAndAdLabel(game, holder.binding.subtitle)
val exposureEvent = ExposureEvent.createEvent(
game,
listOf(ExposureSource("开服管理", "游戏订阅"))
)
holder.binding.subscribe.setOnClickListener {
onUnsubscribeClickListener?.onUnsubscribeClick(game, position)
}
holder.binding.root.setOnClickListener {
GameDetailActivity.startGameDetailActivity(mContext, game.id, "开服管理-游戏订阅", exposureEvent)
}
}
}
override fun getItemCount(): Int = mEntityList.size
class ServersCalendarSubscriptionViewHolder(val binding: ItemServersSubscribedGameBinding) : ViewHolder(binding.root)
interface OnUnsubscribeClickListener {
fun onUnsubscribeClick(gameEntity: GameEntity, position: Int)
}
}

View File

@ -0,0 +1,80 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.os.Bundle
import android.view.View
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.baselist.ListFragment
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.feature.entity.GameEntity
/**
* 开服订阅-开服表-游戏订阅
*/
class ServersSubscribedGameListFragment : ListFragment<GameEntity, ServersSubscribedGameListViewModel>(),
ServersSubscribedGameListAdapter.OnUnsubscribeClickListener {
private var adapter: ServersSubscribedGameListAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNavigationTitle(getString(R.string.servers_calendar_subscribed_game_title))
mCachedView.background = ContextCompat.getDrawable(requireContext(), R.color.background_white)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mListViewModel.error.observe(viewLifecycleOwner) {
ToastUtils.showToast(getString(R.string.network_error_hint))
}
}
override fun provideListViewModel(): ServersSubscribedGameListViewModel {
return viewModelProvider()
}
override fun provideListAdapter(): ListAdapter<GameEntity> {
return adapter ?: ServersSubscribedGameListAdapter(
requireContext()
).apply {
setOnUnsubscribeClickListener(this@ServersSubscribedGameListFragment)
adapter = this
}
}
override fun onUnsubscribeClick(gameEntity: GameEntity, position: Int) {
NewLogUtils.logLaunchServerSubscribeCancel(
gameId = gameEntity.id,
gameName = gameEntity.name ?: ""
)
SensorsBridge.trackLaunchServerSubscribeCancelClick(
gameId = gameEntity.id,
gameName = gameEntity.name ?: ""
)
DialogHelper.showDialog(
context = requireContext(),
title = getString(R.string.servers_subscribed_game_unsubscribe_dialog_title),
content = getString(R.string.servers_subscribed_game_unsubscribe_dialog_content),
confirmText = getString(R.string.servers_subscribed_game_unsubscribe_dialog_confirm),
cancelText = getString(R.string.servers_subscribed_game_unsubscribe_dialog_cancel),
confirmClickCallback = {
mListViewModel.unsubscribeServer(gameEntity.id)
}
)
}
override fun getItemDecoration(): RecyclerView.ItemDecoration? = null
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mCachedView.background = ContextCompat.getDrawable(requireContext(), R.color.background_white)
}
}

View File

@ -0,0 +1,62 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.annotation.SuppressLint
import android.app.Application
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class ServersSubscribedGameListViewModel(application: Application) : ListViewModel<GameEntity, GameEntity>(application) {
val error = NonStickyMutableLiveData<Throwable>()
override fun provideDataObservable(page: Int): Observable<List<GameEntity>> {
return RetrofitManager.getInstance().newApi.serversSubscribedGameList
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) {
mResultLiveData.postValue(it)
}
}
override fun loadStatusControl(size: Int) {
when (size) {
0 -> {
mRetryParams = null
mLoadStatusLiveData.setValue(LoadStatus.INIT_EMPTY)
}
REQUEST_FAILURE_SIZE -> {
mRetryParams = mCurLoadParams
mLoadStatusLiveData.setValue(LoadStatus.INIT_FAILED)
}
else -> {
mRetryParams = null
mLoadStatusLiveData.setValue(LoadStatus.INIT_OVER)
}
}
}
@SuppressLint("CheckResult")
fun unsubscribeServer(gameId: String) {
RetrofitManager.getInstance().newApi
.unsubscribeServer(gameId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
val dataList = mListLiveData.value ?: return@subscribe
val index = dataList.indexOfFirst { it.id == gameId }
if (index != -1) {
dataList.removeAt(index)
mListLiveData.value = dataList
}
}, {
error.postValue(it)
})
}
}

View File

@ -5,6 +5,7 @@ import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.common.constant.Constants
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.core.utils.GsonUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.common.utils.createRequestBody
@ -13,9 +14,11 @@ import com.gh.gamecenter.db.info.GameTrendsInfo
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.feature.entity.MessageUnreadEntity
import com.gh.gamecenter.feature.entity.ConcernEntity
import com.gh.gamecenter.feature.entity.MessageDigestEntity
import com.gh.gamecenter.feature.entity.MessageUnreadCount
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.retrofit.service.ApiService
@ -215,10 +218,33 @@ object MessageUnreadRepository {
}
}
private fun getMessageUnreadDigestList(): Observable<List<MessageDigestEntity>> {
if (!CheckLoginUtils.isLogin()) {
return Observable.just(emptyList())
}
return mNewApi.getMessageUnreadDigestList(1, 100)
.onErrorReturnItem(emptyList())
}
// 获取新消息中心入口未读消息数量
@SuppressLint("CheckResult")
private fun loadNewMessageUnreadCount() {
Observable.zip(getNewMessageUnreadCount(), getDiscoveryData()) { t1, t2 ->
Observable.zip(getNewMessageUnreadCount(), getDiscoveryData(), getMessageUnreadDigestList()) { t1, t2, t3->
t3.forEach {
SensorsBridge.trackMessageReceive(
gameId = it.gameId,
gameName = it.gameName,
sessionMessageType = it.sessionMessageTypeChinese,
messageType = it.messageTypeChinese
)
NewLogUtils.logMessageInformPush(
gameId = it.gameId,
gameName = it.gameName,
sessionMessageType = it.sessionMessageTypeChinese,
messageType = it.messageTypeChinese
)
}
if (t1 != 0) {
messageCenterUnreadCountLiveData.postValue(t1)
t1

View File

@ -205,6 +205,10 @@ class HaloPersonalBannerAdapter(context: Context) : BaseRecyclerAdapter<Recycler
mContext.startActivity(TeenagerModeActivity.getIntent(mContext))
}
"开服管理" -> {// 开服管理
DirectUtils.directToServersCalendarManagement(mContext, "我的光环-活动位")
}
else -> {
DirectUtils.directToLinkPage(mContext, it, "我的光环banner", "")
}

View File

@ -169,6 +169,7 @@ class HaloPersonalFragment : BaseLazyFragment() {
mStubBinding.loginMessageHint.visibility == View.VISIBLE,
"我的"
)
SensorsBridge.trackMessageCenterClick()
// 优先进入有数字提醒的消息tab其次是有红点提醒的游戏动态最后是没有提醒的消息tab
val defaultTabIndex = if ((mUnreadViewModel.messageUnreadCountLiveData.value?.message

View File

@ -199,6 +199,10 @@ class HaloPersonalFunctionAdapter(context: Context) : BaseRecyclerAdapter<Recycl
mContext.startActivity(GameArchiveListActivity.getIntent(mContext))
}
"开服管理" -> {// 开服管理
DirectUtils.directToServersCalendarManagement(mContext, "我的光环-更多功能")
}
else -> {
DirectUtils.directToLinkPage(mContext, it, "我的光环", "更多功能")
}

View File

@ -233,6 +233,10 @@ class HaloPersonalRecommendAdapter(val context: Context) : BaseRecyclerAdapter<R
mContext.startActivity(GameArchiveListActivity.getIntent(mContext))
}
"开服管理" -> {// 开服管理
DirectUtils.directToServersCalendarManagement(mContext, "我的光环-推荐位")
}
else -> {
DirectUtils.directToLinkPage(mContext, it, "我的光环", "推荐位")
}

View File

@ -34,7 +34,6 @@ import org.greenrobot.eventbus.EventBus
import retrofit2.HttpException
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
class HaloPersonalViewModel(application: Application) : AndroidViewModel(application) {
@ -71,6 +70,7 @@ class HaloPersonalViewModel(application: Application) : AndroidViewModel(applica
recommendData.postValue(it.addons)
}
}
"activity" -> activityData.postValue(it.addons)
"more_features" -> moreFeaturesData.postValue(it.addons)
}
@ -159,9 +159,11 @@ class HaloPersonalViewModel(application: Application) : AndroidViewModel(applica
"game" -> {
GameDetailActivity.startGameDetailActivity(context, data.link, entrance)
}
"news" -> {
context.startActivity(NewsDetailActivity.getIntentById(context, data.link, entrance))
}
"column" -> {
SubjectActivity.startSubjectActivity(
context,
@ -172,6 +174,7 @@ class HaloPersonalViewModel(application: Application) : AndroidViewModel(applica
entrance
)
}
else -> {
val linkEntity = LinkEntity()
linkEntity.type = data.type

View File

@ -1,14 +1,13 @@
package com.gh.gamecenter.qa.article.detail
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import androidx.core.view.NestedScrollingParent2
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.RecyclerView
import com.lightgame.utils.Utils
/**
* 资讯详情-外层列表控件
@ -35,6 +34,7 @@ class ArticleDetailRecyclerView @JvmOverloads constructor(
}
override fun onStartNestedScroll(child: View, target: View, axes: Int, type: Int): Boolean {
Utils.log("ArticleDetailRv->onStartNestedScroll->child: $child, $target, axes: $axes, type: $type")
val handleNestedScroll = (axes and View.SCROLL_AXIS_VERTICAL != 0)
if (handleNestedScroll) {
if (type == ViewCompat.TYPE_TOUCH) {
@ -46,10 +46,12 @@ class ArticleDetailRecyclerView @JvmOverloads constructor(
}
override fun onNestedScrollAccepted(child: View, target: View, axes: Int, type: Int) {
Utils.log("ArticleDetailRv->onNestedScrollAccepted->child: $child, target: $target, axes: $axes, type: $type")
onNestedScrollAccepted(child, target, axes)
}
override fun onStopNestedScroll(target: View, type: Int) {
Utils.log("ArticleDetailRv->onStopNestedScroll->target: $target, type: $type")
onStopNestedScroll(target)
if (type == ViewCompat.TYPE_NON_TOUCH) {
targetNestedScrollingView = null
@ -57,12 +59,15 @@ class ArticleDetailRecyclerView @JvmOverloads constructor(
}
override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
Utils.log("ArticleDetailRv->onNestedPreScroll->$target, dx: $dx, dy: $dy, consumed: $consumed, type: $type")
// 该回调发生在内层RecyclerView滚动之前
// 如果是向下滚动并且外层RecyclerView未滚动到底部由外层RecyclerView进行滚动
if (dy > 0 && canScrollVertically(1)) {
Utils.log("ArticleDetailRv->onNestedPreScroll1->$target, dx: $dx, dy: $dy, consumed: $consumed, type: $type")
scrollBy(0, dy)
consumed[1] = dy
} else {
Utils.log("ArticleDetailRv->onNestedPreScroll2->$target, dx: $dx, dy: $dy, consumed: $consumed, type: $type")
onNestedPreScroll(target, dx, dy, consumed)
}
}
@ -75,12 +80,25 @@ class ArticleDetailRecyclerView @JvmOverloads constructor(
dyUnconsumed: Int,
type: Int
) {
Utils.log("ArticleDetailRv->onNestedScroll->$target, dxConsumed: $dxConsumed, dyConsumed: $dyConsumed, dxUnconsumed: $dxUnconsumed, dyUnconsumed: $dyUnconsumed, type: $type")
// 该回调发生在内层RecyclerView滚动之后
// 如果是向上滚动并且内层RecyclerView滚动到顶部由外层RecyclerView进行滚动
if (dyConsumed == 0 && dyUnconsumed < 0) {
Utils.log("ArticleDetailRv->onNestedScroll1->$target, dxConsumed: $dxConsumed, dyConsumed: $dyConsumed, dxUnconsumed: $dxUnconsumed, dyUnconsumed: $dyUnconsumed, type: $type")
scrollBy(0, dyUnconsumed)
} else {
Utils.log("ArticleDetailRv->onNestedScroll2->$target, dxConsumed: $dxConsumed, dyConsumed: $dyConsumed, dxUnconsumed: $dxUnconsumed, dyUnconsumed: $dyUnconsumed, type: $type")
onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed)
}
}
override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {
Utils.log("ArticleDetailRv->onNestedPreFling->$target, velocityX: $velocityX, velocityY: $velocityY")
return super.onNestedPreFling(target, velocityX, velocityY)
}
override fun onNestedFling(target: View, velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {
Utils.log("ArticleDetailRv->onNestedFling->$target, velocityX: $velocityX, velocityY: $velocityY, consumed:$consumed")
return super.onNestedFling(target, velocityX, velocityY, consumed)
}
}

View File

@ -365,7 +365,7 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
mViewModel.currentToolbarStatus = isToolbarWhite
mBinding.toolbar.setNavigationIcon(R.drawable.ic_bar_back_light)
mMoreMenuItem?.setIcon(R.drawable.ic_menu_gamedetail_more_light)
mMoreMenuItem?.setIcon(R.drawable.ic_menu_more_light)
mBinding.toolbar.setBackgroundColor(
ContextCompat.getColor(
requireContext(),

View File

@ -3,13 +3,10 @@ package com.gh.gamecenter.retrofit;
import android.content.Context;
import com.gh.common.constant.Config;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.retrofit.BaseRetrofitManager;
import com.gh.gamecenter.common.utils.EnvHelper;
import com.gh.gamecenter.retrofit.service.ApiService;
import com.gh.gamecenter.retrofit.service.VApiService;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
import okhttp3.OkHttpClient;
@ -30,7 +27,7 @@ public class RetrofitManager extends BaseRetrofitManager {
mApiService = provideService(okHttpNormalConfig, Config.API_HOST, ApiService.class);
mNewApiService = provideService(okHttpNormalConfig, Config.NEW_API_HOST, ApiService.class);
mUploadApiService = provideService(getOkHttpConfig(context, UPLOAD_CALL_TIME_OUT, 1), Config.API_HOST, ApiService.class);
mVApiService = provideService(okHttpNormalConfig, Config.VAPI_HOST, VApiService.class);
mVApiService = provideService(okHttpNormalConfig, Config.VAPI_HOST, VApiService.class);;
}
public static RetrofitManager getInstance() {

View File

@ -19,6 +19,9 @@ import com.gh.gamecenter.entity.BlockEntity;
import com.gh.gamecenter.entity.CarouselEntity;
import com.gh.gamecenter.entity.CatalogEntity;
import com.gh.gamecenter.entity.CategoryEntity;
import com.gh.gamecenter.entity.ServerSubscriptionEntity;
import com.gh.gamecenter.feature.entity.CommentEntity;
import com.gh.gamecenter.feature.entity.CommentnumEntity;
import com.gh.gamecenter.entity.CommonCollectionContentEntity;
import com.gh.gamecenter.entity.CommonCollectionEntity;
import com.gh.gamecenter.entity.DefaultAvatar;
@ -52,6 +55,11 @@ import com.gh.gamecenter.entity.HomeItemTestV2Entity;
import com.gh.gamecenter.entity.ImageInfoEntity;
import com.gh.gamecenter.entity.InterestedGameEntity;
import com.gh.gamecenter.entity.LibaoDetailEntity;
import com.gh.gamecenter.feature.entity.LibaoEntity;
import com.gh.gamecenter.feature.entity.LibaoStatusEntity;
import com.gh.gamecenter.feature.entity.MessageDigestEntity;
import com.gh.gamecenter.feature.entity.MessageUnreadCount;
import com.gh.gamecenter.feature.entity.MessageUnreadEntity;
import com.gh.gamecenter.entity.MyVideoEntity;
import com.gh.gamecenter.entity.NewApiSettingsEntity;
import com.gh.gamecenter.entity.NewSettingsEntity;
@ -87,6 +95,11 @@ import com.gh.gamecenter.entity.VideoDataOverViewEntity;
import com.gh.gamecenter.entity.VideoDraftEntity;
import com.gh.gamecenter.entity.VideoEntity;
import com.gh.gamecenter.entity.VideoTagEntity;
import com.gh.gamecenter.feature.entity.ServerCalendarFormEntity;
import com.gh.gamecenter.feature.entity.ServerCalendarGame;
import com.gh.gamecenter.feature.entity.ServerCalendarNotifySetting;
import com.gh.gamecenter.feature.entity.WXSubscribeMsgConfig;
import com.gh.gamecenter.feature.entity.ViewsEntity;
import com.gh.gamecenter.entity.VoteEntity;
import com.gh.gamecenter.feature.entity.AnswerEntity;
import com.gh.gamecenter.feature.entity.ApkEntity;
@ -116,6 +129,7 @@ import com.gh.gamecenter.gamedetail.entity.BigEvent;
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity;
import com.gh.gamecenter.login.entity.UserInfoEntity;
import com.gh.gamecenter.personalhome.rating.MyRating;
import com.gh.gamecenter.qa.entity.TopCommunityCategory;
import com.gh.gamecenter.qa.entity.AnswerDetailEntity;
import com.gh.gamecenter.qa.entity.AnswerDraftEntity;
import com.gh.gamecenter.qa.entity.ArticleDetailEntity;
@ -1979,7 +1993,9 @@ public interface ApiService {
* 获取游戏开服详情数据(注:和游戏详情获取到的开服数据是有区别的)
*/
@GET("games/{game_id}/server_calendar")
Single<List<ServerCalendarEntity>> getGameServerCalendar(@Path("game_id") String gameId, @Query("view") String view);
Single<List<ServerCalendarEntity>> getGameServerCalendar(@Path("game_id") String gameId,
@Query("view") String view,
@Query("refresh") boolean refresh);
/**
* 获取游戏上传提示
@ -3225,4 +3241,84 @@ public interface ApiService {
*/
@POST("/users/games/{gameId}/archives/{archiveId}/replace")
Single<ResponseBody> replaceArchive(@Path("gameId") String gameId, @Path("archiveId") String archiveId, @Body RequestBody body);
/**
* 游戏开服-加入订阅
*/
@POST("games/{game_id}/servers/subscriptions")
Observable<ResponseBody> subscribeServer(@Path("game_id") String gameId);
/**
* 游戏开服-获取订阅状态
*/
@GET("games/{game_id}/servers/subscriptions")
Single<ServerSubscriptionEntity> getServerSubscription(@Path("game_id") String gameId);
/**
* 游戏开服-取消订阅
*/
@DELETE("games/{game_id}/servers/subscriptions")
Observable<ResponseBody> unsubscribeServer(@Path("game_id") String gameId);
/**
* 游戏开服-开服提醒-添加
*/
@POST("games/{game_id}/server_calendar/{item_id_or_time}/notify_setting")
Single<ResponseBody> addServerCalendarRemind(@Path("game_id") String gameId,
@Path("item_id_or_time") String itemIdOrTime,
@Body RequestBody body);
/**
* 游戏开服-开服提醒-取消
*/
@DELETE("games/{game_id}/server_calendar/{item_id_or_time}/notify_setting")
Single<ResponseBody> removeServerCalendarRemind(@Path("game_id") String gameId,
@Path("item_id_or_time") String itemIdOrTime);
/**
* 游戏开服-开服提醒-获取
*/
@GET("games/{game_id}/server_calendar/{item_id_or_time}/notify_setting")
Single<ServerCalendarNotifySetting> getServerCalendarRemind(@Path("game_id") String gameId,
@Path("item_id_or_time") String itemIdOrTime);
/**
* 游戏开服-获取订阅游戏列表
*/
@GET("games/servers/subscribe_games")
Observable<List<GameEntity>> getServersSubscribedGameList();
/**
* 游戏开服-开服订阅-开服表
*/
@GET("games/servers/notify_servers")
Single<List<ServerCalendarFormEntity>> getServerCalendarList(@Query("page") int page,
@Query("page_size") int pageSize);
/**
* 游戏开服-开服订阅-开服提醒
*/
@GET("games/servers/notify_games")
Single<List<ServerCalendarGame>> getServerCalendarRemindList(@Query("page") int page,
@Query("page_size") int pageSize);
/**
* 游戏开服-开服订阅-获取微信一次订阅消息的参数数据
*/
@GET("messages/wechat/one_time/config")
Single<WXSubscribeMsgConfig> getWxSubscribeMsgConfig(@Query("filter") String filter);
/**
* 游戏开服-开服订阅-提交微信一次订阅消息的授权结果回调
*/
@POST("messages/wechat/one_time/call_back")
Single<ResponseBody> postWxSubscribeMsgCallback(@Query("filter") String filter,
@Body RequestBody body);
/**
* 未读消息-埋点数据提供
*/
@GET("messages/unread/event")
Observable<List<MessageDigestEntity>> getMessageUnreadDigestList(@Query("page") int page,
@Query("page_size") int pageSize);
}