From 273a9f010d7fa5f8e71f97106703b755433ce4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=A8?= Date: Tue, 11 Mar 2025 16:53:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B8=B8=E6=88=8F=E9=A2=84=E7=BA=A6?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=88=E7=AC=AC=E5=85=AD=E6=9C=9F=EF=BC=89?= =?UTF-8?q?=E2=80=94=E5=AE=A2=E6=88=B7=E7=AB=AF=20https://jira.shanqu.cc/b?= =?UTF-8?q?rowse/GHZSCY-6834?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 4 + .../main/java/com/gh/common/DefaultJsApi.kt | 54 ++++- .../gh/common/databind/BindingAdapters.java | 112 ++++++--- .../dialog/ReserveSuccessReminderDialog.kt | 217 ++++++++++++------ .../provider/BindingAdaptersProviderImpl.kt | 17 +- .../java/com/gh/common/util/DirectUtils.kt | 4 +- .../com/gh/common/util/DownloadItemUtils.kt | 6 +- .../com/gh/common/util/ReservationHelper.kt | 3 +- .../java/com/gh/gamecenter/MainActivity.java | 2 +- .../java/com/gh/gamecenter/SkipActivity.java | 11 +- .../com/gh/gamecenter/SplashScreenActivity.kt | 11 +- .../category2/CategoryV2ListAdapter.kt | 2 +- .../entity/ReserveReminderEntity.kt | 47 +++- .../com/gh/gamecenter/entity/SubjectEntity.kt | 20 +- .../gh/gamecenter/game/vertical/GameItemUi.kt | 25 +- .../game/vertical/GameVerticalAdapter.kt | 10 +- .../detail/GameCollectionDetailAdapter.kt | 2 +- .../adapter/GameDetailRelatedGameAdapter.kt | 2 +- .../CustomFoldSlideLargeImageItemAdapter.kt | 2 +- .../custom/adapter/CustomGamePluginAdapter.kt | 2 +- .../CustomGameRefreshVerticalAdapter.kt | 2 +- .../adapter/CustomGameVerticalAdapter.kt | 17 +- .../home/custom/adapter/CustomViewExt.kt | 46 +++- .../home/custom/model/CustomPageRepository.kt | 22 +- .../viewholder/CustomGameItemViewHolder.kt | 6 +- .../CustomHomeGameItemViewHolder.kt | 2 +- ...mHomeHorizontalSlideVideoItemViewHolder.kt | 2 +- .../HomeHorizontalSlideVideoItemViewHolder.kt | 2 +- .../HomeGameTestV2GameListViewHolder.kt | 6 +- .../mygame/MyFollowedGameAdapter.kt | 2 +- .../gamecenter/mygame/MyReservationAdapter.kt | 2 +- .../gh/gamecenter/mygame/PlayedGameAdapter.kt | 2 +- .../search/SearchGameFirstItemViewHolder.kt | 2 +- .../search/SearchGameIndexAdapter.kt | 2 +- .../search/SearchGameResultAdapter.kt | 2 +- .../gametest2/GameBigImageViewHolder.kt | 4 +- .../GameServerTestV2ItemViewHolder.kt | 4 +- .../simulatorgame/SimulatorGameListAdapter.kt | 2 +- .../fragment/game/GamePluginAdapter.java | 2 +- ...kt => ReserveReminderContainerFragment.kt} | 16 +- .../reserve/ReserveReminderRepository.kt | 28 +++ .../reserve/ReserveReminderViewModel.kt | 29 ++- .../drawable/bg_enable_wechat_reminders.xml | 2 +- .../res/drawable/bg_sms_reminders_unable.xml | 2 +- app/src/main/res/layout/game_item_custom.xml | 26 ++- ...ayout_reserve_calendar_reminder_unable.xml | 33 +++ .../layout_reserve_sms_reminder_enable.xml | 1 + .../layout_reserve_sms_reminder_unable.xml | 6 +- .../layout_reserve_wechat_reminder_enable.xml | 1 + .../layout_reserve_wechat_reminder_unable.xml | 6 +- app/src/main/res/values-zh-rTW/strings.xml | 7 + app/src/main/res/values/strings.xml | 9 +- .../common/constant/EntranceConsts.java | 7 + .../common/utils/CalendarEventUtils.kt | 154 +++++++++++++ .../gh/gamecenter/common/utils/ImageUtils.kt | 6 +- .../common/utils/PermissionHelper.kt | 148 +++++++++++- .../gamecenter/common/utils/SensorsBridge.kt | 61 ++++- .../gamecenter/common/view/BasicIconView.kt | 70 ++++++ .../drawable/bg_game_item_selling_point.xml | 7 + .../main/res/drawable/ic_basic_calendar.xml | 10 + .../res/layout/dialog_calendar_permission.xml | 82 +++++++ .../src/main/res/layout/layout_basic_icon.xml | 12 + .../layout/layout_game_item_selling_point.xml | 26 +++ .../src/main/res/values-night/colors.xml | 2 + .../src/main/res/values-zh-rTW/strings.xml | 8 + module_common/src/main/res/values/attrs.xml | 6 + module_common/src/main/res/values/colors.xml | 1 + module_common/src/main/res/values/strings.xml | 8 + module_common/src/main/res/values/style.xml | 6 + .../com/gh/gamecenter/core/utils/TimeUtils.kt | 105 +++++++++ .../src/main/res/values-zh-rTW/strings.xml | 9 + module_core/src/main/res/values/strings.xml | 10 + .../gamecenter/feature/entity/GameEntity.kt | 31 ++- .../gamecenter/feature/entity/TestEntity.kt | 18 ++ .../feature/game/GameItemViewHolder.kt | 9 +- .../provider/IBindingAdaptersProvider.kt | 11 +- .../src/main/res/layout/game_item.xml | 27 ++- 77 files changed, 1463 insertions(+), 219 deletions(-) rename app/src/main/java/com/halo/assistant/fragment/reserve/{ReserveReminderFragment.kt => ReserveReminderContainerFragment.kt} (91%) create mode 100644 app/src/main/res/layout/layout_reserve_calendar_reminder_unable.xml create mode 100644 module_common/src/main/java/com/gh/gamecenter/common/utils/CalendarEventUtils.kt create mode 100644 module_common/src/main/java/com/gh/gamecenter/common/view/BasicIconView.kt create mode 100644 module_common/src/main/res/drawable/bg_game_item_selling_point.xml create mode 100644 module_common/src/main/res/drawable/ic_basic_calendar.xml create mode 100644 module_common/src/main/res/layout/dialog_calendar_permission.xml create mode 100644 module_common/src/main/res/layout/layout_basic_icon.xml create mode 100644 module_common/src/main/res/layout/layout_game_item_selling_point.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1c7a5ba025..b45e80bf60 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -71,6 +71,10 @@ + + + + ? = null // 下载信息回调 private var mExposureEvent: ExposureEvent? = null // 活动曝光实体 + private val handler = Handler(Looper.getMainLooper()) + init { if (mFragment != null) { EventBus.getDefault().register(this) @@ -240,6 +246,12 @@ class DefaultJsApi( VHelper.launch(context, packageName) } } else { + val wechatPkgName = "com.tencent.mm" + if (packageName == wechatPkgName && !PackageUtils.isInstalled(context, wechatPkgName)) { + // 如果是微信客户端,需要检查是否安装微信 + ToastUtils.showToast(R.string.wechat_app_not_install_tips.toResString()) + return@runOnUiThread + } PackageLauncher.launchApp(context, packageName = packageName) } } @@ -502,6 +514,44 @@ class DefaultJsApi( } } + @JavascriptInterface + fun saveWechatQRCode(msg: Any) { + val base64StringData = msg.toString() + runOnUiThread { + (context as? FragmentActivity)?.checkStoragePermissionBeforeAction { + runOnIoThread { + val base64String = base64StringData.replace("data:image/png;base64", "") + tryWithDefaultCatch { + val imageFile = + File(HaloApp.getInstance().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".png") + val decodedString = Base64.decode(base64String, Base64.DEFAULT) + val bos = BufferedOutputStream(FileOutputStream(imageFile)) + bos.write(decodedString) + bos.flush() + bos.close() + + ImageUtils.saveImageToFile(imageFile, "", true) { + // 这里是 ui 线程 + // 保存微信二维码成功,1s 以后跳转微信 + if (mFragment != null && mFragment.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { + handler.removeCallbacksAndMessages(null) + handler.postDelayed({ + val wechatPkgName = "com.tencent.mm" + if (!PackageUtils.isInstalled(context, wechatPkgName)) { + ToastUtils.showToast(R.string.wechat_app_not_install_tips.toResString()) + return@postDelayed + } + PackageLauncher.launchApp(context, packageName = wechatPkgName) + }, 1000) + } + + } + } + } + } + } + } + @JavascriptInterface fun loginWithCallback(msg: Any, handler: CompletionHandler) { mLoginHandler = handler @@ -798,6 +848,8 @@ class DefaultJsApi( } EventBus.getDefault().unregister(this@DefaultJsApi) + + handler.removeCallbacksAndMessages(null) } } diff --git a/app/src/main/java/com/gh/common/databind/BindingAdapters.java b/app/src/main/java/com/gh/common/databind/BindingAdapters.java index b494e1d4fc..99ba512fb0 100644 --- a/app/src/main/java/com/gh/common/databind/BindingAdapters.java +++ b/app/src/main/java/com/gh/common/databind/BindingAdapters.java @@ -1,5 +1,10 @@ package com.gh.common.databind; +import static com.gh.gamecenter.entity.SubjectEntity.SUBJECT_TAG_SELLING_POINT; +import static com.gh.gamecenter.entity.SubjectEntity.SUBJECT_TAG_TEST; +import static com.gh.gamecenter.entity.SubjectEntity.SUBJECT_TAG_TYPE; +import static com.gh.gamecenter.entity.SubjectEntity.SUBJECT_TAG_UPDATE; + import android.content.Context; import android.content.Intent; import android.graphics.Color; @@ -48,6 +53,7 @@ import com.gh.download.server.BrowserInstallHelper; import com.gh.gamecenter.DownloadManagerActivity; import com.gh.gamecenter.R; import com.gh.gamecenter.WebActivity; +import com.gh.gamecenter.common.databinding.LayoutGameItemSellingPointBinding; import com.gh.gamecenter.common.entity.LinkEntity; import com.gh.gamecenter.common.utils.DarkModeUtils; import com.gh.gamecenter.common.utils.ExtensionsKt; @@ -55,6 +61,7 @@ import com.gh.gamecenter.common.utils.FileUtils; import com.gh.gamecenter.common.utils.NewFlatLogUtils; import com.gh.gamecenter.common.utils.SensorsBridge; import com.gh.gamecenter.core.utils.MtaHelper; +import com.gh.gamecenter.core.utils.TimeUtils; import com.gh.gamecenter.core.utils.ToastUtils; import com.gh.gamecenter.feature.entity.ApkEntity; import com.gh.gamecenter.feature.entity.GameEntity; @@ -289,7 +296,7 @@ public class BindingAdapters { }); break; case RESERVED: - ReservationHelper.showCancelReservationDialog(progressBar.getContext(),gameEntity, () -> { + ReservationHelper.showCancelReservationDialog(progressBar.getContext(), gameEntity, () -> { ReservationHelper.cancelReservation(gameEntity, () -> { updateReservation(progressBar, gameEntity); }); @@ -472,39 +479,37 @@ public class BindingAdapters { } } - // 包含测试开服标签 - public static void setGameTags(LinearLayout layout, GameEntity gameEntity) { + /** + * 包含测试开服标签 + * + * @param layout + * @param gameEntity + * @param subjectTag 默认为 “”,只有游戏专题可以配置subjectTag + */ + public static void setGameTags(LinearLayout layout, GameEntity gameEntity, String subjectTag) { try { if (layout.getVisibility() == View.GONE) return; ArrayList tagStyle = new ArrayList<>(); TestEntity test = gameEntity.getTest(); - if (test != null - // 这个判断用于开测表列表 - && !"type_tag".equals(test.getGameTag())) { - if ("custom".equals(test.getGameTag())) { - TagStyleEntity typeTag = new TagStyleEntity(); - if (!TextUtils.isEmpty(test.getText())) { - typeTag.setName(test.getText() != null ? test.getText() : ""); - } else { - typeTag.setName(test.getType() != null ? test.getType() : ""); - } - typeTag.setBackground("E8F3FF"); - typeTag.setColor("1383EB"); - tagStyle.add(typeTag); - } else { - TagStyleEntity typeTag = new TagStyleEntity(); - boolean isDarkModeOn = DarkModeUtils.INSTANCE.isDarkModeOn(layout.getContext()); - typeTag.setName(test.getType() != null ? test.getType() : ""); - typeTag.setBackground("1AFFA142"); - typeTag.setColor(isDarkModeOn ? "EB9238" : "FFA142"); - tagStyle.add(typeTag); + if (test != null && subjectTag.equals(SUBJECT_TAG_TEST)) { + // 显示开测表标签 + TagStyleEntity typeTag = new TagStyleEntity(); + boolean isDarkModeOn = DarkModeUtils.INSTANCE.isDarkModeOn(layout.getContext()); + typeTag.setName(test.getType() != null ? test.getType() : ""); + typeTag.setBackground("1AFFA142"); + typeTag.setColor(isDarkModeOn ? "EB9238" : "FFA142"); + tagStyle.add(typeTag); - TagStyleEntity timeTag = new TagStyleEntity(); + TagStyleEntity timeTag = new TagStyleEntity(); + if (test.getStartPending()) { + timeTag.setName(test.getStartText()); + } else { timeTag.setName(GameViewUtils.getGameTestDate(test.getStart())); - timeTag.setBackground("1A06CEA8"); - timeTag.setColor(isDarkModeOn ? "07A385" : "06CEA8"); - tagStyle.add(timeTag); } + timeTag.setBackground("1A06CEA8"); + timeTag.setColor(isDarkModeOn ? "07A385" : "06CEA8"); + tagStyle.add(timeTag); + } else { tagStyle = gameEntity.getTagStyle(); } @@ -514,6 +519,59 @@ public class BindingAdapters { } } + public static void setGameTagsWithSellingPoint(LinearLayout layout, LayoutGameItemSellingPointBinding binding, GameEntity gameEntity, String subjectTag) { + if (subjectTag.equals(SUBJECT_TAG_SELLING_POINT)) { + layout.setVisibility(View.GONE); + binding.getRoot().setVisibility(View.VISIBLE); + GameEntity.SellingPoints sellingPoints = gameEntity.getSellingPoints(); + if (sellingPoints != null) { + binding.tvSellingPoints.setVisibility(View.VISIBLE); + binding.tvSellingPoints.setText(sellingPoints.getText()); + } else { + binding.tvSellingPoints.setVisibility(View.GONE); + } + + Context context = layout.getContext(); + binding.gtcvTags.removeAllViews(); + ArrayList tagStyle = gameEntity.getTagStyle(); + for (int i = 0; i < tagStyle.size(); i++) { + if (i < 3) { + TextView textView = new TextView(layout.getContext()); + textView.setTextColor(ExtensionsKt.toColor(com.gh.gamecenter.common.R.color.text_tertiary, context)); + textView.setTextSize(10); + textView.setText((i == 0 ? "" : "·") + tagStyle.get(i).getName()); + binding.gtcvTags.addView(textView); + } + } + + } else { + layout.setVisibility(View.VISIBLE); + binding.getRoot().setVisibility(View.GONE); + switch (subjectTag) { + case SUBJECT_TAG_UPDATE: + List updateTags = new ArrayList<>(); + TagStyleEntity updateTag = new TagStyleEntity( + "local_generated", + TimeUtils.getFormatTime(gameEntity.getUpdateTime(), "MM-dd") + " 更新", + "", + "1383EB", + "E8F3FF", + "1383EB", + false + ); + updateTags.add(updateTag); + GameViewUtils.setLabelList(layout.getContext(), layout, updateTags); + break; + case SUBJECT_TAG_TYPE: + GameViewUtils.setLabelList(layout.getContext(), layout, gameEntity.getTagStyle()); + break; + default: + setGameTags(layout, gameEntity, subjectTag); + break; + } + } + } + public static void setVideoDetailGameTags(LinearLayout layout, GameEntity gameEntity) { try { ArrayList tagStyle = new ArrayList<>(); diff --git a/app/src/main/java/com/gh/common/dialog/ReserveSuccessReminderDialog.kt b/app/src/main/java/com/gh/common/dialog/ReserveSuccessReminderDialog.kt index 5547bdfde8..e2b505309d 100644 --- a/app/src/main/java/com/gh/common/dialog/ReserveSuccessReminderDialog.kt +++ b/app/src/main/java/com/gh/common/dialog/ReserveSuccessReminderDialog.kt @@ -16,6 +16,7 @@ import com.gh.common.pop.EditBindWechatPop import com.gh.common.pop.RealNameTipsPop import com.gh.gamecenter.R import com.gh.gamecenter.common.constant.Constants +import com.gh.gamecenter.common.entity.WechatConfigEntity import com.gh.gamecenter.common.utils.dip2px import com.gh.gamecenter.common.utils.goneIf import com.gh.gamecenter.common.utils.toObject @@ -83,79 +84,90 @@ class ReserveSuccessReminderDialog( handlers.clear() binding.flContentContainer.removeAllViews() - val smsConfig = reserveReminder.smsConfig - val wechatConfig = reserveReminder.wechatConfig - when { - reserveReminder.onlyShowWechatReminder && !wechatConfig.isReminderEnable -> { // 只显示微信:未开启 - binding.tvContent.setText(R.string.reverse_success_without_reminder_tips) - arrayListOf(OnlyWechatReminderUnableHandler(16.dp, binding.flContentContainer, this)) + val configTypes = mutableListOf() + // 短信 + if (reserveReminder.hasSmsConfig) { + if (reserveReminder.smsConfig.notice) { + configTypes.add(SMS_REMINDER_ENABLE_TYPE) + } else { + configTypes.add(SMS_REMINDER_UNABLE_TYPE) } - - - reserveReminder.onlyShowWechatReminder && wechatConfig.isReminderEnable -> { // 只显示微信:已开 - binding.tvContent.setText(R.string.reverse_success_with_reminder_tips) - arrayListOf( - WechatReminderEnableHandler( - reserveReminder.wechatConfig.nickName, - 8.dp, - binding.flContentContainer, - this - ) - ) - } - - !smsConfig.notice && !wechatConfig.isReminderEnable -> { // 短信,微信未开启 - binding.tvContent.setText(R.string.reverse_success_without_reminder_tips) - arrayListOf( - SmsReminderUnableHandler(16.dp, binding.flContentContainer, this), - WechatReminderUnableHandler(8.dp, binding.flContentContainer, this) - ) - } - - smsConfig.notice && wechatConfig.isReminderEnable -> {// 短信,微信已开启 - binding.tvContent.setText(R.string.reverse_success_with_reminder_tips) - arrayListOf( - SmsReminderEnableHandler(reserveReminder.smsConfig, 8.dp, binding.flContentContainer, this), - WechatReminderEnableHandler( - reserveReminder.wechatConfig.nickName, - 8.dp, - binding.flContentContainer, - this - ) - ) - } - - - smsConfig.notice && !wechatConfig.isReminderEnable -> { // 短信开启,微信未开启 - binding.tvContent.setText(R.string.reverse_success_with_reminder_tips) - arrayListOf( - SmsReminderEnableHandler(smsConfig, 8.dp, binding.flContentContainer, this), - WechatReminderUnableHandler(16.dp, binding.flContentContainer, this) - ) - } - - - !smsConfig.notice && wechatConfig.isReminderEnable -> { // 微信开启,短信未开启 - binding.tvContent.setText(R.string.reverse_success_with_reminder_tips) - arrayListOf( - WechatReminderEnableHandler( - wechatConfig.nickName, - 8.dp, - binding.flContentContainer, - this - ), - SmsReminderUnableHandler(16.dp, binding.flContentContainer, this) - ) - } - - else -> { - binding.tvContent.setText(R.string.reverse_success_without_reminder_tips) - arrayListOf() - } - }.let { - handlers.clear() - handlers.addAll(it) } + + // 微信 + if (reserveReminder.wechatConfig.isReminderEnable) { + configTypes.add(WECHAT_REMINDER_ENABLE_TYPE) + } else { + configTypes.add(WECHAT_REMINDER_UNABLE_TYPE) + } + + // 日历 + if (reserveReminder.hasCalendarConfig) { + if (reserveReminder.calendarConfig.notice) { + configTypes.add(CALENDAR_REMINDER_ENABLE_TYPE) + } else { + configTypes.add(CALENDAR_REMINDER_UNABLE_TYPE) + } + } + + if (configTypes.size == 1) { + // 只有微信提醒 + if (configTypes.first() == WECHAT_REMINDER_ENABLE_TYPE) { + binding.tvContent.setText(R.string.reverse_success_with_reminder_tips) + handlers.add( + WechatReminderEnableHandler(reserveReminder.wechatConfig, 8.dp, binding.flContentContainer, this) + ) + } else { + binding.tvContent.setText(R.string.reverse_success_without_reminder_tips) + handlers.add(OnlyWechatReminderUnableHandler(16.dp, binding.flContentContainer, this)) + } + } else { + binding.tvContent.setText(R.string.reverse_success_with_reminder_tips) + var isLargerSpacing = true + fun getPaddingTop(): Int { + val paddingTop = if (isLargerSpacing) 16.dp else 8.dp + isLargerSpacing = false + return paddingTop + } + configTypes.sorted().forEach { + when (it) { + SMS_REMINDER_ENABLE_TYPE -> { + isLargerSpacing = true + SmsReminderEnableHandler(reserveReminder.smsConfig, 8.dp, binding.flContentContainer, this) + } + + SMS_REMINDER_UNABLE_TYPE -> { + SmsReminderUnableHandler(getPaddingTop(), binding.flContentContainer, this) + } + + + WECHAT_REMINDER_ENABLE_TYPE -> { + isLargerSpacing = true + WechatReminderEnableHandler( + reserveReminder.wechatConfig, + 8.dp, + binding.flContentContainer, + this + ) + } + + + WECHAT_REMINDER_UNABLE_TYPE -> + WechatReminderUnableHandler(getPaddingTop(), binding.flContentContainer, this) + + CALENDAR_REMINDER_ENABLE_TYPE -> { + isLargerSpacing = true + CalendarReminderEnableHandler(8.dp, binding.flContentContainer, this) + } + + CALENDAR_REMINDER_UNABLE_TYPE -> + CalendarReminderUnableHandler(getPaddingTop(), binding.flContentContainer, this) + + else -> null + }?.let(handlers::add) + } + } + handlers.forEach { binding.flContentContainer.addView(it.init()) } @@ -220,9 +232,14 @@ class ReserveSuccessReminderDialog( listener.changeWechatBinding() } + override fun updateCalendarReminder() { + listener.updateCalendarReminder() + } + override fun onStart() { super.onStart() window?.let { + it.setDimAmount(0.4F) it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) val params = it.attributes params.width = DisplayUtils.dip2px(300F) @@ -244,6 +261,13 @@ class ReserveSuccessReminderDialog( private val Int.dp: Int get() = DisplayUtils.dip2px(this.toFloat()) + private const val SMS_REMINDER_ENABLE_TYPE = 1 + private const val WECHAT_REMINDER_ENABLE_TYPE = 2 + private const val CALENDAR_REMINDER_ENABLE_TYPE = 3 + private const val SMS_REMINDER_UNABLE_TYPE = 4 + private const val WECHAT_REMINDER_UNABLE_TYPE = 5 + private const val CALENDAR_REMINDER_UNABLE_TYPE = 6 + fun create(context: Context, listener: OnReserveReminderListener) = ReserveSuccessReminderDialog( context, @@ -360,7 +384,7 @@ class ReserveSuccessReminderDialog( } class WechatReminderEnableHandler( - private val nickName: String, + private val wechatConfig: WechatConfigEntity, topMargin: Int, parent: ViewGroup, listener: OnReserveSuccessListener @@ -380,7 +404,7 @@ class ReserveSuccessReminderDialog( }.root override fun initView() { - binding.tvWechat.text = nickName + binding.tvWechat.text = wechatConfig.nickName binding.vModifyWechat.setOnClickListener { editWechatPop.showAsDropDown( binding.ivModifyWechat, @@ -411,6 +435,51 @@ class ReserveSuccessReminderDialog( } + class CalendarReminderUnableHandler( + topMargin: Int, + parent: ViewGroup, + listener: OnReserveSuccessListener + ) : ReminderContentHandler(topMargin, parent, listener) { + + private lateinit var binding: LayoutReserveWechatReminderUnableBinding + + // 复用微信提醒未开启状态布局 + override fun createView(inflater: LayoutInflater) = + LayoutReserveWechatReminderUnableBinding.inflate(inflater, parent, false) + .also { + binding = it + }.root + + override fun initView() { + binding.tvWechatReminderTitle.setText(R.string.calendar_reminders) + binding.tvWechatReminderDescription.setText(R.string.calendar_reminders_description) + binding.vWechatAdd.setOnClickListener { + listener.updateCalendarReminder() + } + } + + } + + class CalendarReminderEnableHandler( + topMargin: Int, + parent: ViewGroup, + listener: OnReserveSuccessListener + ) : ReminderContentHandler(topMargin, parent, listener) { + + private lateinit var binding: LayoutReserveCalendarReminderUnableBinding + + override fun createView(inflater: LayoutInflater) = + LayoutReserveCalendarReminderUnableBinding.inflate(inflater, parent, false) + .also { + binding = it + }.root + + override fun initView() { + + } + + + } } @@ -425,4 +494,6 @@ interface OnReserveSuccessListener { fun verifyPhoneNumber() fun changeWechatBinding() + + fun updateCalendarReminder() } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/provider/BindingAdaptersProviderImpl.kt b/app/src/main/java/com/gh/common/provider/BindingAdaptersProviderImpl.kt index f0aab7d911..4628d9f991 100644 --- a/app/src/main/java/com/gh/common/provider/BindingAdaptersProviderImpl.kt +++ b/app/src/main/java/com/gh/common/provider/BindingAdaptersProviderImpl.kt @@ -4,8 +4,10 @@ import android.view.View import android.widget.LinearLayout import android.widget.TextView import com.gh.common.databind.BindingAdapters +import com.gh.gamecenter.common.databinding.LayoutGameItemSellingPointBinding import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.feature.provider.IBindingAdaptersProvider +import com.gh.gamecenter.home.custom.adapter.CustomViewExt @com.therouter.inject.ServiceProvider class BindingAdaptersProviderImpl : IBindingAdaptersProvider { @@ -18,7 +20,7 @@ class BindingAdaptersProviderImpl : IBindingAdaptersProvider { } override fun setGameTags(layout: LinearLayout, gameEntity: GameEntity) { - BindingAdapters.setGameTags(layout, gameEntity) + BindingAdapters.setGameTags(layout, gameEntity, "") } override fun setMessageUnread(view: TextView, unreadCount: Int) { @@ -28,4 +30,17 @@ class BindingAdaptersProviderImpl : IBindingAdaptersProvider { override fun setGame(view: View, gameEntity: GameEntity) { BindingAdapters.setGame(view, gameEntity) } + + override fun setGameTagsWithSellingPoints( + layout: LinearLayout, + sellingPointsBinding: LayoutGameItemSellingPointBinding, + gameEntity: GameEntity, + subjectTag: String + ) { + BindingAdapters.setGameTagsWithSellingPoint(layout, sellingPointsBinding, gameEntity, subjectTag) + } + + override fun setGameDescription(tvDesc: TextView, briefStyle: String, game: GameEntity) { + CustomViewExt.setDescription(tvDesc, briefStyle, game) + } } \ No newline at end of file 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 a6ef4bfb07..73745b0242 100644 --- a/app/src/main/java/com/gh/common/util/DirectUtils.kt +++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt @@ -854,7 +854,8 @@ object DirectUtils { entrance: String? = null, autoDownload: Boolean? = null, tab: String? = "", - traceEvent: ExposureEvent? = null + traceEvent: ExposureEvent? = null, + from: String? = null ) { if (id.isEmpty()) return @@ -862,6 +863,7 @@ object DirectUtils { .path(RouteConsts.activity.gameDetailActivity) .appendQueryParameter(KEY_ENTRANCE, entrance) .appendQueryParameter(KEY_GAME_ID, id) + .appendQueryParameter(KEY_FROM, from) .build() TheRouter diff --git a/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt b/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt index 0fb715e969..4e1351833f 100644 --- a/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt +++ b/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt @@ -655,7 +655,11 @@ object DownloadItemUtils { } // 缺省情况下回落到游戏简介 - if (TextUtils.isEmpty(briefStyle) || briefStyle!!.contains("brief") || briefStyle.contains("recommend")) { + if (TextUtils.isEmpty(briefStyle) + || briefStyle!!.contains("brief") + || briefStyle.contains("recommend") + || briefStyle.contains("test&appointment") + ) { holder.gameDes?.visibility = View.VISIBLE } else { holder.gameDes?.visibility = View.GONE diff --git a/app/src/main/java/com/gh/common/util/ReservationHelper.kt b/app/src/main/java/com/gh/common/util/ReservationHelper.kt index 8deefc2e60..253d7d1160 100644 --- a/app/src/main/java/com/gh/common/util/ReservationHelper.kt +++ b/app/src/main/java/com/gh/common/util/ReservationHelper.kt @@ -95,7 +95,8 @@ object ReservationHelper { it.categoryChinese, data.wechatConfig.isReminderEnable, if (data.hasSmsConfig) data.smsConfig.notice else null, - if (data.isEnableAutoDownload) data.wifiAutoDownload else null + if (data.isEnableAutoDownload) data.wifiAutoDownload else null, + if (data.hasCalendarConfig) false else null ) } diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index 13696f921d..b2293383cc 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -222,7 +222,7 @@ public class MainActivity extends BaseActivity { DialogHelper.showCenterWarningDialog(this, "发生闪退", "光环助手发生了闪退,建议安装到最新版本修复异常" , "马上反馈", "马上安装修复", () -> { - DirectUtils.directToGameDetail(this, Constants.GHZS_GAME_ID, "", "crash", true, "desc", null); + DirectUtils.directToGameDetail(this, Constants.GHZS_GAME_ID, "", "crash", true, "desc", null, ""); return null; }, () -> { diff --git a/app/src/main/java/com/gh/gamecenter/SkipActivity.java b/app/src/main/java/com/gh/gamecenter/SkipActivity.java index d587507c31..6e9989beb9 100644 --- a/app/src/main/java/com/gh/gamecenter/SkipActivity.java +++ b/app/src/main/java/com/gh/gamecenter/SkipActivity.java @@ -35,6 +35,7 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_VIDEO_STREAM import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_VIDEO_STREAMING_HOME; import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_WEB; import static com.gh.gamecenter.common.constant.EntranceConsts.KEY_DATA; +import static com.gh.gamecenter.common.constant.EntranceConsts.KEY_FROM; import static com.gh.gamecenter.common.constant.EntranceConsts.KEY_GAME_NAME; import static com.gh.gamecenter.common.constant.EntranceConsts.KEY_NAME; import static com.gh.gamecenter.common.constant.EntranceConsts.KEY_PACKAGENAME; @@ -100,7 +101,6 @@ public class SkipActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Uri uri = getIntent().getData(); Bundle bundle; if (uri != null) { @@ -160,7 +160,8 @@ public class SkipActivity extends BaseActivity { DirectUtils.directToArticle(this, path, entrance); break; case HOST_GAME: - DirectUtils.directToGameDetail(this, path, "", entrance, "true".equals(uri.getQueryParameter("auto_download")), to, null); + String from = uri.getQueryParameter(KEY_FROM); + DirectUtils.directToGameDetail(this, path, "", entrance, "true".equals(uri.getQueryParameter("auto_download")), to, null, from); break; case HOST_COLUMN: DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), entrance, null, SubjectData.SubjectType.NORMAL); @@ -315,7 +316,7 @@ public class SkipActivity extends BaseActivity { break; case HOST_COLUMN_COLLECTION: - DirectUtils.directToColumnCollection(this, path, -1, entrance, "", "", "", "", null,false); + DirectUtils.directToColumnCollection(this, path, -1, entrance, "", "", "", "", null, false); break; case EntranceConsts.HOST_BLOCK: name = uri.getQueryParameter("name"); @@ -414,13 +415,13 @@ public class SkipActivity extends BaseActivity { break; case HOST_ARCHIVE_LOGIN: String gamePkg = uri.getQueryParameter(EntranceConsts.KEY_GAME_PKG); - if(CheckLoginUtils.isLogin()) { + if (CheckLoginUtils.isLogin()) { VHelper.INSTANCE.updateAuthorizeInfo(true); } else { Bundle newBundle = new Bundle(); newBundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName()); EntranceUtils.jumpActivityCompat(this, newBundle, null, (resultCode, data) -> { - if(CheckLoginUtils.isLogin()) { + if (CheckLoginUtils.isLogin()) { VHelper.INSTANCE.updateAuthorizeInfo(true); } VHelper.launch(this, gamePkg, false, false); diff --git a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt index d593350b69..c9bd657c05 100644 --- a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt @@ -26,6 +26,8 @@ import com.gh.common.util.UsageStatsHelper.checkAndPostUsageStats import com.gh.download.DownloadManager import com.gh.gamecenter.common.base.activity.BaseActivity import com.gh.gamecenter.common.constant.Constants +import com.gh.gamecenter.common.constant.EntranceConsts.KEY_FROM +import com.gh.gamecenter.common.constant.EntranceConsts.KEY_GAMEID import com.gh.gamecenter.common.constant.RouteConsts import com.gh.gamecenter.common.tracker.TrackerLogger import com.gh.gamecenter.common.utils.* @@ -104,7 +106,7 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen { executeDex2OatInAdvance() DialogHelper.showDialog( context = this, - title ="选择环境", + title = "选择环境", content = spanBuilder, confirmText = "正式环境", cancelText = "测试环境", @@ -145,6 +147,9 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen { val trackEvent = JSONObject() // 是否首次使用神策 val isFirstTime = SPUtils.getBoolean(Constants.SP_SENSORS_IS_FIRST_TIME, true) + val from = intent.extras?.getString(KEY_FROM) + val gameId = intent.extras?.getString(KEY_GAMEID) ?: "" + val isFromWechat = from == "wechat_appointment" tryCatchInRelease { trackEvent.run { put("\$is_first_time", isFirstTime) @@ -154,6 +159,10 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen { put("signature", signatureHash) put("app_name", appProvider?.getAppName()) put("install_first_time", if (HaloApp.getInstance().isBrandNewInstall) "是" else "否") + if (isFromWechat) { + put("source_entrance", "微信通知") + put("page_business_id", gameId) + } } } SensorsBridge.trackEvent("AppLaunch", trackEvent) diff --git a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt index 05d58bcbee..42d704d402 100644 --- a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt @@ -242,7 +242,7 @@ class CategoryV2ListAdapter( gameIconView.displayGameIcon(gameEntity) gameRating.textSize = if (gameEntity.commentCount > 3) 12F else 10F BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") gameRating.setDrawableStart(if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable() else null) gameRating.text = if (gameEntity.commentCount > 3) { if (gameEntity.star == 10.0F) "10" else gameEntity.star.toString() diff --git a/app/src/main/java/com/gh/gamecenter/entity/ReserveReminderEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ReserveReminderEntity.kt index 1d2883c72d..550df77974 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/ReserveReminderEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/ReserveReminderEntity.kt @@ -11,6 +11,8 @@ class ReserveReminderEntity( private var _smsConfig: SmsConfig? = null, @SerializedName("wechat_config") private var _wechatConfig: WechatConfigEntity? = null, + @SerializedName("calendar_config") + private var _calendarConfig: CalendarConfig? = null, @SerializedName("mirror_type") private val _mirrorType: String? = null, @SerializedName("wifi_auto_download") @@ -34,8 +36,14 @@ class ReserveReminderEntity( _wechatConfig = value } - val onlyShowWechatReminder: Boolean - get() = _smsConfig == null + val hasCalendarConfig: Boolean + get() = _calendarConfig != null + + var calendarConfig: CalendarConfig + get() = _calendarConfig ?: CalendarConfig() + set(value) { + _calendarConfig = value + } val mirrorType: String get() = _mirrorType ?: "" @@ -81,4 +89,39 @@ class ReserveReminderEntity( } } + + @Parcelize + class CalendarConfig( + @SerializedName("notice") + private val _notice: Boolean? = null, + @SerializedName("title") + private val _title: String? = null, + @SerializedName("time_start") + private val _timeStart: Long? = null, + @SerializedName("time_end") + private val _timeEnd: Long? = null, + @SerializedName("advance_seconds") + private val _advanceSeconds: Long? = null, + @SerializedName("remark") + private val _remark: String? = null + ) : Parcelable { + + val notice: Boolean + get() = _notice ?: false + + val title: String + get() = _title ?: "" + + val timeStart: Long + get() = _timeStart ?: 0L + + val timeEnd: Long + get() = _timeEnd ?: 0L + + val advanceSeconds: Long + get() = _advanceSeconds ?: 0L + + val remark: String + get() = _remark ?: "" + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt index 4f02518f8c..aa25c22005 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt @@ -130,12 +130,13 @@ data class SubjectEntity( @IgnoredOnParcel private var filteredData: MutableList? = null - val subjectType: SubjectData.SubjectType get() = when { - isQQColumn -> SubjectData.SubjectType.QQ_GAME - isWechatColumnCPM -> SubjectData.SubjectType.WECHAT_GAME_CPM - isWechatColumn -> SubjectData.SubjectType.WECHAT_GAME - else -> SubjectData.SubjectType.NORMAL - } + val subjectType: SubjectData.SubjectType + get() = when { + isQQColumn -> SubjectData.SubjectType.QQ_GAME + isWechatColumnCPM -> SubjectData.SubjectType.WECHAT_GAME_CPM + isWechatColumn -> SubjectData.SubjectType.WECHAT_GAME + else -> SubjectData.SubjectType.NORMAL + } val isMiniGame: Boolean get() = isQQColumn || isWechatColumn @@ -148,4 +149,11 @@ data class SubjectEntity( val list: Int get() = max(min(_list ?: 0, data?.size ?: 0), 1) + + companion object { + const val SUBJECT_TAG_UPDATE = "update" // 更新时间 + const val SUBJECT_TAG_TYPE = "type" // 游戏标签 + const val SUBJECT_TAG_TEST = "test" // 开测时间 + const val SUBJECT_TAG_SELLING_POINT = "selling_points&type" // 卖点文案+游戏标签 + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/game/vertical/GameItemUi.kt b/app/src/main/java/com/gh/gamecenter/game/vertical/GameItemUi.kt index a5d19f540d..b42e0bf850 100644 --- a/app/src/main/java/com/gh/gamecenter/game/vertical/GameItemUi.kt +++ b/app/src/main/java/com/gh/gamecenter/game/vertical/GameItemUi.kt @@ -3,10 +3,10 @@ package com.gh.gamecenter.game.vertical import android.content.Context import android.graphics.Color import android.graphics.Typeface -import android.os.Build import android.text.TextUtils import android.util.AttributeSet import android.view.Gravity +import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import android.widget.Space @@ -17,11 +17,12 @@ import androidx.core.content.ContextCompat import com.airbnb.lottie.LottieAnimationView import com.airbnb.lottie.LottieDrawable import com.facebook.drawee.view.SimpleDraweeView -import com.gh.gamecenter.feature.view.DownloadButton -import com.gh.gamecenter.feature.view.GameIconView import com.gh.gamecenter.R +import com.gh.gamecenter.common.databinding.LayoutGameItemSellingPointBinding import com.gh.gamecenter.common.utils.setDrawableEnd import com.gh.gamecenter.common.view.GameTagContainerView +import com.gh.gamecenter.feature.view.DownloadButton +import com.gh.gamecenter.feature.view.GameIconView import splitties.dimensions.dip import splitties.views.backgroundColor import splitties.views.dsl.constraintlayout.* @@ -63,6 +64,7 @@ class GameItemUi(override val ctx: Context) : Ui { var gamePlayCountTv: TextView var mGameDesSpace: Space + var sellingPointsBinding: LayoutGameItemSellingPointBinding override val root: ConstraintLayout = constraintLayout { padding = dip(16) @@ -84,6 +86,7 @@ class GameItemUi(override val ctx: Context) : Ui { gameTagContainer = GameTagContainerView(ctx).apply { id = R.id.label_list } mGameDesSpace = space { }.apply { id = R.id.gameDesSpace } recommendConstraintLayout = initRecommendConstraintLayout() + sellingPointsBinding = LayoutGameItemSellingPointBinding.inflate(LayoutInflater.from(context)) add(iconIv, lParams(dip(64), dip(64)) { topOfParent() @@ -142,6 +145,12 @@ class GameItemUi(override val ctx: Context) : Ui { endToEndOf(mGameDesSpace) orientation = LinearLayout.HORIZONTAL }) + add(sellingPointsBinding.root, lParams(0, wrapContent) { + topToBottomOf(mGameDesSpace) + bottomToBottomOf(iconIv) + startToEndOf(gamePlayCountTv) + endToEndOf(mGameDesSpace) + }) add(gamePlayCountTv, lParams(wrapContent, wrapContent) { topToBottomOf(mGameDesSpace) bottomToBottomOf(iconIv) @@ -197,7 +206,8 @@ class GameItemUi(override val ctx: Context) : Ui { startPadding = dip(2) endPadding = dip(2) ellipsize = TextUtils.TruncateAt.END - background = ContextCompat.getDrawable(context, com.gh.gamecenter.feature.R.drawable.bg_advance_download_game_subtitle) + background = + ContextCompat.getDrawable(context, com.gh.gamecenter.feature.R.drawable.bg_advance_download_game_subtitle) setTextColor(ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.text_secondary)) visibility = View.GONE } @@ -305,7 +315,12 @@ class GameItemUi(override val ctx: Context) : Ui { gravity = Gravity.CENTER text = "展开" setTextColor(ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.white)) - setDrawableEnd(AppCompatResources.getDrawable(context, com.gh.gamecenter.feature.R.drawable.ic_jump_universal)) + setDrawableEnd( + AppCompatResources.getDrawable( + context, + com.gh.gamecenter.feature.R.drawable.ic_jump_universal + ) + ) compoundDrawablePadding = dip(2) visibility = View.GONE } diff --git a/app/src/main/java/com/gh/gamecenter/game/vertical/GameVerticalAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/vertical/GameVerticalAdapter.kt index 3d073e08ba..4532c32a45 100644 --- a/app/src/main/java/com/gh/gamecenter/game/vertical/GameVerticalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/vertical/GameVerticalAdapter.kt @@ -166,7 +166,7 @@ class GameVerticalAdapter( false ) BindingAdapters.setGame(iconIv, gameEntity) - BindingAdapters.setGameTags(gameTagContainer, gameEntity) + BindingAdapters.setGameTags(gameTagContainer, gameEntity, subjectData?.tag ?: "") GameItemViewHolder.initServerType(gameNameTv, serverTypeTv, gameEntity) gameDesTv.text = gameEntity.decoratedDes GameItemViewHolder.initGameSubtitleAndAdLabel( @@ -225,10 +225,10 @@ class GameVerticalAdapter( subjectData?.briefStyle ) - DownloadItemUtils.setOnClickListener( - context, downloadTv, gameEntity, position, - adapter, entrance, location = location, traceEvent = gameEntity.exposureEvent - ) + DownloadItemUtils.setOnClickListener( + context, downloadTv, gameEntity, position, + adapter, entrance, location = location, traceEvent = gameEntity.exposureEvent + ) root.setPadding(paddingStart, 8F.dip2px(), paddingEnd, 8F.dip2px()) } diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailAdapter.kt index f7c0127097..2eeb21723b 100644 --- a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailAdapter.kt @@ -610,7 +610,7 @@ open class GameCollectionDetailAdapter( gameIconView.displayGameIcon(gameEntity) gameRating.textSize = if (gameEntity.commentCount > 3) 12F else 10F BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") gameRating.setDrawableStart( if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable(mContext) else null ) diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/detail/adapter/GameDetailRelatedGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/detail/adapter/GameDetailRelatedGameAdapter.kt index 0c408c4c75..44dd9fac29 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/detail/adapter/GameDetailRelatedGameAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/detail/adapter/GameDetailRelatedGameAdapter.kt @@ -51,7 +51,7 @@ class GameDetailRelatedGameAdapter( holder.binding.root.setPadding(paddingStart, 8F.dip2px(), paddingEnd, 8F.dip2px()) holder.binding.gameNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context)) holder.binding.gameNameTv.text = gameEntity.name - BindingAdapters.setGameTags(holder.binding.gameLabelLl, gameEntity) + BindingAdapters.setGameTags(holder.binding.gameLabelLl, gameEntity, "") holder.binding.gameIconView.displayGameIcon(gameEntity) holder.binding.gameIconView.setBorderColor(com.gh.gamecenter.common.R.color.resource_border) holder.itemView.setOnClickListener { diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomFoldSlideLargeImageItemAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomFoldSlideLargeImageItemAdapter.kt index a4a8bb8c35..44c142e760 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomFoldSlideLargeImageItemAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomFoldSlideLargeImageItemAdapter.kt @@ -187,7 +187,7 @@ class CustomFoldSlideLargeImageItemAdapter( binding.gStar.goneIf(!(data.data.showStar && game.commentCount > 3)) { binding.tvStar.text = if (game.star == 10.0F) "10" else game.star.toString() } - BindingAdapters.setGameTags(binding.llLabel, game) + BindingAdapters.setGameTags(binding.llLabel, game, "") binding.cvContainer.setCardBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(itemView.context)) try { diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGamePluginAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGamePluginAdapter.kt index 0574ff0dbc..3a5ff18e1b 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGamePluginAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGamePluginAdapter.kt @@ -91,7 +91,7 @@ class CustomGamePluginAdapter( binding.gameRating.textSize = (if (gameEntity.commentCount > 3) 12 else 10).toFloat() BindingAdapters.setGameName(binding.gameName, gameEntity, true) - BindingAdapters.setGameTags(binding.labelList, gameEntity) + BindingAdapters.setGameTags(binding.labelList, gameEntity, "") binding.gameRating.setDrawableStart( if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable() else null, null, diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameRefreshVerticalAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameRefreshVerticalAdapter.kt index aef57e6c19..a1422c4004 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameRefreshVerticalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameRefreshVerticalAdapter.kt @@ -142,7 +142,7 @@ class CustomGameRefreshVerticalAdapter( false ) BindingAdapters.setGame(iconIv, gameEntity) - BindingAdapters.setGameTags(gameTagContainer, gameEntity) + BindingAdapters.setGameTags(gameTagContainer, gameEntity, "") GameItemViewHolder.initServerType(gameNameTv, serverTypeTv, gameEntity) gameDesTv.text = gameEntity.decoratedDes GameItemViewHolder.initGameSubtitleAndAdLabel( diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameVerticalAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameVerticalAdapter.kt index 9536b4e87d..9e7749fcf7 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameVerticalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameVerticalAdapter.kt @@ -59,7 +59,8 @@ class CustomGameVerticalAdapter( briefStyle = _data.briefStyle, adIconActive = _data.adIconActive, showSubscript = _data.showIndexIconSubscript, - showSubTitle = _data.showIndexSubtitle + showSubTitle = _data.showIndexSubtitle, + subjectTag = _data.tag ?: "" ) holder.itemView.setOnClickListener { @@ -116,7 +117,8 @@ class CustomGameVerticalAdapter( briefStyle: String, adIconActive: Boolean, showSubscript: Boolean, - showSubTitle: Boolean + showSubTitle: Boolean, + subjectTag: String = "" ) { val context = itemView.context @@ -141,16 +143,23 @@ class CustomGameVerticalAdapter( with(ui) { gameNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context)) serverTypeTv.setTextColor(com.gh.gamecenter.common.R.color.primary_theme.toColor(context)) - downloadTv.background = com.gh.gamecenter.common.R.drawable.download_button_normal_style.toDrawable(context) + downloadTv.background = + com.gh.gamecenter.common.R.drawable.download_button_normal_style.toDrawable(context) gameDesTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context)) BindingAdapters.setGameName( gameNameTv, gameEntity, + false ) iconIv.displayGameIconWithIfShowSubscript(gameEntity, showSubscript) - BindingAdapters.setGameTags(gameTagContainer, gameEntity) + BindingAdapters.setGameTagsWithSellingPoint( + gameTagContainer, + sellingPointsBinding, + gameEntity, + subjectTag + ) GameItemViewHolder.initServerType(gameNameTv, serverTypeTv, gameEntity) val styleResId = R.style.CustomPageGameRating diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomViewExt.kt b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomViewExt.kt index 0f62f9b3f4..5cccb841c3 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomViewExt.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomViewExt.kt @@ -1,9 +1,14 @@ -package com.gh.gamecenter.home.custom.adapter +package com.gh.gamecenter.home.custom.adapter +import android.content.Context import android.widget.TextView +import com.gh.gamecenter.R import com.gh.gamecenter.common.utils.goneIf +import com.gh.gamecenter.common.utils.toResString import com.gh.gamecenter.common.utils.visibleIf +import com.gh.gamecenter.core.utils.TimeUtils import com.gh.gamecenter.feature.entity.GameEntity +import kotlin.math.roundToInt object CustomViewExt { @@ -45,9 +50,48 @@ object CustomViewExt { "size&brief" -> getBriefWithSize() "star&brief" -> game.brief "recommend" -> game.columnRecommend?.text ?: getBriefWithSize() + "test&appointment" -> getBriefWithTestAndAppointment(game, tvDesc.context) else -> getBriefWithSize() } tvDesc.text = brief } + + private fun getBriefWithTestAndAppointment(game: GameEntity, context: Context) = + if (game.test?.startPending == true) { + val startText = game.test?.startText ?: "" + if (startText.isBlank()) { + getBookVolumeText(game.appointmentCount, context, false) + } else { + "$startText${getBookVolumeText(game.appointmentCount, context, true)}" + } + } else { + "${getTestDescription(game)}${getBookVolumeText(game.appointmentCount, context, true)}" + } + + private fun getTestDescription(game: GameEntity): String { + val timeText = TimeUtils.formatTestTime(game.test?.start ?: 0L) + val eventName = if (game.test?.type == "删档内测") { + R.string.first_release.toResString() + } else { + R.string.go_live.toResString() + } + return "$timeText$eventName" + } + + private fun getBookVolumeText(number: Int, context: Context, showDivider: Boolean): String = + when { + number == 0 -> "" + number <= 99999 -> context.getString( + R.string.number_of_reservations, + if (showDivider) " | $number" else "$number" + ) + + else -> context.getString( + R.string.number_of_reservations, + if (showDivider) " | ${(number / 10000F).roundToInt()}W" else "${(number / 10000F).roundToInt()}W" + ) + + } + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageRepository.kt b/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageRepository.kt index 78a8cb8856..9646050134 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageRepository.kt @@ -23,6 +23,12 @@ import com.gh.gamecenter.entity.GameUpdateEntity import com.gh.gamecenter.entity.PullDownPush import com.gh.gamecenter.entity.SubjectEntity import com.gh.gamecenter.feature.entity.* +import com.gh.gamecenter.entity.SubjectEntity.Companion.SUBJECT_TAG_SELLING_POINT +import com.gh.gamecenter.entity.SubjectEntity.Companion.SUBJECT_TAG_UPDATE +import com.gh.gamecenter.feature.entity.FloatingWindowEntity +import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.feature.entity.PluginLocation +import com.gh.gamecenter.feature.entity.TagStyleEntity import com.gh.gamecenter.feature.utils.ApkActiveUtils import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_BANNER @@ -711,22 +717,6 @@ class CustomPageRepository private constructor( // 替换游戏 substituteGameIfNeeded(gameSubject) - if (gameSubject.tag == "update") { - // 优先显示更新标签 - gameSubject.data?.forEach { - it.tagStyle.clear() - it.tagStyle.add( - TagStyleEntity( - id = "local_generated", - name = TimeUtils.getFormatTime(it.updateTime, "MM-dd") + " 更新", - color = "1383EB", - background = "E8F3FF", - column = "1383EB" - ) - ) - } - } - when (gameSubject.type) { COMPONENTS_GAME_SUBJECT_TYPE_DOUBLE_CARD, COMPONENTS_SUBJECT_TYPE_DOUBLE_GAME_WELFARE_CARD, COMPONENTS_SUBJECT_TYPE_GAME_VERTICAL_IMAGE_TEXT -> { // 双列卡片 双列福利卡片 竖式图文列表 diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomGameItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomGameItemViewHolder.kt index 42aac9e2ce..ef858dc673 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomGameItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomGameItemViewHolder.kt @@ -17,6 +17,7 @@ import com.gh.gamecenter.common.view.DrawableView import com.gh.gamecenter.core.runOnIoThread import com.gh.gamecenter.core.utils.StringUtils import com.gh.gamecenter.databinding.GameItemCustomBinding +import com.gh.gamecenter.entity.SubjectEntity.Companion.SUBJECT_TAG_SELLING_POINT import com.gh.gamecenter.feature.R import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.feature.minigame.MiniGameItemHelper @@ -65,7 +66,8 @@ class CustomGameItemViewHolder( root.setPadding(root.paddingLeft, root.paddingTop, root.paddingRight, paddingBottom) - clContainer.background = com.gh.gamecenter.common.R.drawable.reuse_listview_item_style.toDrawable(root.context) + clContainer.background = + com.gh.gamecenter.common.R.drawable.reuse_listview_item_style.toDrawable(root.context) selectIv.setImageDrawable(DrawableView.getCheckSelectorDrawable(root.context)) gameKaifuType.setBackgroundColor(com.gh.gamecenter.common.R.color.primary_theme.toColor(root.context)) gameName.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(root.context)) @@ -75,7 +77,7 @@ class CustomGameItemViewHolder( gameIconView.displayGameIconWithIfShowSubscript(entity, item.data.showIndexIconSubscript) val provider = TheRouter.get(IBindingAdaptersProvider::class.java) provider?.setGameName(gameName, entity, false) - provider?.setGameTags(labelList, entity) + provider?.setGameTagsWithSellingPoints(labelList, layoutSellingPoints, entity, subject.tag ?: "") CustomViewExt.setGameRatting(gameRating, subject.briefStyle, entity) CustomViewExt.setDescription(gameDes, subject.briefStyle, entity) diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomHomeGameItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomHomeGameItemViewHolder.kt index ee498130c3..1406bd5531 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomHomeGameItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomHomeGameItemViewHolder.kt @@ -187,7 +187,7 @@ class CustomHomeGameItemViewHolder( binding.gameRating.text = game.star.toString() binding.gameRating2.text = game.star.toString() binding.gameRating.setDrawableStart(R.drawable.home_game_rating, 12F.dip2px(), 12F.dip2px()) - BindingAdapters.setGameTags(binding.gameTags, game) + BindingAdapters.setGameTags(binding.gameTags, game, "") GameItemViewHolder.initGameSubtitleAndAdLabelOnGameSubject( game, diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomHomeHorizontalSlideVideoItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomHomeHorizontalSlideVideoItemViewHolder.kt index 802e2f59d3..30112b7074 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomHomeHorizontalSlideVideoItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/viewholder/CustomHomeHorizontalSlideVideoItemViewHolder.kt @@ -93,7 +93,7 @@ class CustomHomeHorizontalSlideVideoItemViewHolder( binding.gameIcon.displayGameIconWithIfShowSubscript(gameEntity, showSubscript) binding.gameName.text = gameEntity.name binding.gameName.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(binding.root.context)) - BindingAdapters.setGameTags(binding.gameTags, gameEntity) + BindingAdapters.setGameTags(binding.gameTags, gameEntity, "") GameItemViewHolder.initGameSubtitleAndAdLabelOnGameSubject( gameEntity, binding.gameSubtitleTv, diff --git a/app/src/main/java/com/gh/gamecenter/home/horizontalslidevideo/HomeHorizontalSlideVideoItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/horizontalslidevideo/HomeHorizontalSlideVideoItemViewHolder.kt index 2a1ca92a8b..cd721261b8 100644 --- a/app/src/main/java/com/gh/gamecenter/home/horizontalslidevideo/HomeHorizontalSlideVideoItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/home/horizontalslidevideo/HomeHorizontalSlideVideoItemViewHolder.kt @@ -75,7 +75,7 @@ class HomeHorizontalSlideVideoItemViewHolder(val binding: ItemHomeHorizontalSlid binding.gameIcon.displayGameIcon(gameEntity) binding.gameName.text = gameEntity.name binding.gameName.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(binding.root.context)) - BindingAdapters.setGameTags(binding.gameTags, gameEntity) + BindingAdapters.setGameTags(binding.gameTags, gameEntity, "") GameItemViewHolder.initGameSubtitleAndAdLabel(gameEntity, binding.gameSubtitleTv) MiniGameItemHelper.setMiniGameUsage(binding.gamePlayCount, gameEntity) diff --git a/app/src/main/java/com/gh/gamecenter/home/test_v2/HomeGameTestV2GameListViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/test_v2/HomeGameTestV2GameListViewHolder.kt index a05e8787fa..aa92edffff 100644 --- a/app/src/main/java/com/gh/gamecenter/home/test_v2/HomeGameTestV2GameListViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/home/test_v2/HomeGameTestV2GameListViewHolder.kt @@ -43,7 +43,7 @@ class HomeGameTestV2GameListViewHolder( mBinding.run { gameIconView.displayGameIcon(gameEntity) BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") GameItemViewHolder.initGameSubtitleAndAdLabel(gameEntity, gameSubtitleTv) @@ -62,8 +62,8 @@ class HomeGameTestV2GameListViewHolder( ) //开服日期 - val gameTimeText = if (gameEntity.openTest?.startPending == true) { - gameEntity.openTest?.startText ?: "" + val gameTimeText = if (gameEntity.test?.startPending == true) { + gameEntity.test?.startText ?: "" } else { getGameTimeText(gameEntity) } diff --git a/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameAdapter.kt index 30cca531cd..41f84f39c8 100644 --- a/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameAdapter.kt @@ -81,7 +81,7 @@ class MyFollowedGameAdapter(context: Context, var mViewModel: MyFollowedGameView gameIconView.displayGameIcon(gameEntity) gameRating.textSize = if (gameEntity.commentCount > 3) 12F else 10F BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") gameRating.setDrawableStart(if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable() else null) gameRating.setPadding(0, 0, if (gameEntity.commentCount > 3) 8F.dip2px() else 0, 0) gameRating.text = if (gameEntity.commentCount > 3) { diff --git a/app/src/main/java/com/gh/gamecenter/mygame/MyReservationAdapter.kt b/app/src/main/java/com/gh/gamecenter/mygame/MyReservationAdapter.kt index 63c7435796..bda1133f98 100644 --- a/app/src/main/java/com/gh/gamecenter/mygame/MyReservationAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/mygame/MyReservationAdapter.kt @@ -133,7 +133,7 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo gameIconView.displayGameIcon(gameEntity) gameRating.textSize = if (gameEntity.commentCount > 3) 12F else 10F BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") gameRating.setDrawableStart( if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable(mContext) else null ) diff --git a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt index 15ec01c06a..7819f6737d 100644 --- a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt @@ -118,7 +118,7 @@ open class PlayedGameAdapter( gameIconView.displayGameIcon(gameEntity) gameRating.textSize = if (gameEntity.commentCount > 3) 12F else 10F BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") gameRating.setDrawableStart(if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable() else null) gameRating.setPadding(0, 0, if (gameEntity.commentCount > 3) 8F.dip2px() else 0, 0) gameRating.text = if (gameEntity.commentCount > 3) { diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameFirstItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameFirstItemViewHolder.kt index 109aaed790..dc1b64dad9 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameFirstItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameFirstItemViewHolder.kt @@ -135,7 +135,7 @@ class SearchGameFirstItemViewHolder( gameIconView.displayGameIcon(gameEntity) gameRating.textSize = if (gameEntity.commentCount > 3) 12F else 10F BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") gameRating.setDrawableStart(if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable() else null) gameRating.setPadding(0, 0, if (gameEntity.commentCount > 3) 8F.dip2px() else 0, 0) gameRating.text = if (gameEntity.commentCount > 3) { diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt index 9021196878..12befa7f06 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt @@ -141,7 +141,7 @@ class SearchGameIndexAdapter( gameIconView.displayGameIcon(gameEntity) gameRating.textSize = if (gameEntity.commentCount > 3) 12F else 10F BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") gameRating.setDrawableStart(if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable() else null) gameRating.setPadding(0, 0, if (gameEntity.commentCount > 3) 8F.dip2px() else 0, 0) gameRating.text = if (gameEntity.commentCount > 3) { diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt index 552627a99c..0e66f7e63b 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt @@ -382,7 +382,7 @@ class SearchGameResultAdapter( gameIconView.displayGameIcon(gameEntity) gameRating.textSize = if (gameEntity.commentCount > 3) 12F else 10F BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") gameRating.setDrawableStart(if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable() else null) gameRating.setPadding(0, 0, if (gameEntity.commentCount > 3) 8F.dip2px() else 0, 0) gameRating.text = if (gameEntity.commentCount > 3) { diff --git a/app/src/main/java/com/gh/gamecenter/servers/gametest2/GameBigImageViewHolder.kt b/app/src/main/java/com/gh/gamecenter/servers/gametest2/GameBigImageViewHolder.kt index d34104afb7..9290495a97 100644 --- a/app/src/main/java/com/gh/gamecenter/servers/gametest2/GameBigImageViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/servers/gametest2/GameBigImageViewHolder.kt @@ -104,8 +104,8 @@ class GameBigImageViewHolder(val binding: ItemGameServerTestBigImageBinding) : binding.infoContainer.background = com.gh.gamecenter.common.R.drawable.reuse_listview_item_style.toDrawable(binding.root.context) binding.gameIcon.displayGameIcon(gameEntity) binding.gameName.text = gameEntity.name - val time = if (gameEntity.openTest?.startPending == true) { - gameEntity.openTest?.startText ?: "" + val time = if (gameEntity.test?.startPending == true) { + gameEntity.test?.startText ?: "" } else { TimeUtils.getGameServerTestTransformedTime(gameEntity.time?.time ?: 0L) } diff --git a/app/src/main/java/com/gh/gamecenter/servers/gametest2/GameServerTestV2ItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/servers/gametest2/GameServerTestV2ItemViewHolder.kt index be7ffdcdc4..b1368ecb3a 100644 --- a/app/src/main/java/com/gh/gamecenter/servers/gametest2/GameServerTestV2ItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/servers/gametest2/GameServerTestV2ItemViewHolder.kt @@ -69,8 +69,8 @@ class GameServerTestV2ItemViewHolder(val binding: ItemGameServerTestV2Binding) : binding.infoContainer.background = com.gh.gamecenter.common.R.drawable.reuse_listview_item_style.toDrawable(binding.root.context) binding.gameIcon.displayGameIcon(gameEntity) binding.gameName.text = gameEntity.name - val time = if (gameEntity.openTest?.startPending == true) { - gameEntity.openTest?.startText ?: "" + val time = if (gameEntity.test?.startPending == true) { + gameEntity.test?.startText ?: "" } else { TimeUtils.getGameServerTestTransformedTime(gameEntity.time?.time ?: 0L) } diff --git a/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameListAdapter.kt b/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameListAdapter.kt index 693f00467e..1fdfba235f 100644 --- a/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameListAdapter.kt @@ -185,7 +185,7 @@ class SimulatorGameListAdapter( gameIconView.displayGameIcon(gameEntity) gameRating.textSize = if (gameEntity.commentCount > 3) 12F else 10F BindingAdapters.setGameName(gameName, gameEntity, false) - BindingAdapters.setGameTags(labelList, gameEntity) + BindingAdapters.setGameTags(labelList, gameEntity, "") gameRating.setDrawableStart(if (gameEntity.commentCount > 3) com.gh.gamecenter.feature.R.drawable.game_horizontal_rating.toDrawable() else null) gameRating.setPadding(0, 0, if (gameEntity.commentCount > 3) 8F.dip2px() else 0, 0) gameRating.text = if (gameEntity.commentCount > 3) { diff --git a/app/src/main/java/com/halo/assistant/fragment/game/GamePluginAdapter.java b/app/src/main/java/com/halo/assistant/fragment/game/GamePluginAdapter.java index ecb0ce78e9..7b333c2cf0 100644 --- a/app/src/main/java/com/halo/assistant/fragment/game/GamePluginAdapter.java +++ b/app/src/main/java/com/halo/assistant/fragment/game/GamePluginAdapter.java @@ -109,7 +109,7 @@ public class GamePluginAdapter extends BaseRecyclerAdapter { binding.gameItemIncluded.gameIconView.displayGameIcon(gameEntity); binding.gameItemIncluded.gameRating.setTextSize(gameEntity.getCommentCount() > 3 ? 12 : 10); BindingAdapters.setGameName(binding.gameItemIncluded.gameName, gameEntity, true); - BindingAdapters.setGameTags(binding.gameItemIncluded.labelList, gameEntity); + BindingAdapters.setGameTags(binding.gameItemIncluded.labelList, gameEntity, ""); ExtensionsKt.setDrawableStart(binding.gameItemIncluded.gameRating, gameEntity.getCommentCount() > 3 ? ExtensionsKt.toDrawable(com.gh.gamecenter.feature.R.drawable.game_horizontal_rating) : null, null, null); binding.gameItemIncluded.gameRating.setPadding(0, 0, gameEntity.getCommentCount() > 3 ? DisplayUtils.dip2px(8) : 0, 0); binding.gameItemIncluded.gameRating.setText(gameEntity.getCommentCount() > 3 ? (gameEntity.getStar() == 10.0 ? "10" : String.valueOf(gameEntity.getStar())) : ""); diff --git a/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderFragment.kt b/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderContainerFragment.kt similarity index 91% rename from app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderFragment.kt rename to app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderContainerFragment.kt index 21fce3524e..73e9f50847 100644 --- a/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderFragment.kt +++ b/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderContainerFragment.kt @@ -15,6 +15,7 @@ import com.gh.gamecenter.ShellActivity.Companion.getIntent import com.gh.gamecenter.WebActivity import com.gh.gamecenter.common.constant.Constants import com.gh.gamecenter.common.entity.WechatConfigEntity +import com.gh.gamecenter.common.utils.PermissionHelper import com.gh.gamecenter.common.utils.SensorsBridge import com.gh.gamecenter.common.utils.toObject import com.gh.gamecenter.core.utils.CurrentActivityHolder @@ -131,6 +132,12 @@ class ReserveReminderContainerFragment : Fragment(), OnReserveReminderListener { requireContext().startActivity(intent) } + override fun updateCalendarReminder() { + PermissionHelper.checkCalendarPermissions(this, game?.id ?: "", game?.name ?: "", game?.categoryChinese ?: "") { + viewModel.addCalendarEvent(game?.id ?: "", reserveReminderEntity.calendarConfig) + } + } + private fun showPhoneNumberDialog(dialogType: Int, phone: String, serviceId: String = "") { isCanDismissed = false @@ -175,7 +182,11 @@ class ReserveReminderContainerFragment : Fragment(), OnReserveReminderListener { game?.id ?: "", game?.name ?: "", game?.categoryChinese ?: "", - "关闭弹窗" + "关闭弹窗", + wechatRemind = reserveReminderEntity.wechatConfig.isReminderEnable, + messageRemind = if (reserveReminderEntity.hasSmsConfig) reserveReminderEntity.smsConfig.notice else null, + automaticDownload = reserveReminderEntity.isEnableAutoDownload, + calendarRemind = if (reserveReminderEntity.hasCalendarConfig) reserveReminderEntity.calendarConfig.notice else null ) val ft = parentFragmentManager.beginTransaction() ft.remove(this) @@ -199,6 +210,7 @@ class ReserveReminderContainerFragment : Fragment(), OnReserveReminderListener { ) } + companion object { private const val KEY_RESERVE_REMINDER = "key_reserve_reminder" @@ -254,4 +266,6 @@ interface OnReserveReminderListener { fun enableAutoDownload(isEnable: Boolean) fun realName() + + fun updateCalendarReminder() } \ No newline at end of file diff --git a/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderRepository.kt b/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderRepository.kt index 9376bffb3e..24872bc65b 100644 --- a/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderRepository.kt +++ b/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderRepository.kt @@ -1,9 +1,11 @@ package com.halo.assistant.fragment.reserve import android.annotation.SuppressLint +import android.content.Context import android.os.Handler import android.os.Looper import android.os.Message +import com.gh.gamecenter.common.utils.CalendarEventUtils import com.gh.gamecenter.common.utils.SensorsBridge import com.gh.gamecenter.common.utils.toRequestBody import com.gh.gamecenter.entity.ReserveModifyEntity @@ -13,6 +15,7 @@ import com.gh.gamecenter.entity.ValidateCodeResponse import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.retrofit.RetrofitManager import com.gh.gamecenter.retrofit.service.ApiService +import com.halo.assistant.HaloApp import io.reactivex.Single import io.reactivex.schedulers.Schedulers import okhttp3.RequestBody @@ -92,6 +95,31 @@ class ReserveReminderRepository( return apiService.reserveSetting(requestBody) } + @SuppressLint("CheckResult") + fun addCalendarEvent(gameId: String, calendarConfig: ReserveReminderEntity.CalendarConfig) = + Single.create { + val calendarEvent = CalendarEventUtils.CalendarEvent( + title = calendarConfig.title, + startTime = calendarConfig.timeStart * 1000, + endTIme = calendarConfig.timeEnd * 1000, + reminderTime = calendarConfig.advanceSeconds * 1000, + remark = calendarConfig.remark + ) + + val eventId = CalendarEventUtils.addCalendarEvent(calendarEvent, HaloApp.getInstance()) + if (eventId != null) { + it.onSuccess(eventId) + } else { + it.onError(Throwable(message = "Failed to add calendar event")) + } + }.doOnSuccess { + val body = hashMapOf( + "calendar_config" to hashMapOf("notice" to true) + ).toRequestBody() + apiService.reserveModify(gameId, body) + .subscribe({}, {}) + } + companion object { private const val MESSAGE_WHAT_ENABLE_AUTO_DOWNLOAD = 1 diff --git a/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderViewModel.kt b/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderViewModel.kt index b8d3dc5dc6..70ba264784 100644 --- a/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderViewModel.kt +++ b/app/src/main/java/com/halo/assistant/fragment/reserve/ReserveReminderViewModel.kt @@ -1,10 +1,14 @@ package com.halo.assistant.fragment.reserve +import android.annotation.SuppressLint +import android.app.Application +import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel import com.gh.gamecenter.common.retrofit.BiResponse import com.gh.gamecenter.common.utils.singleToMain +import com.gh.gamecenter.common.utils.toResString +import com.gh.gamecenter.core.utils.ToastUtils import com.gh.gamecenter.entity.ReserveModifyEntity import com.gh.gamecenter.entity.ReserveReminderEntity import com.gh.gamecenter.entity.ValidateCodeResponse @@ -12,7 +16,7 @@ import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.livedata.Event import io.reactivex.disposables.CompositeDisposable -class ReserveReminderViewModel : ViewModel() { +class ReserveReminderViewModel(app: Application) : AndroidViewModel(app) { private val repository = ReserveReminderRepository.newInstance() @@ -59,6 +63,27 @@ class ReserveReminderViewModel : ViewModel() { repository.enableAutoDownload(game, enable) } + /** + * 日历添加事件 + * 如果在日历添加期间,用户退出当前页面,操作仍然继续 + * 所以,这里不和ui层生命周期绑定 + */ + @SuppressLint("CheckResult") + fun addCalendarEvent(gameId: String, calendarConfig: ReserveReminderEntity.CalendarConfig) { + repository.addCalendarEvent(gameId, calendarConfig) + .compose(singleToMain()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: Long) { + ToastUtils.showToast(com.gh.gamecenter.common.R.string.add_calendar_event_successfully.toResString()) + val reminderEntity = _reserveReminder.value ?: return + reminderEntity.calendarConfig = ReserveReminderEntity.CalendarConfig(_notice = true) + updateReserveReminder(reminderEntity) + } + }) + + } + + override fun onCleared() { composeDisposable.clear() diff --git a/app/src/main/res/drawable/bg_enable_wechat_reminders.xml b/app/src/main/res/drawable/bg_enable_wechat_reminders.xml index 487238ff1a..75606ba0da 100644 --- a/app/src/main/res/drawable/bg_enable_wechat_reminders.xml +++ b/app/src/main/res/drawable/bg_enable_wechat_reminders.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_sms_reminders_unable.xml b/app/src/main/res/drawable/bg_sms_reminders_unable.xml index d3a6306522..263625bdba 100644 --- a/app/src/main/res/drawable/bg_sms_reminders_unable.xml +++ b/app/src/main/res/drawable/bg_sms_reminders_unable.xml @@ -4,5 +4,5 @@ android:endColor="#0A2496FF"/> - + \ No newline at end of file diff --git a/app/src/main/res/layout/game_item_custom.xml b/app/src/main/res/layout/game_item_custom.xml index 01927f8933..158d16ca26 100644 --- a/app/src/main/res/layout/game_item_custom.xml +++ b/app/src/main/res/layout/game_item_custom.xml @@ -156,12 +156,12 @@ style="@style/CustomPageGameRating" android:layout_width="wrap_content" android:layout_height="wrap_content" - tools:text="10" + app:layout_constraintBottom_toBottomOf="@id/gameDesSpace" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintLeft_toLeftOf="@+id/gameDesSpace" app:layout_constraintRight_toLeftOf="@+id/game_des" app:layout_constraintTop_toTopOf="@+id/gameDesSpace" - app:layout_constraintBottom_toBottomOf="@id/gameDesSpace" /> + tools:text="10" /> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_reserve_sms_reminder_enable.xml b/app/src/main/res/layout/layout_reserve_sms_reminder_enable.xml index c374c98f2f..bb76e8ed0e 100644 --- a/app/src/main/res/layout/layout_reserve_sms_reminder_enable.xml +++ b/app/src/main/res/layout/layout_reserve_sms_reminder_enable.xml @@ -13,6 +13,7 @@ android:layout_marginStart="12dp" android:gravity="center" android:text="@string/sms_reminder" + android:textStyle="bold" android:textColor="@color/text_tertiary" android:textSize="13dp" app:layout_constraintBottom_toBottomOf="parent" diff --git a/app/src/main/res/layout/layout_reserve_sms_reminder_unable.xml b/app/src/main/res/layout/layout_reserve_sms_reminder_unable.xml index 6b061fe9d2..2857887ae0 100644 --- a/app/src/main/res/layout/layout_reserve_sms_reminder_unable.xml +++ b/app/src/main/res/layout/layout_reserve_sms_reminder_unable.xml @@ -62,8 +62,8 @@ android:id="@+id/v_sms_add" android:layout_width="0dp" android:layout_height="0dp" - app:layout_constraintBottom_toBottomOf="@id/tv_sms_reminder_open" - app:layout_constraintEnd_toEndOf="@id/tv_sms_reminder_open" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@id/iv_sms_add" - app:layout_constraintTop_toTopOf="@id/tv_sms_reminder_open" /> + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_reserve_wechat_reminder_enable.xml b/app/src/main/res/layout/layout_reserve_wechat_reminder_enable.xml index 2d33d6f1de..292bd1d8b7 100644 --- a/app/src/main/res/layout/layout_reserve_wechat_reminder_enable.xml +++ b/app/src/main/res/layout/layout_reserve_wechat_reminder_enable.xml @@ -12,6 +12,7 @@ android:layout_height="wrap_content" android:layout_marginStart="12dp" android:gravity="center" + android:textStyle="bold" android:text="@string/wechat_reminder" android:textColor="@color/text_tertiary" android:textSize="13dp" diff --git a/app/src/main/res/layout/layout_reserve_wechat_reminder_unable.xml b/app/src/main/res/layout/layout_reserve_wechat_reminder_unable.xml index 49ce80e7b4..3340eba82c 100644 --- a/app/src/main/res/layout/layout_reserve_wechat_reminder_unable.xml +++ b/app/src/main/res/layout/layout_reserve_wechat_reminder_unable.xml @@ -58,8 +58,8 @@ android:id="@+id/v_wechat_add" android:layout_width="0dp" android:layout_height="0dp" - app:layout_constraintBottom_toBottomOf="@id/tv_wechat_reminder_open" - app:layout_constraintEnd_toEndOf="@id/tv_wechat_reminder_open" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@id/iv_wechat_add" - app:layout_constraintTop_toTopOf="@id/tv_wechat_reminder_open" /> + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 24a2263751..679cc79395 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -601,6 +601,9 @@ 開啟 微信提醒 只需一次設置,即可永久有效 + 日曆提醒 + 遊戲上線前將收到手機日曆提醒 + 已新增日曆提醒 遊戲上線後WiFi環境自動下載 根據相關政策要求,遊戲自動下載需通過實名認證,馬上實名 > 修改手機號 @@ -680,5 +683,9 @@ 選擇加速區服 新用戶免費3小時 最近在玩 + 先發 + 上線 + %1$s人預約 + 請檢查是否安裝微信客戶端 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2ba003266f..b9f6827d72 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -601,6 +601,9 @@ 开启 微信提醒 只需一次设置,即可永久有效 + 日历提醒 + 游戏上线前将收到手机日历提醒 + 已添加日历提醒 游戏上线后WiFi环境自动下载 根据相关政策要求,游戏自动下载需要通过实名认证,马上实名 > 修改手机号 @@ -645,7 +648,7 @@ 短信验证失败,请重新输入验证码 验证已取消 游戏已开启WiFi环境自动下载 - 游戏已取消WiFi环境自动下载” + 游戏已取消WiFi环境自动下载 游戏暂不支持WiFi环境自动下载 我的游戏 玩过 @@ -680,4 +683,8 @@ 选择加速区服 新用户免费3小时 最近在玩 + 首发 + 上线 + %1$s人预约 + 请检查是否安装微信客户端 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 e2e0d05004..8fa8d16d59 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 @@ -373,4 +373,11 @@ public class EntranceConsts { public static final String KEY_ACCELERATOR_REQUEST = "accelerator_request"; public static final String KEY_PERFORM_CONTENT_CARD_CLICK_TYPE = "perform_content_card_click_type"; + public static final String KEY_FROM = "from"; + + public static final String TAB_TYPE_DESC = "详情"; + public static final String TAB_TYPE_TRENDS = "专区"; + public static final String TAB_TYPE_ARCHIVE = "云存档"; + public static final String TAB_TYPE_RATING = "评价"; + public static final String TAB_TYPE_BBS = "论坛"; } diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/CalendarEventUtils.kt b/module_common/src/main/java/com/gh/gamecenter/common/utils/CalendarEventUtils.kt new file mode 100644 index 0000000000..5d83040b82 --- /dev/null +++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/CalendarEventUtils.kt @@ -0,0 +1,154 @@ +package com.gh.gamecenter.common.utils + +import android.content.ContentUris +import android.content.ContentValues +import android.content.Context +import android.provider.CalendarContract +import java.util.* + + +/** + * 日历事件 工具类 + */ +object CalendarEventUtils { + + // 添加日历事件 + fun addCalendarEvent(event: CalendarEvent, context: Context): Long? { + val calendarId = getDefaultCalendarId(context) + if (calendarId == -1L) return null + + val isExists = checkEventExistsStrict(calendarId, event, context) + if (isExists) { + return 0 + } + + val startTime = event.startTime + val endTime = event.endTIme + val values = ContentValues().apply { + put(CalendarContract.Events.CALENDAR_ID, calendarId) + put(CalendarContract.Events.TITLE, event.title) + put(CalendarContract.Events.DESCRIPTION, event.remark) + put(CalendarContract.Events.DTSTART, startTime) + put(CalendarContract.Events.DTEND, endTime) + put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().id) + + // 可选属性 + put(CalendarContract.Events.HAS_ALARM, 1) // 是否需要提醒 + } + + try { + val uri = context.contentResolver.insert( + CalendarContract.Events.CONTENT_URI, + values + ) + + val eventId = ContentUris.parseId(uri!!) + // 添加提醒 + addEventReminder(eventId, event.reminderTime, context) + return eventId + } catch (e: Exception) { + e.printStackTrace() + return null + } + } + + // 添加事件提醒 + private fun addEventReminder(eventId: Long, reminderTime: Long, context: Context) { + val reminderMinutes = reminderTime / (1000 * 60) + val values = ContentValues().apply { + put(CalendarContract.Reminders.EVENT_ID, eventId) + put(CalendarContract.Reminders.MINUTES, reminderMinutes) + put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_DEFAULT) + } + + try { + context.contentResolver.insert( + CalendarContract.Reminders.CONTENT_URI, + values + ) + } catch (_: Exception) { + } + } + + private fun getDefaultCalendarId(context: Context): Long { + var calendarId: Long = -1 + val projection = arrayOf( + CalendarContract.Calendars._ID, + CalendarContract.Calendars.CALENDAR_DISPLAY_NAME + ) + + context.contentResolver.query( + CalendarContract.Calendars.CONTENT_URI, projection, null, null, null + )?.use { cursor -> + if (cursor.moveToFirst()) { + val index = cursor.getColumnIndex(CalendarContract.Calendars._ID) + if (index >= 0) { + calendarId = cursor.getLong(index) + } + + } + } + + return calendarId + } + + private fun checkEventExistsStrict( + calendarId: Long, + event: CalendarEvent, + context: Context + ): Boolean { + try { + val projection = arrayOf( + CalendarContract.Events._ID, + CalendarContract.Events.TITLE, + CalendarContract.Events.DESCRIPTION, + CalendarContract.Events.DTSTART, + CalendarContract.Events.DTEND, + CalendarContract.Events.CALENDAR_ID + ) + + val selectionParts = mutableListOf() + val selectionArgs = mutableListOf() + + // 添加必需的条件 + selectionParts.add("${CalendarContract.Events.CALENDAR_ID} = ?") + selectionArgs.add(calendarId.toString()) + + selectionParts.add("${CalendarContract.Events.TITLE} = ?") + selectionArgs.add(event.title) + + selectionParts.add("${CalendarContract.Events.DTSTART} = ?") + selectionArgs.add("${event.startTime}") + + selectionParts.add("${CalendarContract.Events.DTEND} = ?") + selectionArgs.add("${event.endTIme}") + + // 添加可选条件 + selectionParts.add("${CalendarContract.Events.DESCRIPTION} = ?") + selectionArgs.add(event.remark) + + val selection = selectionParts.joinToString(" AND ") + + context.contentResolver.query( + CalendarContract.Events.CONTENT_URI, + projection, + selection, + selectionArgs.toTypedArray(), + null + )?.use { cursor -> + return cursor.count > 0 + } + } catch (_: Exception) { + + } + return false + } + + data class CalendarEvent( + val title: String, + val startTime: Long, // 单位 ms + val endTIme: Long, // 单位 ms + val reminderTime: Long, // 单位 ms + val remark: String + ) +} \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/ImageUtils.kt b/module_common/src/main/java/com/gh/gamecenter/common/utils/ImageUtils.kt index 552e53a738..7e3322e5e5 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/utils/ImageUtils.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/ImageUtils.kt @@ -735,7 +735,7 @@ object ImageUtils { * @param url 图片原地址,用来截取当图片名称用的 * @param useRandomName 是否使用随机名称 */ - fun saveImageToFile(imageFile: File, url: String?, useRandomName: Boolean = false) { + fun saveImageToFile(imageFile: File, url: String?, useRandomName: Boolean = false, callback: ((Boolean) -> Unit)? = null) { var `in`: InputStream? = null var out: OutputStream? = null try { @@ -764,10 +764,14 @@ object ImageUtils { runOnUiThread { ToastUtils.toast("图片已保存到/Pictures/ghzhushou/") + callback?.invoke(true) } BitmapUtils.refreshImage(HaloApp.getInstance(), dst) } catch (e: Exception) { Utils.log("图片保存失败:$e") + runOnUiThread { + callback?.invoke(false) + } } finally { tryWithDefaultCatch { out?.close() diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt b/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt index 7b36c63395..7892e3eba8 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt @@ -19,16 +19,18 @@ import android.text.Spanned import android.view.Gravity import android.view.LayoutInflater import android.view.Window +import android.view.WindowManager import android.widget.FrameLayout import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams +import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import com.therouter.TheRouter import com.gh.gamecenter.common.R import com.gh.gamecenter.common.constant.Constants -import com.gh.gamecenter.common.constant.RouteConsts +import com.gh.gamecenter.common.databinding.DialogCalendarPermissionBinding import com.gh.gamecenter.common.databinding.DialogExternalStoragePermissionIntroBinding import com.gh.gamecenter.common.dialog.ManageExternalStoragePermissionDialogFragment import com.gh.gamecenter.common.view.ImprovedBulletSpan @@ -113,7 +115,8 @@ object PermissionHelper { ) { // 无需申请存储权限的场景 (gameFormat 等于 APK/XAPK/APKS) - val ignoreStoragePermission = gameFormat == Constants.APK_FORMAT || gameFormat == Constants.XAPK_FORMAT || gameFormat == Constants.XAPK_APKS_FORMAT + val ignoreStoragePermission = + gameFormat == Constants.APK_FORMAT || gameFormat == Constants.XAPK_FORMAT || gameFormat == Constants.XAPK_APKS_FORMAT if (ignoreStoragePermission) { emptyCallback.onCallback() @@ -185,7 +188,8 @@ object PermissionHelper { private fun showPermissionPermanentlyDeniedDialog( activity: Activity, permissionName: String, - callback: () -> Unit + dimAmount: Float = 0.2F, + callback: () -> Unit, ) { DialogHelper.showDialog( context = activity, @@ -200,7 +204,7 @@ object PermissionHelper { }, uiModificationCallback = { wrapper -> wrapper.dialog.window?.setGravity(Gravity.BOTTOM) - wrapper.dialog.window?.setDimAmount(0.2F) + wrapper.dialog.window?.setDimAmount(dimAmount) val wmlp = wrapper.dialog.window?.attributes wmlp?.y = 30F.dip2px() wrapper.dialog.setOnDismissListener { @@ -328,7 +332,7 @@ object PermissionHelper { val liStringList = arrayListOf( "游戏上传及导入\n", "使用安装包清理功能\n", - "图片保存(游戏详情、游戏单、资讯论坛、个人主页、信息中心)\n", + "图片保存(游戏详情、游戏单、资讯论坛、个人主页、信息中心、设置微信提醒)\n", "图片/视频上传(个人主页信息修改、内容发布/编辑、游戏投稿、意见反馈、实名认证人工审核)" ) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { @@ -367,7 +371,8 @@ object PermissionHelper { } fun checkManageAllFilesOrStoragePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) { - val activity = context as? FragmentActivity ?: AppManager.getInstance().currentActivity() as? FragmentActivity ?: return + val activity = + context as? FragmentActivity ?: AppManager.getInstance().currentActivity() as? FragmentActivity ?: return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Environment.isExternalStorageManager()) { emptyCallback.onCallback() @@ -548,4 +553,135 @@ object PermissionHelper { } } + fun checkCalendarPermissions( + fragment: Fragment, + gameId: String, + gameName: String, + gameType: String, + block: () -> Unit + ) { + val context = fragment.context ?: return + val activity = fragment.activity ?: return + val permissions = arrayOf(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR) + val hasPermission = permissions.all { + context.checkCallingOrSelfPermission(it) == PackageManager.PERMISSION_GRANTED + } + if (hasPermission) { + block() + } else { + var isDismissByUser = false + val dialog = Dialog(context, R.style.NoAnimationDialog) + val binding = + DialogCalendarPermissionBinding.inflate(LayoutInflater.from(context)) + dialog.setContentView(binding.root) + dialog.show() + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + dialog.window?.setLayout( + (context.resources.displayMetrics.widthPixels - 60F.dip2px()), + WindowManager.LayoutParams.WRAP_CONTENT + ) + dialog.setOnDismissListener { + if (!isDismissByUser) { + SensorsBridge.trackCalendarPermissionsDialogClick("关闭弹窗", gameId, gameName, gameType) + } + } + + binding.tvCancel.setOnClickListener { + isDismissByUser = true + SensorsBridge.trackCalendarPermissionsDialogClick("暂不授权", gameId, gameName, gameType) + dialog.dismiss() + } + binding.tvSubmit.setOnClickListener { + isDismissByUser = true + SensorsBridge.trackCalendarPermissionsDialogClick("开启权限", gameId, gameName, gameType) + dialog.dismiss() + + val descriptionDialog = showCalendarPermissionDescriptionDialog(activity) + val shouldShowRequestPermissionRationale = + permissions.any(fragment::shouldShowRequestPermissionRationale) + if (shouldShowRequestPermissionRationale) { + showPermissionPermanentlyDeniedDialog( + activity = activity, + permissionName = R.string.calendar_permission.toResString(), + 0.4F + ) { + descriptionDialog.dismiss() + } + } else { + requestCalendarPermission(descriptionDialog, activity, block) + } + + } + + SensorsBridge.trackCalendarPermissionsDialogShow(gameId, gameName, gameType) + } + } + + @SuppressLint("CheckResult") + private fun requestCalendarPermission(descriptionDialog: Dialog, activity: FragmentActivity, block: () -> Unit) { + RxPermissions(activity) + .requestEachCombined(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR) + .subscribe { permission -> + when { + permission.granted -> { + descriptionDialog.dismiss() + SensorsBridge.trackCalendarPermissionsDialogResult(true) + block() + } + + permission.shouldShowRequestPermissionRationale -> { + // do nothing + descriptionDialog.dismiss() + SensorsBridge.trackCalendarPermissionsDialogResult(false) + } + + else -> { + SensorsBridge.trackCalendarPermissionsDialogResult(false) + showPermissionPermanentlyDeniedDialog( + activity = activity, + permissionName = R.string.calendar_permission.toResString() + ) { + descriptionDialog.dismiss() + } + } + } + } + } + + private fun showCalendarPermissionDescriptionDialog(activity: FragmentActivity): Dialog { + val dialog = Dialog(activity, R.style.NoAnimationDialog) + + val binding = DialogExternalStoragePermissionIntroBinding.inflate(LayoutInflater.from(activity)) + + val spannableBuilder = + SpannableStringBuilder("当您使用APP时,在以下场景向您请求日历权限,用于帮助您将游戏上线提醒写入日历:\n") + + val liStringList = arrayListOf( + "游戏预约”开启“日历提醒" + ) + + for (li in liStringList) { + val liSpanned = SpannableStringBuilder(li).apply { + setSpan( + ImprovedBulletSpan(bulletRadius = 1.5F.dip2px(), gapWidth = 14F.dip2px()), + 0, + li.length, + Spanned.SPAN_INCLUSIVE_EXCLUSIVE + ) + } + spannableBuilder.append(liSpanned) + } + + binding.contentTv.text = spannableBuilder + binding.titleTv.text = "权限使用说明" + + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) + dialog.setContentView(binding.root) + dialog.window?.setGravity(Gravity.TOP) + dialog.window?.setDimAmount(0.4F) + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + dialog.show() + return dialog + } + } \ 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 90d296473e..6717552480 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 @@ -132,6 +132,7 @@ object SensorsBridge { private const val KEY_PAYMENT_AMOUNT = "payment_amount" private const val KEY_PAYMENT_TYPE = "payment_type" const val EVENT_NAME = "event_name" + private const val KEY_CALENDAR_REMIND = "calendar_remind" private const val EVENT_GAME_DETAIL_PAGE_TAB_SELECT = "GameDetailPageTabSelect" private const val EVENT_GAME_DETAIL_PAGE_TAG_CLICK = "GameDetailPageGameTagClick" @@ -333,6 +334,9 @@ object SensorsBridge { private const val EVENT_MEMBER_RECHARGE_RESULT = "MemberRechargeResult" private const val EVENT_MY_ASSETS_PAGE_CONTACT_CUSTOMER_SERVICE_CLICK = "MyAssetsPageContactCustomerServiceClick" private const val EVENT_STOP_ACCELERATING_DIALOG_SHOW = "StopAcceleratingDialogShow" + private const val EVENT_CALENDAR_PERMISSIONS_DIALOG_SHOW = "CalendarPermissionsDialogShow" + private const val EVENT_CALENDAR_PERMISSIONS_DIALOG_CLICK = "CalendarPermissionsDialogClick" + private const val CALENDAR_PERMISSIONS_DIALOG_RESULT = "CalendarPermissionsDialogResult" private var mIsSensorsEnabled = false @@ -4694,7 +4698,8 @@ object SensorsBridge { gameType: String, wechatRemind: Boolean, messageRemind: Boolean?, - automaticDownload: Boolean? + automaticDownload: Boolean?, + calendarRemind: Boolean? ) { val json = json { KEY_GAME_ID to gameId @@ -4703,6 +4708,7 @@ object SensorsBridge { KEY_WECHAT_REMIND to wechatRemind KEY_MESSAGE_REMIND to messageRemind KEY_AUTOMATIC_DOWNLOAD to automaticDownload + KEY_CALENDAR_REMIND to calendarRemind } trackEvent(EVENT_APPOINTMENT_SUCCESS_DIALOG_SHOW, json) } @@ -4719,7 +4725,8 @@ object SensorsBridge { buttonName: String, wechatRemind: Boolean? = null, messageRemind: Boolean? = null, - automaticDownload: Boolean? = null + automaticDownload: Boolean? = null, + calendarRemind: Boolean? = null ) { val json = json { KEY_GAME_ID to gameId @@ -4729,6 +4736,7 @@ object SensorsBridge { KEY_WECHAT_REMIND to wechatRemind KEY_MESSAGE_REMIND to messageRemind KEY_AUTOMATIC_DOWNLOAD to automaticDownload + KEY_CALENDAR_REMIND to calendarRemind } trackEvent(EVENT_APPOINTMENT_SUCCESS_DIALOG_CLICK, json) } @@ -5281,4 +5289,53 @@ object SensorsBridge { } trackEvent(EVENT_STOP_ACCELERATING_DIALOG_SHOW, json) } + + /** + * 事件ID:CalendarPermissionsDialogShow + * 事件名称:获取日历权限弹窗展示事件 + */ + fun trackCalendarPermissionsDialogShow( + gameId: String, + gameName: String, + gameType: String + ) { + val json = json { + KEY_GAME_ID to gameId + KEY_GAME_NAME to gameName + KEY_GAME_TYPE to gameType + } + trackEvent(EVENT_CALENDAR_PERMISSIONS_DIALOG_SHOW, json) + } + + /** + * 事件ID:CalendarPermissionsDialogClick + * 事件名称:获取日历权限弹窗点击事件 + */ + fun trackCalendarPermissionsDialogClick( + buttonName: String, + gameId: String, + gameName: String, + gameType: String + ) { + val json = json { + KEY_BUTTON_NAME to buttonName + KEY_GAME_ID to gameId + KEY_GAME_NAME to gameName + KEY_GAME_TYPE to gameType + } + trackEvent(EVENT_CALENDAR_PERMISSIONS_DIALOG_CLICK, json) + } + + /** + * 事件ID:CalendarPermissionsDialogResult + * 事件名称:获取日历权限结果 + */ + fun trackCalendarPermissionsDialogResult( + result: Boolean + ) { + val json = json { + KEY_RESULT to if (result) "授权" else "未授权" + } + trackEvent(CALENDAR_PERMISSIONS_DIALOG_RESULT, json) + } } \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/view/BasicIconView.kt b/module_common/src/main/java/com/gh/gamecenter/common/view/BasicIconView.kt new file mode 100644 index 0000000000..391ba8cc5c --- /dev/null +++ b/module_common/src/main/java/com/gh/gamecenter/common/view/BasicIconView.kt @@ -0,0 +1,70 @@ +package com.gh.gamecenter.common.view + +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import androidx.appcompat.content.res.AppCompatResources +import androidx.core.view.updateLayoutParams +import com.gh.gamecenter.common.R +import com.gh.gamecenter.common.databinding.LayoutBasicIconBinding +import com.gh.gamecenter.common.utils.dip2px +import com.gh.gamecenter.common.utils.toColor + +class BasicIconView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) { + + private var binding: LayoutBasicIconBinding = + LayoutBasicIconBinding.inflate(LayoutInflater.from(context), this, true) + + private var backGroundColor = R.color.primary_theme_10.toColor(context) + private var iconColor = Color.parseColor("#000000") + private var iconResourceId = 0 + private var iconWidth = 0 + + private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.FILL } + + init { + initAttrs(context, attrs) + } + + private fun initAttrs(context: Context, attrs: AttributeSet?) { + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.BasicIconView) + backGroundColor = typedArray.getColor(R.styleable.BasicIconView_background_color, backGroundColor) + iconColor = typedArray.getColor(R.styleable.BasicIconView_icon_color, iconColor) + iconResourceId = typedArray.getResourceId(R.styleable.BasicIconView_icon_resource, iconResourceId) + iconWidth = typedArray.getDimensionPixelSize(R.styleable.BasicIconView_icon_width, 24F.dip2px()) + typedArray.recycle() + + binding.ivIcon.updateLayoutParams { + width = iconWidth + height = iconWidth + } + if (iconResourceId != 0) { + val drawable = AppCompatResources.getDrawable(context, iconResourceId) + drawable?.setTint(iconColor) + binding.ivIcon.setImageDrawable(drawable) + binding.ivIcon.setColorFilter(iconColor) + } + + paint.color = backGroundColor + } + + override fun dispatchDraw(canvas: Canvas) { + val centerX = width / 2f + val centerY = height / 2f + val radius = width.coerceAtMost(height) / 2f + canvas.drawCircle(centerX, centerY, radius, paint) + super.dispatchDraw(canvas) + } + +} \ No newline at end of file diff --git a/module_common/src/main/res/drawable/bg_game_item_selling_point.xml b/module_common/src/main/res/drawable/bg_game_item_selling_point.xml new file mode 100644 index 0000000000..d4961bfb4f --- /dev/null +++ b/module_common/src/main/res/drawable/bg_game_item_selling_point.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/module_common/src/main/res/drawable/ic_basic_calendar.xml b/module_common/src/main/res/drawable/ic_basic_calendar.xml new file mode 100644 index 0000000000..1337e8b625 --- /dev/null +++ b/module_common/src/main/res/drawable/ic_basic_calendar.xml @@ -0,0 +1,10 @@ + + + diff --git a/module_common/src/main/res/layout/dialog_calendar_permission.xml b/module_common/src/main/res/layout/dialog_calendar_permission.xml new file mode 100644 index 0000000000..8104c1e3c6 --- /dev/null +++ b/module_common/src/main/res/layout/dialog_calendar_permission.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/module_common/src/main/res/layout/layout_basic_icon.xml b/module_common/src/main/res/layout/layout_basic_icon.xml new file mode 100644 index 0000000000..02dac2a19b --- /dev/null +++ b/module_common/src/main/res/layout/layout_basic_icon.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/module_common/src/main/res/layout/layout_game_item_selling_point.xml b/module_common/src/main/res/layout/layout_game_item_selling_point.xml new file mode 100644 index 0000000000..5ed31d9c59 --- /dev/null +++ b/module_common/src/main/res/layout/layout_game_item_selling_point.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/module_common/src/main/res/values-night/colors.xml b/module_common/src/main/res/values-night/colors.xml index b1bf77e819..7fa489a6e8 100644 --- a/module_common/src/main/res/values-night/colors.xml +++ b/module_common/src/main/res/values-night/colors.xml @@ -89,6 +89,8 @@ #332888E0 #142888E0 + #1F2888E0 + #002888E0 #991383EB diff --git a/module_common/src/main/res/values-zh-rTW/strings.xml b/module_common/src/main/res/values-zh-rTW/strings.xml index 07f417abda..621d5fdd5d 100644 --- a/module_common/src/main/res/values-zh-rTW/strings.xml +++ b/module_common/src/main/res/values-zh-rTW/strings.xml @@ -92,4 +92,12 @@ 1. 遊戲下載功能(XAPK與APKS文件下載)\n2. 圖片上傳功能(頭像、主頁背景、帖子、遊戲單)\n3. 視頻上傳功能(視頻流、帖子)\n4. 圖片保存功能\n5. 遊戲投稿功能 簡訊 複製連結 + + 光環助手需要取得以下權限 + 日曆 + 授權取得日曆權限,用於協助您設定遊戲上線提醒 + 暫不授權 + 開啟權限 + 日曆權限 + 新增成功,上線前將收到手機日曆提醒 \ No newline at end of file diff --git a/module_common/src/main/res/values/attrs.xml b/module_common/src/main/res/values/attrs.xml index 72e857946b..91a4219e8f 100644 --- a/module_common/src/main/res/values/attrs.xml +++ b/module_common/src/main/res/values/attrs.xml @@ -318,4 +318,10 @@ + + + + + + \ No newline at end of file diff --git a/module_common/src/main/res/values/colors.xml b/module_common/src/main/res/values/colors.xml index 0b9addfec8..f047879f0d 100644 --- a/module_common/src/main/res/values/colors.xml +++ b/module_common/src/main/res/values/colors.xml @@ -94,6 +94,7 @@ #CC2496FF #1F2496FF #142496FF + #002496FF #991383EB diff --git a/module_common/src/main/res/values/strings.xml b/module_common/src/main/res/values/strings.xml index fd956cc75d..0333cda45e 100644 --- a/module_common/src/main/res/values/strings.xml +++ b/module_common/src/main/res/values/strings.xml @@ -93,4 +93,12 @@ 短信 复制链接 + 光环助手需要获取如下权限 + 日历 + 授权获取日历权限,用于帮助您设置游戏上线提醒 + 暂不授权 + 开启权限 + 日历权限 + 添加成功,上线前将收到手机日历提醒 + \ No newline at end of file diff --git a/module_common/src/main/res/values/style.xml b/module_common/src/main/res/values/style.xml index b0d396bd38..64f6e69f96 100644 --- a/module_common/src/main/res/values/style.xml +++ b/module_common/src/main/res/values/style.xml @@ -23,6 +23,12 @@ @color/black + +