Compare commits

...

2 Commits

114 changed files with 5142 additions and 302 deletions

View File

@ -72,6 +72,7 @@ android_build:
only:
- dev
- dev-5.32.0
- feature-GHZS-3350
# 代码检查
sonarqube_analysis:
@ -136,7 +137,7 @@ oss-upload&send-email:
BUCKET: "shanqu" # 固定值
FILE_PATH: "app/build/tmp/" # APK 存放路径
Email_To_List: $EMAIL_TO_LIST # 邮件接受人列表
Email_Title: "光环助手 $CI_COMMIT_BRANCH" # 邮件标题
Email_Title: "光环助手】游戏开服/开测消息通知 $CI_COMMIT_BRANCH" # 邮件标题
PIPELINE_ID: $CI_PIPELINE_ID # 流水线id
COMMIT_BRANCH: $CI_COMMIT_BRANCH # 提交分支
MAIL_MESSAGE: "[$CI_COMMIT_AUTHOR] $CI_COMMIT_MESSAGE"
@ -152,4 +153,5 @@ oss-upload&send-email:
- /usr/local/bin/python /ci-android-mail.py
only:
- dev
- dev-5.32.0
- dev-5.32.0
- feature-GHZS-3350

View File

@ -474,6 +474,14 @@
android:name="com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity"
android:screenOrientation="portrait" />
<activity
android:name=".gamedetail.fuli.kaifu.ServersCalendarManagementActivity"
android:screenOrientation="portrait" />
<activity
android:name=".gamedetail.fuli.kaifu.ServersSubscribedGameListActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.answer.draft.AnswerDraftActivity"
android:screenOrientation="portrait" />
@ -753,10 +761,6 @@
android:name="com.gh.gamecenter.qgame.QGameSearchActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameSubjectActivity"
android:screenOrientation="portrait" />
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->

View File

@ -61,6 +61,8 @@ import com.gh.gamecenter.gamecollection.hotlist.GameCollectionHotListActivity
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
@ -189,6 +191,8 @@ object DirectUtils {
}
}
"game_server_calendar" -> directToGameServerCalendar(context, linkEntity.link)
"column", "游戏专题" -> directToSubject(
context, linkEntity.link
?: "", linkEntity.text, BaseActivity.mergeEntranceAndPath(entrance, path), exposureEvent
@ -512,12 +516,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)
@ -2080,4 +2085,24 @@ object DirectUtils {
.withInt(BaseActivity_TabLayout.PAGE_INDEX, defaultTabIndex)
.navigation()
}
/**
* 跳转到游戏订阅页面
* @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

@ -2486,4 +2486,181 @@ object NewLogUtils {
}
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_cancel"
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

@ -396,7 +396,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

@ -1641,7 +1641,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.exposure.meta.MetaUtil.refreshMeta
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.SPUtils
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
@ -106,6 +110,8 @@ class ServersCalendarActivity : ToolBarActivity() {
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))
mViewModel.calendarLiveData.observeNonNull(this, callback = {
val adapter = ServersCalendarAdapter(this, mViewModel, it)
mBinding.recyclerView.isNestedScrollingEnabled = false
@ -113,7 +119,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 +131,49 @@ 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
)
}
}
mBaseHandler.postDelayed(mDelayLogRunnable, 3000)
}
@ -133,6 +182,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
@ -276,129 +334,52 @@ 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 subscriptionStatus = mViewModel.serverSubscriptionLiveData.value
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 +404,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,149 @@
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.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>(COMPARATOR) {
companion object {
private val COMPARATOR = 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, "游戏详情-开服日历表-开服详情-开服提醒") {
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,168 @@
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.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.ListAdapter
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.dip2px
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.databinding.DialogServersCalendearDetailBinding
import com.gh.gamecenter.databinding.DialogServersCalendearDetailItemBinding
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 com.lightgame.adapter.BaseRecyclerAdapter
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(savedInstanceState)
setStyle(STYLE_NO_TITLE, R.style.DialogWindowTransparent)
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)
)
)
}
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,263 @@
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 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.databinding.DialogServersCalendearDetailBinding
import com.gh.gamecenter.databinding.LayoutServersCalendarDetailNoDataBinding
import com.gh.gamecenter.feature.entity.ServerCalendarNotifySetting
import com.gh.gamecenter.help.HelpAndFeedbackBridge
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())
}
}.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
}
)
}
wxApi.liveData.observe(viewLifecycleOwner) {
if (it.action == "confirm") {
viewModel.addServerCalendarRemindWithWechat(
gameId = parentViewModel.game.id,
openId = it.openId,
templateId = it.templateID,
action = it.action,
reserved = it.reserved,
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
appRemind.alpha = 0.4F
appRemind.setOnClickListener(null)
wechatRemind.isEnabled = false
wechatRemind.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_remind)
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
appRemind.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
wechatRemind.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, "游戏详情-开服日历表-未知服详情") {
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,131 @@
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.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 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)
}, {})
}
@SuppressLint("CheckResult")
fun removeServerCalendarRemind(gameId: String) {
RetrofitManager.getInstance().newApi
.removeServerCalendarRemind(gameId, timeInSeconds.toString())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
getServerCalenderRemind(gameId)
}, {
it.printStackTrace()
})
}
@SuppressLint("CheckResult")
fun getWXSubscribeMsgConfig() {
RetrofitManager.getInstance().testApi
.getWxSubscribeMsgConfig(UrlFilterUtils.getFilterQuery("type", "server_new"))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
wxSubscribeMsgConfigLiveData.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)
}, {})
}
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,305 @@
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.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.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.appRemind.alpha = 0.4F
viewBinding.appRemind.isEnabled = false
viewBinding.wechatRemind.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 {
viewModel.removeServerCalendarRemind(activityViewModel.game.id)
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 = "已知服"
)
}
} 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.appRemind.alpha = 1.0F
viewBinding.appRemind.isEnabled = true
viewBinding.wechatRemind.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 {
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@setOnClickListener
}
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
}
)
}
wxApi.liveData.observe(viewLifecycleOwner) {
if (it.action == "confirm") {
viewModel.addServerCalendarRemindWithWechat(
gameId = activityViewModel.game.id,
openId = it.openId,
templateId = it.templateID,
action = it.action,
reserved = it.reserved,
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,149 @@
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.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() {
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().testApi
.getWxSubscribeMsgConfig(UrlFilterUtils.getFilterQuery("type", "server_open"))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
wxSubscribeMsgConfigLiveData.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)
}, {})
}
@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)
}, {})
}
@SuppressLint("CheckResult")
fun removeServerCalendarRemind(gameId: String) {
RetrofitManager.getInstance().newApi
.removeServerCalendarRemind(gameId, id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
getServerCalenderRemind(gameId)
}, {})
}
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,164 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.view.View
import android.view.ViewGroup
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
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!!
holder.binding.icon.displayGameIcon(game.toGameEntity())
holder.binding.gameName.text = game.name
// 副标题
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()
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.timeTv.text =
ServersCalendarListFragment.formatTime(mContext, mEntityList[position].time!! * 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,144 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.os.Bundle
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.game.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,22 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.content.Intent
import com.gh.gamecenter.common.base.activity.ToolBarActivity
class ServersCalendarManagementActivity : ToolBarActivity() {
override fun provideNormalIntent(): Intent {
return getTargetIntent(
this,
ServersCalendarManagementActivity::class.java,
ServersCalendarManagementFragment::class.java
)
}
companion object {
fun getIntent(context: Context): Intent {
return Intent(context, ServersCalendarManagementActivity::class.java)
}
}
}

View File

@ -0,0 +1,27 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.os.Bundle
import androidx.fragment.app.Fragment
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseFragment_TabLayout
/**
* 开服订阅
*/
class ServersCalendarManagementFragment : BaseFragment_TabLayout() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNavigationTitle(getString(R.string.servers_calendar_subscription_title))
}
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))
}
}

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,184 @@
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!!
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.first()
val notifySetting = server.notifySetting!!
if (server.getNote().isNullOrEmpty() && server.remark.isEmpty()) {// 未知服
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 notifyStatus = game.notifyStatus!!
// 设置提醒状态文字颜色
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.white)
}
override fun getItemDecoration(): RecyclerView.ItemDecoration? = null
override fun provideListViewModel(): ServersCalendarRemindListViewModel {
return viewModelProvider()
}
}

