diff --git a/app/proguard-rules.txt b/app/proguard-rules.txt index 801a46e8bb..2142fe8df9 100644 --- a/app/proguard-rules.txt +++ b/app/proguard-rules.txt @@ -92,3 +92,7 @@ native ; } +-keepclassmembernames class com.contrarywind.view.WheelView { + private int itemsVisible; +} + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e1a8e04023..7291d315eb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -474,6 +474,14 @@ android:name="com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity" android:screenOrientation="portrait" /> + + + + diff --git a/app/src/main/java/com/gh/common/util/DirectUtils.kt b/app/src/main/java/com/gh/common/util/DirectUtils.kt index 2f30221b19..c99818755b 100644 --- a/app/src/main/java/com/gh/common/util/DirectUtils.kt +++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt @@ -63,6 +63,8 @@ import com.gh.gamecenter.gamecollection.hotlist.GameCollectionListDetailActivity import com.gh.gamecenter.gamecollection.square.GameCollectionSquareActivity import com.gh.gamecenter.gamedetail.GameDetailFragment import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity +import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarManagementActivity +import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersSubscribedGameListActivity import com.gh.gamecenter.gamedetail.history.HistoryApkListActivity import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity import com.gh.gamecenter.help.HelpAndFeedbackBridge @@ -192,6 +194,8 @@ object DirectUtils { } } + "game_server_calendar" -> directToGameServerCalendar(context, linkEntity.link) + "column", "游戏专题" -> directToSubject( context, linkEntity.link ?: "", linkEntity.text, BaseActivity.mergeEntranceAndPath(entrance, path), exposureEvent @@ -543,12 +547,13 @@ object DirectUtils { * 跳转至游戏日历表 */ @JvmStatic - fun directToGameServerCalendar(context: Context, gameId: String?) { + fun directToGameServerCalendar(context: Context, gameId: String?, kaifuTime: Long = 0) { val bundle = Bundle() bundle.putString(KEY_TO, ServersCalendarActivity::class.java.name) bundle.putParcelable(GameEntity::class.java.simpleName, GameEntity().apply { id = gameId ?: "" }) + bundle.putLong(KEY_KAIFU_TIME, kaifuTime) bundle.putParcelable(GameDetailServer::class.java.simpleName, GameDetailServer()) bundle.putParcelable(MeEntity::class.java.simpleName, MeEntity()) jumpActivity(context, bundle) @@ -2117,4 +2122,24 @@ object DirectUtils { ) ) } + + /** + * 跳转到游戏订阅页面 + * @param context 上下文 + */ + @JvmStatic + fun directToServersSubscribedGameList(context: Context) { + context.startActivity(ServersSubscribedGameListActivity.getIntent(context)) + } + + /** + * 跳转到开服订阅页面 + * @param context 上下文 + */ + @JvmStatic + fun directToServersCalendarManagement(context: Context, entrance: String) { + CheckLoginUtils.checkLogin(context, entrance) { + context.startActivity(ServersCalendarManagementActivity.getIntent(context)) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/NewLogUtils.kt b/app/src/main/java/com/gh/common/util/NewLogUtils.kt index a2fbe9c0b4..a82aea46f1 100644 --- a/app/src/main/java/com/gh/common/util/NewLogUtils.kt +++ b/app/src/main/java/com/gh/common/util/NewLogUtils.kt @@ -2487,4 +2487,209 @@ object NewLogUtils { } log(json, LOG_STORE_EVENT) } + + /** + * 埋点序号:117 + * 事件ID:message_inform_push + * 事件名称:消息推送事件 + * 触发时机:系统触发消息推送 + * @param gameId 游戏ID + * @param gameName 游戏名称 + * @param sessionMessageType 会话类型 + * @param messageType 消息类型 + */ + @JvmStatic + fun logMessageInformPush( + gameId: String, + gameName: String, + sessionMessageType: String, + messageType: String + ) { + val json = json { + KEY_EVENT to "message_inform_push" + KEY_GAME_ID to gameId + KEY_GAME_NAME to gameName + "session_message_type" to sessionMessageType + "message_type" to messageType + parseAndPutMeta().invoke(this) + } + log(json, LOG_STORE_EVENT) + } + + /** + * 埋点序号:118 + * 事件ID:launch_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 + * 事件ID:launch_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 + * 事件ID:launch_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 + * 事件ID:launch_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 + * 事件ID:launch_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 + * 事件ID:launch_server_reminder_click + * 事件名称:点击开服提醒事件 + * 触发时机:点击开服管理的提醒记录 + * @param gameId 游戏ID + * @param gameName 游戏名称 + * @param reminderTime 设置提醒时间: 已知服是上传以秒为单位的时间戳,未知服则是当天0点的时间戳 + * @param status 记录状态: todo 待提醒 coming 即将开服 opened 已开服 has_new 有新服 expired 已过期 + */ + @JvmStatic + fun logLaunchServerReminderClick( + gameId: String, + gameName: String, + reminderTime: Int, + status: String, + ) { + val json = json { + KEY_EVENT to "launch_server_reminder_click" + KEY_GAME_ID to gameId + KEY_GAME_NAME to gameName + "reminder_time" to reminderTime + "status" to status + parseAndPutMeta().invoke(this) + } + log(json, LOG_STORE_EVENT) + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/SkipActivity.java b/app/src/main/java/com/gh/gamecenter/SkipActivity.java index 83a6693dc1..f7f09af1e1 100644 --- a/app/src/main/java/com/gh/gamecenter/SkipActivity.java +++ b/app/src/main/java/com/gh/gamecenter/SkipActivity.java @@ -385,7 +385,7 @@ public class SkipActivity extends BaseActivity { EntranceConsts.ENTRANCE_BROWSER); break; case EntranceConsts.HOST_GAME_CALENDAR: - DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID)); + DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID), 0); break; case EntranceConsts.HOST_HISTORY_APK: DirectUtils.directToHistoryApk(this, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID)); diff --git a/app/src/main/java/com/gh/gamecenter/entity/CalendarEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/CalendarEntity.kt index 3b59116802..60dd504998 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/CalendarEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/CalendarEntity.kt @@ -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 = ArrayList() -} +) : Parcelable diff --git a/app/src/main/java/com/gh/gamecenter/entity/ServerSubscriptionEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ServerSubscriptionEntity.kt new file mode 100644 index 0000000000..9890f80767 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/entity/ServerSubscriptionEntity.kt @@ -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 +) \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java index 77e6a584f3..a304fe4a4d 100644 --- a/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java +++ b/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java @@ -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(); diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt index 5faaf654d8..422ed9746f 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt @@ -1648,7 +1648,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable { true ) updateConcernMenuIcon(mNewGameDetailEntity?.me?.isGameConcerned ?: false) - mMoreMenuItem?.setIcon(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.ic_menu_gamedetail_more else R.drawable.ic_menu_gamedetail_more_light) + mMoreMenuItem?.setIcon(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.ic_menu_more else R.drawable.ic_menu_more_light) mSearchMenuItem?.setIcon(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.ic_column_search else R.drawable.ic_column_search_light) mDownloadMenuIcon?.setImageResource(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.toolbar_download else R.drawable.toolbar_download_light) DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn && isToolbarWhite) diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarActivity.kt index 7681d450f3..ce75678d85 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarActivity.kt @@ -5,36 +5,33 @@ import android.app.Dialog import android.content.Context import android.content.Intent import android.graphics.Color -import android.graphics.Paint import android.os.Bundle import android.text.TextUtils -import android.view.Gravity import android.view.LayoutInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup -import android.widget.TextView import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.CheckLoginUtils import com.gh.common.util.NewLogUtils import com.gh.gamecenter.R import com.gh.gamecenter.common.base.activity.ToolBarActivity -import com.gh.gamecenter.common.entity.SuggestType +import com.gh.gamecenter.common.constant.Constants +import com.gh.gamecenter.common.constant.EntranceConsts +import com.gh.gamecenter.common.eventbus.EBReuse import com.gh.gamecenter.common.utils.* import com.gh.gamecenter.core.utils.SPUtils +import com.gh.gamecenter.core.utils.ToastUtils import com.gh.gamecenter.databinding.ActivityServersCalendarBinding -import com.gh.gamecenter.databinding.DialogServersCalendearDetailItemBinding import com.gh.gamecenter.entity.CalendarEntity import com.gh.gamecenter.feature.entity.GameDetailServer import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.feature.entity.MeEntity import com.gh.gamecenter.feature.entity.ServerCalendarEntity -import com.gh.gamecenter.help.HelpAndFeedbackBridge -import com.gh.gamecenter.servers.add.AddKaiFuActivity -import com.google.android.material.bottomsheet.BottomSheetDialog import com.halo.assistant.HaloApp -import com.lightgame.adapter.BaseRecyclerAdapter +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode import java.text.SimpleDateFormat import java.util.* @@ -46,6 +43,13 @@ class ServersCalendarActivity : ToolBarActivity() { NewLogUtils.logGameDetailOpenCalendarView(mViewModel.game.name ?: "", mViewModel.game.id) } + private val mMoreDialog by lazy { ServersCalendarMoreDialog() } + + private val mWeChatSubscriptionSuccessDialog by lazy { ServersCalendarWeChatSubscriptionSuccessDialog() } + + private val mSubscriptionSuccessDialog by lazy { ServersCalendarSubscriptionSuccessDialog() } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) val serverCalendars = mViewModel.serverCalendarLiveData.value ?: return @@ -85,6 +89,20 @@ class ServersCalendarActivity : ToolBarActivity() { } override fun onCreate(savedInstanceState: Bundle?) { + val game = intent?.getParcelableExtra(GameEntity::class.java.simpleName) + val serverList = intent?.getParcelableExtra(GameDetailServer::class.java.simpleName) + val meEntity = intent?.getParcelableExtra(MeEntity::class.java.simpleName) + if (game == null || serverList == null) { + throwExceptionInDebug() + return + } + + // 必须放在super.onCreate前面,因为子Fragment的onCreate方法也是在super.onCreate回调的时候调用 + // 如果放在super.onCreate之后,那么在页面重构时,子Fragment在onCreate方法引用通过viewModels方法获取parentViewModel将触发崩溃 + val factory = ServersCalendarViewModel.Factory(HaloApp.getInstance().application, game, serverList, meEntity) + mViewModel = ViewModelProviders.of(this, factory).get(ServersCalendarViewModel::class.java) + mViewModel.setKaifuTime(intent.getLongExtra(EntranceConsts.KEY_KAIFU_TIME, 0)) + super.onCreate(savedInstanceState) updateStatusBarColor(R.color.background_white, R.color.background_white) setNavigationTitle("开服日历表") @@ -96,16 +114,6 @@ class ServersCalendarActivity : ToolBarActivity() { mViewModel.loadServerData() } - val game = intent?.getParcelableExtra(GameEntity::class.java.simpleName) - val serverList = intent?.getParcelableExtra(GameDetailServer::class.java.simpleName) - val meEntity = intent?.getParcelableExtra(MeEntity::class.java.simpleName) - if (game == null || serverList == null) { - throwExceptionInDebug() - return - } - - val factory = ServersCalendarViewModel.Factory(HaloApp.getInstance().application, game, serverList, meEntity) - mViewModel = ViewModelProviders.of(this, factory).get(ServersCalendarViewModel::class.java) mViewModel.calendarLiveData.observeNonNull(this, callback = { val adapter = ServersCalendarAdapter(this, mViewModel, it) mBinding.recyclerView.isNestedScrollingEnabled = false @@ -113,7 +121,7 @@ class ServersCalendarActivity : ToolBarActivity() { mBinding.recyclerView.adapter = adapter }) mViewModel.serversDetailLiveData.observeNonNull(this, callback = { - showServersDetailDialog(it) + showServersCalendarDetailDialog(it) NewLogUtils.logGameDetailOpenCalendarClick(mViewModel.game.name ?: "", mViewModel.game.id) }) mViewModel.serverCalendarLiveData.observe(this) { @@ -125,6 +133,52 @@ class ServersCalendarActivity : ToolBarActivity() { mBinding.includeNoConnection.root.visibility = View.VISIBLE } } + mViewModel.serverSubscriptionLiveData.observe(this) { + // 用户订阅状态 + if (it?.byApp == true) {// 用户已登录并处于已订阅状态 + clearMenu() + setToolbarMenu(R.menu.menu_server_calendar_more) + mBinding.subscribe.visibility = View.GONE + mBinding.subscribeHint1.visibility = View.GONE + mBinding.subscribeHint2.visibility = View.GONE + mBinding.subscribe.setOnClickListener(null) + } else {// 用户已登录并处于未订阅状态 + clearMenu() + mBinding.subscribe.visibility = View.VISIBLE + mBinding.subscribeHint1.visibility = View.VISIBLE + mBinding.subscribeHint2.visibility = View.VISIBLE + mBinding.subscribe.setOnClickListener { + CheckLoginUtils.checkLogin(this, "游戏详情-开服日历表-开启订阅") { + mViewModel.subscribeServer() + NewLogUtils.logLaunchServerSubscribeAdd( + gameId = mViewModel.game.id, + gameName = mViewModel.game.name ?: "" + ) + SensorsBridge.trackLaunchServerSubscribeClick( + gameId = mViewModel.game.id, + gameName = mViewModel.game.name ?: "" + ) + } + } + } + } + mViewModel.subscribeServerSuccessEvent.observe(this) { + val serverSubscription = mViewModel.serverSubscriptionLiveData.value + if (serverSubscription?.byWeChat != true && !mWeChatSubscriptionSuccessDialog.isAdded) {// 开启微信提醒弹窗 + mWeChatSubscriptionSuccessDialog.showNow( + supportFragmentManager, + SERVERS_CALENDAR_WECHAT_SUBSCRIPTION_DIALOG_TAG + ) + } else if (!mSubscriptionSuccessDialog.isAdded) {// 开启订阅成功提醒弹窗 + mSubscriptionSuccessDialog.showNow( + supportFragmentManager, + SERVERS_CALENDAR_SUBSCRIPTION_DIALOG_TAG + ) + } + } + mViewModel.error.observe(this) { + ToastUtils.showToast(getString(R.string.network_error_hint)) + } mBaseHandler.postDelayed(mDelayLogRunnable, 3000) } @@ -133,6 +187,15 @@ class ServersCalendarActivity : ToolBarActivity() { mBaseHandler.removeCallbacks(mDelayLogRunnable) } + override fun onMenuItemClick(item: MenuItem?): Boolean { + if (item?.itemId == R.id.menu_more) { + if (!mMoreDialog.isAdded) { + mMoreDialog.showNow(supportFragmentManager, SERVERS_CALENDAR_MORE_DIALOG_TAG) + } + } + return super.onMenuItemClick(item) + } + fun initView() { mBinding.contentContainer.visibility = View.VISIBLE mBinding.includeLoading.root.visibility = View.GONE @@ -184,7 +247,7 @@ class ServersCalendarActivity : ToolBarActivity() { } - if (!mViewModel.isExistCurServer) { + if (!mViewModel.isExistCurServer) {// 这里已经不执行了,估计是遗留下的旧代码... mViewModel.selectedMonth = MonthType.NEXT_MONTH mBinding.curMonth.visibility = View.GONE @@ -193,13 +256,41 @@ class ServersCalendarActivity : ToolBarActivity() { mBinding.nextMonth.setTextColor(Color.WHITE) mBinding.year.text = formatYearText.format(previousTime) } else { - mViewModel.selectedMonth = MonthType.CUR_MONTH - mBinding.curMonth.visibility = View.VISIBLE - mBinding.curMonth.setBackgroundResource(R.drawable.download_oval_hint_up) mBinding.curMonth.text = formatMonthText.format(curTime) mBinding.year.text = formatYearText.format(curTime) + + when (mViewModel.selectedMonth) { + MonthType.CUR_MONTH -> { + mBinding.curMonth.setBackgroundResource(R.drawable.download_oval_hint_up) + mBinding.curMonth.setTextColor(Color.WHITE) + + mBinding.previousMonth.setBackgroundColor(0) + mBinding.previousMonth.setTextColor(R.color.text_title.toColor(this)) + mBinding.nextMonth.setBackgroundColor(0) + mBinding.nextMonth.setTextColor(R.color.text_title.toColor(this)) + } + MonthType.NEXT_MONTH -> { + mBinding.nextMonth.setBackgroundResource(R.drawable.download_oval_hint_up) + mBinding.nextMonth.setTextColor(Color.WHITE) + + mBinding.curMonth.setBackgroundColor(0) + mBinding.curMonth.setTextColor(R.color.text_title.toColor(this)) + mBinding.previousMonth.setBackgroundColor(0) + mBinding.previousMonth.setTextColor(R.color.text_title.toColor(this)) + } + else -> { + mBinding.previousMonth.setBackgroundResource(R.drawable.download_oval_hint_up) + mBinding.previousMonth.setTextColor(Color.WHITE) + + mBinding.nextMonth.setBackgroundColor(0) + mBinding.nextMonth.setTextColor(R.color.text_title.toColor(this)) + mBinding.curMonth.setBackgroundColor(0) + mBinding.curMonth.setTextColor(R.color.text_title.toColor(this)) + } + } + } mBinding.nextMonth.setOnClickListener { v -> @@ -276,129 +367,51 @@ class ServersCalendarActivity : ToolBarActivity() { } - private fun showServersDetailDialog(calendarEntity: CalendarEntity) { - val contentView = LayoutInflater.from(this).inflate(R.layout.dialog_servers_calendear_detail, null) - val params = ViewGroup.LayoutParams(resources.displayMetrics.widthPixels, ViewGroup.LayoutParams.WRAP_CONTENT) - val dialog = Dialog(this, R.style.DialogWindowTransparent) - val window = dialog.window - window?.setGravity(Gravity.BOTTOM) - window?.setWindowAnimations(R.style.community_publication_animation) - dialog.setContentView(contentView, params) - dialog.show() + private fun showServersCalendarDetailDialog(calendarEntity: CalendarEntity) { + val currentCalendar = Calendar.getInstance().apply { + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + } + val serverCalendar = Calendar.getInstance().apply { + set(calendarEntity.year, calendarEntity.month - 1, calendarEntity.day, 0, 0, 0) + } - val calendarHint = contentView.findViewById(R.id.calendar_hint) - calendarHint.text = (calendarEntity.server.first().getFormatTime("MM-dd") + "详细开服") + // 开服表详情是否显示提醒按钮,条件如下: + // 2. 当前开服表日期大于当天日期 + val isRemindFeatureSupported = serverCalendar >= currentCalendar - val addBtn = contentView.findViewById(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(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, - mViewModel.game.id, calendarEntity.server.first().getTime() * 1000 - ), GAME_DETAIL_ADD_KAIFU_REQUEST - ) - } else { - dialog.dismiss() - showServersDetailReportDialog(calendarEntity) - } - } - - contentView.findViewById(R.id.close).setOnClickListener { - dialog.dismiss() - } - - val recyclerView = contentView.findViewById(R.id.recycler_view) - recyclerView.layoutManager = LinearLayoutManager(this) - recyclerView.adapter = object : BaseRecyclerAdapter(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, - 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(R.id.recycler_view) - val adapter = ServersDetailReportAdapter(this, calendarEntity.server) - recyclerView.layoutManager = LinearLayoutManager(this) - recyclerView.adapter = adapter - - contentView.findViewById(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(R.id.close).setOnClickListener { - dialog.dismiss() + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(reuse: EBReuse) { + if (reuse.type == Constants.LOGIN_TAG || reuse.type == Constants.LOGOUT_TAG) { + mViewModel.loadServerData() } } @@ -423,6 +436,10 @@ class ServersCalendarActivity : ToolBarActivity() { const val GAME_DETAIL_ADD_KAIFU_KEY = "GAME_DETAIL_ADD_KAIFU_KEY" const val GAME_DETAIL_PATCH_KAIFU_KEY = "GAME_DETAIL_PATCH_KAIFU_KEY" + const val SERVERS_CALENDAR_MORE_DIALOG_TAG = "ServersCalendarMoreDialog" + const val SERVERS_CALENDAR_WECHAT_SUBSCRIPTION_DIALOG_TAG = "ServersCalendarWeChatSubscriptionDialog" + const val SERVERS_CALENDAR_SUBSCRIPTION_DIALOG_TAG = "ServersCalendarSubscriptionDialog" + fun getIntent(context: Context, game: GameEntity, gameServer: GameDetailServer, me: MeEntity?): Intent { val intent = Intent(context, ServersCalendarActivity::class.java) intent.putExtra(GameEntity::class.java.simpleName, game) diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarAdapter.kt index 221d9f1279..12a1b38d2f 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarAdapter.kt @@ -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}") diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarAdvancedTime.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarAdvancedTime.kt new file mode 100644 index 0000000000..2540b1b04f --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarAdvancedTime.kt @@ -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 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailAdapter.kt new file mode 100644 index 0000000000..14d8fb819d --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailAdapter.kt @@ -0,0 +1,151 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.app.Activity +import android.graphics.Paint +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import com.gh.common.util.CheckLoginUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.common.base.BaseRecyclerViewHolder +import com.gh.gamecenter.common.constant.EntranceConsts +import com.gh.gamecenter.common.utils.dip2px +import com.gh.gamecenter.common.utils.layoutInflater +import com.gh.gamecenter.common.utils.toColor +import com.gh.gamecenter.core.utils.ToastUtils +import com.gh.gamecenter.databinding.DialogServersCalendearDetailItemBinding +import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.feature.entity.MeEntity +import com.gh.gamecenter.feature.entity.ServerCalendarEntity +import com.gh.gamecenter.servers.add.AddKaiFuActivity +import com.gh.gamecenter.servers.patch.PatchKaifuActivity +import com.lightgame.utils.Utils +import java.util.* + +class ServersCalendarDetailAdapter( + private val fragment: Fragment, + private val viewModel: ServersCalendarDetailViewModel, + private val parentViewModel: ServersCalendarViewModel +) : ListAdapter( + object : DiffUtil.ItemCallback() { + 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, + parentViewModel.game.id, + parentViewModel.getSelectTime( + viewModel.year, + viewModel.month, + viewModel.day + ) + ), ServersCalendarActivity.GAME_DETAIL_ADD_KAIFU_REQUEST + ) + } + + holder.itemView.layoutParams = (holder.itemView.layoutParams as ViewGroup.MarginLayoutParams).apply { + bottomMargin = if (itemCount == position + 1) 7F.dip2px() else 0 + } + + holder.binding.remindTitle.visibility = View.GONE + + holder.binding.remind.visibility = if (viewModel.showRemind) View.VISIBLE else View.GONE + + holder.binding.remind.isSelected = data.notifySetting != null + + holder.binding.remind.setOnClickListener { + CheckLoginUtils.checkLogin(it.context, "游戏详情-开服日历表-开服详情-开服提醒") { + if ((System.currentTimeMillis() - (data.getTime() * 1000)) > 0) { + ToastUtils.showToast(it.context.getString(R.string.servers_calendar_time_out_of_date)) + return@checkLogin + } + ServersCalendarDetailsRemindDialog().apply { + arguments = Bundle().apply { + putString(EntranceConsts.KEY_SERVER_CALENDAR_ID, data.id) + } + showNow(fragment.childFragmentManager, null) + } + } + } + } + + class ServersCalendarDetailViewHolder(val binding: DialogServersCalendearDetailItemBinding) : + BaseRecyclerViewHolder(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 + ) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailDialog.kt new file mode 100644 index 0000000000..d145bf2f8e --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailDialog.kt @@ -0,0 +1,164 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.app.Dialog +import android.graphics.Paint +import android.os.Bundle +import android.view.* +import android.widget.TextView +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.activityViewModels +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.gh.gamecenter.R +import com.gh.gamecenter.common.constant.EntranceConsts +import com.gh.gamecenter.common.entity.SuggestType +import com.gh.gamecenter.common.utils.viewModelProvider +import com.gh.gamecenter.databinding.DialogServersCalendearDetailBinding +import com.gh.gamecenter.databinding.LayoutServersCalendarDetailListBinding +import com.gh.gamecenter.entity.CalendarEntity +import com.gh.gamecenter.feature.entity.ServerCalendarEntity +import com.gh.gamecenter.help.HelpAndFeedbackBridge +import com.gh.gamecenter.servers.add.AddKaiFuActivity +import com.google.android.material.bottomsheet.BottomSheetDialog +import java.text.SimpleDateFormat +import java.util.* + +/** + * 游戏开服-开服表详情弹窗 + */ +class ServersCalendarDetailDialog : DialogFragment() { + + private lateinit var detailViewBinding: DialogServersCalendearDetailBinding + + private lateinit var listViewBinding: LayoutServersCalendarDetailListBinding + + private val titleFormat = SimpleDateFormat("MM-dd", Locale.CHINA) + + private val parentViewModel by activityViewModels() + + private lateinit var viewModel: ServersCalendarDetailViewModel + + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return super.onCreateDialog(savedInstanceState).apply { + window?.setWindowAnimations(R.style.community_publication_animation) + window?.setGravity(Gravity.BOTTOM) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + // 必须放在super.onCreate前面,因为子Fragment的onCreate方法也是在super.onCreate回调的时候调用 + // 如果放在super.onCreate之后,那么在页面重构时,子Fragment在onCreate方法引用通过viewModels方法获取parentViewModel将触发崩溃 + viewModel = viewModelProvider( + ServersCalendarDetailViewModel.Factory( + source = parentViewModel.calendarLiveData, + year = requireArguments().getInt(EntranceConsts.KEY_CALENDAR_YEAR, 0), + month = requireArguments().getInt(EntranceConsts.KEY_CALENDAR_MONTH, 0), + day = requireArguments().getInt(EntranceConsts.KEY_CALENDAR_DAY, 0), + showRemind = requireArguments().getBoolean(EntranceConsts.KEY_SHOW_REMIND, false) + ) + ) + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_TITLE, R.style.DialogWindowTransparent) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return DialogServersCalendearDetailBinding.inflate(inflater, container, false) + .also { + detailViewBinding = it.apply { + content.layoutResource = R.layout.layout_servers_calendar_detail_list + listViewBinding = LayoutServersCalendarDetailListBinding.bind(content.inflate()) + } + }.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // 在这里加这句代码,才能保证弹窗宽度占满屏幕 + // 如果在弹窗的Theme里面加false,那么这句代码可以去掉 + 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, + 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(R.id.recycler_view) + val adapter = ServersCalendarDetailReportAdapter(requireContext(), calendarEntity.server) + recyclerView.layoutManager = LinearLayoutManager(requireContext()) + recyclerView.adapter = adapter + + contentView.findViewById(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(R.id.close).setOnClickListener { + dialog.dismiss() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailNoDataDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailNoDataDialog.kt new file mode 100644 index 0000000000..947e9db670 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailNoDataDialog.kt @@ -0,0 +1,281 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.app.Dialog +import android.graphics.Paint +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams +import androidx.core.content.ContextCompat +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.activityViewModels +import com.gh.common.constant.Config +import com.gh.common.util.CheckLoginUtils +import com.gh.common.util.NewLogUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.common.constant.Constants +import com.gh.gamecenter.common.constant.EntranceConsts +import com.gh.gamecenter.common.entity.SuggestType +import com.gh.gamecenter.common.eventbus.EBReuse +import com.gh.gamecenter.common.utils.SensorsBridge +import com.gh.gamecenter.common.utils.WXAPIProxyFactory +import com.gh.gamecenter.common.utils.viewModelProvider +import com.gh.gamecenter.common.view.DrawableView +import com.gh.gamecenter.core.utils.SPUtils +import com.gh.gamecenter.core.utils.ToastUtils +import com.gh.gamecenter.databinding.DialogServersCalendearDetailBinding +import com.gh.gamecenter.databinding.LayoutServersCalendarDetailNoDataBinding +import com.gh.gamecenter.feature.entity.ServerCalendarNotifySetting +import com.gh.gamecenter.help.HelpAndFeedbackBridge +import com.gh.gamecenter.login.user.UserManager +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.tencent.mm.opensdk.modelbase.BaseResp +import com.tencent.mm.opensdk.modelbiz.SubscribeMessage +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import java.text.SimpleDateFormat +import java.util.* + +/** + * 游戏开服-未知服详情弹窗 + */ +class ServersCalendarDetailNoDataDialog : BottomSheetDialogFragment() { + + private val titleFormat = SimpleDateFormat("MM-dd", Locale.CHINA) + + private lateinit var detailViewBinding: DialogServersCalendearDetailBinding + private lateinit var noDataViewBinding: LayoutServersCalendarDetailNoDataBinding + + private val parentViewModel by activityViewModels() + + private lateinit var viewModel: ServersCalendarDetailNoDataViewModel + + private lateinit var wxApi: WXAPIProxyFactory.WXAPIProxy + + 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 { + private val reserved = System.currentTimeMillis().toString() + + override fun handleOnReq(req: SubscribeMessage.Req) { + req.reserved = reserved + } + + override fun handleOnResp(resp: BaseResp): SubscribeMessage.Resp? { + if (resp is SubscribeMessage.Resp && reserved == resp.reserved) { + return resp + } + return null + } + } + ) + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return DialogServersCalendearDetailBinding.inflate(inflater, container, false) + .also { + detailViewBinding = it.apply { + content.layoutResource = R.layout.layout_servers_calendar_detail_no_data + noDataViewBinding = LayoutServersCalendarDetailNoDataBinding.bind(content.inflate()) + content.layoutParams = content.layoutParams.apply { + height = LayoutParams.WRAP_CONTENT + } + } + it.container.layoutParams = it.container.layoutParams.apply { + height = LayoutParams.WRAP_CONTENT + } + }.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + detailViewBinding.calendarHint.text = "${titleFormat.format(viewModel.serverTimeInMills)}详细开服" + + detailViewBinding.feedback.paint.flags = Paint.UNDERLINE_TEXT_FLAG + detailViewBinding.feedback.paint.isAntiAlias = true + detailViewBinding.feedback.text = "意见反馈" + detailViewBinding.feedback.setOnClickListener { + HelpAndFeedbackBridge.startSuggestionActivity( + it.context, + SuggestType.GAME, + "service" + ) + } + + detailViewBinding.close.setOnClickListener { + dismissAllowingStateLoss() + } + + noDataViewBinding.appRemindCheckIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(requireContext())) + noDataViewBinding.wechatRemindCheckIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(requireContext())) + + viewModel.getServerCalenderRemind(parentViewModel.game.id) + viewModel.serverCalendarRemindLiveData.observe(viewLifecycleOwner) { + bindNoDataView(it) + } + + viewModel.wxSubscribeMsgConfigLiveData.observe(viewLifecycleOwner) { + wxApi.sendReq( + SubscribeMessage.Req().apply { + scene = it.scene + templateID = it.templateId + reserved = it.reserved + } + ) + } + + viewModel.error.observe(viewLifecycleOwner) { + ToastUtils.showToast(getString(R.string.network_error_hint)) + } + + wxApi.liveData.observe(viewLifecycleOwner) { + if (it.action == "confirm") { + viewModel.addServerCalendarRemindWithWechat( + gameId = parentViewModel.game.id, + openId = it.openId, + templateId = it.templateID, + action = it.action, + reserved = UserManager.getInstance().userId, + scene = it.scene + ) + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(reuse: EBReuse) { + if (reuse.type == Constants.LOGIN_TAG || reuse.type == Constants.LOGOUT_TAG) { + viewModel.getServerCalenderRemind(parentViewModel.game.id) + } + } + + private fun bindNoDataView(notifySetting: ServerCalendarNotifySetting?) { + viewModel.initData(notifySetting) + noDataViewBinding.run { + appRemindCheckIv.isChecked = viewModel.appRemind + wechatRemindCheckIv.isChecked = viewModel.wechatRemind + + if (notifySetting != null) { + appRemind.isEnabled = false + appRemindCheckIv.alpha = 0.4F + appRemind.setOnClickListener(null) + + wechatRemind.isEnabled = false + wechatRemindCheckIv.alpha = 0.4F + wechatRemind.setOnClickListener(null) + + addOrCancelRemind.text = getString(R.string.servers_detail_cancel_remind) + addOrCancelRemind.background = + ContextCompat.getDrawable(requireContext(), R.drawable.bg_servers_detail_cancel_no_data) + addOrCancelRemind.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.text_subtitle + ) + ) + addOrCancelRemind.setOnClickListener { + CheckLoginUtils.checkLogin(it.context, "游戏详情-开服日历表-未知服详情") { + viewModel.removeServerCalendarRemind(parentViewModel.game.id) + NewLogUtils.logLaunchServerReminderCancel( + gameId = parentViewModel.game.id, + gameName = parentViewModel.game.name ?: "", + reminderTime = viewModel.timeInSeconds, + reminderType = "未知服", + serverName = "", + launchServerTime = viewModel.timeInSeconds, + isApp = viewModel.appRemind, + isWechat = viewModel.wechatRemind + ) + SensorsBridge.trackLaunchServerReminderCancelClick( + gameId = parentViewModel.game.id, + gameName = parentViewModel.game.name ?: "", + reminderType = "未知服", + ) + } + } + } else { + appRemind.isEnabled = true + appRemindCheckIv.alpha = 1.0F + appRemind.setOnClickListener { + appRemindCheckIv.isChecked = !appRemindCheckIv.isChecked + viewModel.appRemind = appRemindCheckIv.isChecked + SPUtils.setBoolean(Constants.SP_SERVERS_CALENDAR_BY_APP, appRemindCheckIv.isChecked) + } + + wechatRemind.isEnabled = true + wechatRemindCheckIv.alpha = 1.0F + wechatRemind.setOnClickListener { + wechatRemindCheckIv.isChecked = !wechatRemindCheckIv.isChecked + viewModel.wechatRemind = wechatRemindCheckIv.isChecked + SPUtils.setBoolean(Constants.SP_SERVERS_CALENDAR_BY_WECHAT, wechatRemindCheckIv.isChecked) + } + + addOrCancelRemind.text = getString(R.string.servers_detail_add_remind) + addOrCancelRemind.setTextColor(ContextCompat.getColor(requireContext(), R.color.white)) + addOrCancelRemind.background = + ContextCompat.getDrawable(requireContext(), R.drawable.download_button_normal_style) + addOrCancelRemind.setOnClickListener { + CheckLoginUtils.checkLogin(it.context, "游戏详情-开服日历表-未知服详情") { + if (!viewModel.wechatRemind && !viewModel.appRemind) { + ToastUtils.showToast(getString(R.string.servers_calendar_no_remind_checked_hint)) + return@checkLogin + } + + NewLogUtils.logLaunchServerReminderAdd( + gameId = parentViewModel.game.id, + gameName = parentViewModel.game.name ?: "", + reminderTime = viewModel.timeInSeconds, + reminderType = "未知服", + serverName = "", + launchServerTime = viewModel.timeInSeconds, + isApp = viewModel.appRemind, + isWechat = viewModel.wechatRemind + ) + SensorsBridge.trackLaunchServerReminderClick( + gameId = parentViewModel.game.id, + gameName = parentViewModel.game.name ?: "", + reminderType = "未知服", + ) + + if (viewModel.wechatRemind) {// 勾选微信订阅后需要微信授权一次性订阅消息 + viewModel.getWXSubscribeMsgConfig() + } else { + viewModel.addServerCalendarRemind(parentViewModel.game.id) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailNoDataViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailNoDataViewModel.kt new file mode 100644 index 0000000000..3bc5a43452 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailNoDataViewModel.kt @@ -0,0 +1,140 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.annotation.SuppressLint +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.gh.common.util.CheckLoginUtils +import com.gh.gamecenter.common.constant.Constants +import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData +import com.gh.gamecenter.common.utils.toRequestBody +import com.gh.gamecenter.core.utils.SPUtils +import com.gh.gamecenter.core.utils.UrlFilterUtils +import com.gh.gamecenter.feature.entity.ServerCalendarNotifySetting +import com.gh.gamecenter.feature.entity.WXSubscribeMsgConfig +import com.gh.gamecenter.retrofit.RetrofitManager +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +class ServersCalendarDetailNoDataViewModel( + val serverTimeInMills: Long +) : ViewModel() { + + val error = NonStickyMutableLiveData() + + val wxSubscribeMsgConfigLiveData = MutableLiveData() + + val serverCalendarRemindLiveData: MutableLiveData = MutableLiveData() + + private var isDataInit = false + + var appRemind: Boolean = false + + var wechatRemind: Boolean = false + + val timeInSeconds: Int = (serverTimeInMills / 1000).toInt() + + fun initData(notifySetting: ServerCalendarNotifySetting?) { + if (isDataInit) return + appRemind = notifySetting?.byApp ?: SPUtils.getBoolean(Constants.SP_SERVERS_CALENDAR_BY_APP, true) + wechatRemind = notifySetting?.byWechat ?: SPUtils.getBoolean(Constants.SP_SERVERS_CALENDAR_BY_WECHAT, true) + isDataInit = true + } + + @SuppressLint("CheckResult") + fun getServerCalenderRemind(gameId: String) { + if (!CheckLoginUtils.isLogin()) { + serverCalendarRemindLiveData.postValue(null) + return + } + RetrofitManager.getInstance().newApi + .getServerCalendarRemind(gameId, timeInSeconds.toString()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + serverCalendarRemindLiveData.postValue(it) + }, { + serverCalendarRemindLiveData.postValue(null) + }) + } + + @SuppressLint("CheckResult") + fun addServerCalendarRemind(gameId: String) { + val requestBody = mapOf( + "by_app" to appRemind, + "by_wechat" to wechatRemind + ).toRequestBody() + RetrofitManager.getInstance().newApi + .addServerCalendarRemind(gameId, timeInSeconds.toString(), requestBody) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + getServerCalenderRemind(gameId) + }, { + error.postValue(it) + }) + } + + @SuppressLint("CheckResult") + fun removeServerCalendarRemind(gameId: String) { + RetrofitManager.getInstance().newApi + .removeServerCalendarRemind(gameId, timeInSeconds.toString()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + getServerCalenderRemind(gameId) + }, { + error.postValue(it) + }) + } + + @SuppressLint("CheckResult") + fun getWXSubscribeMsgConfig() { + RetrofitManager.getInstance().newApi + .getWxSubscribeMsgConfig(UrlFilterUtils.getFilterQuery("type", "server_new")) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + wxSubscribeMsgConfigLiveData.postValue(it) + }, { + error.postValue(it) + }) + } + + @SuppressLint("CheckResult") + fun addServerCalendarRemindWithWechat( + gameId: String, + openId: String?, + templateId: String?, + action: String, + reserved: String, + scene: Int, + ) { + val requestBody = mapOf( + "openid" to openId, + "template_id" to templateId, + "action" to action, + "scene" to scene, + "user_id" to reserved + ).toRequestBody() + + RetrofitManager.getInstance().newApi + .postWxSubscribeMsgCallback(UrlFilterUtils.getFilterQuery("type", "server_new"), requestBody) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + addServerCalendarRemind(gameId) + }, { + error.postValue(it) + }) + } + + class Factory( + private val serverTimeInMills: Long + ) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return ServersCalendarDetailNoDataViewModel(serverTimeInMills) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersDetailReportAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailReportAdapter.kt similarity index 57% rename from app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersDetailReportAdapter.kt rename to app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailReportAdapter.kt index 0d83ee7574..4105af851a 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersDetailReportAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailReportAdapter.kt @@ -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 -) : BaseRecyclerAdapter(context) { + private val serverList: List +) : BaseRecyclerAdapter(context) { private val selectedPositions = mutableListOf() @@ -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(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)) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailViewModel.kt new file mode 100644 index 0000000000..3097073d5a --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailViewModel.kt @@ -0,0 +1,38 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import androidx.lifecycle.* +import com.gh.gamecenter.entity.CalendarEntity + +class ServersCalendarDetailViewModel( + source: LiveData>, + 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>, + private val year: Int, + private val month: Int, + private val day: Int, + private val showRemind: Boolean + ) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return ServersCalendarDetailViewModel(source, year, month, day, showRemind) as T + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailsRemindDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailsRemindDialog.kt new file mode 100644 index 0000000000..66bf93b113 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailsRemindDialog.kt @@ -0,0 +1,320 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.app.Dialog +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import com.gh.common.constant.Config +import com.gh.common.util.CheckLoginUtils +import com.gh.common.util.NewLogUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.common.constant.Constants +import com.gh.gamecenter.common.constant.EntranceConsts +import com.gh.gamecenter.common.utils.SensorsBridge +import com.gh.gamecenter.common.utils.WXAPIProxyFactory +import com.gh.gamecenter.common.utils.WXAPIProxyFactory.WXAPIProxy +import com.gh.gamecenter.common.utils.WXAPIProxyFactory.WXHandler +import com.gh.gamecenter.common.utils.dip2px +import com.gh.gamecenter.common.utils.setDrawableEnd +import com.gh.gamecenter.common.utils.viewModelProvider +import com.gh.gamecenter.common.view.DrawableView +import com.gh.gamecenter.core.utils.SPUtils +import com.gh.gamecenter.core.utils.ToastUtils +import com.gh.gamecenter.databinding.DialogServersDetailRemindBinding +import com.gh.gamecenter.login.user.UserManager +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.tencent.mm.opensdk.modelbase.BaseResp +import com.tencent.mm.opensdk.modelbiz.SubscribeMessage +import com.tencent.mm.opensdk.openapi.IWXAPI +import com.tencent.mm.opensdk.openapi.WXAPIFactory +import java.text.SimpleDateFormat +import java.util.* + +/** + * 游戏开服-开服表详情-提醒详情弹窗 + */ +class ServersCalendarDetailsRemindDialog : BottomSheetDialogFragment() { + + private lateinit var viewBinding: DialogServersDetailRemindBinding + + private lateinit var viewModel: ServersCalendarDetailsRemindViewModel + + private lateinit var wxApi: WXAPIProxy + + private val parentViewModel by viewModels({ + parentFragment ?: this + }) + + private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()) + + private val activityViewModel by activityViewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NORMAL, R.style.DialogWindowTransparent) + wxApi = WXAPIProxyFactory.createWXAPI( + requireContext(), + Config.WECHAT_APPID, + object: WXHandler { + private val reserved = System.currentTimeMillis().toString() + + override fun handleOnReq(req: SubscribeMessage.Req) { + req.reserved = reserved + } + + override fun handleOnResp(resp: BaseResp): SubscribeMessage.Resp? { + if (resp is SubscribeMessage.Resp && reserved == resp.reserved) { + return resp + } + return null + } + } + ) + viewModel = viewModelProvider( + ServersCalendarDetailsRemindViewModel.Factory( + arguments?.getString(EntranceConsts.KEY_SERVER_CALENDAR_ID, "") ?: "" + ) + ) + viewModel.initCalendarLiveData(parentViewModel.calendarEntityLiveData) + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return super.onCreateDialog(savedInstanceState).apply { + window?.setWindowAnimations(R.style.community_publication_animation) + window?.setGravity(Gravity.BOTTOM) + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return DialogServersDetailRemindBinding.inflate(inflater, container, false).also { + viewBinding = it + }.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewBinding.appRemindCheckIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(requireContext())) + viewBinding.wechatRemindCheckIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(requireContext())) + + viewModel.serverCalendarEntityLiveData.observe(viewLifecycleOwner) { entity -> + entity?.let { + val serverName = if (it.getNote().isNullOrEmpty()) it.remark else it.getNote() + + viewModel.initData(it) + + viewBinding.serverName.text = serverName + viewBinding.serverTime.text = dateFormat.format(viewModel.selectedNotifyTime) + viewBinding.serverRemindTime.text = viewModel.selectedAdvancedTime.text + + viewBinding.appRemindCheckIv.isChecked = viewModel.appRemind + viewBinding.wechatRemindCheckIv.isChecked = viewModel.wechatRemind + + val notifySetting = it.notifySetting + if (notifySetting != null) { + viewBinding.serverTime.isEnabled = false + viewBinding.serverTime.setPadding(12F.dip2px(), 0, 0, 0) + viewBinding.serverTime.setDrawableEnd(null) + viewBinding.serverTime.background = + ContextCompat.getDrawable(requireContext(), R.drawable.bg_server_detail_remind_time_disabled) + viewBinding.serverTime.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.text_subtitleDesc + ) + ) + + viewBinding.serverRemindTime.isEnabled = false + viewBinding.serverRemindTime.setPadding(12F.dip2px(), 0, 0, 0) + viewBinding.serverRemindTime.setDrawableEnd(null) + viewBinding.serverRemindTime.background = + ContextCompat.getDrawable(requireContext(), R.drawable.bg_server_detail_remind_time_disabled) + viewBinding.serverRemindTime.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.text_subtitleDesc + ) + ) + + viewBinding.appRemindCheckIv.alpha = 0.4F + viewBinding.appRemind.isEnabled = false + + viewBinding.wechatRemindCheckIv.alpha = 0.4F + viewBinding.wechatRemind.isEnabled = false + + viewBinding.addOrCancelRemind.text = getString(R.string.servers_detail_cancel_remind) + viewBinding.addOrCancelRemind.background = + ContextCompat.getDrawable(requireContext(), R.drawable.bg_servers_detail_cancel_remind) + viewBinding.addOrCancelRemind.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.text_subtitle + ) + ) + viewBinding.addOrCancelRemind.setOnClickListener { + CheckLoginUtils.checkLogin(view.context, "游戏详情-开服日历表-已知服详情") { + NewLogUtils.logLaunchServerReminderCancel( + gameId = activityViewModel.game.id, + gameName = activityViewModel.game.name ?: "", + reminderTime = viewModel.selectedNotifySeconds - viewModel.selectedAdvancedTime.value, + reminderType = "已知服", + serverName = serverName ?: "", + launchServerTime = viewModel.selectedNotifySeconds, + isApp = viewModel.appRemind, + isWechat = viewModel.wechatRemind + ) + SensorsBridge.trackLaunchServerReminderCancelClick( + gameId = activityViewModel.game.id, + gameName = activityViewModel.game.name ?: "", + reminderType = "已知服" + ) + viewModel.removeServerCalendarRemind(activityViewModel.game.id) + } + } + } else { + viewBinding.serverTime.isEnabled = true + viewBinding.serverTime.setPadding(12F.dip2px(), 0, 12F.dip2px(), 0) + viewBinding.serverTime.background = + ContextCompat.getDrawable(requireContext(), R.drawable.bg_server_detail_remind_time) + viewBinding.serverTime.setDrawableEnd(R.drawable.ic_arrow_gray) + viewBinding.serverTime.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_subtitle)) + + viewBinding.serverRemindTime.isEnabled = true + viewBinding.serverRemindTime.setPadding(12F.dip2px(), 0, 12F.dip2px(), 0) + viewBinding.serverRemindTime.background = + ContextCompat.getDrawable(requireContext(), R.drawable.bg_server_detail_remind_time) + viewBinding.serverRemindTime.setDrawableEnd(R.drawable.ic_arrow_gray) + viewBinding.serverRemindTime.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.text_subtitle + ) + ) + + viewBinding.appRemindCheckIv.alpha = 1.0F + viewBinding.appRemind.isEnabled = true + + viewBinding.wechatRemindCheckIv.alpha = 1.0F + viewBinding.wechatRemind.isEnabled = true + + viewBinding.addOrCancelRemind.text = getString(R.string.servers_detail_add_remind) + viewBinding.addOrCancelRemind.setTextColor(ContextCompat.getColor(requireContext(), R.color.white)) + viewBinding.addOrCancelRemind.background = + ContextCompat.getDrawable(requireContext(), R.drawable.download_button_normal_style) + viewBinding.addOrCancelRemind.setOnClickListener { view -> + CheckLoginUtils.checkLogin(view.context, "游戏详情-开服日历表-已知服详情") { + if (!viewModel.wechatRemind && !viewModel.appRemind) { + ToastUtils.showToast(getString(R.string.servers_calendar_no_remind_checked_hint)) + return@checkLogin + } + + val selectedNotifyTime = viewModel.selectedNotifyTime + val selectedAdvancedTime = viewModel.selectedAdvancedTime.value + if (selectedNotifyTime - selectedAdvancedTime * 1000 < System.currentTimeMillis()) { + ToastUtils.showToast(getString(R.string.servers_calendar_remind_time_out_of_date)) + return@checkLogin + } + + NewLogUtils.logLaunchServerReminderAdd( + gameId = activityViewModel.game.id, + gameName = activityViewModel.game.name ?: "", + reminderTime = viewModel.selectedNotifySeconds - viewModel.selectedAdvancedTime.value, + reminderType = "已知服", + serverName = serverName ?: "", + launchServerTime = viewModel.selectedNotifySeconds, + isApp = viewModel.appRemind, + isWechat = viewModel.wechatRemind + ) + + SensorsBridge.trackLaunchServerReminderClick( + gameId = activityViewModel.game.id, + gameName = activityViewModel.game.name ?: "", + reminderType = "已知服" + ) + + if (viewModel.wechatRemind) {// 勾选微信订阅后需要微信授权一次性订阅消息 + viewModel.getWXSubscribeMsgConfig() + } else { + viewModel.addServerCalendarRemind(activityViewModel.game.id) + } + } + } + } + } + } + + viewModel.wxSubscribeMsgConfigLiveData.observe(viewLifecycleOwner) { + wxApi.sendReq( + SubscribeMessage.Req().apply { + scene = it.scene + templateID = it.templateId + reserved = it.reserved + } + ) + } + + viewModel.error.observe(viewLifecycleOwner) { + ToastUtils.showToast(getString(R.string.network_error_hint)) + } + + wxApi.liveData.observe(viewLifecycleOwner) { + if (it.action == "confirm") { + viewModel.addServerCalendarRemindWithWechat( + gameId = activityViewModel.game.id, + openId = it.openId, + templateId = it.templateID, + action = it.action, + reserved = UserManager.getInstance().userId, + scene = it.scene + ) + } + } + + viewBinding.close.setOnClickListener { + dismissAllowingStateLoss() + } + + viewBinding.serverTime.setOnClickListener { + val entity = viewModel.serverCalendarEntityLiveData.value ?: return@setOnClickListener + ServersCalendarTimeSettingDialog + .create(viewModel.selectedNotifyTime, entity.getTime() * 1000) { + viewModel.selectedNotifyTime = it + viewBinding.serverTime.text = dateFormat.format(it) + } + .showNow(childFragmentManager, null) + } + + viewBinding.serverRemindTime.setOnClickListener { + ServersCalendarRemindTimeSettingDialog().also { + it.setSelectCallback { time -> + viewModel.selectedAdvancedTime = time + viewBinding.serverRemindTime.text = time.text + } + it.showNow(childFragmentManager, null) + } + } + + viewBinding.appRemind.setOnClickListener { + viewBinding.appRemindCheckIv.isChecked = !viewBinding.appRemindCheckIv.isChecked + viewModel.appRemind = viewBinding.appRemindCheckIv.isChecked + SPUtils.setBoolean(Constants.SP_SERVERS_CALENDAR_BY_APP, viewBinding.appRemindCheckIv.isChecked) + } + + viewBinding.wechatRemind.setOnClickListener { + viewBinding.wechatRemindCheckIv.isChecked = !viewBinding.wechatRemindCheckIv.isChecked + viewModel.wechatRemind = viewBinding.wechatRemindCheckIv.isChecked + SPUtils.setBoolean(Constants.SP_SERVERS_CALENDAR_BY_WECHAT, viewBinding.wechatRemindCheckIv.isChecked) + } + + viewModel.notifySettingChangeLiveData.observe(viewLifecycleOwner) { + activityViewModel.dispatchNotifySettingChange(it.first, it.second) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailsRemindViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailsRemindViewModel.kt new file mode 100644 index 0000000000..9fe53477f1 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarDetailsRemindViewModel.kt @@ -0,0 +1,160 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.annotation.SuppressLint +import androidx.lifecycle.* +import com.gh.gamecenter.common.constant.Constants +import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData +import com.gh.gamecenter.common.utils.toRequestBody +import com.gh.gamecenter.core.utils.SPUtils +import com.gh.gamecenter.core.utils.UrlFilterUtils +import com.gh.gamecenter.entity.CalendarEntity +import com.gh.gamecenter.feature.entity.ServerCalendarEntity +import com.gh.gamecenter.feature.entity.ServerCalendarNotifySetting +import com.gh.gamecenter.feature.entity.WXSubscribeMsgConfig +import com.gh.gamecenter.retrofit.RetrofitManager +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +class ServersCalendarDetailsRemindViewModel( + val id: String +) : ViewModel() { + + val error = NonStickyMutableLiveData() + + lateinit var serverCalendarEntityLiveData: LiveData + private set + + val notifySettingChangeLiveData = MutableLiveData>() + + val wxSubscribeMsgConfigLiveData = MutableLiveData() + + 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) { + serverCalendarEntityLiveData = Transformations.switchMap(source) { + Transformations.distinctUntilChanged( + MutableLiveData( + it?.server?.find { calendar -> + calendar.id == id + } + ) + ) + } + } + + fun initData(calendarEntity: ServerCalendarEntity) { + if (isDataInit) return + val notifySetting = calendarEntity.notifySetting + selectedAdvancedTime = ServersCalendarAdvancedTime.valueOf(notifySetting?.secondsAdvance) + selectedNotifyTime = (notifySetting?.notifyTime ?: calendarEntity.getTime()) * 1000 + appRemind = notifySetting?.byApp ?: SPUtils.getBoolean(Constants.SP_SERVERS_CALENDAR_BY_APP, true) + wechatRemind = notifySetting?.byWechat ?: SPUtils.getBoolean(Constants.SP_SERVERS_CALENDAR_BY_WECHAT, true) + isDataInit = true + } + + @SuppressLint("CheckResult") + fun getServerCalenderRemind(gameId: String) { + RetrofitManager.getInstance().newApi + .getServerCalendarRemind(gameId, id) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + notifySettingChangeLiveData.postValue(id to it) + }, { + notifySettingChangeLiveData.postValue(id to null) + }) + } + + @SuppressLint("CheckResult") + fun getWXSubscribeMsgConfig() { + RetrofitManager.getInstance().newApi + .getWxSubscribeMsgConfig(UrlFilterUtils.getFilterQuery("type", "server_open")) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + wxSubscribeMsgConfigLiveData.postValue(it) + }, { + error.postValue(it) + }) + } + + @SuppressLint("CheckResult") + fun addServerCalendarRemind(gameId: String) { + val requestBody = mapOf( + "notify_time" to selectedNotifySeconds, + "seconds_advance" to selectedAdvancedTime.value, + "by_app" to appRemind, + "by_wechat" to wechatRemind + ).toRequestBody() + + RetrofitManager.getInstance().newApi + .addServerCalendarRemind(gameId, id, requestBody) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + getServerCalenderRemind(gameId) + }, { + error.postValue(it) + }) + } + + @SuppressLint("CheckResult") + fun addServerCalendarRemindWithWechat( + gameId: String, + openId: String?, + templateId: String?, + action: String, + reserved: String, + scene: Int, + ) { + val requestBody = mapOf( + "openid" to openId, + "template_id" to templateId, + "action" to action, + "scene" to scene, + "user_id" to reserved + ).toRequestBody() + + RetrofitManager.getInstance().newApi + .postWxSubscribeMsgCallback(UrlFilterUtils.getFilterQuery("type", "server_open"), requestBody) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + addServerCalendarRemind(gameId) + }, { + error.postValue(it) + }) + } + + @SuppressLint("CheckResult") + fun removeServerCalendarRemind(gameId: String) { + RetrofitManager.getInstance().newApi + .removeServerCalendarRemind(gameId, id) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + getServerCalenderRemind(gameId) + }, { + error.postValue(it) + }) + } + + class Factory( + private val id: String + ) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return ServersCalendarDetailsRemindViewModel(id) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarListAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarListAdapter.kt new file mode 100644 index 0000000000..bed32bfb09 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarListAdapter.kt @@ -0,0 +1,176 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.content.Context +import android.util.Log +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import com.gh.common.util.DirectUtils +import com.gh.common.util.NewLogUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.common.baselist.ListAdapter +import com.gh.gamecenter.common.baselist.LoadType +import com.gh.gamecenter.common.utils.dip2px +import com.gh.gamecenter.common.utils.toBinding +import com.gh.gamecenter.common.viewholder.FooterViewHolder +import com.gh.gamecenter.databinding.ItemGameServerTestTimeBinding +import com.gh.gamecenter.databinding.ItemServerCalendarServerBinding +import com.gh.gamecenter.databinding.ItemServersCalendarBinding +import com.gh.gamecenter.feature.game.GameItemViewHolder +import splitties.views.backgroundColor + +class ServersCalendarListAdapter( + context: Context, + private val viewModel: ServersCalendarListViewModel +) : ListAdapter(context) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return when (viewType) { + ITEM_TYPE_FOOTER -> FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)) + ITEM_TYPE_DATA_ITEM -> ServersCalendarViewHolder(parent.toBinding()) + else -> ServersCalendarTimeViewHolder(parent.toBinding()) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + when (holder) { + is ServersCalendarViewHolder -> { + val game = mEntityList[position].game ?: return + + holder.binding.root.backgroundColor = ContextCompat.getColor(mContext, R.color.background_white) + + holder.binding.icon.displayGameIcon(game.toGameEntity()) + holder.binding.gameName.text = game.name + holder.binding.gameName.setTextColor(ContextCompat.getColor(mContext, R.color.text_title)) + + // 副标题 + GameItemViewHolder.initGameSubtitleAndAdLabel( + game.toGameEntity(), + holder.binding.subtitle + ) + + // 如果开服表总数超过3个,显示开服表总数 + if (game.serversTotal > MAX_DISPLAY_SERVER_LIST_SIZE) { + holder.binding.serverCount.visibility = View.VISIBLE + holder.binding.serverCount.text = + holder.binding.root.context.getString( + R.string.servers_calendar_list_server_count, + game.serversTotal + ) + } else { + holder.binding.serverCount.visibility = View.GONE + } + + // 最多显示3条开服列表数据 + val serverList = if (game.servers.size > MAX_DISPLAY_SERVER_LIST_SIZE) { + game.servers.subList(0, MAX_DISPLAY_SERVER_LIST_SIZE) + } else { + game.servers + } + holder.binding.servers.removeAllViews() + holder.binding.serversContainer.background = ContextCompat.getDrawable( + mContext, + R.drawable.bg_shape_f8_radius_8 + ) + serverList.forEachIndexed { index, server -> + ItemServerCalendarServerBinding.inflate( + mLayoutInflater, + holder.binding.servers, + true + ).apply { + // 优先展示服务器名字,若服务器名字为空则展示备注 + val note = server.getNote() + val remark = server.remark + val name = if (note.isNullOrEmpty()) remark else note + this.name.text = name + this.time.text = server.getFormatTime("HH:mm") + root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply { + bottomMargin = if (index < serverList.size - 1) 8F.dip2px() else 0 + } + } + } + + holder.binding.root.setOnClickListener { + DirectUtils.directToGameServerCalendar( + context = it.context, + gameId = game.id, + kaifuTime = game.startMidnight + ) + NewLogUtils.logLaunchServerSubscribeClick( + gameId = game.id, + gameName = game.name, + launchServerTime = game.startMidnight.toInt() + ) + } + } + + is ServersCalendarTimeViewHolder -> { + holder.binding.root.backgroundColor = ContextCompat.getColor(mContext, R.color.background_white) + holder.binding.timeTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_subtitle)) + holder.binding.timeTv.text = + ServersCalendarListFragment.formatTime(mContext, (mEntityList[position].time ?: 0) * 1000) + } + + is FooterViewHolder -> initFooterViewHolder(holder, mIsLoading, mIsNetworkError, mIsOver) + } + } + + fun initFooterViewHolder( + viewHolder: FooterViewHolder, + isLoading: Boolean, + isNetworkError: Boolean, + isOver: Boolean + ) { + viewHolder.run { + if (isNetworkError) { + loading.visibility = View.GONE + hint.setText(R.string.loading_failed_retry) + itemView.isClickable = true + itemView.setOnClickListener { viewModel.load(LoadType.RETRY) } + } else if (isOver) { + loading.visibility = View.GONE + hint.setText(R.string.load_over_hint) + itemView.isClickable = false + itemView.setOnClickListener(null) + } else if (isLoading) { + loading.visibility = View.VISIBLE + hint.setText(R.string.loading) + itemView.isClickable = false + itemView.setOnClickListener(null) + } else { + loading.visibility = View.GONE + hint.setText(R.string.loading_more_hint) + itemView.isClickable = false + itemView.setOnClickListener(null) + } + } + } + + override fun getItemViewType(position: Int): Int { + return if (mEntityList[position].footer) { + ITEM_TYPE_FOOTER + } else if(mEntityList[position].time != null) { + ITEM_TYPE_DATE_HEADER + } else { + ITEM_TYPE_DATA_ITEM + } + } + + override fun getItemCount(): Int = mEntityList.size + + class ServersCalendarViewHolder(val binding: ItemServersCalendarBinding) : ViewHolder(binding.root) + + class ServersCalendarTimeViewHolder(var binding: ItemGameServerTestTimeBinding) : ViewHolder(binding.root) + + companion object { + + private const val ITEM_TYPE_FOOTER = 100 + + private const val ITEM_TYPE_DATE_HEADER = 200 + + private const val ITEM_TYPE_DATA_ITEM = 300 + + private const val MAX_DISPLAY_SERVER_LIST_SIZE = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarListFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarListFragment.kt new file mode 100644 index 0000000000..c25064135f --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarListFragment.kt @@ -0,0 +1,143 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.content.Context +import android.view.View +import android.widget.FrameLayout +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.DirectUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.common.baselist.LazyListFragment +import com.gh.gamecenter.common.baselist.ListAdapter +import com.gh.gamecenter.common.utils.viewModelProvider +import com.gh.gamecenter.databinding.FragmentServersCalendarListBinding +import java.text.SimpleDateFormat +import java.util.* + +/** + * 开服订阅-开服表 + */ +class ServersCalendarListFragment : + LazyListFragment() { + + 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) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarListViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarListViewModel.kt new file mode 100644 index 0000000000..1c60e4d677 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarListViewModel.kt @@ -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( + application + ) { + + override fun provideDataObservable(page: Int): Observable>? { + return null + } + + override fun provideDataSingle(page: Int): Single> { + return RetrofitManager.getInstance().newApi + .getServerCalendarList(page, 20) + .map { list -> + val dataList = mutableListOf() + for (formEntity in list) { + dataList.add(ItemData(time = formEntity.startMidnight)) + dataList.addAll(formEntity.games.map { game -> + ItemData(game = game.apply { + startMidnight = formEntity.startMidnight + }) + }) + } + dataList + } + } + + fun getTimeByPosition(position: Int): Long { + var time = 0L + val dataList = mResultLiveData.value + + dataList?.let { + for ((index, value) in dataList.withIndex()) { + if (value.time != null) { + time = value.time + } + if (index == position) { + return time + } + } + } + return time + } + + fun getItemAtPosition(position: Int): ItemData? { + if (position < (mResultLiveData?.value?.size ?: 0)) { + return mResultLiveData.value?.get(position) + } + return null + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { list -> + mResultLiveData.postValue( + mutableListOf() + .also { + it.addAll(list) + it.add(ItemData(footer = true)) + } + ) + } + } + + data class ItemData(val game: ServerCalendarGame? = null, val time: Long? = null, val footer: Boolean = false) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarManagementActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarManagementActivity.kt new file mode 100644 index 0000000000..ead3a6852a --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarManagementActivity.kt @@ -0,0 +1,40 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.os.PersistableBundle +import androidx.fragment.app.Fragment +import com.gh.gamecenter.R +import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout +import com.gh.gamecenter.common.utils.updateStatusBarColor + +class ServersCalendarManagementActivity : BaseActivity_TabLayout() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setNavigationTitle(R.string.servers_calendar_subscription_title) + updateStatusBarColor(R.color.background_white, R.color.background_white) + } + + override fun initFragmentList(fragments: MutableList?) { + fragments?.add(ServersCalendarListFragment()) + fragments?.add(ServersCalendarRemindListFragment()) + } + + override fun initTabTitleList(tabTitleList: MutableList?) { + tabTitleList?.add(getString(R.string.servers_calendar_list_tab)) + tabTitleList?.add(getString(R.string.servers_calendar_remind_list_tab)) + } + + override fun onDarkModeChanged() { + super.onDarkModeChanged() + updateStatusBarColor(R.color.background_white, R.color.background_white) + } + + companion object { + fun getIntent(context: Context): Intent { + return Intent(context, ServersCalendarManagementActivity::class.java) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarMoreDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarMoreDialog.kt new file mode 100644 index 0000000000..8c92788cbf --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarMoreDialog.kt @@ -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() + + 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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindListAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindListAdapter.kt new file mode 100644 index 0000000000..80569e100a --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindListAdapter.kt @@ -0,0 +1,186 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import com.gh.common.util.DirectUtils +import com.gh.common.util.NewLogUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.common.baselist.ListAdapter +import com.gh.gamecenter.common.baselist.LoadType +import com.gh.gamecenter.common.utils.toBinding +import com.gh.gamecenter.common.viewholder.FooterViewHolder +import com.gh.gamecenter.databinding.ItemServersCalendarRemindBinding +import com.gh.gamecenter.feature.game.GameItemViewHolder +import java.text.SimpleDateFormat +import java.util.* + +class ServersCalendarRemindListAdapter( + context: Context, + private val viewModel: ServersCalendarRemindListViewModel +) : ListAdapter(context) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return when (viewType) { + ITEM_TYPE_FOOTER -> FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)) + else -> ServersCalendarRemindViewHolder(parent.toBinding()) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + if (holder is ServersCalendarRemindViewHolder) { + val game = mEntityList[position].game ?: return + + holder.binding.icon.displayGameIcon(game.toGameEntity()) + holder.binding.gameName.text = game.name + + // 副标题 + GameItemViewHolder.initGameSubtitleAndAdLabel( + game.toGameEntity(), + holder.binding.subtitle + ) + + val context = holder.binding.root.context + + // 已知服: 展示设置开服时间+服务器名字/备注 + // 未知服: 展示关注开服日期 + val server = game.servers.firstOrNull() ?: return + val notifySetting = server.notifySetting ?: return + // 提醒状态 + val notifyStatus = game.notifyStatus ?: return + if ((server.getNote() + .isNullOrEmpty() && server.remark.isEmpty()) || notifyStatus == NOTIFY_STATUS_HAS_NEW || notifyStatus == NOTIFY_STATUS_EXPIRED + ) {// 未知服或未知服相关状态,仅展示日期 + val format = SimpleDateFormat("MM月dd日", Locale.getDefault()) + holder.binding.time.text = format.format(notifySetting.notifyTime * 1000) + } else {// 已知服 + val format = SimpleDateFormat("MM月dd日 HH:mm", Locale.getDefault()) + // 优先展示服务器名字,若服务器名字为空则展示备注 + val note = server.getNote() + val remark = server.remark + val name = if (note.isNullOrEmpty()) remark else note + holder.binding.time.text = context.getString( + R.string.servers_calendar_remind_list_server_name, + format.format(notifySetting.notifyTime * 1000), + name + ) + } + + // 设置提醒状态文字颜色 + val statusTextColorId = if (notifyStatus == NOTIFY_STATUS_TODO || notifyStatus == NOTIFY_STATUS_COMING) { + R.color.theme_font + } else { + R.color.text_subtitleDesc + } + holder.binding.status.setTextColor(ContextCompat.getColor(context, statusTextColorId)) + + // 设置提醒状态文案 + val statusTextId = when (notifyStatus) { + NOTIFY_STATUS_TODO -> R.string.servers_calendar_remind_status_todo + NOTIFY_STATUS_COMING -> R.string.servers_calendar_remind_status_coming + NOTIFY_STATUS_OPENED -> R.string.servers_calendar_remind_status_opened + NOTIFY_STATUS_HAS_NEW -> R.string.servers_calendar_remind_status_has_new + else -> R.string.servers_calendar_remind_status_expired + } + holder.binding.status.text = context.getString(statusTextId) + + holder.binding.root.setOnClickListener { + DirectUtils.directToGameServerCalendar( + context = it.context, + gameId = game.id, + kaifuTime = server.getTime() + ) + NewLogUtils.logLaunchServerReminderClick( + gameId = game.id, + gameName = game.name, + reminderTime = (notifySetting.notifyTime - notifySetting.secondsAdvance).toInt(), + status = notifyStatus + ) + } + + } else if (holder is FooterViewHolder) { + initFooterViewHolder(holder, mIsLoading, mIsNetworkError, mIsOver) + } + } + + fun initFooterViewHolder( + viewHolder: FooterViewHolder, + isLoading: Boolean, + isNetworkError: Boolean, + isOver: Boolean + ) { + viewHolder.run { + if (isNetworkError) { + loading.visibility = View.GONE + hint.setText(R.string.loading_failed_retry) + itemView.isClickable = true + itemView.setOnClickListener { viewModel.load(LoadType.RETRY) } + } else if (isOver) { + loading.visibility = View.GONE + hint.setText(R.string.load_over_hint) + itemView.isClickable = false + itemView.setOnClickListener(null) + } else if (isLoading) { + loading.visibility = View.VISIBLE + hint.setText(R.string.loading) + itemView.isClickable = false + itemView.setOnClickListener(null) + } else { + loading.visibility = View.GONE + hint.setText(R.string.loading_more_hint) + itemView.isClickable = false + itemView.setOnClickListener(null) + } + } + } + + override fun getItemViewType(position: Int): Int { + return if (mEntityList[position].footer) { + ITEM_TYPE_FOOTER + } else { + ITEM_TYPE_DATA + } + } + + override fun getItemCount(): Int = mEntityList.size + + class ServersCalendarRemindViewHolder(val binding: ItemServersCalendarRemindBinding) : ViewHolder(binding.root) + + companion object { + + /** + * 待提醒 + */ + private const val NOTIFY_STATUS_TODO = "todo" + + /** + * 即将开服 + */ + private const val NOTIFY_STATUS_COMING = "coming" + + /** + * 已开服 + */ + private const val NOTIFY_STATUS_OPENED = "opened" + + /** + * 有新服 + */ + private const val NOTIFY_STATUS_HAS_NEW = "has_new" + + /** + * 已过期 + */ + private const val NOTIFY_STATUS_EXPIRED = "expired" + + /** + * 未知服 + */ + private const val SERVER_TYPE_UNKNOWN = "未知服" + + private const val ITEM_TYPE_FOOTER = 100 + private const val ITEM_TYPE_DATA = 200 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindListFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindListFragment.kt new file mode 100644 index 0000000000..01a53c12ff --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindListFragment.kt @@ -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() { + + private var adapter: ServersCalendarRemindListAdapter? = null + + override fun provideListAdapter(): ListAdapter<*> { + return adapter ?: ServersCalendarRemindListAdapter( + requireContext(), + mListViewModel + ).apply { + adapter = this + } + } + + override fun onFragmentFirstVisible() { + super.onFragmentFirstVisible() + mCachedView.background = ContextCompat.getDrawable(requireContext(), R.color.background_white) + } + + override fun getItemDecoration(): RecyclerView.ItemDecoration? = null + + override fun provideListViewModel(): ServersCalendarRemindListViewModel { + return viewModelProvider() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindListViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindListViewModel.kt new file mode 100644 index 0000000000..7eae72147f --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindListViewModel.kt @@ -0,0 +1,44 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.app.Application +import com.gh.gamecenter.common.baselist.ListViewModel +import com.gh.gamecenter.feature.entity.ServerCalendarGame +import com.gh.gamecenter.retrofit.RetrofitManager +import io.reactivex.Observable +import io.reactivex.Single + +class ServersCalendarRemindListViewModel(application: Application) : + ListViewModel(application) { + + override fun provideDataObservable(page: Int): Observable>? { + return null + } + + override fun provideDataSingle(page: Int): Single> { + return RetrofitManager.getInstance().newApi + .getServerCalendarRemindList(page, 20) + .map { list -> + val dataList = mutableListOf() + list.forEach { game -> + if (game.servers.isNotEmpty()) { + dataList.add(ItemData(game = game)) + } + } + dataList + } + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { list -> + mResultLiveData.postValue( + mutableListOf() + .also { + it.addAll(list) + it.add(ItemData(footer = true)) + } + ) + } + } + + data class ItemData(val game: ServerCalendarGame? = null, val footer: Boolean = false) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindTimeSettingAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindTimeSettingAdapter.kt new file mode 100644 index 0000000000..fca221b4b5 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindTimeSettingAdapter.kt @@ -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(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(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindTimeSettingDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindTimeSettingDialog.kt new file mode 100644 index 0000000000..da6d0b38be --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarRemindTimeSettingDialog.kt @@ -0,0 +1,59 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.app.Dialog +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import com.gh.gamecenter.R +import com.gh.gamecenter.common.view.VerticalItemDecoration +import com.gh.gamecenter.databinding.DialogServersCalendarRemindTimeSettingBinding +import com.google.android.material.bottomsheet.BottomSheetDialogFragment + +/** + * 设置提醒时间弹窗 + */ +class ServersCalendarRemindTimeSettingDialog : BottomSheetDialogFragment() { + + private lateinit var viewBinding: DialogServersCalendarRemindTimeSettingBinding + + private var selectCallback: ((ServersCalendarAdvancedTime) -> Unit)? = null + + fun setSelectCallback(callback: ((ServersCalendarAdvancedTime) -> Unit)?) { + this.selectCallback = callback + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NORMAL, R.style.DialogWindowTransparent) + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return super.onCreateDialog(savedInstanceState).apply { + window?.setWindowAnimations(R.style.community_publication_animation) + window?.setGravity(Gravity.BOTTOM) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewBinding.cancel.setOnClickListener { + dismissAllowingStateLoss() + } + + viewBinding.rv.adapter = ServersCalendarRemindTimeSettingAdapter(requireContext()) { + this.selectCallback?.invoke(it) + dismissAllowingStateLoss() + } + viewBinding.rv.layoutManager = LinearLayoutManager(context) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return DialogServersCalendarRemindTimeSettingBinding.inflate(inflater, container, false).also { + viewBinding = it + }.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarSubscriptionSuccessDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarSubscriptionSuccessDialog.kt new file mode 100644 index 0000000000..e8340576dd --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarSubscriptionSuccessDialog.kt @@ -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() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarTimeSettingDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarTimeSettingDialog.kt new file mode 100644 index 0000000000..3873718708 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarTimeSettingDialog.kt @@ -0,0 +1,229 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.app.Dialog +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import com.bigkoo.pickerview.adapter.ArrayWheelAdapter +import com.contrarywind.adapter.WheelAdapter +import com.contrarywind.view.WheelView +import com.gh.gamecenter.R +import com.gh.gamecenter.common.constant.EntranceConsts +import com.gh.gamecenter.databinding.DialogServersCalendarTimeSettingBinding +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import java.text.SimpleDateFormat +import java.util.* + +/** + * 设置开服时间弹窗 + */ +class ServersCalendarTimeSettingDialog private constructor() : BottomSheetDialogFragment() { + + private lateinit var viewBinding: DialogServersCalendarTimeSettingBinding + + private lateinit var kaifuCalendar: Calendar + + private lateinit var selectKaifuCalendar: Calendar + + private val currentCalendar = Calendar.getInstance() + + private val dateFormat = SimpleDateFormat("yyyy-MM-dd hh时 mm分", Locale.getDefault()) + + private var selectCallback: ((Long) -> Unit)? = null + + fun setSelectCallback(callback: ((Long) -> Unit)?) { + this.selectCallback = callback + } + + private fun dispatchSelectCallback() { + val date = viewBinding.date.adapter.getItem(viewBinding.date.currentItem) + val hour = viewBinding.hour.adapter.getItem(viewBinding.hour.currentItem) + val minute = viewBinding.minute.adapter.getItem(viewBinding.minute.currentItem) + dateFormat.parse("$date $hour $minute")?.let { + selectCallback?.invoke(it.time) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NORMAL, R.style.DialogWindowTransparent) + selectKaifuCalendar = Calendar.getInstance().apply { + timeInMillis = arguments?.getLong(EntranceConsts.KEY_KAIFU_SELECT_TIME) ?: 0L + } + kaifuCalendar = Calendar.getInstance().apply { + timeInMillis = arguments?.getLong(EntranceConsts.KEY_KAIFU_TIME) ?: 0L + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return super.onCreateDialog(savedInstanceState).apply { + window?.setWindowAnimations(R.style.community_publication_animation) + window?.setGravity(Gravity.BOTTOM) + if (this is BottomSheetDialog) { + behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { + override fun onStateChanged(bottomSheet: View, newState: Int) { + if (newState == BottomSheetBehavior.STATE_DRAGGING) { + behavior.state = BottomSheetBehavior.STATE_EXPANDED + } + } + + override fun onSlide(bottomSheet: View, slideOffset: Float) { + } + }) + } + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return DialogServersCalendarTimeSettingBinding.inflate(inflater, container, false).also { + viewBinding = it + }.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewBinding.cancel.setOnClickListener { + dismissAllowingStateLoss() + } + + viewBinding.confirm.setOnClickListener { + dispatchSelectCallback() + dismissAllowingStateLoss() + } + + + val dateList = buildDates(currentCalendar, kaifuCalendar) + + initWheelView( + viewBinding.date, + ArrayWheelAdapter(dateList), + calculateCurrentDateItem(currentCalendar, selectKaifuCalendar), + false + ) + + initWheelView( + viewBinding.hour, + ArrayWheelAdapter(buildHours()), + selectKaifuCalendar.get(Calendar.HOUR_OF_DAY) + ) + + initWheelView( + viewBinding.minute, + ArrayWheelAdapter(buildMinutes()), + selectKaifuCalendar.get(Calendar.MINUTE) + ) + } + + companion object { + + fun create( + kaifuSelectTime: Long, + kaifuTime: Long, + selectCallback: (Long) -> Unit + ): ServersCalendarTimeSettingDialog = + ServersCalendarTimeSettingDialog().apply { + arguments = Bundle().apply { + putLong(EntranceConsts.KEY_KAIFU_SELECT_TIME, kaifuSelectTime) + putLong(EntranceConsts.KEY_KAIFU_TIME, kaifuTime) + } + setSelectCallback(selectCallback) + } + + private fun initWheelView( + wheelView: WheelView, + adapter: WheelAdapter<*>, + currentIndex: Int, + isLoop: Boolean = true + ) { + wheelView.javaClass.getDeclaredField("itemsVisible").apply { + isAccessible = true + set(wheelView, 7) + } + wheelView.setLabel("") + wheelView.setCyclic(isLoop) + wheelView.setGravity(Gravity.CENTER) + wheelView.adapter = adapter + wheelView.currentItem = currentIndex + wheelView.setTextSize(14F) + wheelView.setLineSpacingMultiplier(3F) + wheelView.setTextXOffset(0) + wheelView.setDividerColor(ContextCompat.getColor(wheelView.context, R.color.transparent)) + wheelView.setTextColorCenter(ContextCompat.getColor(wheelView.context, R.color.text_title)) + wheelView.setTextColorCenter(ContextCompat.getColor(wheelView.context, R.color.text_title)) + } + + private fun calculateCurrentDateItem( + currentCalendar: Calendar, + selectKaifuCalendar: Calendar + ): Int { + val selectKaifuTime = Calendar.getInstance().apply { + timeInMillis = selectKaifuCalendar.timeInMillis + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + val currentTime = Calendar.getInstance().apply { + timeInMillis = currentCalendar.timeInMillis + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + return ((selectKaifuTime - currentTime) / (24 * 60 * 60 * 1000)).toInt() + + } + + private fun buildDates(currentCalendar: Calendar, kaifuCalendar: Calendar): List { + val dateList = mutableListOf() + val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + val calendar = Calendar.getInstance().apply { + timeInMillis = currentCalendar.timeInMillis + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + } + + val kaifuTime = Calendar.getInstance().apply { + timeInMillis = kaifuCalendar.timeInMillis + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + var dateTime = calendar.timeInMillis + var dateOffset = (kaifuTime - dateTime) / (24 * 60 * 60 * 1000) + while (dateOffset >= 0) { + dateList.add(dateFormat.format(dateTime)) + dateTime = calendar.apply { + add(Calendar.DAY_OF_YEAR, 1) + }.timeInMillis + dateOffset = (kaifuTime - dateTime) / (24 * 60 * 60 * 1000) + } + return dateList + } + + private fun buildHours(): List { + val hourList = mutableListOf() + for (hour in 0..23) { + hourList.add("${hour}时") + } + return hourList + } + + private fun buildMinutes(): List { + val minuteList = mutableListOf() + for (minute in 0..59) { + minuteList.add("${minute}分") + } + return minuteList + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarViewModel.kt index c3afdd7e37..8709437666 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarViewModel.kt @@ -7,14 +7,12 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.gh.common.util.CheckLoginUtils -import com.gh.gamecenter.common.utils.throwExceptionInDebug -import com.gh.gamecenter.entity.* +import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData import com.gh.gamecenter.common.retrofit.BiResponse +import com.gh.gamecenter.common.utils.throwExceptionInDebug import com.gh.gamecenter.common.utils.toRequestBody -import com.gh.gamecenter.feature.entity.GameDetailServer -import com.gh.gamecenter.feature.entity.GameEntity -import com.gh.gamecenter.feature.entity.MeEntity -import com.gh.gamecenter.feature.entity.ServerCalendarEntity +import com.gh.gamecenter.entity.* +import com.gh.gamecenter.feature.entity.* import com.gh.gamecenter.login.user.UserManager import com.gh.gamecenter.retrofit.RetrofitManager import io.reactivex.Single @@ -23,18 +21,21 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import java.text.SimpleDateFormat import java.util.* -import kotlin.collections.ArrayList class ServersCalendarViewModel( application: Application, val game: GameEntity, val gameServer: GameDetailServer, - var meEntity: MeEntity? + var meEntity: MeEntity?, ) : AndroidViewModel(application) { + val error = NonStickyMutableLiveData() + val calendarLiveData: MutableLiveData> = MutableLiveData() val serversDetailLiveData: MutableLiveData = MutableLiveData() - val serverCalendarLiveData: MutableLiveData> = MutableLiveData() + val serverCalendarLiveData: MutableLiveData?> = MutableLiveData() + val serverSubscriptionLiveData = MutableLiveData() + val subscribeServerSuccessEvent = MutableLiveData() var monthCount = 0 var curWeek = 0 @@ -44,6 +45,7 @@ class ServersCalendarViewModel( var isExistCurServer = true// 当月是否存在开服 + var kaifuCalendar: Calendar? = null init { // checkExistCurSerer() @@ -59,21 +61,149 @@ class ServersCalendarViewModel( } } + /** + * 设置选中的开服表日期 + * @param kaifuTime 选中日期的时间戳 + */ + fun setKaifuTime(kaifuTime: Long) { + if (kaifuTime == 0L) return + + val currentCalendar = Calendar.getInstance().apply { + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + } + + val kaifuCalendar = Calendar.getInstance().also { + this.kaifuCalendar = it + it.timeInMillis = kaifuTime * 1000 + } + val kaifuYear = kaifuCalendar.get(Calendar.YEAR) + val kaifuMonth = kaifuCalendar.get(Calendar.MONTH) + + val currentYear = currentCalendar.get(Calendar.YEAR) + val currentMonth = currentCalendar.get(Calendar.MONTH) + + this.selectedMonth = if (kaifuYear == currentYear && kaifuMonth == currentMonth - 1) { + MonthType.PREVIOUS_MONTH + } else if (kaifuYear == currentYear && kaifuMonth == currentMonth + 1) { + MonthType.NEXT_MONTH + } else { + MonthType.CUR_MONTH + } + } + @SuppressLint("CheckResult") fun loadServerData(isMirror: Boolean = false) { - RetrofitManager.getInstance().api - .getGameServerCalendar(game.id, if (isMirror) "mirror" else "") + var apiService = RetrofitManager.getInstance().api + .getGameServerCalendar(game.id, if (isMirror) "mirror" else "", true) + + if (!CheckLoginUtils.isLogin()) { + serverSubscriptionLiveData.postValue(null) + } else { + apiService = RetrofitManager.getInstance().newApi + .getServerSubscription(game.id) + .onErrorReturnItem(ServerSubscriptionEntity()) + .zipWith(apiService) { subscription, list -> + serverSubscriptionLiveData.postValue(subscription) + list + } + } + apiService .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : BiResponse>() { - override fun onSuccess(data: MutableList) { - serverCalendarLiveData.postValue(data) - } - - override fun onFailure(exception: Exception) { + .subscribe( + { + serverCalendarLiveData.postValue(it) + }, + { serverCalendarLiveData.postValue(null) } - }) + ) + } + + @SuppressLint("CheckResult") + fun getServerSubscription(notifySubscribeSuccess: Boolean = false) { + if (!CheckLoginUtils.isLogin()) { + serverSubscriptionLiveData.postValue(null) + return + } + + // 已登录状态下检查开服表订阅状态 + RetrofitManager.getInstance().newApi + .getServerSubscription(game.id) + .onErrorReturnItem(ServerSubscriptionEntity()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + serverSubscriptionLiveData.postValue(it) + if (notifySubscribeSuccess && it.byApp) {// 发送订阅成功通知 + subscribeServerSuccessEvent.postValue(null) + } + }, + { + serverSubscriptionLiveData.postValue(null) + } + ) + } + + @SuppressLint("CheckResult") + fun subscribeServer() { + RetrofitManager.getInstance().newApi + .subscribeServer(game.id) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + getServerSubscription(true) + }, + { + error.postValue(it) + } + ) + } + + @SuppressLint("CheckResult") + fun unsubscribeServer() { + RetrofitManager.getInstance().newApi + .unsubscribeServer(game.id) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + getServerSubscription() + }, { + error.postValue(it) + } + ) + } + + fun dispatchNotifySettingChange(id: String, notifySetting: ServerCalendarNotifySetting?) { + val serverCalendarList = serverCalendarLiveData.value ?: return + + val index = serverCalendarList.indexOfFirst { + it.id == id + } + + if (index != -1) { + val oldServerCalendar = serverCalendarList[index] + val newServerCalendar = ServerCalendarEntity().apply { + this.id = oldServerCalendar.id + this.setTime(oldServerCalendar.getTime()) + this.setNote(oldServerCalendar.getNote()) + this.remark = oldServerCalendar.remark + this.setFirstName(oldServerCalendar.getFirstName()) + this.setServerName(oldServerCalendar.getServerName()) + this.type = oldServerCalendar.type + this.setDataMark(oldServerCalendar.getDataMark()) + this.notifySetting = notifySetting + } + serverCalendarList[index] = newServerCalendar + serverCalendarLiveData.value = serverCalendarList + } + } @SuppressLint("CheckResult") @@ -81,7 +211,10 @@ class ServersCalendarViewModel( val requestMap = hashMapOf>() 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() { @@ -189,6 +322,19 @@ class ServersCalendarViewModel( emitter.onSuccess(curDayData) }.subscribe(object : BiResponse>() { override fun onSuccess(data: MutableList) { + 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) } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarWeChatSubscriptionSuccessDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarWeChatSubscriptionSuccessDialog.kt new file mode 100644 index 0000000000..2c043e19b5 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarWeChatSubscriptionSuccessDialog.kt @@ -0,0 +1,58 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatDialogFragment +import androidx.fragment.app.activityViewModels +import androidx.viewpager.widget.ViewPager.LayoutParams +import com.gh.gamecenter.R +import com.gh.gamecenter.WebActivity +import com.gh.gamecenter.common.utils.dip2px +import com.gh.gamecenter.databinding.DialogWechatReserveSuccessBinding +import com.google.android.material.bottomsheet.BottomSheetDialogFragment + +/** + * 游戏订阅成功-未绑定微信弹窗 + */ +class ServersCalendarWeChatSubscriptionSuccessDialog : AppCompatDialogFragment() { + + private lateinit var viewBinding: DialogWechatReserveSuccessBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(BottomSheetDialogFragment.STYLE_NORMAL, R.style.DialogWindowTransparent) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + val rootView = DialogWechatReserveSuccessBinding.inflate(inflater, container, false) + .also { + viewBinding = it + }.root + return rootView.apply { + layoutParams = ViewGroup.LayoutParams(300F.dip2px(), LayoutParams.WRAP_CONTENT) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewBinding.closeBtn.setOnClickListener { + dismissAllowingStateLoss() + } + + viewBinding.closeBtn.setOnClickListener { + dismissAllowingStateLoss() + } + + viewBinding.titleIv.setImageResource(R.drawable.bg_servers_calendar_reserve_success) + + viewBinding.openBtn.setOnClickListener { + it.context.startActivity(WebActivity.getBindWechatIntent(context)) + dismissAllowingStateLoss() + } + + viewBinding.contentTv.text = getString(R.string.servers_calendar_subscription_dialog_wechat_content) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersDetailReportViewHolder.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersDetailReportViewHolder.kt deleted file mode 100644 index ae7ac30072..0000000000 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersDetailReportViewHolder.kt +++ /dev/null @@ -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(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)) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersDetailViewHolder.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersDetailViewHolder.kt deleted file mode 100644 index 15d442474d..0000000000 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersDetailViewHolder.kt +++ /dev/null @@ -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(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 - ) - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListActivity.kt new file mode 100644 index 0000000000..373cfa8262 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListActivity.kt @@ -0,0 +1,36 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.os.PersistableBundle +import com.gh.gamecenter.R +import com.gh.gamecenter.common.base.activity.ToolBarActivity +import com.gh.gamecenter.common.utils.updateStatusBarColor + +class ServersSubscribedGameListActivity : ToolBarActivity() { + + override fun provideNormalIntent(): Intent { + return getTargetIntent( + this, + ServersSubscribedGameListActivity::class.java, + ServersSubscribedGameListFragment::class.java + ) + } + + override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) { + super.onCreate(savedInstanceState, persistentState) + updateStatusBarColor(R.color.background_white, R.color.background_white) + } + + override fun onDarkModeChanged() { + super.onDarkModeChanged() + updateStatusBarColor(R.color.background_white, R.color.background_white) + } + + companion object { + fun getIntent(context: Context): Intent { + return Intent(context, ServersSubscribedGameListActivity::class.java) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListAdapter.kt new file mode 100644 index 0000000000..dc51c1c516 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListAdapter.kt @@ -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(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) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListFragment.kt new file mode 100644 index 0000000000..560c76c9ca --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListFragment.kt @@ -0,0 +1,80 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.os.Bundle +import android.view.View +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.NewLogUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.common.baselist.ListAdapter +import com.gh.gamecenter.common.baselist.ListFragment +import com.gh.gamecenter.common.utils.DialogHelper +import com.gh.gamecenter.common.utils.NewFlatLogUtils +import com.gh.gamecenter.common.utils.SensorsBridge +import com.gh.gamecenter.common.utils.viewModelProvider +import com.gh.gamecenter.core.utils.ToastUtils +import com.gh.gamecenter.feature.entity.GameEntity + +/** + * 开服订阅-开服表-游戏订阅 + */ +class ServersSubscribedGameListFragment : ListFragment(), + ServersSubscribedGameListAdapter.OnUnsubscribeClickListener { + + private var adapter: ServersSubscribedGameListAdapter? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setNavigationTitle(getString(R.string.servers_calendar_subscribed_game_title)) + mCachedView.background = ContextCompat.getDrawable(requireContext(), R.color.background_white) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mListViewModel.error.observe(viewLifecycleOwner) { + ToastUtils.showToast(getString(R.string.network_error_hint)) + } + } + + override fun provideListViewModel(): ServersSubscribedGameListViewModel { + return viewModelProvider() + } + + override fun provideListAdapter(): ListAdapter { + return adapter ?: ServersSubscribedGameListAdapter( + requireContext() + ).apply { + setOnUnsubscribeClickListener(this@ServersSubscribedGameListFragment) + adapter = this + } + } + + override fun onUnsubscribeClick(gameEntity: GameEntity, position: Int) { + NewLogUtils.logLaunchServerSubscribeCancel( + gameId = gameEntity.id, + gameName = gameEntity.name ?: "" + ) + SensorsBridge.trackLaunchServerSubscribeCancelClick( + gameId = gameEntity.id, + gameName = gameEntity.name ?: "" + ) + + DialogHelper.showDialog( + context = requireContext(), + title = getString(R.string.servers_subscribed_game_unsubscribe_dialog_title), + content = getString(R.string.servers_subscribed_game_unsubscribe_dialog_content), + confirmText = getString(R.string.servers_subscribed_game_unsubscribe_dialog_confirm), + cancelText = getString(R.string.servers_subscribed_game_unsubscribe_dialog_cancel), + confirmClickCallback = { + mListViewModel.unsubscribeServer(gameEntity.id) + } + ) + } + + override fun getItemDecoration(): RecyclerView.ItemDecoration? = null + + override fun onDarkModeChanged() { + super.onDarkModeChanged() + mCachedView.background = ContextCompat.getDrawable(requireContext(), R.color.background_white) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListViewModel.kt new file mode 100644 index 0000000000..caf1b6f5d1 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersSubscribedGameListViewModel.kt @@ -0,0 +1,62 @@ +package com.gh.gamecenter.gamedetail.fuli.kaifu + +import android.annotation.SuppressLint +import android.app.Application +import com.gh.gamecenter.common.baselist.ListViewModel +import com.gh.gamecenter.common.baselist.LoadStatus +import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData +import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.retrofit.RetrofitManager +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +class ServersSubscribedGameListViewModel(application: Application) : ListViewModel(application) { + + val error = NonStickyMutableLiveData() + + override fun provideDataObservable(page: Int): Observable> { + return RetrofitManager.getInstance().newApi.serversSubscribedGameList + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { + mResultLiveData.postValue(it) + } + } + + override fun loadStatusControl(size: Int) { + when (size) { + 0 -> { + mRetryParams = null + mLoadStatusLiveData.setValue(LoadStatus.INIT_EMPTY) + } + REQUEST_FAILURE_SIZE -> { + mRetryParams = mCurLoadParams + mLoadStatusLiveData.setValue(LoadStatus.INIT_FAILED) + } + else -> { + mRetryParams = null + mLoadStatusLiveData.setValue(LoadStatus.INIT_OVER) + } + } + } + + @SuppressLint("CheckResult") + fun unsubscribeServer(gameId: String) { + RetrofitManager.getInstance().newApi + .unsubscribeServer(gameId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + val dataList = mListLiveData.value ?: return@subscribe + val index = dataList.indexOfFirst { it.id == gameId } + if (index != -1) { + dataList.removeAt(index) + mListLiveData.value = dataList + } + }, { + error.postValue(it) + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/message/MessageUnreadRepository.kt b/app/src/main/java/com/gh/gamecenter/message/MessageUnreadRepository.kt index 372d808464..a342e83dbd 100644 --- a/app/src/main/java/com/gh/gamecenter/message/MessageUnreadRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/message/MessageUnreadRepository.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import com.gh.gamecenter.common.constant.Constants import com.gh.common.util.CheckLoginUtils +import com.gh.common.util.NewLogUtils import com.gh.gamecenter.core.utils.GsonUtils import com.gh.gamecenter.core.utils.SPUtils import com.gh.gamecenter.common.utils.createRequestBody @@ -13,9 +14,11 @@ import com.gh.gamecenter.db.info.GameTrendsInfo import com.gh.gamecenter.login.user.UserManager import com.gh.gamecenter.common.retrofit.BiResponse import com.gh.gamecenter.common.retrofit.Response +import com.gh.gamecenter.common.utils.SensorsBridge import com.gh.gamecenter.entity.* import com.gh.gamecenter.feature.entity.MessageUnreadEntity import com.gh.gamecenter.feature.entity.ConcernEntity +import com.gh.gamecenter.feature.entity.MessageDigestEntity import com.gh.gamecenter.feature.entity.MessageUnreadCount import com.gh.gamecenter.retrofit.RetrofitManager import com.gh.gamecenter.retrofit.service.ApiService @@ -215,10 +218,33 @@ object MessageUnreadRepository { } } + private fun getMessageUnreadDigestList(): Observable> { + if (!CheckLoginUtils.isLogin()) { + return Observable.just(emptyList()) + } + return mNewApi.getMessageUnreadDigestList(1, 100) + .onErrorReturnItem(emptyList()) + } + // 获取新消息中心入口未读消息数量 @SuppressLint("CheckResult") private fun loadNewMessageUnreadCount() { - Observable.zip(getNewMessageUnreadCount(), getDiscoveryData()) { t1, t2 -> + Observable.zip(getNewMessageUnreadCount(), getDiscoveryData(), getMessageUnreadDigestList()) { t1, t2, t3-> + t3.forEach { + SensorsBridge.trackMessageReceive( + gameId = it.gameId, + gameName = it.gameName, + sessionMessageType = it.sessionMessageTypeChinese, + messageType = it.messageTypeChinese + ) + NewLogUtils.logMessageInformPush( + gameId = it.gameId, + gameName = it.gameName, + sessionMessageType = it.sessionMessageTypeChinese, + messageType = it.messageTypeChinese + ) + } + if (t1 != 0) { messageCenterUnreadCountLiveData.postValue(t1) t1 diff --git a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalBannerAdapter.kt b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalBannerAdapter.kt index 6bb07d4f9f..e1db85f6d6 100644 --- a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalBannerAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalBannerAdapter.kt @@ -205,6 +205,10 @@ class HaloPersonalBannerAdapter(context: Context) : BaseRecyclerAdapter {// 开服管理 + DirectUtils.directToServersCalendarManagement(mContext, "我的光环-活动位") + } + else -> { DirectUtils.directToLinkPage(mContext, it, "我的光环banner", "") } diff --git a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalFragment.kt b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalFragment.kt index 0cd8bc480d..9bcef958b1 100644 --- a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalFragment.kt @@ -169,6 +169,7 @@ class HaloPersonalFragment : BaseLazyFragment() { mStubBinding.loginMessageHint.visibility == View.VISIBLE, "我的" ) + SensorsBridge.trackMessageCenterClick() // 优先进入有数字提醒的消息tab,其次是有红点提醒的游戏动态,最后是没有提醒的消息tab val defaultTabIndex = if ((mUnreadViewModel.messageUnreadCountLiveData.value?.message diff --git a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalFunctionAdapter.kt b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalFunctionAdapter.kt index 1e41f9295f..ad89ac4452 100644 --- a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalFunctionAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalFunctionAdapter.kt @@ -199,6 +199,10 @@ class HaloPersonalFunctionAdapter(context: Context) : BaseRecyclerAdapter {// 开服管理 + DirectUtils.directToServersCalendarManagement(mContext, "我的光环-更多功能") + } + else -> { DirectUtils.directToLinkPage(mContext, it, "我的光环", "更多功能") } diff --git a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalRecommendAdapter.kt b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalRecommendAdapter.kt index 0e1f5db633..3b9d1ec15a 100644 --- a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalRecommendAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalRecommendAdapter.kt @@ -233,6 +233,10 @@ class HaloPersonalRecommendAdapter(val context: Context) : BaseRecyclerAdapter {// 开服管理 + DirectUtils.directToServersCalendarManagement(mContext, "我的光环-推荐位") + } + else -> { DirectUtils.directToLinkPage(mContext, it, "我的光环", "推荐位") } diff --git a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalViewModel.kt b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalViewModel.kt index 1ec7323350..ec5d745452 100644 --- a/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/personal/HaloPersonalViewModel.kt @@ -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 diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailRecyclerView.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailRecyclerView.kt index 0557ba8114..58adef595c 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailRecyclerView.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailRecyclerView.kt @@ -1,14 +1,13 @@ package com.gh.gamecenter.qa.article.detail import android.content.Context -import android.os.Build import android.util.AttributeSet -import android.util.Log import android.view.MotionEvent import android.view.View import androidx.core.view.NestedScrollingParent2 import androidx.core.view.ViewCompat import androidx.recyclerview.widget.RecyclerView +import com.lightgame.utils.Utils /** * 资讯详情-外层列表控件 @@ -35,6 +34,7 @@ class ArticleDetailRecyclerView @JvmOverloads constructor( } override fun onStartNestedScroll(child: View, target: View, axes: Int, type: Int): Boolean { + Utils.log("ArticleDetailRv->onStartNestedScroll->child: $child, $target, axes: $axes, type: $type") val handleNestedScroll = (axes and View.SCROLL_AXIS_VERTICAL != 0) if (handleNestedScroll) { if (type == ViewCompat.TYPE_TOUCH) { @@ -46,10 +46,12 @@ class ArticleDetailRecyclerView @JvmOverloads constructor( } override fun onNestedScrollAccepted(child: View, target: View, axes: Int, type: Int) { + Utils.log("ArticleDetailRv->onNestedScrollAccepted->child: $child, target: $target, axes: $axes, type: $type") onNestedScrollAccepted(child, target, axes) } override fun onStopNestedScroll(target: View, type: Int) { + Utils.log("ArticleDetailRv->onStopNestedScroll->target: $target, type: $type") onStopNestedScroll(target) if (type == ViewCompat.TYPE_NON_TOUCH) { targetNestedScrollingView = null @@ -57,12 +59,15 @@ class ArticleDetailRecyclerView @JvmOverloads constructor( } override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) { + Utils.log("ArticleDetailRv->onNestedPreScroll->$target, dx: $dx, dy: $dy, consumed: $consumed, type: $type") // 该回调发生在内层RecyclerView滚动之前 // 如果是向下滚动并且外层RecyclerView未滚动到底部,由外层RecyclerView进行滚动 if (dy > 0 && canScrollVertically(1)) { + Utils.log("ArticleDetailRv->onNestedPreScroll1->$target, dx: $dx, dy: $dy, consumed: $consumed, type: $type") scrollBy(0, dy) consumed[1] = dy } else { + Utils.log("ArticleDetailRv->onNestedPreScroll2->$target, dx: $dx, dy: $dy, consumed: $consumed, type: $type") onNestedPreScroll(target, dx, dy, consumed) } } @@ -75,12 +80,25 @@ class ArticleDetailRecyclerView @JvmOverloads constructor( dyUnconsumed: Int, type: Int ) { + Utils.log("ArticleDetailRv->onNestedScroll->$target, dxConsumed: $dxConsumed, dyConsumed: $dyConsumed, dxUnconsumed: $dxUnconsumed, dyUnconsumed: $dyUnconsumed, type: $type") // 该回调发生在内层RecyclerView滚动之后 // 如果是向上滚动并且内层RecyclerView滚动到顶部,由外层RecyclerView进行滚动 if (dyConsumed == 0 && dyUnconsumed < 0) { + Utils.log("ArticleDetailRv->onNestedScroll1->$target, dxConsumed: $dxConsumed, dyConsumed: $dyConsumed, dxUnconsumed: $dxUnconsumed, dyUnconsumed: $dyUnconsumed, type: $type") scrollBy(0, dyUnconsumed) } else { + Utils.log("ArticleDetailRv->onNestedScroll2->$target, dxConsumed: $dxConsumed, dyConsumed: $dyConsumed, dxUnconsumed: $dxUnconsumed, dyUnconsumed: $dyUnconsumed, type: $type") onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed) } } + + override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean { + Utils.log("ArticleDetailRv->onNestedPreFling->$target, velocityX: $velocityX, velocityY: $velocityY") + return super.onNestedPreFling(target, velocityX, velocityY) + } + + override fun onNestedFling(target: View, velocityX: Float, velocityY: Float, consumed: Boolean): Boolean { + Utils.log("ArticleDetailRv->onNestedFling->$target, velocityX: $velocityX, velocityY: $velocityY, consumed:$consumed") + return super.onNestedFling(target, velocityX, velocityY, consumed) + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt index 3c78dbf8bd..725991c5ad 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt @@ -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(), diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java b/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java index 573c0ec0d9..7d8f3fb14e 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java @@ -3,13 +3,10 @@ package com.gh.gamecenter.retrofit; import android.content.Context; import com.gh.common.constant.Config; -import com.gh.gamecenter.BuildConfig; import com.gh.gamecenter.common.retrofit.BaseRetrofitManager; -import com.gh.gamecenter.common.utils.EnvHelper; import com.gh.gamecenter.retrofit.service.ApiService; import com.gh.gamecenter.retrofit.service.VApiService; import com.halo.assistant.HaloApp; -import com.lightgame.utils.Utils; import okhttp3.OkHttpClient; @@ -30,7 +27,7 @@ public class RetrofitManager extends BaseRetrofitManager { mApiService = provideService(okHttpNormalConfig, Config.API_HOST, ApiService.class); mNewApiService = provideService(okHttpNormalConfig, Config.NEW_API_HOST, ApiService.class); mUploadApiService = provideService(getOkHttpConfig(context, UPLOAD_CALL_TIME_OUT, 1), Config.API_HOST, ApiService.class); - mVApiService = provideService(okHttpNormalConfig, Config.VAPI_HOST, VApiService.class); + mVApiService = provideService(okHttpNormalConfig, Config.VAPI_HOST, VApiService.class);; } public static RetrofitManager getInstance() { diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index 3bbd444faa..f456ac1875 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -19,6 +19,9 @@ import com.gh.gamecenter.entity.BlockEntity; import com.gh.gamecenter.entity.CarouselEntity; import com.gh.gamecenter.entity.CatalogEntity; import com.gh.gamecenter.entity.CategoryEntity; +import com.gh.gamecenter.entity.ServerSubscriptionEntity; +import com.gh.gamecenter.feature.entity.CommentEntity; +import com.gh.gamecenter.feature.entity.CommentnumEntity; import com.gh.gamecenter.entity.CommonCollectionContentEntity; import com.gh.gamecenter.entity.CommonCollectionEntity; import com.gh.gamecenter.entity.DefaultAvatar; @@ -52,6 +55,11 @@ import com.gh.gamecenter.entity.HomeItemTestV2Entity; import com.gh.gamecenter.entity.ImageInfoEntity; import com.gh.gamecenter.entity.InterestedGameEntity; import com.gh.gamecenter.entity.LibaoDetailEntity; +import com.gh.gamecenter.feature.entity.LibaoEntity; +import com.gh.gamecenter.feature.entity.LibaoStatusEntity; +import com.gh.gamecenter.feature.entity.MessageDigestEntity; +import com.gh.gamecenter.feature.entity.MessageUnreadCount; +import com.gh.gamecenter.feature.entity.MessageUnreadEntity; import com.gh.gamecenter.entity.MyVideoEntity; import com.gh.gamecenter.entity.NewApiSettingsEntity; import com.gh.gamecenter.entity.NewSettingsEntity; @@ -87,6 +95,11 @@ import com.gh.gamecenter.entity.VideoDataOverViewEntity; import com.gh.gamecenter.entity.VideoDraftEntity; import com.gh.gamecenter.entity.VideoEntity; import com.gh.gamecenter.entity.VideoTagEntity; +import com.gh.gamecenter.feature.entity.ServerCalendarFormEntity; +import com.gh.gamecenter.feature.entity.ServerCalendarGame; +import com.gh.gamecenter.feature.entity.ServerCalendarNotifySetting; +import com.gh.gamecenter.feature.entity.WXSubscribeMsgConfig; +import com.gh.gamecenter.feature.entity.ViewsEntity; import com.gh.gamecenter.entity.VoteEntity; import com.gh.gamecenter.feature.entity.AnswerEntity; import com.gh.gamecenter.feature.entity.ApkEntity; @@ -116,6 +129,7 @@ import com.gh.gamecenter.gamedetail.entity.BigEvent; import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity; import com.gh.gamecenter.login.entity.UserInfoEntity; import com.gh.gamecenter.personalhome.rating.MyRating; +import com.gh.gamecenter.qa.entity.TopCommunityCategory; import com.gh.gamecenter.qa.entity.AnswerDetailEntity; import com.gh.gamecenter.qa.entity.AnswerDraftEntity; import com.gh.gamecenter.qa.entity.ArticleDetailEntity; @@ -1979,7 +1993,9 @@ public interface ApiService { * 获取游戏开服详情数据(注:和游戏详情获取到的开服数据是有区别的) */ @GET("games/{game_id}/server_calendar") - Single> getGameServerCalendar(@Path("game_id") String gameId, @Query("view") String view); + Single> getGameServerCalendar(@Path("game_id") String gameId, + @Query("view") String view, + @Query("refresh") boolean refresh); /** * 获取游戏上传提示 @@ -3225,4 +3241,84 @@ public interface ApiService { */ @POST("/users/games/{gameId}/archives/{archiveId}/replace") Single replaceArchive(@Path("gameId") String gameId, @Path("archiveId") String archiveId, @Body RequestBody body); + + /** + * 游戏开服-加入订阅 + */ + @POST("games/{game_id}/servers/subscriptions") + Observable subscribeServer(@Path("game_id") String gameId); + + /** + * 游戏开服-获取订阅状态 + */ + @GET("games/{game_id}/servers/subscriptions") + Single getServerSubscription(@Path("game_id") String gameId); + + /** + * 游戏开服-取消订阅 + */ + @DELETE("games/{game_id}/servers/subscriptions") + Observable unsubscribeServer(@Path("game_id") String gameId); + + /** + * 游戏开服-开服提醒-添加 + */ + @POST("games/{game_id}/server_calendar/{item_id_or_time}/notify_setting") + Single 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 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 getServerCalendarRemind(@Path("game_id") String gameId, + @Path("item_id_or_time") String itemIdOrTime); + + /** + * 游戏开服-获取订阅游戏列表 + */ + @GET("games/servers/subscribe_games") + Observable> getServersSubscribedGameList(); + + + /** + * 游戏开服-开服订阅-开服表 + */ + @GET("games/servers/notify_servers") + Single> getServerCalendarList(@Query("page") int page, + @Query("page_size") int pageSize); + + /** + * 游戏开服-开服订阅-开服提醒 + */ + @GET("games/servers/notify_games") + Single> getServerCalendarRemindList(@Query("page") int page, + @Query("page_size") int pageSize); + + /** + * 游戏开服-开服订阅-获取微信一次订阅消息的参数数据 + */ + @GET("messages/wechat/one_time/config") + Single getWxSubscribeMsgConfig(@Query("filter") String filter); + + /** + * 游戏开服-开服订阅-提交微信一次订阅消息的授权结果回调 + */ + @POST("messages/wechat/one_time/call_back") + Single postWxSubscribeMsgCallback(@Query("filter") String filter, + @Body RequestBody body); + /** + * 未读消息-埋点数据提供 + */ + @GET("messages/unread/event") + Observable> getMessageUnreadDigestList(@Query("page") int page, + @Query("page_size") int pageSize); } \ No newline at end of file diff --git a/app/src/main/res/drawable-night/ic_menu_gamedetail_more.xml b/app/src/main/res/drawable-night/ic_menu_more.xml similarity index 100% rename from app/src/main/res/drawable-night/ic_menu_gamedetail_more.xml rename to app/src/main/res/drawable-night/ic_menu_more.xml diff --git a/app/src/main/res/drawable-xxxhdpi/bg_servers_calendar_reserve_success.webp b/app/src/main/res/drawable-xxxhdpi/bg_servers_calendar_reserve_success.webp new file mode 100644 index 0000000000..7ed2745f85 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_servers_calendar_reserve_success.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_servers_calendar_detail_cancel_remind.png b/app/src/main/res/drawable-xxxhdpi/ic_servers_calendar_detail_cancel_remind.png new file mode 100644 index 0000000000..342f85154d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_servers_calendar_detail_cancel_remind.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_servers_calendar_detail_remind.png b/app/src/main/res/drawable-xxxhdpi/ic_servers_calendar_detail_remind.png new file mode 100644 index 0000000000..3d261c413b Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_servers_calendar_detail_remind.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_servers_subscribed_game_management.png b/app/src/main/res/drawable-xxxhdpi/ic_servers_subscribed_game_management.png new file mode 100644 index 0000000000..2cb88a84a9 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_servers_subscribed_game_management.png differ diff --git a/app/src/main/res/drawable/bg_datetime_picker_mask_bottom.xml b/app/src/main/res/drawable/bg_datetime_picker_mask_bottom.xml new file mode 100644 index 0000000000..afdeab0233 --- /dev/null +++ b/app/src/main/res/drawable/bg_datetime_picker_mask_bottom.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_datetime_picker_mask_top.xml b/app/src/main/res/drawable/bg_datetime_picker_mask_top.xml new file mode 100644 index 0000000000..6e93e72f92 --- /dev/null +++ b/app/src/main/res/drawable/bg_datetime_picker_mask_top.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_server_detail_remind_time.xml b/app/src/main/res/drawable/bg_server_detail_remind_time.xml new file mode 100644 index 0000000000..96a761dbdf --- /dev/null +++ b/app/src/main/res/drawable/bg_server_detail_remind_time.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_server_detail_remind_time_disabled.xml b/app/src/main/res/drawable/bg_server_detail_remind_time_disabled.xml new file mode 100644 index 0000000000..76dcdba322 --- /dev/null +++ b/app/src/main/res/drawable/bg_server_detail_remind_time_disabled.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_servers_detail_cancel_no_data.xml b/app/src/main/res/drawable/bg_servers_detail_cancel_no_data.xml new file mode 100644 index 0000000000..96fd57e0ad --- /dev/null +++ b/app/src/main/res/drawable/bg_servers_detail_cancel_no_data.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_servers_detail_cancel_remind.xml b/app/src/main/res/drawable/bg_servers_detail_cancel_remind.xml new file mode 100644 index 0000000000..e53aeb6c44 --- /dev/null +++ b/app/src/main/res/drawable/bg_servers_detail_cancel_remind.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shape_f5_radius_2.xml b/app/src/main/res/drawable/bg_shape_f5_radius_2.xml new file mode 100644 index 0000000000..b4295e2cf0 --- /dev/null +++ b/app/src/main/res/drawable/bg_shape_f5_radius_2.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shape_white_radius_12_top_only.xml b/app/src/main/res/drawable/bg_shape_white_radius_12_top_only.xml new file mode 100644 index 0000000000..0e8bdb2eb4 --- /dev/null +++ b/app/src/main/res/drawable/bg_shape_white_radius_12_top_only.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_menu_gamedetail_more.xml b/app/src/main/res/drawable/ic_menu_more.xml similarity index 100% rename from app/src/main/res/drawable/ic_menu_gamedetail_more.xml rename to app/src/main/res/drawable/ic_menu_more.xml diff --git a/app/src/main/res/drawable/ic_menu_gamedetail_more_light.xml b/app/src/main/res/drawable/ic_menu_more_light.xml similarity index 100% rename from app/src/main/res/drawable/ic_menu_gamedetail_more_light.xml rename to app/src/main/res/drawable/ic_menu_more_light.xml diff --git a/app/src/main/res/drawable/selector_servers_calendar_detail_item_remind.xml b/app/src/main/res/drawable/selector_servers_calendar_detail_item_remind.xml new file mode 100644 index 0000000000..e7264fe9b4 --- /dev/null +++ b/app/src/main/res/drawable/selector_servers_calendar_detail_item_remind.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_servers_calendar.xml b/app/src/main/res/layout/activity_servers_calendar.xml index d0c861a85f..f82624338d 100644 --- a/app/src/main/res/layout/activity_servers_calendar.xml +++ b/app/src/main/res/layout/activity_servers_calendar.xml @@ -148,6 +148,46 @@ app:layout_constraintTop_toBottomOf="@id/recycler_view" tools:text="官方服:腾讯版 \n混服:九游" /> + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_servers_calendar_remind_time_setting.xml b/app/src/main/res/layout/dialog_servers_calendar_remind_time_setting.xml new file mode 100644 index 0000000000..7032477ccb --- /dev/null +++ b/app/src/main/res/layout/dialog_servers_calendar_remind_time_setting.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_servers_calendar_time_setting.xml b/app/src/main/res/layout/dialog_servers_calendar_time_setting.xml new file mode 100644 index 0000000000..8086fbb8a0 --- /dev/null +++ b/app/src/main/res/layout/dialog_servers_calendar_time_setting.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_servers_calendear_detail.xml b/app/src/main/res/layout/dialog_servers_calendear_detail.xml index 07eb1bb979..18c6c107b4 100644 --- a/app/src/main/res/layout/dialog_servers_calendear_detail.xml +++ b/app/src/main/res/layout/dialog_servers_calendear_detail.xml @@ -6,6 +6,7 @@ android:layout_height="match_parent"> + app:layout_constraintTop_toTopOf="@id/calendar_hint" + app:layout_constraintBottom_toBottomOf="@id/calendar_hint" /> + tools:text="07-02详细开服" /> - - - + app:layout_constraintTop_toBottomOf="@id/close" /> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_servers_calendear_detail_item.xml b/app/src/main/res/layout/dialog_servers_calendear_detail_item.xml index 137c8fbe31..26d68b8b09 100644 --- a/app/src/main/res/layout/dialog_servers_calendear_detail_item.xml +++ b/app/src/main/res/layout/dialog_servers_calendear_detail_item.xml @@ -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,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" + android:layout_marginTop="12dp" + android:layout_marginBottom="12dp" + android:paddingEnd="8dp" android:text="区服名称" android:textColor="@color/text_subtitleDesc" android:textSize="12sp" /> @@ -34,11 +38,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" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_game_server_test_v2_list.xml b/app/src/main/res/layout/fragment_game_server_test_v2_list.xml index 49cb38fe9e..d55ac9c017 100644 --- a/app/src/main/res/layout/fragment_game_server_test_v2_list.xml +++ b/app/src/main/res/layout/fragment_game_server_test_v2_list.xml @@ -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" /> + android:layout_marginTop="-50dp" + android:visibility="visible" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_server_calendar_server.xml b/app/src/main/res/layout/item_server_calendar_server.xml new file mode 100644 index 0000000000..7a142de3f5 --- /dev/null +++ b/app/src/main/res/layout/item_server_calendar_server.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_servers_calendar.xml b/app/src/main/res/layout/item_servers_calendar.xml new file mode 100644 index 0000000000..e591991a3c --- /dev/null +++ b/app/src/main/res/layout/item_servers_calendar.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_servers_calendar_remind.xml b/app/src/main/res/layout/item_servers_calendar_remind.xml new file mode 100644 index 0000000000..7055b3af77 --- /dev/null +++ b/app/src/main/res/layout/item_servers_calendar_remind.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_servers_calendar_remind_time_setting.xml b/app/src/main/res/layout/item_servers_calendar_remind_time_setting.xml new file mode 100644 index 0000000000..94f6a12154 --- /dev/null +++ b/app/src/main/res/layout/item_servers_calendar_remind_time_setting.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_servers_subscribed_game.xml b/app/src/main/res/layout/item_servers_subscribed_game.xml new file mode 100644 index 0000000000..bae292b2fc --- /dev/null +++ b/app/src/main/res/layout/item_servers_subscribed_game.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_servers_calendar_detail_list.xml b/app/src/main/res/layout/layout_servers_calendar_detail_list.xml new file mode 100644 index 0000000000..95396dedcc --- /dev/null +++ b/app/src/main/res/layout/layout_servers_calendar_detail_list.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_servers_calendar_detail_no_data.xml b/app/src/main/res/layout/layout_servers_calendar_detail_no_data.xml new file mode 100644 index 0000000000..2322c311d2 --- /dev/null +++ b/app/src/main/res/layout/layout_servers_calendar_detail_no_data.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_article_detail.xml b/app/src/main/res/menu/menu_article_detail.xml index 0d62f21478..bdf8b539e9 100644 --- a/app/src/main/res/menu/menu_article_detail.xml +++ b/app/src/main/res/menu/menu_article_detail.xml @@ -10,7 +10,7 @@ diff --git a/app/src/main/res/menu/menu_comment_detail.xml b/app/src/main/res/menu/menu_comment_detail.xml index 3b63d7452f..baa35c84ab 100644 --- a/app/src/main/res/menu/menu_comment_detail.xml +++ b/app/src/main/res/menu/menu_comment_detail.xml @@ -4,7 +4,7 @@ diff --git a/app/src/main/res/menu/menu_forum_video_detail.xml b/app/src/main/res/menu/menu_forum_video_detail.xml index 282fb29378..f85c1266ce 100644 --- a/app/src/main/res/menu/menu_forum_video_detail.xml +++ b/app/src/main/res/menu/menu_forum_video_detail.xml @@ -3,7 +3,7 @@ diff --git a/app/src/main/res/menu/menu_game_detail.xml b/app/src/main/res/menu/menu_game_detail.xml index ff48abdbab..0caadc7a09 100644 --- a/app/src/main/res/menu/menu_game_detail.xml +++ b/app/src/main/res/menu/menu_game_detail.xml @@ -16,7 +16,7 @@ diff --git a/app/src/main/res/menu/menu_server_calendar_more.xml b/app/src/main/res/menu/menu_server_calendar_more.xml new file mode 100644 index 0000000000..32aeeda7b9 --- /dev/null +++ b/app/src/main/res/menu/menu_server_calendar_more.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8dfe8c52ec..a095ca582b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -471,4 +471,50 @@ QQ小游戏 存档数量已达上限 请选择替换覆盖的存档 + 加入订阅 + 订阅开服表,订阅后助你获得一手新服信息 + 通知时间:8:00、12:00、18:00 + 操作 + 取消订阅 + 不再接收开服消息 + 取消 + 游戏发布新服信息时,您将在消息中心收到通知。为了避免错过通知,建议您开启微信公众号提醒 + 游戏发布新服信息时,您将在消息中心和微信公众号收到通知,不会错过任何开服的消息 + 游戏订阅成功 + 我知道了 + 设置提醒时间 + 订阅游戏管理 + 开服表 + 开服提醒 + 开服订阅 + 游戏订阅 + 设置时间 + 取消 + 确认 + 当前日期暂无开服信息 + 游戏发布当天新服时提醒 + APP发送提醒信息 + 微信发送提醒信息 + 添加提醒 + 取消提醒 + 提醒详情 + 区服名称 + +%1$d + 今天 + 明天 + 待提醒 + 即将开服 + 已开服 + 有新服 + 已过期 + %1$s %2$s + 已订阅 + 取消订阅 + 确定取消订阅吗 + 确定 + 取消 + 您添加的提醒时间已过期! + 至少勾选一种提醒方式 + 区服已开服,不能设置提醒 + 网络异常,请检查手机网络状态 diff --git a/module_common/proguard-rules.pro b/module_common/proguard-rules.pro index 5a6d71fa65..7b37d9ccaf 100644 --- a/module_common/proguard-rules.pro +++ b/module_common/proguard-rules.pro @@ -74,4 +74,7 @@ ### keep models -keep class com.gh.gamecenter.common.entity.** {;} -keep class com.gh.gamecenter.common.eventbus.* {*;} --keep class com.gh.gamecenter.common.retrofit.* {*;} \ No newline at end of file +-keep class com.gh.gamecenter.common.retrofit.* {*;} + +### NonStickyMutableLiveData +-keep class androidx.arch.core.internal.** {*;} \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/constant/Constants.java b/module_common/src/main/java/com/gh/gamecenter/common/constant/Constants.java index 8443077bc5..012c7d0c0d 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/constant/Constants.java +++ b/module_common/src/main/java/com/gh/gamecenter/common/constant/Constants.java @@ -493,4 +493,8 @@ public class Constants { public static final String SP_SHOW_COMMUNITY_HOME_VIDEO_GUIDE = "show_community_home_video_guide"; public static final String SP_COMMUNITY_HOME_VIDEO_LOTTIE_LAST_PLAY_TIME = "community_home_video_lottie_last_play_time"; + + 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"; } diff --git a/module_common/src/main/java/com/gh/gamecenter/common/constant/EntranceConsts.java b/module_common/src/main/java/com/gh/gamecenter/common/constant/EntranceConsts.java index 7d4cded9f2..dea5cb5f23 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/constant/EntranceConsts.java +++ b/module_common/src/main/java/com/gh/gamecenter/common/constant/EntranceConsts.java @@ -228,6 +228,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"; @@ -306,4 +307,10 @@ public class EntranceConsts { public static final String KEY_SHOW_DOWNLOAD_MENU = "show_download_menu"; public static final String KEY_IS_FROM_MAIN_WRAPPER = "is_from_main_wrapper"; public static final String KEY_IS_FROM_HOME_TOOLBAR_WRAPPER = "is_from_home_toolbar_wrapper"; + 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"; } diff --git a/module_common/src/main/java/com/gh/gamecenter/common/livedata/NonStickyMutableLiveData.kt b/module_common/src/main/java/com/gh/gamecenter/common/livedata/NonStickyMutableLiveData.kt new file mode 100644 index 0000000000..02cb8e97be --- /dev/null +++ b/module_common/src/main/java/com/gh/gamecenter/common/livedata/NonStickyMutableLiveData.kt @@ -0,0 +1,54 @@ +package com.gh.gamecenter.common.livedata + +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer +import java.lang.reflect.Field +import java.lang.reflect.Method + +/** + * “非粘性”状态的MutableLiveData,支持用于事件传递,可避免数据倒灌等情况发生 + * 主要特点是observe方法被调用时,不会回调onChanged事件 + */ +class NonStickyMutableLiveData : MutableLiveData { + constructor(): super() + + constructor(value: T): super(value) + + override fun observe(owner: LifecycleOwner, observer: Observer) { + hook(observer) + super.observe(owner, observer) + } + + /** + * 通过反射保持Observer的mLastVersion值与LiveData的值相同, 实现LiveData的“非粘性”状态 + * @param observer observer实例 + */ + private fun hook(observer: Observer<*>) { + val classLiveData = LiveData::class.java + val fieldObservers: Field = classLiveData.getDeclaredField("mObservers") + fieldObservers.isAccessible = true + val objectObservers: Any = fieldObservers.get(this) ?: return + val classObservers: Class<*> = objectObservers.javaClass + val methodGet: Method = classObservers.getDeclaredMethod("get", Any::class.java) + methodGet.isAccessible = true + val objectWrapperEntry: Any = methodGet.invoke(objectObservers, observer) ?: return + var objectWrapper: Any? = null + if (objectWrapperEntry is Map.Entry<*, *>) { + objectWrapper = objectWrapperEntry.value + } + if (objectWrapper == null) { + throw NullPointerException("Wrapper can not be bull!") + } + val classObserverWrapper: Class<*> = objectWrapper.javaClass.superclass ?: return + val fieldLastVersion: Field = classObserverWrapper.getDeclaredField("mLastVersion") + fieldLastVersion.isAccessible = true + //get livedata's version + val fieldVersion: Field = classLiveData.getDeclaredField("mVersion") + fieldVersion.isAccessible = true + val objectVersion: Any = fieldVersion.get(this) ?: return + //set wrapper's version + fieldLastVersion.set(objectWrapper, objectVersion) + } +} \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/SensorsBridge.kt b/module_common/src/main/java/com/gh/gamecenter/common/utils/SensorsBridge.kt index 30ff1bf106..8e87084498 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/utils/SensorsBridge.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/SensorsBridge.kt @@ -55,6 +55,9 @@ object SensorsBridge { private const val KEY_SEARCH_TYPE = "search_type" private const val KEY_SEARCH_RESULT = "search_result" private const val KEY_IS_NOT_PROMPT = "is_not_prompt" + 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" @@ -117,6 +120,15 @@ object SensorsBridge { private const val EVENT_SEARCH_RESULT_RETURN = "SearchResultReturn" private const val EVENT_SEARCH_RESULT_CLICK = "SearchResultClick" private const val EVENT_ARTICLE_SEARCH_TAB_CLICK = "ArticleSearchTabClick" + 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 @@ -1949,4 +1961,202 @@ object SensorsBridge { trackEvent(EVENT_INSTALL_GAME_FINISH, json) } + /** + * 事件ID:MessageReceive + * 事件名称:消息接收事件 + * @param gameId 游戏ID + * @param gameName 游戏名称 + * @param sessionMessageType 会话类型: 游戏消息、系统消息、客服消息、互动消息、运营消息 + * @param messageType 消息类型 + * @see EVENT_MESSAGE_RECEIVE + */ + @JvmStatic + fun trackMessageReceive( + 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_RECEIVE, json) + } + + /** + * 事件ID:MessageCenterClick + * 事件名称:消息中心点击事件 + * @see EVENT_MESSAGE_CENTER_CLICK + */ + @JvmStatic + fun trackMessageCenterClick() { + val json = json {} + + trackEvent(EVENT_MESSAGE_CENTER_CLICK, json) + } + + /** + * 事件ID:MessageSessionClick + * 事件名称:消息会话点击事件 + * @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) + } + + /** + * 事件ID:MessageItemClick + * 事件名称:消息点击事件 + * @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) + } + + + /** + * 事件ID:MessageItemLinkClick + * 事件名称:消息点击事件 + * @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) + } + + /** + * 事件ID:LaunchServerSubscribeClick + * 事件名称:加入开服订阅事件 + * @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) + } + + /** + * 事件ID:LaunchServerSubscribeCancelClick + * 事件名称:取消开服订阅事件 + * @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) + } + + /** + * 事件ID:LaunchServerReminderClick + * 事件名称:添加开服提醒事件 + * @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) + } + + /** + * 事件ID:LaunchServerReminderCancelClick + * 事件名称:游戏安装完成事件 + * @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) + } } \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/WXAPIProxyFactory.java b/module_common/src/main/java/com/gh/gamecenter/common/utils/WXAPIProxyFactory.java new file mode 100644 index 0000000000..1af346a6fe --- /dev/null +++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/WXAPIProxyFactory.java @@ -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 mRespLiveData = new MutableLiveData<>(); + + public static WXAPIProxy createWXAPI(Context context, String appid) { + + final String transaction = String.valueOf(System.currentTimeMillis()); + + return createWXAPI(context, appid, new WXHandler() { + + @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 WXAPIProxy createWXAPI(Context context, String appid, WXHandler handler) { + return new WXAPIProxy<>(context, appid, handler); + } + + public static MutableLiveData getLiveData() { + return mRespLiveData; + } + + public final static class WXAPIProxy { + + private final IWXAPI mWxAPI; + + private WXHandler mHandler; + + private final MediatorLiveData mLiveData = new MediatorLiveData() {{ + addSource(mRespLiveData, input -> { + R resp = mHandler.handleOnResp(input); + if (resp != null) { + mLiveData.setValue(resp); + } + }); + }}; + + private WXAPIProxy(Context context, String appid, WXHandler 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 getLiveData() { + return mLiveData; + } + + } + + public interface WXHandler { + void handleOnReq(T req); + + R handleOnResp(BaseResp resp); + } +} diff --git a/app/src/main/res/drawable/bg_shape_f8_radius_8.xml b/module_common/src/main/res/drawable/bg_shape_f8_radius_8.xml similarity index 100% rename from app/src/main/res/drawable/bg_shape_f8_radius_8.xml rename to module_common/src/main/res/drawable/bg_shape_f8_radius_8.xml diff --git a/module_common/src/main/res/values-night/colors.xml b/module_common/src/main/res/values-night/colors.xml index 522d20e635..ff9f12b13d 100644 --- a/module_common/src/main/res/values-night/colors.xml +++ b/module_common/src/main/res/values-night/colors.xml @@ -93,6 +93,10 @@ #44AEEB + @color/theme + @color/theme_font + #0AFFFFFF + #05C400 #FFB13C diff --git a/module_common/src/main/res/values/colors.xml b/module_common/src/main/res/values/colors.xml index 95a10bed8b..53d2e041a1 100644 --- a/module_common/src/main/res/values/colors.xml +++ b/module_common/src/main/res/values/colors.xml @@ -103,6 +103,11 @@ @color/text_4BC7FF + + @color/theme + @color/theme_font + @color/black_alpha_7 + #05C400 #FFB13C diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/MessageDigestEntity.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/MessageDigestEntity.kt new file mode 100644 index 0000000000..8772e57246 --- /dev/null +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/MessageDigestEntity.kt @@ -0,0 +1,69 @@ +package com.gh.gamecenter.feature.entity + +import com.google.gson.annotations.SerializedName +import kotlinx.parcelize.IgnoredOnParcel + +data class MessageDigestEntity( + @SerializedName("_id") + var id: String = "", + @SerializedName("session_message_type") + var sessionMessageType: String = "", + @SerializedName("message_type") + var messageType: String = "", + @SerializedName("game_id") + var gameId: String = "", + @SerializedName("game_name") + var gameName: String = "" +) { + @IgnoredOnParcel + val messageTypeChinese: String + get() = when (messageType) { + "求加速回复" -> "求加速版本" + "求版本回复" -> "投票" + "comment_vote", + "answer_vote", + "answer_comment_vote", + "community_article_comment_vote", + "community_article_comment_reply_vote", + "community_article_vote", + "game_comment_vote", + "game_comment_reply_vote", + "video_vote", + "video_comment_vote", + "video_comment_reply_vote", + "game_list_comment_vote", + "game_list_vote", + "activity_comment_vote", + "activity_comment_reply_vote" -> "赞同" + "reply", + "answer", + "update-answer", + "follow_question", + "reply_answer_comment", + "answer_comment", + "community_article_comment", + "reply_community_article_comment", + "game_comment_reply", + "video_comment", + "video_comment_reply", + "game_list_comment", + "game_list_comment_reply", + "reply_activity_comment" -> "普通消息" + "system_invited", + "invited" -> "邀请" + "game_server_opening" -> "游戏开服日历" + else -> messageType + } + + @IgnoredOnParcel + val sessionMessageTypeChinese: String + get() = when (sessionMessageType) { + "system" -> "系统消息" + "user" -> "互动消息" + "announcement" -> "运营消息" + "service" -> "客服消息" + "game" -> "游戏消息" + "bbs" -> "论坛消息" + else -> sessionMessageType + } +} \ No newline at end of file diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarEntity.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarEntity.kt index 157b836363..25da966dfa 100644 --- a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarEntity.kt +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarEntity.kt @@ -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 { diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarFormEntity.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarFormEntity.kt new file mode 100644 index 0000000000..569edaa667 --- /dev/null +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarFormEntity.kt @@ -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 games: List +) \ No newline at end of file diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarGame.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarGame.kt new file mode 100644 index 0000000000..3d42b4d41d --- /dev/null +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarGame.kt @@ -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 = 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 + } +} \ No newline at end of file diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarNotifySetting.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarNotifySetting.kt new file mode 100644 index 0000000000..4aa2f23e02 --- /dev/null +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/ServerCalendarNotifySetting.kt @@ -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) + } +} \ No newline at end of file diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/WXSubscribeMsgConfig.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/WXSubscribeMsgConfig.kt new file mode 100644 index 0000000000..b809b54525 --- /dev/null +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/WXSubscribeMsgConfig.kt @@ -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 +) \ No newline at end of file diff --git a/module_login/src/main/java/com/gh/gamecenter/wxapi/WXEntryActivity.java b/module_login/src/main/java/com/gh/gamecenter/wxapi/WXEntryActivity.java index b7bc2ab61e..a27a496fb7 100644 --- a/module_login/src/main/java/com/gh/gamecenter/wxapi/WXEntryActivity.java +++ b/module_login/src/main/java/com/gh/gamecenter/wxapi/WXEntryActivity.java @@ -8,6 +8,7 @@ import android.widget.TextView; import com.alibaba.android.arouter.launcher.ARouter; import com.gh.gamecenter.common.utils.SensorsBridge; +import com.gh.gamecenter.common.utils.WXAPIProxyFactory; import com.gh.gamecenter.core.provider.IQGameProvider; import com.gh.gamecenter.login.utils.LoginHelper; import com.gh.gamecenter.common.constant.RouteConsts; @@ -100,6 +101,8 @@ public class WXEntryActivity extends Activity implements IWXAPIEventHandler, WeC if (iqGameProvider != null) { iqGameProvider.onWechatLogin(this, (SendAuth.Resp) baseResp); } + } else { + WXAPIProxyFactory.getLiveData().postValue(baseResp); } String resultString = ""; diff --git a/module_message/src/main/java/com/gh/gamecenter/message/entity/MessageGameEntity.kt b/module_message/src/main/java/com/gh/gamecenter/message/entity/MessageGameEntity.kt index 48c0f4ae50..b604d6a504 100644 --- a/module_message/src/main/java/com/gh/gamecenter/message/entity/MessageGameEntity.kt +++ b/module_message/src/main/java/com/gh/gamecenter/message/entity/MessageGameEntity.kt @@ -1,7 +1,6 @@ package com.gh.gamecenter.message.entity import com.gh.gamecenter.common.entity.LinkEntity -import com.gh.gamecenter.feature.entity.MessageEntity import com.gh.gamecenter.feature.entity.TimeEntity import com.gh.gamecenter.feature.entity.UserEntity import com.google.gson.annotations.SerializedName @@ -18,6 +17,8 @@ data class MessageGameEntity( ) { data class Content( var link: LinkEntity? = null, - var images: List = listOf() + var images: List = listOf(), + var type: String = "", + var lines: List> = emptyList() ) } \ No newline at end of file diff --git a/module_message/src/main/java/com/gh/gamecenter/message/utils/NewLogUtils.kt b/module_message/src/main/java/com/gh/gamecenter/message/utils/NewLogUtils.kt index db9e21a881..631b4471d8 100644 --- a/module_message/src/main/java/com/gh/gamecenter/message/utils/NewLogUtils.kt +++ b/module_message/src/main/java/com/gh/gamecenter/message/utils/NewLogUtils.kt @@ -51,6 +51,9 @@ object NewLogUtils { newsId: String, gameId: String, gameCollectionId: String, + sessionGameId: String, + sessionGameName: String, + sessionMessageType: String, messageType: String ) { val json = json { @@ -59,6 +62,9 @@ object NewLogUtils { "news_id" to newsId KEY_GAME_ID to gameId "game_collect_id" to gameCollectionId + "session_game_id" to sessionGameId + "session_game_name" to sessionGameName + "session_message_type" to sessionMessageType "message_type" to messageType parseAndPutMeta().invoke(this) } diff --git a/module_message/src/main/java/com/gh/gamecenter/message/view/KeFuFragmentAdapter.java b/module_message/src/main/java/com/gh/gamecenter/message/view/KeFuFragmentAdapter.java index 0408a78cd8..67fccd48a9 100644 --- a/module_message/src/main/java/com/gh/gamecenter/message/view/KeFuFragmentAdapter.java +++ b/module_message/src/main/java/com/gh/gamecenter/message/view/KeFuFragmentAdapter.java @@ -197,9 +197,9 @@ public class KeFuFragmentAdapter extends ListAdapter { linkNewSkip(linkEntity); if ("求加速回复".equals(keFuEntity.getType())) { - NewLogUtils.logMessageInformClick("", "", "", "", "求加速版本"); + NewLogUtils.logMessageInformClick("", "", "", "", "", "", "", "求加速版本"); } else if ("求版本回复".equals(keFuEntity.getType())) { - NewLogUtils.logMessageInformClick("", "", "", "", "投票"); + NewLogUtils.logMessageInformClick("", "", "", "", "", "", "", "投票"); } }); } @@ -223,9 +223,9 @@ public class KeFuFragmentAdapter extends ListAdapter { linkSkip(link); if ("求加速回复".equals(keFuEntity.getType())) { - NewLogUtils.logMessageInformClick("", "", link.getId() == null ? "" : link.getId(), "", "求加速版本"); + NewLogUtils.logMessageInformClick("", "", link.getId() == null ? "" : link.getId(), "", "", "", "", "求加速版本"); } else if ("求版本回复".equals(keFuEntity.getType())) { - NewLogUtils.logMessageInformClick("", "", link.getId() == null ? "" : link.getId(), "", "投票"); + NewLogUtils.logMessageInformClick("", "", link.getId() == null ? "" : link.getId(), "", "", "", "", "投票"); } }); } diff --git a/module_message/src/main/java/com/gh/gamecenter/message/view/MessageFragment.kt b/module_message/src/main/java/com/gh/gamecenter/message/view/MessageFragment.kt index 98a91e06ba..13961416f5 100644 --- a/module_message/src/main/java/com/gh/gamecenter/message/view/MessageFragment.kt +++ b/module_message/src/main/java/com/gh/gamecenter/message/view/MessageFragment.kt @@ -128,7 +128,8 @@ class MessageFragment : ListFragment() { entity, mEntrance, "消息_一级列表", - path + path, + "", "", "" ) if (!entity.read) { mListViewModel.postMessageRead(entity.id, entity.type) diff --git a/module_message/src/main/java/com/gh/gamecenter/message/view/MessageNormalFragment.java b/module_message/src/main/java/com/gh/gamecenter/message/view/MessageNormalFragment.java index aead04ea36..390ea8c4a8 100644 --- a/module_message/src/main/java/com/gh/gamecenter/message/view/MessageNormalFragment.java +++ b/module_message/src/main/java/com/gh/gamecenter/message/view/MessageNormalFragment.java @@ -102,7 +102,7 @@ public class MessageNormalFragment extends ListFragment }); } - public static void messageItemClickSkip(View view, MessageEntity entity, String entrance, String outerInfo, String path) { + public static void messageItemClickSkip(View view, MessageEntity entity, String entrance, String outerInfo, String path, String sessionGameId, String sessionGameName, String sessionMessageType) { if (view == null || entity == null) return; Context context = view.getContext(); CommunityEntity community; @@ -641,6 +642,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder "", entity.getArticle().getId(), "", "", + sessionGameId, sessionGameName, sessionMessageType, + "赞同" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "赞同" ); if (view.getId() == R.id.message_original) { @@ -661,6 +669,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder "", entity.getArticle().getId(), "", "", + sessionGameId, sessionGameName, sessionMessageType, + "普通消息" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "普通消息" ); if (view.getId() == R.id.message_original) { @@ -680,6 +695,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getQuestion().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + "邀请" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "邀请" ); if (view.getId() == R.id.message_original || view.getId() == R.id.message_item) { @@ -705,6 +727,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getQuestion().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + messageType + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, messageType ); ARouter.getInstance().build(RouteConsts.activity.questionDetailActivity) @@ -720,6 +749,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getQuestion().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + "普通消息" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "普通消息" ); if (view.getId() == R.id.message_original) { @@ -742,6 +778,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getQuestion().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + "普通消息" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "普通消息" ); if (newCommentDetailProvider != null) { @@ -765,6 +808,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getQuestion().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + messageType + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, messageType ); if (newCommentDetailProvider != null) { @@ -788,6 +838,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getArticle().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + messageType + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, messageType ); community = new CommunityEntity(entity.getArticle().getCommunityId(), ""); @@ -804,6 +861,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getArticle().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + "赞同" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "赞同" ); if (newCommentDetailProvider != null) { @@ -822,6 +886,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getArticle().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + "赞同" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "赞同" ); community = new CommunityEntity(entity.getArticle().getCommunityId(), ""); @@ -836,6 +907,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getArticle().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + "普通消息" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "普通消息" ); if (newCommentDetailProvider != null) { @@ -855,6 +933,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder "", "", entity.getGame().getId(), "", + sessionGameId, sessionGameName, sessionMessageType, + "赞同" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "赞同" ); IGameDetailProvider gameDetailProvider = (IGameDetailProvider) ARouter.getInstance().build(RouteConsts.provider.gameDetail).navigation(); @@ -883,6 +968,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder "", "", entity.getGame().getId(), "", + sessionGameId, sessionGameName, sessionMessageType, + messageType + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, messageType ); ExposureSource exposureSource = new ExposureSource("消息中心", ""); @@ -901,6 +993,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getVideo().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + "赞同" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "赞同" ); IDirectProvider directUtils = (IDirectProvider) ARouter.getInstance().build(RouteConsts.provider.directUtils).navigation(); @@ -921,6 +1020,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getVideo().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + messageType + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, messageType ); ARouter.getInstance().build(RouteConsts.activity.forumVideoDetailActivity) @@ -933,6 +1039,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getVideo().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + "普通消息" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "普通消息" ); String commentId; @@ -956,6 +1069,13 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder NewLogUtils.logMessageInformClick( entity.getVideo().getId(), "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + "赞同" + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, "赞同" ); if (newCommentDetailProvider != null) { @@ -973,6 +1093,23 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder case "reply_activity_comment": case "activity_comment_vote": case "activity_comment_reply_vote": + if ("reply_activity_comment".equals(entity.getType())) { + messageType = "普通消息"; + } else { + messageType = "赞同"; + } + NewLogUtils.logMessageInformClick( + entity.getVideo().getId(), + "", "", "", + sessionGameId, sessionGameName, sessionMessageType, + messageType + ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, + messageType + ); IWebProvider webProvider = (IWebProvider) ARouter.getInstance().build(RouteConsts.provider.webActivity).navigation(); if (webProvider != null) { if (view.getId() == R.id.message_original) { @@ -986,9 +1123,16 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder case "game_list_comment": NewLogUtils.logMessageInformClick( "", "", "", + sessionGameId, sessionGameName, sessionMessageType, entity.getGameList().getId(), "普通消息" ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, + "普通消息" + ); if (gameCollectionDetailProvider != null) { context.startActivity(gameCollectionDetailProvider.getSpecifiedCommentIntent( context, @@ -1000,9 +1144,16 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder case "game_list_comment_vote": NewLogUtils.logMessageInformClick( "", "", "", + sessionGameId, sessionGameName, sessionMessageType, entity.getGameList().getId(), "赞同" ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, + "赞同" + ); if (gameCollectionDetailProvider != null && newCommentDetailProvider != null) { if (TextUtils.isEmpty(entity.getComment().getTopId())) { intent = gameCollectionDetailProvider.getSpecifiedCommentIntent( @@ -1026,9 +1177,16 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder case "game_list_comment_reply": NewLogUtils.logMessageInformClick( "", "", "", + sessionGameId, sessionGameName, sessionMessageType, entity.getGameList().getId(), "普通消息" ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, + "普通消息" + ); if (newCommentDetailProvider != null) { context.startActivity(newCommentDetailProvider.getGameCollectionCommentIntent( context, @@ -1044,9 +1202,16 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder case "game_list_vote": NewLogUtils.logMessageInformClick( "", "", "", + sessionGameId, sessionGameName, sessionMessageType, entity.getGameList().getId(), "赞同" ); + SensorsBridge.trackMessageItemClick( + sessionGameId, + sessionGameName, + sessionMessageType, + "赞同" + ); if (gameCollectionDetailProvider != null) { context.startActivity(gameCollectionDetailProvider.getIntent( context, diff --git a/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListActivity.kt b/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListActivity.kt index 4f272d6a4a..75aa76b699 100644 --- a/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListActivity.kt +++ b/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListActivity.kt @@ -24,11 +24,12 @@ class MessageListActivity : ToolBarActivity() { } companion object { - fun getIntent(context: Context, type: String, name: String, gameId: String, entrance: String): Intent { + fun getIntent(context: Context, type: String, name: String, gameId: String, gameName: String, entrance: String): Intent { val bundle = Bundle() bundle.putString(EntranceConsts.KEY_TYPE, type) bundle.putString(EntranceConsts.KEY_NAME, name) bundle.putString(EntranceConsts.KEY_GAMEID, gameId) + bundle.putString(EntranceConsts.KEY_GAMENAME, gameName) bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance) return getTargetIntent( context, diff --git a/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListAdapter.kt b/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListAdapter.kt index 2713a75710..c59992e1fe 100644 --- a/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListAdapter.kt +++ b/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListAdapter.kt @@ -6,6 +6,7 @@ import android.text.Html import android.text.TextUtils import android.view.View import android.view.ViewGroup +import android.view.ViewGroup.MarginLayoutParams import android.widget.LinearLayout import android.widget.TextView import androidx.core.view.isVisible @@ -31,6 +32,7 @@ import com.gh.gamecenter.feature.provider.ILinkDirectUtilsProvider import com.gh.gamecenter.feature.provider.ISubjectProvider import com.gh.gamecenter.login.user.UserManager import com.gh.gamecenter.message.R +import com.gh.gamecenter.message.databinding.MessageLineItemBinding import com.gh.gamecenter.message.entity.MessageGameEntity import com.gh.gamecenter.message.entity.MessageItemData import com.gh.gamecenter.message.entity.MessageKeFuEntity @@ -41,6 +43,8 @@ import com.lightgame.utils.Utils class MessageListAdapter( context: Context, + private val mGameId: String, + private val mGameName: String, private val mType: String, private val mListViewModel: MessageListViewModel, private val mEntrance: String @@ -70,9 +74,8 @@ class MessageListAdapter( MessageItemViewHolder.messageItemClickSkip( view, data as MessageEntity, - "", - "", - "" + "", "", "", + mGameId, mGameName, mType ) } }, @@ -196,9 +199,21 @@ class MessageListAdapter( } linkNewSkip(linkEntity) if ("求加速回复" == entity.type) { - com.gh.gamecenter.message.utils.NewLogUtils.logMessageInformClick("", "", "", "", "求加速版本") + com.gh.gamecenter.message.utils.NewLogUtils.logMessageInformClick("", "", "", "", mGameId, mGameName, mType, "求加速版本") + SensorsBridge.trackMessageItemClick( + gameId = mGameId, + gameName = mGameName, + sessionMessageType = mType, + messageType = "求加速回复" + ) } else if ("求版本回复" == entity.type) { - com.gh.gamecenter.message.utils.NewLogUtils.logMessageInformClick("", "", "", "", "投票") + com.gh.gamecenter.message.utils.NewLogUtils.logMessageInformClick("", "", "", "", mGameId, mGameName, mType, "投票") + SensorsBridge.trackMessageItemClick( + gameId = mGameId, + gameName = mGameName, + sessionMessageType = mType, + messageType = "投票" + ) } } } @@ -224,12 +239,28 @@ class MessageListAdapter( if ("求加速回复" == entity.type) { com.gh.gamecenter.message.utils.NewLogUtils.logMessageInformClick( "", "", - (if (link.id == null) "" else link.id)!!, "", "求加速版本" + (if (link.id == null) "" else link.id)!!, "", + mGameId, mGameName, mType, + "求加速版本" + ) + SensorsBridge.trackMessageItemClick( + gameId = mGameId, + gameName = mGameName, + sessionMessageType = mType, + messageType = "求加速版本" ) } else if ("求版本回复" == entity.type) { com.gh.gamecenter.message.utils.NewLogUtils.logMessageInformClick( "", "", - (if (link.id == null) "" else link.id)!!, "", "投票" + (if (link.id == null) "" else link.id)!!, "", + mGameId, mGameName, mType, + "投票" + ) + SensorsBridge.trackMessageItemClick( + gameId = mGameId, + gameName = mGameName, + sessionMessageType = mType, + messageType = "投票" ) } } @@ -317,6 +348,32 @@ class MessageListAdapter( spannableText.copyTextAndToast("已复制:$spannableText") } + if (entity.content?.type == "game_server_opening" && entity.content?.lines?.isNotEmpty() == true) { + messageLinesContainer.removeAllViews() + messageLinesContainer.visibility = View.VISIBLE + val lines = if (entity.content!!.lines.size > 3) { + entity.content!!.lines.subList(0, 3) + } else { + entity.content!!.lines + } + lines.forEachIndexed { index, line -> + MessageLineItemBinding.inflate( + mLayoutInflater, + messageLinesContainer, + true + ).apply { + ImageUtils.display(icon, line[0]) + date.text = line[1] + serverName.text = line[2] + root.layoutParams = (root.layoutParams as MarginLayoutParams).apply { + bottomMargin = if (index < lines.size - 1) 10F.dip2px() else 0 + } + } + } + } else { + messageLinesContainer.visibility = View.GONE + } + if (!entity.content?.images.isNullOrEmpty()) { holder.binding.messageKefuImagesContainer.removeAllViews() holder.binding.messageKefuImagesContainer.visibility = View.VISIBLE @@ -369,10 +426,38 @@ class MessageListAdapter( "", "", "", + mGameId, mGameName, mType, "求加速版本" ) + SensorsBridge.trackMessageItemClick( + gameId = mGameId, + gameName = mGameName, + sessionMessageType = mType, + messageType = "求加速版本" + ) } else if ("求版本回复" == entity.type) { - com.gh.gamecenter.message.utils.NewLogUtils.logMessageInformClick("", "", "", "", "投票") + com.gh.gamecenter.message.utils.NewLogUtils.logMessageInformClick("", "", "", "", mGameId, mGameName, mType, "投票") + SensorsBridge.trackMessageItemClick( + gameId = mGameId, + gameName = mGameName, + sessionMessageType = mType, + messageType = "投票" + ) + } else if ("game_server_calendar" == linkEntity.type) { + com.gh.gamecenter.message.utils.NewLogUtils.logMessageInformClick( + "", + "", + "", + "", + mGameId, mGameName, mType, + "游戏开服日历" + ) + SensorsBridge.trackMessageItemClick( + gameId = mGameId, + gameName = mGameName, + sessionMessageType = mType, + messageType = "游戏开服日历" + ) } } } @@ -578,7 +663,6 @@ class MessageListAdapter( .withString(EntranceConsts.KEY_ENTRANCE, "消息中心-系统消息") .navigation() } - else -> { var exposureEvent: ExposureEvent? = null if (type == "游戏" || type == "game") { diff --git a/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListFragment.kt b/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListFragment.kt index 0f6d0c6f99..35c3479da7 100644 --- a/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListFragment.kt +++ b/module_message/src/main/java/com/gh/gamecenter/message/view/message/MessageListFragment.kt @@ -14,10 +14,11 @@ class MessageListFragment : ListFragment( private var mAdapter: MessageListAdapter? = null private var mType = "" private var mGameId = "" + private var mGameName = "" override fun provideListAdapter(): MessageListAdapter { if (mAdapter == null) { - mAdapter = MessageListAdapter(requireContext(), mType, mViewModel, mEntrance) + mAdapter = MessageListAdapter(requireContext(), mGameId, mGameName, mType, mViewModel, mEntrance) } return mAdapter as MessageListAdapter } @@ -30,6 +31,7 @@ class MessageListFragment : ListFragment( override fun onCreate(savedInstanceState: Bundle?) { mType = requireArguments().getString(EntranceConsts.KEY_TYPE, "") mGameId = requireArguments().getString(EntranceConsts.KEY_GAMEID, "") + mGameName = requireArguments().getString(EntranceConsts.KEY_GAMENAME, "") super.onCreate(savedInstanceState) setNavigationTitle(requireArguments().getString(EntranceConsts.KEY_NAME, "")) } diff --git a/module_message/src/main/java/com/gh/gamecenter/message/view/message/SortedMessageListAdapter.kt b/module_message/src/main/java/com/gh/gamecenter/message/view/message/SortedMessageListAdapter.kt index 201314298c..dd745c639b 100644 --- a/module_message/src/main/java/com/gh/gamecenter/message/view/message/SortedMessageListAdapter.kt +++ b/module_message/src/main/java/com/gh/gamecenter/message/view/message/SortedMessageListAdapter.kt @@ -118,6 +118,11 @@ class SortedMessageListAdapter( entity.unreadCount, "点击进入消息列表" ) + SensorsBridge.trackMessageSessionClick( + gameId = gameId, + gameName = gameName, + sessionMessageType = entity.typeChinese + ) if (entity.unreadCount > 0) { mViewModel.markSortedMessageRead(position, entity.id) } @@ -127,6 +132,7 @@ class SortedMessageListAdapter( entity.type, entity.title, gameId, + gameName, BaseActivity.mergeEntranceAndPath(mEntrance, "二级列表") ) ) diff --git a/module_message/src/main/res/layout/message_kefu_item.xml b/module_message/src/main/res/layout/message_kefu_item.xml index 30d42c68fa..c9fd5d7d3e 100644 --- a/module_message/src/main/res/layout/message_kefu_item.xml +++ b/module_message/src/main/res/layout/message_kefu_item.xml @@ -117,6 +117,21 @@ android:visibility="visible" tools:text="Kris is here to help" /> + + + + + + + + + + + \ No newline at end of file diff --git a/module_sensors_data/src/main/java/com/gh/gamecenter/sensorsdata/SensorsHelper.kt b/module_sensors_data/src/main/java/com/gh/gamecenter/sensorsdata/SensorsHelper.kt index 16b560ce5c..dcc248e9af 100644 --- a/module_sensors_data/src/main/java/com/gh/gamecenter/sensorsdata/SensorsHelper.kt +++ b/module_sensors_data/src/main/java/com/gh/gamecenter/sensorsdata/SensorsHelper.kt @@ -131,7 +131,7 @@ object SensorsHelper { @JvmStatic fun trackEvent(eventName: String, jsonObject: JSONObject) { try { - Utils.log("SensorHelper", "eventName:$eventName\n ${jsonObject.toString(4)}") + Utils.log("SensorsHelper", "eventName:$eventName\n ${jsonObject.toString(4)}") SensorsDataAPI.sharedInstance().track(eventName, jsonObject) } catch (e: JSONException) { e.printStackTrace()