View File

@ -0,0 +1,36 @@
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 -> list.map { ItemData(game = it) } }
}
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,60 @@
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)
viewBinding.rv.addItemDecoration(VerticalItemDecoration(context, 1, false, R.color.divider))
}
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,204 @@
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)
)
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
) {
wheelView.javaClass.getDeclaredField("itemsVisible").apply {
isAccessible = true
set(wheelView, 7)
}
wheelView.setLabel("")
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 = selectKaifuCalendar.timeInMillis
val currentTime = currentCalendar.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
}
val kaifuTime = kaifuCalendar.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,11 @@ 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.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 +20,19 @@ 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 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 +42,7 @@ class ServersCalendarViewModel(
var isExistCurServer = true// 当月是否存在开服
var kaifuCalendar: Calendar? = null
init {
// checkExistCurSerer()
@ -59,21 +58,138 @@ 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) }, {})
}
@SuppressLint("CheckResult")
fun unsubscribeServer() {
RetrofitManager.getInstance().newApi
.unsubscribeServer(game.id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
getServerSubscription()
}, {})
}
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 +197,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 +308,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_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,22 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.content.Context
import android.content.Intent
import com.gh.gamecenter.common.base.activity.ToolBarActivity
class ServersSubscribedGameListActivity : ToolBarActivity() {
override fun provideNormalIntent(): Intent {
return getTargetIntent(
this,
ServersSubscribedGameListActivity::class.java,
ServersSubscribedGameListFragment::class.java
)
}
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,65 @@
package com.gh.gamecenter.gamedetail.fuli.kaifu
import android.os.Bundle
import android.view.View
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.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))
}
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
}

View File

@ -0,0 +1,57 @@
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.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) {
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
}
}, {})
}
}

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

@ -35,6 +35,7 @@ class ArticleDetailRecyclerView @JvmOverloads constructor(
}
override fun onStartNestedScroll(child: View, target: View, axes: Int, type: Int): Boolean {
Log.d("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 +47,12 @@ class ArticleDetailRecyclerView @JvmOverloads constructor(
}
override fun onNestedScrollAccepted(child: View, target: View, axes: Int, type: Int) {
Log.d("ArticleDetailRv", "onNestedScrollAccepted->child: $child, target: $target, axes: $axes, type: $type")
onNestedScrollAccepted(child, target, axes)
}
override fun onStopNestedScroll(target: View, type: Int) {
Log.d("ArticleDetailRv", "onStopNestedScroll->target: $target, type: $type")
onStopNestedScroll(target)
if (type == ViewCompat.TYPE_NON_TOUCH) {
targetNestedScrollingView = null
@ -57,12 +60,15 @@ class ArticleDetailRecyclerView @JvmOverloads constructor(
}
override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
Log.d("ArticleDetailRv", "onNestedPreScroll->$target, dx: $dx, dy: $dy, consumed: $consumed, type: $type")
// 该回调发生在内层RecyclerView滚动之前
// 如果是向下滚动并且外层RecyclerView未滚动到底部由外层RecyclerView进行滚动
if (dy > 0 && canScrollVertically(1)) {
Log.d("ArticleDetailRv", "onNestedPreScroll1->$target, dx: $dx, dy: $dy, consumed: $consumed, type: $type")
scrollBy(0, dy)
consumed[1] = dy
} else {
Log.d("ArticleDetailRv", "onNestedPreScroll2->$target, dx: $dx, dy: $dy, consumed: $consumed, type: $type")
onNestedPreScroll(target, dx, dy, consumed)
}
}
@ -75,12 +81,25 @@ class ArticleDetailRecyclerView @JvmOverloads constructor(
dyUnconsumed: Int,
type: Int
) {
Log.d("ArticleDetailRv", "onNestedScroll->$target, dxConsumed: $dxConsumed, dyConsumed: $dyConsumed, dxUnconsumed: $dxUnconsumed, dyUnconsumed: $dyUnconsumed, type: $type")
// 该回调发生在内层RecyclerView滚动之后
// 如果是向上滚动并且内层RecyclerView滚动到顶部由外层RecyclerView进行滚动
if (dyConsumed == 0 && dyUnconsumed < 0) {
Log.d("ArticleDetailRv", "onNestedScroll1->$target, dxConsumed: $dxConsumed, dyConsumed: $dyConsumed, dxUnconsumed: $dxUnconsumed, dyUnconsumed: $dyUnconsumed, type: $type")
scrollBy(0, dyUnconsumed)
} else {
Log.d("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 {
Log.d("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 {
Log.d("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

@ -9,7 +9,6 @@ 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;
@ -24,6 +23,8 @@ public class RetrofitManager extends BaseRetrofitManager {
private final ApiService mUploadApiService;
private final VApiService mVApiService;
private final ApiService mTestApiService;
private RetrofitManager() {
Context context = HaloApp.getInstance().getApplicationContext();
OkHttpClient okHttpNormalConfig = getOkHttpConfig(context, 0, 2);
@ -31,6 +32,7 @@ public class RetrofitManager extends BaseRetrofitManager {
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);
mTestApiService = provideService(okHttpNormalConfig, "http://192.168.14.199:8881", ApiService.class);
}
public static RetrofitManager getInstance() {
@ -45,6 +47,10 @@ public class RetrofitManager extends BaseRetrofitManager {
return mNewApiService;
}
public ApiService getTestApi() {
return mTestApiService;
}
public ApiService getUploadApi() {
return mUploadApiService;
}

View File

@ -19,6 +19,7 @@ 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;
@ -93,6 +94,10 @@ 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;
@ -1122,6 +1127,7 @@ public interface ApiService {
/**
* 内容详情-相关内容列表
*
* @param contentId 内容ID
*/
@GET("bbses/contents/{content_id}/related_contents")
@ -1978,7 +1984,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);
/**
* 获取游戏上传提示
@ -3200,4 +3208,78 @@ public interface ApiService {
*/
@GET("messages/count/unread")
Single<MessageUnreadCount> getMessageUnreadCount();
/**
* 游戏开服-加入订阅
*/
@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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient android:startColor="@color/white"
android:endColor="@color/transparent"
android:angle="90" />
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient android:startColor="@color/transparent"
android:endColor="@color/white"
android:angle="90" />
</shape>

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:topLeftRadius="12dp"
android:topRightRadius="12dp"
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp" />
<solid android:color="@color/background_white" />
</shape>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/ic_servers_calendar_detail_cancel_remind" />
<item android:state_selected="true" android:drawable="@drawable/ic_servers_calendar_detail_cancel_remind" />
<item android:drawable="@drawable/ic_servers_calendar_detail_remind" />
</selector>

View File

@ -148,6 +148,46 @@
app:layout_constraintTop_toBottomOf="@id/recycler_view"
tools:text="官方服:腾讯版 \n混服九游" />
<TextView
android:id="@+id/subscribe_hint_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:layout_marginBottom="7dp"
android:text="@string/servers_calendar_subscribe_hint_1"
android:textColor="@color/text_subtitleDesc"
android:textSize="11sp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="@id/subscribe"
app:layout_constraintBottom_toTopOf="@id/subscribe_hint_2" />
<TextView
android:id="@+id/subscribe_hint_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:layout_marginBottom="15dp"
android:text="@string/servers_calendar_subscribe_hint_2"
android:textColor="@color/text_subtitleDesc"
android:textSize="11sp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="@id/subscribe"
app:layout_constraintBottom_toTopOf="@id/subscribe" />
<TextView
android:id="@+id/subscribe"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
style="@style/PrimaryGradientButton"
android:gravity="center"
android:text="@string/servers_calendar_subscribe"
android:textSize="14sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<include

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@drawable/bg_shape_white_radius_12_top_only"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/servers_calendar_more_dialog_title"
android:textColor="@color/text_subtitleDesc"
android:textSize="14sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<LinearLayout
android:id="@+id/unsubscribe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintStart_toStartOf="parent"
android:gravity="center"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="@dimen/divider_1px"
android:background="@color/divider" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:text="@string/servers_calendar_dialog_unsubscribe_title"
android:textSize="16sp"
android:layout_marginTop="16dp"
android:textColor="@color/text_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:layout_marginTop="4dp"
android:layout_marginBottom="16dp"
android:textSize="12sp"
android:textColor="@color/text_subtitleDesc"
android:text="@string/servers_calendar_dialog_unsubscribe_hint" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/divider_1px"
android:background="@color/divider" />
</LinearLayout>
<TextView
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:text="@string/servers_calendar_more_dialog_cancel_title"
android:gravity="center"
android:background="@drawable/bg_shape_f5_radius_999"
app:layout_constraintTop_toBottomOf="@id/unsubscribe"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@drawable/bg_shape_white_radius_12_top_only"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:includeFontPadding="false"
android:text="@string/servers_calendar_remind_time_setting_dialog_title"
android:textColor="@color/text_subtitleDesc"
android:textSize="14sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<View
android:id="@+id/divider_1"
android:layout_width="match_parent"
android:layout_height="@dimen/divider_1px"
android:background="@color/divider"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/divider_1"
app:layout_constraintStart_toStartOf="parent" />
<View
android:id="@+id/divider_2"
android:layout_width="match_parent"
android:layout_height="@dimen/divider_1px"
android:background="@color/divider"
app:layout_constraintTop_toBottomOf="@id/rv" />
<TextView
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:text="@string/servers_calendar_more_dialog_cancel_title"
android:gravity="center"
android:background="@drawable/bg_shape_f5_radius_999"
app:layout_constraintTop_toBottomOf="@id/divider_2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:padding="16dp"
android:layout_gravity="bottom"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/bg_shape_white_radius_12_top_only">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="@color/text_title"
android:textSize="16sp"
android:text="@string/servers_calendar_time_setting_dialog_title"/>
<View
android:id="@+id/datetime_picker_select_bg"
android:layout_width="match_parent"
android:layout_height="36dp"
android:background="@drawable/bg_shape_f5_radius_8"
app:layout_constraintTop_toTopOf="@id/datetime_picker"
app:layout_constraintBottom_toBottomOf="@id/datetime_picker" />
<LinearLayout
android:id="@+id/datetime_picker"
android:layout_width="match_parent"
android:layout_height="160dp"
android:orientation="horizontal"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@id/title">
<com.contrarywind.view.WheelView
android:id="@+id/date"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/hour"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/minute"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
<View
android:id="@+id/datetime_picker_mask_top"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="@drawable/bg_datetime_picker_mask_top"
app:layout_constraintTop_toTopOf="@id/datetime_picker" />
<View
android:id="@+id/datetime_picker_mask_bottom"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="@drawable/bg_datetime_picker_mask_bottom"
app:layout_constraintBottom_toBottomOf="@id/datetime_picker" />
<TextView
android:id="@+id/cancel"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="@string/servers_calendar_time_setting_dialog_cancel"
android:gravity="center"
android:layout_marginTop="16dp"
android:textSize="14sp"
android:textColor="@color/text_subtitle"
android:background="@drawable/bg_shape_f5_radius_999"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/datetime_picker"
app:layout_constraintEnd_toStartOf="@id/confirm" />
<TextView
android:id="@+id/confirm"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="@string/servers_calendar_time_setting_dialog_confirm"
android:gravity="center"
android:background="@drawable/download_button_normal_style"
android:textColor="@color/white"
android:textSize="14sp"
android:layout_marginStart="8dp"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintTop_toTopOf="@id/cancel"
app:layout_constraintBottom_toBottomOf="@id/cancel"
app:layout_constraintStart_toEndOf="@id/cancel"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -39,7 +39,7 @@
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="请选择存在信息错误的区服" />
tools:text="07-02详细开服" />
<ImageView
android:id="@+id/close"
@ -50,26 +50,13 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include
android:id="@+id/title_include"
layout="@layout/dialog_servers_calendear_detail_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginRight="3dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/calendar_hint" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
<ViewStub
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginRight="3dp"
app:layout_constraintTop_toBottomOf="@id/title_include"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
android:scrollbarThumbVertical="@drawable/scrollbar_vertical"
android:scrollbars="vertical" />
app:layout_constraintTop_toBottomOf="@id/calendar_hint" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -4,8 +4,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:gravity="center_vertical"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/feedback">
@ -16,6 +15,8 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:text="时间"
android:textColor="@color/text_subtitleDesc"
android:textSize="12sp" />
@ -25,6 +26,8 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:text="区服名称"
android:textColor="@color/text_subtitleDesc"
android:textSize="12sp" />
@ -34,11 +37,35 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:text="备注"
android:layout_marginRight="16dp"
android:textColor="@color/text_subtitleDesc"
android:textSize="12sp" />
<TextView
android:id="@+id/remind_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:paddingStart="6dp"
android:paddingEnd="6dp"
android:textSize="12sp"
android:layout_marginRight="16dp"
android:textColor="@color/text_subtitleDesc"
android:text="提醒" />
<ImageView
android:id="@+id/remind"
android:layout_width="36dp"
android:layout_height="36dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:layout_marginRight="16dp"
android:src="@drawable/selector_servers_calendar_detail_item_remind"
android:visibility="gone" />
<TextView
android:id="@+id/add"
android:layout_width="wrap_content"

View File

@ -4,8 +4,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center_vertical"

View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:layout_gravity="bottom"
android:background="@drawable/bg_shape_white_radius_12_top_only"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:includeFontPadding="false"
android:text="@string/servers_detail_remind_title"
android:textColor="@color/text_title"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<ImageView
android:id="@+id/close"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="16dp"
android:src="@drawable/dialog_servers_calendear_detail_close"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/server_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:text="@string/servers_detail_server_title"
android:textSize="12sp"
android:textColor="@color/text_subtitleDesc"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/server_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:textColor="@color/text_title"
android:textSize="14sp"
app:layout_constraintTop_toBottomOf="@id/server_title"
app:layout_constraintStart_toStartOf="parent"
tools:text="官方专服|S128 繁丝绕羽" />
<TextView
android:id="@+id/server_time"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="24dp"
android:layout_marginStart="16dp"
android:gravity="center_vertical"
android:paddingStart="12dp"
android:textSize="14sp"
android:paddingEnd="12dp"
app:drawableEndCompat="@drawable/ic_arrow_gray"
android:textColor="@color/text_subtitleDesc"
android:background="@drawable/bg_server_detail_remind_time"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintTop_toBottomOf="@id/server_name"
app:layout_constraintEnd_toStartOf="@id/server_remind_time"
app:layout_constraintStart_toStartOf="parent"
tools:text="2023-08-09 05:00" />
<TextView
android:id="@+id/server_remind_time"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="24dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:paddingEnd="13dp"
android:textSize="14sp"
android:textColor="@color/text_subtitleDesc"
android:background="@drawable/bg_server_detail_remind_time"
android:gravity="center_vertical"
android:paddingStart="12dp"
tools:text="准时提醒"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintTop_toBottomOf="@id/server_name"
app:layout_constraintStart_toEndOf="@id/server_time"
app:layout_constraintEnd_toEndOf="parent"
app:drawableEndCompat="@drawable/ic_arrow_gray" />
<LinearLayout
android:id="@+id/app_remind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="16dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintEnd_toStartOf="@id/wechat_remind"
app:layout_constraintTop_toBottomOf="@id/server_remind_time"
app:layout_constraintStart_toStartOf="parent" >
<com.lightgame.view.CheckableImageView
android:id="@+id/app_remind_check_iv"
android:layout_width="24dp"
android:layout_height="24dp"
android:padding="4dp" />
<TextView
android:id="@+id/app_remind_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:textColor="@color/text_subtitle"
android:textSize="12sp"
android:text="@string/servers_detail_app_remind_title" />
</LinearLayout>
<LinearLayout
android:id="@+id/wechat_remind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="@id/app_remind"
app:layout_constraintStart_toEndOf="@id/app_remind">
<com.lightgame.view.CheckableImageView
android:id="@+id/wechat_remind_check_iv"
android:layout_width="24dp"
android:layout_height="24dp"
android:padding="4dp" />
<TextView
android:id="@+id/wechat_remind_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:textColor="@color/text_subtitle"
android:textSize="12sp"
android:text="@string/servers_detail_wechat_remind_title" />
</LinearLayout>
<TextView
android:id="@+id/add_or_cancel_remind"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="20dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintTop_toBottomOf="@id/app_remind"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@drawable/download_button_normal_style"
android:text="@string/servers_detail_add_remind"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -23,12 +23,15 @@
android:id="@+id/list_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
android:visibility="visible" />
<include
android:id="@+id/topDateContainer"
android:layout_width="match_parent"
android:layout_height="40dp"
layout="@layout/item_game_server_test_time"
android:visibility="gone" />
android:layout_marginTop="-50dp"
android:visibility="visible" />
<ImageView
android:id="@+id/pullDownTipIv"

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<FrameLayout
android:id="@+id/skeleton"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/subscribedGameManagementLayout"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:background="@drawable/bg_top_border"
android:gravity="center">
<TextView
android:id="@+id/subscribedGameManagementTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/servers_calendar_subscribed_game_management"
android:includeFontPadding="false"
android:drawablePadding="4dp"
android:textColor="@color/text_subtitleDesc"
android:textSize="13sp"
app:drawableStartCompat="@drawable/ic_servers_subscribed_game_management" />
</LinearLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/list_refresh"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentTop="true"
android:layout_above="@id/subscribedGameManagementLayout">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/topDateContainer"
android:layout_width="match_parent"
android:layout_height="40dp"
layout="@layout/item_game_server_test_time"
android:layout_marginTop="-50dp"
android:visibility="gone" />
</FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<include
android:id="@+id/reuse_ll_loading"
layout="@layout/reuse_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<include
android:id="@+id/reuse_no_connection"
layout="@layout/reuse_no_connection" />
<include
android:id="@+id/reuse_none_data"
layout="@layout/reuse_none_data" />
<include
android:id="@+id/reuse_data_exception"
layout="@layout/reuse_data_exception" />
</RelativeLayout>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal">
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="11sp"
android:includeFontPadding="false"
android:textColor="@color/text_subtitle"
tools:text="11:35" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="11dp"
android:textSize="11sp"
android:includeFontPadding="false"
android:textColor="@color/text_subtitle"
tools:text="官方专服征服者1288" />
</LinearLayout>

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="@color/white"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<com.gh.gamecenter.feature.view.GameIconView
android:id="@+id/icon"
android:layout_width="64dp"
android:layout_height="64dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/game_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:layout_marginStart="12dp"
android:textSize="14sp"
android:textColor="@color/text_title"
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintTop_toTopOf="@id/icon"
tools:text="崩坏:星穹铁道" />
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:layout_marginStart="4dp"
tools:text="测试版"
android:textColor="@color/text_subtitle"
android:textSize="10sp"
android:background="@drawable/bg_shape_f5_radius_2"
app:layout_constraintStart_toEndOf="@id/game_name"
app:layout_constraintTop_toTopOf="@id/game_name"
app:layout_constraintBottom_toBottomOf="@id/game_name"/>
<FrameLayout
android:id="@+id/servers_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="12dp"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/game_name"
app:layout_constraintStart_toStartOf="@id/game_name"
android:background="@drawable/bg_shape_f8_radius_8"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:id="@+id/servers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<TextView
android:id="@+id/server_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:textSize="11sp"
android:textColor="@color/text_subtitleDesc"
android:visibility="gone" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<com.gh.gamecenter.feature.view.GameIconView
android:id="@+id/icon"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/game_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:layout_marginStart="12dp"
android:layout_marginEnd="4dp"
android:textSize="14sp"
android:textColor="@color/text_title"
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintEnd_toStartOf="@id/subtitle"
app:layout_constraintTop_toTopOf="@id/icon"
app:layout_constraintBottom_toTopOf="@id/time"
tools:text="崩坏:星穹铁道星穹铁道星穹铁道星穹铁道星穹铁道星穹铁道" />
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:layout_marginStart="12dp"
android:layout_marginTop="7dp"
android:textSize="11sp"
android:textColor="@color/text_subtitleDesc"
tools:text="11:35 官方专服征服者1288"
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintTop_toBottomOf="@id/game_name"
app:layout_constraintBottom_toBottomOf="@id/icon" />
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:layout_marginEnd="4dp"
tools:text="测试版"
android:textColor="@color/text_subtitle"
android:textSize="10sp"
android:visibility="gone"
android:background="@drawable/bg_shape_f5_radius_2"
app:layout_constraintStart_toEndOf="@id/game_name"
app:layout_constraintEnd_toStartOf="@id/status"
app:layout_constraintTop_toTopOf="@id/game_name"
app:layout_constraintBottom_toBottomOf="@id/game_name"/>
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toTopOf="@id/icon"
app:layout_constraintBottom_toBottomOf="@id/icon"
app:layout_constraintEnd_toEndOf="parent"
android:textSize="12sp"
tools:textColor="@color/theme_font"
tools:text="待提醒" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nameTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:gravity="center"
android:textSize="16sp"
android:textColor="@color/text_title"
tools:text="准时提醒" />

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<com.gh.gamecenter.feature.view.GameIconView
android:id="@+id/icon"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/game_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:layout_marginStart="12dp"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:textSize="14sp"
android:maxLines="1"
android:ellipsize="end"
android:textColor="@color/text_title"
app:layout_constraintEnd_toStartOf="@id/subtitle"
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintTop_toTopOf="@id/icon"
app:layout_constraintBottom_toBottomOf="@id/icon"
tools:text="崩坏:星穹铁道" />
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="14dp"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:background="@drawable/bg_advance_download_game_subtitle"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:singleLine="true"
android:textColor="@color/text_subtitle"
android:textSize="@dimen/tag_text_size"
android:visibility="gone"
tools:visibility="visible"
tools:text="副标题副标题副标题"
app:layout_constraintEnd_toStartOf="@id/subscribe"
app:layout_constraintStart_toEndOf="@id/game_name"
app:layout_constraintTop_toTopOf="@id/icon"
app:layout_constraintBottom_toBottomOf="@id/icon" />
<TextView
android:id="@+id/subscribe"
android:layout_width="56dp"
android:layout_height="28dp"
android:gravity="center"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toTopOf="@id/icon"
app:layout_constraintBottom_toBottomOf="@id/icon"
app:layout_constraintEnd_toEndOf="parent"
android:textSize="12sp"
android:textColor="@color/text_subtitleDesc"
android:background="@drawable/bg_shape_f8_radius_12"
android:text="@string/servers_subscribed_game_subscribed" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto">
<include
android:id="@+id/title_include"
layout="@layout/dialog_servers_calendear_detail_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="3dp"
android:scrollbarThumbVertical="@drawable/scrollbar_vertical"
android:scrollbars="vertical" />
</LinearLayout>

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/no_server_hint"
android:layout_width="match_parent"
android:layout_height="88dp"
android:text="@string/servers_detail_no_data_hint"
android:textSize="14sp"
android:textColor="@color/text_subtitleDesc"
android:gravity="center" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/remind_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_shape_f5_radius_8">
<TextView
android:id="@+id/remind_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="@color/text_title"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="@string/servers_detail_no_data_content" />
<LinearLayout
android:id="@+id/app_remind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintEnd_toStartOf="@id/wechat_remind"
app:layout_constraintTop_toBottomOf="@id/remind_title"
app:layout_constraintStart_toStartOf="parent" >
<com.lightgame.view.CheckableImageView
android:id="@+id/app_remind_check_iv"
android:layout_width="24dp"
android:layout_height="24dp"
android:padding="4dp" />
<TextView
android:id="@+id/app_remind_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:textColor="@color/text_subtitle"
android:textSize="12sp"
android:text="@string/servers_detail_app_remind_title" />
</LinearLayout>
<LinearLayout
android:id="@+id/wechat_remind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:layout_marginStart="20dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@id/remind_title"
app:layout_constraintStart_toEndOf="@id/app_remind"
app:layout_constraintEnd_toEndOf="parent" >
<com.lightgame.view.CheckableImageView
android:id="@+id/wechat_remind_check_iv"
android:layout_width="24dp"
android:layout_height="24dp"
android:padding="4dp" />
<TextView
android:id="@+id/wechat_remind_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:textColor="@color/text_subtitle"
android:textSize="12sp"
android:text="@string/servers_detail_wechat_remind_title" />
</LinearLayout>
<TextView
android:id="@+id/add_or_cancel_remind"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="12dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintTop_toBottomOf="@id/app_remind"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@drawable/download_button_normal_style"
android:text="@string/servers_detail_add_remind"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@ -10,7 +10,7 @@
<item
android:id="@+id/menu_more"
android:icon="@drawable/ic_menu_gamedetail_more"
android:icon="@drawable/ic_menu_more"
android:title="更多"
app:showAsAction="always" />

View File

@ -4,7 +4,7 @@
<item
android:id="@+id/menu_more"
android:icon="@drawable/ic_menu_gamedetail_more"
android:icon="@drawable/ic_menu_more"
android:title="更多"
app:showAsAction="always" />

View File

@ -3,7 +3,7 @@
<item
android:id="@+id/menu_more"
android:icon="@drawable/ic_menu_gamedetail_more"
android:icon="@drawable/ic_menu_more"
android:orderInCategory="1"
android:title="@string/menu_more"
app:showAsAction="always" />

View File

@ -16,7 +16,7 @@
<item
android:id="@+id/menu_more"
android:icon="@drawable/ic_menu_gamedetail_more"
android:icon="@drawable/ic_menu_more"
android:orderInCategory="1"
android:title="@string/menu_more"
app:showAsAction="always" />

View File

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

View File

@ -471,4 +471,46 @@
<string name="article_detail_comment_list_tab_title">评论 %1$d</string>
<string name="article_detail_related_content_vote_and_comment">点赞 %1$d · 评论 %2$d</string>
<string name="qgame_title">QQ小游戏</string>
<string name="servers_calendar_subscribe">加入订阅</string>
<string name="servers_calendar_subscribe_hint_1">订阅开服表,订阅后助你获得一手新服信息</string>
<string name="servers_calendar_subscribe_hint_2">通知时间:8:00、12:00、18:00</string>
<string name="servers_calendar_more_dialog_title">操作</string>
<string name="servers_calendar_dialog_unsubscribe_title">取消订阅</string>
<string name="servers_calendar_dialog_unsubscribe_hint">不再接收开服消息</string>
<string name="servers_calendar_more_dialog_cancel_title">取消</string>
<string name="servers_calendar_subscription_dialog_content">游戏发布新服信息时,您将在消息中心收到通知。为了避免错过通知,建议您开启微信公众号提醒</string>
<string name="servers_calendar_subscription_dialog_title">游戏订阅成功</string>
<string name="servers_calendar_subscription_dialog_confirm">我知道了</string>
<string name="servers_calendar_remind_time_setting_dialog_title">设置提醒时间</string>
<string name="servers_calendar_subscribed_game_management">订阅游戏管理</string>
<string name="servers_calendar_list_tab">开服表</string>
<string name="servers_calendar_remind_list_tab">开服提醒</string>
<string name="servers_calendar_subscription_title">开服订阅</string>
<string name="servers_calendar_subscribed_game_title">游戏订阅</string>
<string name="servers_calendar_time_setting_dialog_title">设置时间</string>
<string name="servers_calendar_time_setting_dialog_cancel">取消</string>
<string name="servers_calendar_time_setting_dialog_confirm">确认</string>
<string name="servers_detail_no_data_hint">当前日期暂无开服信息</string>
<string name="servers_detail_no_data_content">游戏发布当天新服时提醒</string>
<string name="servers_detail_app_remind_title">APP发送提醒信息</string>
<string name="servers_detail_wechat_remind_title">微信发送提醒信息</string>
<string name="servers_detail_add_remind">添加提醒</string>
<string name="servers_detail_cancel_remind">取消提醒</string>
<string name="servers_detail_remind_title">提醒详情</string>
<string name="servers_detail_server_title">区服名称</string>
<string name="servers_calendar_list_server_count">+%1$d</string>
<string name="servers_calendar_list_date_today">今天</string>
<string name="servers_calendar_list_date_tomorrow">明天</string>
<string name="servers_calendar_remind_status_todo">待提醒</string>
<string name="servers_calendar_remind_status_coming">即将开服</string>
<string name="servers_calendar_remind_status_opened">已开服</string>
<string name="servers_calendar_remind_status_has_new">有新服</string>
<string name="servers_calendar_remind_status_expired">已过期</string>
<string name="servers_calendar_remind_list_server_name">%1$s %2$s</string>
<string name="servers_subscribed_game_subscribed">已订阅</string>
<string name="servers_subscribed_game_unsubscribe_dialog_title">取消订阅</string>
<string name="servers_subscribed_game_unsubscribe_dialog_content">确定取消订阅吗</string>
<string name="servers_subscribed_game_unsubscribe_dialog_confirm">确定</string>
<string name="servers_subscribed_game_unsubscribe_dialog_cancel">取消</string>
<string name="servers_calendar_remind_time_out_of_date">您添加的提醒时间已过期!</string>
</resources>

View File

@ -156,7 +156,7 @@ public abstract class LazyListFragment<T, VM extends BaseListViewModel /* 该泛
mListRefresh.setColorSchemeResources(R.color.theme);
mListRefresh.setOnRefreshListener(this);
}
mLayoutManager = new FixLinearLayoutManager(getContext());
mLayoutManager = new LinearLayoutManager(getContext());
((DefaultItemAnimator) mListRv.getItemAnimator()).setSupportsChangeAnimations(false);
mListRv.setLayoutManager(mLayoutManager);
mListRv.setAdapter(provideListAdapter());

View File

@ -486,4 +486,8 @@ public class Constants {
public static final String SP_ACCELERATE_NOTIFICATION_POP_UP_SET = "accelerate_notification_popup";
public static final String SP_GAME_SERVER_TEST_V2_CATEGORY_SET = "game_server_test_v2_category";
public static final String SP_SERVERS_CALENDAR_BY_APP = "servers_calendar_by_app";
public static final String SP_SERVERS_CALENDAR_BY_WECHAT = "servers_calendar_by_wechat";
}

View File

@ -225,6 +225,7 @@ public class EntranceConsts {
public static final String KEY_ARTICLE_OPEN_IN_NEW_PAGE = "openArticleInNewPage";
public static final String KEY_ONLY_CREATE_DRAFT = "onlyCreateDraft";
public static final String KEY_KAIFU_SELECT_TIME = "kaifuSelectTime";
public static final String KEY_KAIFU_TIME = "kaifuTime";
public static final String KEY_POSTER_PATH = "posterPath";
public static final String KEY_BLACK_THEME = "blackTheme";
public static final String KEY_FROM_LOGIN = "fromLogin";
@ -301,4 +302,10 @@ public class EntranceConsts {
public static final String KEY_SMOOTH_GAME = "smooth_game";
public static final String KEY_CREATE_GAME_COLLECTION = "create_game_collection";
public static final String KEY_MY_RELATED_QA = "my_related_qa";
public static final String KEY_SHOW_REMIND = "show_remind";
public static final String KEY_CALENDAR_YEAR = "calendar_year";
public static final String KEY_CALENDAR_MONTH = "calendar_month";
public static final String KEY_CALENDAR_DAY = "calendar_day";
public static final String KEY_SERVER_CALENDAR_ID = "server_calendar_id";
}

View File

@ -49,6 +49,9 @@ object SensorsBridge {
private const val KEY_COLUMN_COLLECTION_ID = "column_collection_id"
private const val KEY_GAME_COLUMN_NAME = "game_column_name"
private const val KEY_GAME_COLUMN_ID = "game_column_id"
private const val KEY_SESSION_MESSAGE_TYPE = "session_message_type"
private const val KEY_REMINDER_TYPE = "reminder_type"
private const val KEY_MESSAGE_TYPE = "message_type"
private const val EVENT_GAME_DETAIL_PAGE_TAB_SELECT = "GameDetailPageTabSelect"
private const val EVENT_GAME_DETAIL_PAGE_TAG_CLICK = "GameDetailPageGameTagClick"
@ -106,6 +109,15 @@ object SensorsBridge {
private const val EVENT_UNLOAD_GAME_FINISH = "UnloadGameFinish"
private const val EVENT_INSTALL_GAME_CLICK = "InstallGameClick"
private const val EVENT_INSTALL_GAME_FINISH = "InstallGameFinish"
private const val EVENT_MESSAGE_RECEIVE = "MessageReceive"
private const val EVENT_MESSAGE_CENTER_CLICK = "MessageCenterClick"
private const val EVENT_MESSAGE_SESSION_CLICK = "MessageSessionClick"
private const val EVENT_MESSAGE_ITEM_CLICK = "MessageItemClick"
private const val EVENT_MESSAGE_ITEM_LINK_CLICK = "MessageItemLinkClick"
private const val EVENT_LAUNCH_SERVER_SUBSCRIBE_CLICK = "LaunchServerSubscribeClick"
private const val EVENT_LAUNCH_SERVER_SUBSCRIBE_CANCEL_CLICK = "LaunchServerSubscribeCancelClick"
private const val EVENT_LAUNCH_SERVER_REMINDER_CLICK = "LaunchServerReminderClick"
private const val EVENT_LAUNCH_SERVER_REMINDER_CANCEL_CLICK ="LaunchServerReminderCancelClick"
private var mIsSensorsEnabled = false
@ -1800,4 +1812,200 @@ object SensorsBridge {
trackEvent(EVENT_INSTALL_GAME_FINISH, json)
}
/**
* 事件IDMessageReceive
* 事件名称:消息接收事件
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param sessionMessageType 会话类型: 游戏消息、系统消息、客服消息、互动消息、运营消息
* @see EVENT_MESSAGE_RECEIVE
*/
@JvmStatic
fun trackMessageReceive(
gameId: String,
gameName: String,
sessionMessageType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_SESSION_MESSAGE_TYPE to sessionMessageType
}
trackEvent(EVENT_MESSAGE_RECEIVE, json)
}
/**
* 事件IDMessageCenterClick
* 事件名称:消息中心点击事件
* @see EVENT_MESSAGE_CENTER_CLICK
*/
@JvmStatic
fun trackMessageCenterClick() {
val json = json {}
trackEvent(EVENT_MESSAGE_CENTER_CLICK, json)
}
/**
* 事件IDMessageSessionClick
* 事件名称:消息会话点击事件
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param sessionMessageType 会话类型: 游戏消息、系统消息、客服消息、互动消息、运营消息
* @see EVENT_MESSAGE_SESSION_CLICK
*/
@JvmStatic
fun trackMessageSessionClick(
gameId: String,
gameName: String,
sessionMessageType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_SESSION_MESSAGE_TYPE to sessionMessageType
}
trackEvent(EVENT_MESSAGE_SESSION_CLICK, json)
}
/**
* 事件IDMessageItemClick
* 事件名称:消息点击事件
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param sessionMessageType 会话类型: 游戏消息、系统消息、客服消息、互动消息、运营消息
* @param messageType 消息类型
* @see EVENT_MESSAGE_ITEM_CLICK
*/
@JvmStatic
fun trackMessageItemClick(
gameId: String,
gameName: String,
sessionMessageType: String,
messageType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_SESSION_MESSAGE_TYPE to sessionMessageType
KEY_MESSAGE_TYPE to messageType
}
trackEvent(EVENT_MESSAGE_ITEM_CLICK, json)
}
/**
* 事件IDMessageItemLinkClick
* 事件名称:消息点击事件
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param sessionMessageType 会话类型: 游戏消息、系统消息、客服消息、互动消息、运营消息
* @param messageType 消息类型
* @see EVENT_MESSAGE_ITEM_LINK_CLICK
*/
@JvmStatic
fun trackMessageItemLinkClick(
gameId: String,
gameName: String,
sessionMessageType: String,
messageType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_SESSION_MESSAGE_TYPE to sessionMessageType
KEY_MESSAGE_TYPE to messageType
}
trackEvent(EVENT_MESSAGE_ITEM_LINK_CLICK, json)
}
/**
* 事件IDLaunchServerSubscribeClick
* 事件名称:加入开服订阅事件
* @param gameId 游戏ID
* @param gameName 游戏名称
* @see EVENT_LAUNCH_SERVER_SUBSCRIBE_CLICK
*/
@JvmStatic
fun trackLaunchServerSubscribeClick(
gameId: String,
gameName: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
}
trackEvent(EVENT_LAUNCH_SERVER_SUBSCRIBE_CLICK, json)
}
/**
* 事件IDLaunchServerSubscribeCancelClick
* 事件名称:取消开服订阅事件
* @param gameId 游戏ID
* @param gameName 游戏名称
* @see EVENT_LAUNCH_SERVER_SUBSCRIBE_CANCEL_CLICK
*/
@JvmStatic
fun trackLaunchServerSubscribeCancelClick(
gameId: String,
gameName: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
}
trackEvent(EVENT_LAUNCH_SERVER_SUBSCRIBE_CANCEL_CLICK, json)
}
/**
* 事件IDLaunchServerReminderClick
* 事件名称:添加开服提醒事件
* @param gameId 游戏ID
* @param gameName 游戏名称
* @param reminderType 提醒类型: 已知服、未知服
* @see EVENT_LAUNCH_SERVER_REMINDER_CLICK
*/
@JvmStatic
fun trackLaunchServerReminderClick(
gameId: String,
gameName: String,
reminderType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_REMINDER_TYPE to reminderType
}
trackEvent(EVENT_LAUNCH_SERVER_REMINDER_CLICK, json)
}
/**
* 事件IDLaunchServerReminderCancelClick
* 事件名称:游戏安装完成事件
* @param gameId 游戏ID
* @param gameName 游戏名称
* @see EVENT_LAUNCH_SERVER_REMINDER_CANCEL_CLICK
*/
@JvmStatic
fun trackLaunchServerReminderCancelClick(
gameId: String,
gameName: String,
reminderType: String
) {
val json = json {
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_REMINDER_TYPE to reminderType
}
trackEvent(EVENT_LAUNCH_SERVER_REMINDER_CANCEL_CLICK, json)
}
}

View File

@ -0,0 +1,136 @@
package com.gh.gamecenter.common.utils;
import android.content.Context;
import android.content.Intent;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import com.tencent.mm.opensdk.utils.ILog;
import java.util.Collections;
import java.util.List;
/**
* 通用微信SDK代理工厂类
* 1. 构造通用微信SDK代理类实例
* 2. 处理WXEntryActivity的结果回调
*/
public final class WXAPIProxyFactory {
private WXAPIProxyFactory() {
}
private static final MutableLiveData<BaseResp> mRespLiveData = new MutableLiveData<>();
public static <T extends BaseReq, R extends BaseResp> WXAPIProxy<T, R> createWXAPI(Context context, String appid) {
final String transaction = String.valueOf(System.currentTimeMillis());
return createWXAPI(context, appid, new WXHandler<T, R>() {
@Override
public void handleOnReq(T req) {
req.transaction = transaction;
}
@Override
public R handleOnResp(BaseResp resp) {
if (transaction.equals(resp.transaction)) {
return (R) resp;
}
return null;
}
});
}
public static <T extends BaseReq, R extends BaseResp> WXAPIProxy<T, R> createWXAPI(Context context, String appid, WXHandler<T, R> handler) {
return new WXAPIProxy<>(context, appid, handler);
}
public static MutableLiveData<BaseResp> getLiveData() {
return mRespLiveData;
}
public final static class WXAPIProxy<T extends BaseReq, R extends BaseResp> {
private final IWXAPI mWxAPI;
private WXHandler<T, R> mHandler;
private final MediatorLiveData<R> mLiveData = new MediatorLiveData<R>() {{
addSource(mRespLiveData, input -> {
R resp = mHandler.handleOnResp(input);
if (resp != null) {
mLiveData.setValue(resp);
}
});
}};
private WXAPIProxy(Context context, String appid, WXHandler<T, R> handler) {
mHandler = handler;
mWxAPI = WXAPIFactory.createWXAPI(context, appid);
}
public boolean registerApp(String s) {
return mWxAPI.registerApp(s);
}
public boolean registerApp(String s, long l) {
return mWxAPI.registerApp(s, l);
}
public void unregisterApp() {
mWxAPI.unregisterApp();
}
public boolean handleIntent(Intent var1, IWXAPIEventHandler var2) {
return mWxAPI.handleIntent(var1, var2);
}
public boolean isWXAppInstalled() {
return mWxAPI.isWXAppInstalled();
}
public int getWXAppSupportAPI() {
return mWxAPI.getWXAppSupportAPI();
}
public boolean openWXApp() {
return mWxAPI.openWXApp();
}
public boolean sendReq(T req) {
mHandler.handleOnReq(req);
return mWxAPI.sendReq(req);
}
public boolean sendResp(R resp) {
return mWxAPI.sendResp(resp);
}
public void detach() {
mWxAPI.detach();
}
public void setLogImpl(ILog var1) {
mWxAPI.setLogImpl(var1);
}
public LiveData<R> getLiveData() {
return mLiveData;
}
}
public interface WXHandler<T extends BaseReq, R extends BaseResp> {
void handleOnReq(T req);
R handleOnResp(BaseResp resp);
}
}

View File

@ -9,9 +9,7 @@ import com.google.gson.annotations.SerializedName
import java.text.SimpleDateFormat
import java.util.*
/**
* Created by khy on 2017/3/17.
*/
class ServerCalendarEntity() : Parcelable, BaseObservable() {
@SerializedName("_id")
@ -31,6 +29,9 @@ class ServerCalendarEntity() : Parcelable, BaseObservable() {
var remark: String = ""
@SerializedName("notify_setting")
var notifySetting: ServerCalendarNotifySetting? = null
fun setNote(note: String?) {
this.note = note
notifyPropertyChanged(BR.note)
@ -97,6 +98,7 @@ class ServerCalendarEntity() : Parcelable, BaseObservable() {
dest.writeLong(this.time)
dest.writeString(this.type)
dest.writeString(this.remark)
dest.writeParcelable(this.notifySetting, flags)
}
constructor(source: Parcel) : this() {
@ -105,6 +107,7 @@ class ServerCalendarEntity() : Parcelable, BaseObservable() {
this.time = source.readLong()
this.type = source.readString()
this.remark = source.readString() ?: ""
this.notifySetting = source.readParcelable(ServerCalendarNotifySetting::class.java.classLoader)
}
companion object {

View File

@ -0,0 +1,9 @@
package com.gh.gamecenter.feature.entity
import com.google.gson.annotations.SerializedName
class ServerCalendarFormEntity(
@SerializedName("start_midnight")
val startMidnight: Long,
val game: List<ServerCalendarGame>
)

View File

@ -0,0 +1,52 @@
package com.gh.gamecenter.feature.entity
import com.gh.gamecenter.common.entity.IconFloat
import com.google.gson.annotations.SerializedName
data class ServerCalendarGame(
@SerializedName("_id")
val id: String = "",
val name: String = "",
val category: String = "",
val brief: String = "",
val icon: String = "",
@SerializedName("ori_icon")
val oriIcon: String? = null,
@SerializedName("mirror_status")
val mirrorStatus: String = "off",
@SerializedName("_seq")
val seq: Int = 0,
@SerializedName("icon_float")
val iconFloat: IconFloat? = null,
@SerializedName("mirror_status2")
val mirrorStatus2: String = "off",
@SerializedName("icon_subscript")
var iconSubscript: String = "",
var subtitle: String? = "",
@SerializedName("subtitle_style")
var subtitleStyle: TagStyleEntity? = null,
val servers: List<ServerCalendarEntity> = emptyList(),
@SerializedName("servers_total")
val serversTotal: Int = 0,
@SerializedName("notify_status")
val notifyStatus: String? = null //todo 待提醒 coming 即将开服 opened 已开服 has_new 有新服 expired 已过期
) {
var startMidnight: Long = 0
fun toGameEntity(): GameEntity {
val gameEntity = GameEntity(id = id, name = name)
gameEntity.sequence = seq
gameEntity.icon = icon
gameEntity.rawIcon = oriIcon
gameEntity.iconSubscript = iconSubscript
gameEntity.mirrorStatus = mirrorStatus
gameEntity.mirrorStatus2 = mirrorStatus2
gameEntity.subtitle = subtitle ?: ""
gameEntity.subtitleStyle = subtitleStyle
gameEntity.iconFloat = iconFloat
gameEntity.brief = brief
gameEntity.category = category
return gameEntity
}
}

View File

@ -0,0 +1,25 @@
package com.gh.gamecenter.feature.entity
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import java.text.SimpleDateFormat
import java.util.*
@Parcelize
class ServerCalendarNotifySetting(
@SerializedName("notify_time")
val notifyTime: Long = 0,
@SerializedName("seconds_advance")
val secondsAdvance: Int = 0,
@SerializedName("by_app")
val byApp: Boolean = false,
@SerializedName("by_wechat")
val byWechat: Boolean = false
) : Parcelable {
fun getFormatTime(pattern: String): String? {
if (notifyTime == 0L) return null
val formatTime = SimpleDateFormat(pattern, Locale.CHINA)
return formatTime.format(notifyTime * 1000)
}
}

View File

@ -0,0 +1,13 @@
package com.gh.gamecenter.feature.entity
import com.google.gson.annotations.SerializedName
class WXSubscribeMsgConfig(
val appid: String,
val scene: Int,
@SerializedName("template_id")
val templateId: String,
@SerializedName("redirect_url")
val redirectUrl: String,
val reserved: String
)

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