Compare commits

...

23 Commits

Author SHA1 Message Date
888332ed82 Merge branch 'feature-issues1865_content_provider_sync_certification' into 'feature-issues1865_content_provider'
feat: 添加同步实名的 ContentProvider

See merge request halo/android/assistant-android!260
2022-06-10 11:26:57 +08:00
2bcf8bf330 feat: 添加同步实名的 ContentProvider 2022-06-10 11:26:57 +08:00
c7dfac8f46 fix: 更正实名状态为空时的处理
【单机插件】实名认证功能第二期(https://git.shanqu.cc/pm/halo-plugin-issues/-/issues/221)
2022-06-06 15:45:01 +08:00
08af4a99f8 fix: 移除无用对象声明
【单机插件】实名认证功能第二期(https://git.shanqu.cc/pm/halo-plugin-issues/-/issues/221)
2022-06-06 15:38:08 +08:00
f3a358eb2d feat: 对接未成年人字段
【单机插件】实名认证功能第二期(https://git.shanqu.cc/pm/halo-plugin-issues/-/issues/221)
2022-06-06 15:36:40 +08:00
6abac72ee7 添加简单的占位 Content Provider 2022-06-02 11:46:31 +08:00
b027c57a7c 提供实名认证ContentProvider 2022-06-02 11:42:19 +08:00
84b876394d Merge branch 'hotfix-v5.9.0-532-crashes' into 'release'
修复首页游戏单轮播引发的一些闪退

See merge request halo/android/assistant-android!256
2022-05-27 18:27:22 +08:00
3fb031c329 修复首页游戏单轮播引发的一些闪退 2022-05-27 18:25:22 +08:00
e46afac397 Merge branch 'hotfix-v5.9.0-532-crashes' into 'release'
修复首页游戏单安利墙引发的一些闪退

See merge request halo/android/assistant-android!255
2022-05-27 17:46:49 +08:00
fdf2c80667 修复首页游戏单安利墙引发的一些闪退 2022-05-27 17:34:01 +08:00
d12a1037a2 版本更新至 5.9.0-532 2022-05-24 17:51:10 +08:00
056400d4d1 Merge branch 'dev' into 'release'
累积变更

See merge request halo/android/assistant-android!253
2022-05-21 16:02:02 +08:00
26cbdeaf2d Merge branch 'feature-issues1865' into 'release'
【合规相关】单机游戏内实名校验功能(3) https://git.shanqu.cc/pm/halo-app-issues/-/issues/1865

See merge request halo/android/assistant-android!252
2022-05-21 15:58:45 +08:00
6a5f7f8284 【合规相关】单机游戏内实名校验功能(3) https://git.shanqu.cc/pm/halo-app-issues/-/issues/1865 2022-05-21 15:57:23 +08:00
f272e486f8 【光环助手v5.10.0】前端优化汇总5月第3周(9) https://git.shanqu.cc/pm/halo-app-issues/-/issues/1858 2022-05-20 11:40:29 +08:00
7b0514c055 处理 SonarQube 问题 2022-05-19 15:18:00 +08:00
909e7f33a8 Merge branch 'hotfix-v5.9.0-531-night_mode_switch' into 'release'
关闭遗漏的夜间模式切换代码

See merge request halo/android/assistant-android!251
2022-05-19 11:54:24 +08:00
677511b119 关闭遗漏的夜间模式切换代码 2022-05-19 11:52:57 +08:00
26a2605cd7 Merge branch 'hotfix-v5.9.0-530-crash' into 'release'
修复首页未初始化时切换日夜间模式导致的闪退

See merge request halo/android/assistant-android!250
2022-05-19 11:21:20 +08:00
b02f650a34 修复首页未初始化时切换日夜间模式导致的闪退 2022-05-19 11:19:25 +08:00
7ecc227df5 修复从其他页面返回首页搜索栏变成深色的问题 2022-05-18 11:49:25 +08:00
a32829fd0d 【光环助手v5.10.0】前端优化汇总5月第3周(6) https://git.shanqu.cc/pm/halo-app-issues/-/issues/1858 2022-05-18 11:45:25 +08:00
40 changed files with 579 additions and 79 deletions

View File

@ -759,6 +759,12 @@
android:resource="@xml/provider_paths" />
</provider>
<provider
android:name="com.gh.gamecenter.provider.GhContentProvider"
android:authorities="${applicationId}.provider"
android:enabled="true"
android:exported="true"/>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"

View File

@ -280,12 +280,8 @@ RE.replaceAllDfImage = function(imgRuleFlag, gifRuleFlag) {
i--;
} else {
if(img.src.indexOf(".gif") > 0) {
if(gifRuleFlag.indexOf(",default") > 0) {
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
img.src = img.src.split("?")[0] + gifRuleFlag
}
img.src = img.src.split("?")[0] + gifRuleFlag
} else {
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
img.src = img.src.split("?")[0] + imgRuleFlag
}
}
@ -301,7 +297,7 @@ RE.hideShowBigPic = function() {
var img = imgs[i];
var imageClassName = img.className;
if (imageClassName == "image-link" || img.className == "poster") continue;
if(img.src.indexOf(",thumbnail") > 0 && img.src.indexOf(".gif") == -1) {
if (img.src.indexOf(".gif") == -1) {
j++;
}
}
@ -327,7 +323,6 @@ RE.replaceDfImageByUrl = function(imgUrl, imgRuleFlag, gifRuleFlag) {
var imageClassName = img.className;
if (imageClassName == "image-link" || img.className == "poster") continue;
if (img.src.indexOf(imgUrl) != -1) {
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
if(img.src.indexOf(".gif") > 0) {
img.src = img.src.split("?")[0] + gifRuleFlag
} else {

View File

@ -179,7 +179,9 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
super.onResume();
startPageTime = System.currentTimeMillis();
if (!NightModeUtils.INSTANCE.getSystemMode() && mNightMode != NightModeUtils.INSTANCE.isNightMode(this)) {
if (BuildConfig.IS_NIGHT_MODE_ON
&& !NightModeUtils.INSTANCE.getSystemMode()
&& mNightMode != NightModeUtils.INSTANCE.isNightMode(this)) {
onNightModeChange();
}
}

View File

@ -242,7 +242,9 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
isEverPause = false;
startPageTime = System.currentTimeMillis();
if (!NightModeUtils.INSTANCE.getSystemMode() && mNightMode != NightModeUtils.INSTANCE.isNightMode(requireContext())) {
if (BuildConfig.IS_NIGHT_MODE_ON
&& !NightModeUtils.INSTANCE.getSystemMode()
&& mNightMode != NightModeUtils.INSTANCE.isNightMode(requireContext())) {
onNightModeChange();
}
}
@ -352,7 +354,9 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
onNightModeChange();
if (BuildConfig.IS_NIGHT_MODE_ON) {
onNightModeChange();
}
}
protected void onNightModeChange() {

View File

@ -580,6 +580,7 @@ public class BindingAdapters {
case notfound:
case uncertificated:
case unqualified:
case unavailable:
break;
default:
break;

View File

@ -0,0 +1,97 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.view.*
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentTransaction
import com.gh.base.fragment.BaseDialogFragment
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogSyncCertificationBinding
class SyncCertificationDialogFragment : BaseDialogFragment() {
private var mCallBack: ((isSuccess: Boolean) -> Unit)? = null
private val mBinding by lazy { DialogSyncCertificationBinding.inflate(layoutInflater) }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return mBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
}
private fun initUI() {
mBinding.contentTv.text = getString(R.string.dialog_sync_certification_content)
mBinding.refuseTv.setOnClickListener {
dismissAllowingStateLoss()
}
mBinding.agreeTv.setOnClickListener {
mCallBack?.invoke(true)
dismissAllowingStateLoss()
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val createDialog = super.onCreateDialog(savedInstanceState)
createDialog.setCanceledOnTouchOutside(false)
createDialog.setOnKeyListener(object : DialogInterface.OnKeyListener {
override fun onKey(dialog: DialogInterface?, keyCode: Int, event: KeyEvent?): Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK) {
return true
}
return false
}
})
val window = createDialog.window
window?.setGravity(Gravity.CENTER)
return createDialog
}
//
// override fun onStart() {
// super.onStart()
// val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
// val height = ViewGroup.LayoutParams.WRAP_CONTENT
// dialog?.window?.setLayout(width, height)
// }
companion object {
@JvmStatic
fun show(activity: FragmentActivity, callBack: ((isSuccess: Boolean) -> Unit)?) {
var certificationDialogFragment =
activity.supportFragmentManager.findFragmentByTag(SyncCertificationDialogFragment::class.java.simpleName) as? SyncCertificationDialogFragment
if (certificationDialogFragment != null) {
certificationDialogFragment.mCallBack = callBack
val transaction: FragmentTransaction =
activity.supportFragmentManager.beginTransaction()
transaction.show(certificationDialogFragment)
transaction.commit()
} else {
certificationDialogFragment = SyncCertificationDialogFragment().apply {
mCallBack = callBack
}
}
certificationDialogFragment.show(
activity.supportFragmentManager,
SyncCertificationDialogFragment::class.java.simpleName
)
}
}
}

View File

@ -91,6 +91,9 @@ class SimulatorDownloadManager private constructor() {
DownloadStatus.unqualified == downloadEntity.status -> {
ToastUtils.showToast("未成年人暂不允许在此时间下载游戏")
}
DownloadStatus.unavailable == downloadEntity.status -> {
ToastUtils.showToast("该游戏未接入防沉迷系统,暂不支持下载")
}
DownloadStatus.hijack == downloadEntity.status -> {
ToastUtils.showToast("网络劫持,请稍后重试")
}

View File

@ -3,16 +3,23 @@ package com.gh.common.util;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import androidx.annotation.RequiresApi;
import com.gh.common.AppExecutor;
import com.gh.common.constant.Constants;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.IdCardEntity;
import com.gh.gamecenter.entity.UserInfoEntity;
import com.gh.gamecenter.provider.GhContentProvider;
import com.gh.gamecenter.retrofit.BiResponse;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gid.GidCallback;
@ -24,7 +31,6 @@ import com.lightgame.utils.Utils;
import java.util.HashMap;
import java.util.Map;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import io.sentry.Sentry;
import io.sentry.android.core.SentryAndroid;
@ -42,11 +48,10 @@ public class DataUtils {
* @param channel
*/
public static void init(final Application context, String channel) {
if (CommonDebug.IS_DEBUG) {
return;
}
// 初始化 Sentry 约占用 90ms这里切换到子线程初始化
AppExecutor.getIoExecutor().execute(() -> initSentry(context, channel));
@ -118,7 +123,7 @@ public class DataUtils {
// }
}
private static void initSentry(Context context, String channel) {
SentryAndroid.init(context, options -> {
// Sentry 疯狂报 ANR (很大一部分还是莫名奇妙的 ANR)严重影响到其它闪退日志的收集
@ -129,12 +134,12 @@ public class DataUtils {
} else {
options.setAnrEnabled(false);
}
options.setDebug(BuildConfig.DEBUG);
options.setEnableSessionTracking(true);
options.setEnvironment(BuildConfig.FLAVOR);
options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.shanqu.cc/22");
options.setBeforeSend((event, hint) -> {
if (BuildConfig.DEBUG) {
return null;
@ -143,7 +148,7 @@ public class DataUtils {
}
});
});
Sentry.configureScope(scope -> {
if (BuildConfig.BUILD_TIME != 0L) {
scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME);
@ -200,9 +205,26 @@ public class DataUtils {
.getCertification()
.subscribeOn(Schedulers.io())
.subscribe(new BiResponse<UserInfoEntity>() {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onSuccess(UserInfoEntity data) {
SPUtils.setString(Constants.SP_DEVICE_CERTIFICATION_PREFIX + gid, GsonUtils.toJson(data));
ContentValues values = new ContentValues();
IdCardEntity idCardEntity = data.getIdCard();
if (idCardEntity != null) {
values.put(GhContentProvider.KEY_IS_CERTIFICATED, !TextUtils.isEmpty(data.getIdCard().getId())); // 是否认证
values.put(GhContentProvider.KEY_IS_ADULT,
data.getIdCard().getMinor() == null
|| !data.getIdCard().getMinor()
);
} else {
values.put(GhContentProvider.KEY_IS_CERTIFICATED, false);
values.put(GhContentProvider.KEY_IS_ADULT, false);
}
HaloApp.getInstance().getContentResolver().insert(Uri.parse("content://com.gh.gamecenter.provider/certification"), values);
}
});
}

View File

@ -200,6 +200,7 @@ public class DetailDownloadUtils {
case notfound:
case uncertificated:
case unqualified:
case unavailable:
detailInitDownload(viewHolder, false);
break;
default:

View File

@ -112,6 +112,7 @@ object DownloadNotificationHelper {
|| entity.status == DownloadStatus.cancel
|| entity.status == DownloadStatus.hijack
|| entity.status == DownloadStatus.unqualified
|| entity.status == DownloadStatus.unavailable
|| entity.status == DownloadStatus.uncertificated
|| entity.status == DownloadStatus.notfound
|| entity.status == DownloadStatus.overflow

View File

@ -36,7 +36,6 @@ import okhttp3.MediaType
import okhttp3.RequestBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
import java.util.*
object DownloadObserver {
@ -109,6 +108,20 @@ object DownloadObserver {
// 未成年
RealNameHelper.showRealNameUnqualifiedDialog(downloadEntity)
// 删除任务
downloadEntity.status = DownloadStatus.cancel
downloadManager.cancel(downloadEntity.url)
} else if (DownloadStatus.unavailable == downloadEntity.status) {
// 未接入防沉迷系统
val currentActivity = AppManager.getInstance().currentActivity() ?: return
DialogHelper.showDialog(
context = currentActivity,
title = "温馨提示",
content = "该游戏未接入防沉迷系统,暂不支持下载",
confirmText = "知道了",
cancelText = "")
// 删除任务
downloadEntity.status = DownloadStatus.cancel
downloadManager.cancel(downloadEntity.url)

View File

@ -47,6 +47,7 @@ public class EntranceUtils {
public static final String KEY_GAMENAME = "gameName";
public static final String KEY_PACKAGE_MD5 = "package_md5";
public static final String HOST_ARTICLE = "article";
public static final String HOST_INVOKE_ONLY = "invoke_only";
public static final String HOST_UPLOAD_VIDEO = "upload_video";//上传视频
public static final String HOST_UPLOAD_VIDEO_NEW = "upload_video_new"; // 上传视频新(AKA 发视频)
public static final String HOST_VIDEO_SINGLE = "video_single";//指定视频-不能划动

View File

@ -24,7 +24,6 @@ import com.gh.common.util.GsonUtils;
import com.gh.common.util.HtmlUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.RichEditorUtils;
import com.gh.common.util.SPUtils;
@ -62,8 +61,8 @@ import java.util.Locale;
public class RichEditor extends WebView {
// 和 rich_editor.js 同步
public static String IMAGE_FLAG_DEFAULT = ",default";
public static String IMAGE_FLAG_THUMBNAIL = ",thumbnail";
// public static String IMAGE_FLAG_DEFAULT = ",default";
// public static String IMAGE_FLAG_THUMBNAIL = ",thumbnail";
private boolean mContentOwner;
private boolean mInputEnabled;
@ -132,7 +131,7 @@ public class RichEditor extends WebView {
int widthPixels = getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(40);
mThumbnailImageWidth = widthPixels / 3;
mDefaultImageWidth = widthPixels * 2;
mDefaultImageWidth = widthPixels;
}
@SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"})
@ -251,13 +250,7 @@ public class RichEditor extends WebView {
exec("javascript:RE.setHtmlByVideoStatus('" + URLEncoder.encode(contents, "UTF-8") + "');");
if (isLoadTbImage) {
if (!NetworkUtils.isWifiOr4GConnected(getContext())) {
exec("javascript:RE.replaceTbImage('" +
ImageUtils.getLimitWidthRule(mThumbnailImageWidth) + IMAGE_FLAG_THUMBNAIL + "','" +
ImageUtils.getWatermarkWidthGifRule(mThumbnailImageWidth) + IMAGE_FLAG_THUMBNAIL + "');");
} else {
replaceAllDfImageExcludeGif();
}
replaceAllDfImage();
exec("javascript:RE.ImageClickListener()");
}
@ -370,21 +363,21 @@ public class RichEditor extends WebView {
public void replaceAllDfImageExcludeGif() {
exec("javascript:RE.replaceAllDfImage('" +
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + IMAGE_FLAG_DEFAULT + "','" +
ImageUtils.getWatermarkWidthGifRule(mThumbnailImageWidth) + IMAGE_FLAG_THUMBNAIL + "')");
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + "','" +
ImageUtils.getWatermarkWidthGifRule(mThumbnailImageWidth) + "')");
}
public void replaceAllDfImage() {
exec("javascript:RE.replaceAllDfImage('" +
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + IMAGE_FLAG_DEFAULT + "','" +
ImageUtils.getDefaultGifRule() + IMAGE_FLAG_DEFAULT + "')");
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + "','" +
ImageUtils.getDefaultGifRule() + "')");
}
public void replaceDfImageByUrl(String imgUrl) {
exec("javascript:RE.replaceDfImageByUrl('" + imgUrl + "','" +
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + IMAGE_FLAG_DEFAULT + "','" +
ImageUtils.getDefaultGifRule() + IMAGE_FLAG_DEFAULT + "');");
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + "','" +
ImageUtils.getDefaultGifRule() + "');");
}
public void loadCSS(String cssFile) {

View File

@ -82,6 +82,8 @@ object DownloadDataHelper {
"未实名"
} else if (status == DownloadStatus.unqualified) {
"未成年"
} else if (status == DownloadStatus.unavailable) {
"未接入防沉迷系统,暂不支持下载"
} else if (status == DownloadStatus.redirected) {
"重定向至最终地址"
} else {

View File

@ -38,6 +38,7 @@ import static com.gh.common.util.EntranceUtils.HOST_DOWNLOAD;
import static com.gh.common.util.EntranceUtils.HOST_GAME;
import static com.gh.common.util.EntranceUtils.HOST_GAME_COLLECTION_DETAIL;
import static com.gh.common.util.EntranceUtils.HOST_GAME_COLLECTION_SQUARE;
import static com.gh.common.util.EntranceUtils.HOST_INVOKE_ONLY;
import static com.gh.common.util.EntranceUtils.HOST_LIBAO;
import static com.gh.common.util.EntranceUtils.HOST_QQ;
import static com.gh.common.util.EntranceUtils.HOST_QQ_GROUP;
@ -100,6 +101,9 @@ public class SkipActivity extends BaseActivity {
if (host != null) {
Intent intent;
switch (host) {
case HOST_INVOKE_ONLY:
// 仅唤起光环助手,不进入光环页面。用于类似 ContentProvider 的用途
break;
case HOST_ARTICLE:
DirectUtils.directToArticle(this, path, ENTRANCE_BROWSER);
break;

View File

@ -158,7 +158,7 @@ class AmwayFragment : LazyListFragment<AmwayListItemData, AmwayViewModel>() {
collapsingToolbar.scrimVisibleHeightTrigger = collapsingTrigger
collapsingToolbar.scrimShownAction = {
mIsCollapsed = it
DisplayUtils.setLightStatusBar(requireActivity(), if (mNightMode) false else it)
DisplayUtils.setLightStatusBar(requireActivity(), !mNightMode && it)
if (it) {
titleTv.alpha = 1F
titleTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_black))

View File

@ -0,0 +1,11 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class CertificationDialogEntity(
var realName: String = "",
var idCard: String = "") : Parcelable

View File

@ -8,6 +8,7 @@ data class IdCardEntity(
var id: String? = null,
var name: String? = null,
var revise: Boolean? = false,
var minor: Boolean? = false, // 是否是未成年人
@SerializedName("id_photo")
var idPhoto: String? = null
)

View File

@ -33,8 +33,12 @@ data class SettingsEntity(
var gameDomeSwitch: String = "",//试玩显示开关on打开
@SerializedName("permission_popup_switch")
var permissionPopupSwitch: String = "off",//权限引导弹窗开关on/off
@SerializedName("certification_sync_switch")
var certificationSyncSwitch: String = "off",//实名信息同步开关on/off默认off
@SerializedName("permission_popup_applied_versions")
var permissionPopupAppliedVersions: PermissionPopupAppliedVersions = PermissionPopupAppliedVersions()
) {
fun setCommunityEntrance(communityEntrance: String) {

View File

@ -488,7 +488,7 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
mBinding?.statusBar?.setBackgroundColor(color)
mBinding?.tabContainer?.setBackgroundColor(color)
mSearchToolbarFragment.updateStyle(if (NightModeUtils.isNightMode(requireContext())) true else useLightStyle)
mSearchToolbarFragment.updateStyle(NightModeUtils.isNightMode(requireContext()) || useLightStyle)
}
private fun generateTabView(title: String): TabItemMainBinding {

View File

@ -4,14 +4,15 @@ import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.drawable.Animatable;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import androidx.annotation.ColorRes;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
@ -27,13 +28,13 @@ import com.facebook.imagepipeline.image.ImageInfo;
import com.gh.base.OnDoubleTapListener;
import com.gh.base.fragment.BaseFragment_ViewPager_Checkable;
import com.gh.common.constant.Config;
import com.gh.common.constant.Constants;
import com.gh.common.dialog.PrivacyPolicyDialogFragment;
import com.gh.common.dialog.SyncCertificationDialogFragment;
import com.gh.common.syncpage.SyncPageRepository;
import com.gh.common.tracker.TrackerLogger;
import com.gh.common.util.BiCallback;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.ExtensionsKt;
@ -43,11 +44,9 @@ import com.gh.common.util.ImageUtils;
import com.gh.common.util.IntegralLogHelper;
import com.gh.common.util.LogUtils;
import com.gh.common.util.NightModeUtils;
import com.gh.common.util.SPUtils;
import com.gh.common.view.ReserveDialog;
import com.gh.gamecenter.R;
import com.gh.gamecenter.databinding.FragmentMainBinding;
import com.gh.gamecenter.entity.PrivacyPolicyEntity;
import com.gh.gamecenter.entity.SettingsEntity;
import com.gh.gamecenter.entity.SubjectRecommendEntity;
import com.gh.gamecenter.entity.WelcomeDialogEntity;
@ -59,6 +58,7 @@ import com.gh.gamecenter.game.GameFragment;
import com.gh.gamecenter.message.MessageUnreadRepository;
import com.gh.gamecenter.message.MessageUnreadViewModel;
import com.gh.gamecenter.personal.PersonalFragment;
import com.gh.gamecenter.user.UserRepository;
import com.gh.gamecenter.video.detail.HomeVideoFragment;
import com.halo.assistant.HaloApp;
import com.lightgame.listeners.OnBackPressedListener;
@ -185,14 +185,25 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
if (reserveData != null && !reserveData.isEmpty()) {
ReserveDialog reserveDialog = ReserveDialog.getInstance(reserveData);
reserveDialog.setOnDismissListener(() -> {
mViewModel.showSyncCertificationDialog();
MessageUnreadRepository.INSTANCE.loadMessageUnreadData();
return null;
});
reserveDialog.show(getChildFragmentManager(), "reserveDialog");
} else {
mViewModel.showSyncCertificationDialog();
MessageUnreadRepository.INSTANCE.loadMessageUnreadData();
}
});
mViewModel.getSyncCertificationDialog().observe(this,certificationDialogEntity -> {
if (certificationDialogEntity != null){
SyncCertificationDialogFragment.show(requireActivity(), isSuccess -> {
//发送同步实名认证请求
UserRepository.getInstance().syncCertificate(certificationDialogEntity.getRealName(), certificationDialogEntity.getIdCard());
return null;
});
}
});
ViewModelProviders.of(this)
.get(MessageUnreadViewModel.class)
.getUnreadMessageTotalLiveData().observe(this, isShow -> ExtensionsKt.goneIf(mBinding.mainIvMessageHint, !isShow));
@ -224,6 +235,7 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
WelcomeDialogFragment welcomeDialog = WelcomeDialogFragment.getInstance(welcomeDialogEntity);
welcomeDialog.setOnDismissListener(() -> {
mViewModel.requestReserveDialog();
return null;
});

View File

@ -2,19 +2,21 @@ package com.gh.gamecenter.fragment
import android.annotation.SuppressLint
import android.app.Application
import android.net.Uri
import android.preference.PreferenceManager
import android.text.TextUtils
import android.util.Base64
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import com.gh.common.constant.Config
import com.gh.common.constant.Constants
import com.gh.common.runOnIoThread
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.HomeBottomBarHelper
import com.gh.common.util.PackageUtils
import com.gh.common.util.SPUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.entity.DialogEntity
import com.gh.gamecenter.entity.SimpleGameEntity
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.entity.WelcomeDialogEntity
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
@ -29,10 +31,11 @@ class MainWrapperViewModel(application: Application) : AndroidViewModel(applicat
val navBar = MutableLiveData<SubjectRecommendEntity?>()
// 弹窗优先级: 隐私政策弹窗->启动弹窗->预约弹窗->消息弹窗
// 弹窗优先级: 隐私政策弹窗->启动弹窗->预约弹窗->同步认证弹窗
val openingDialog = MutableLiveData<WelcomeDialogEntity?>()
val reserveDialog = MutableLiveData<List<SimpleGameEntity>?>()
val privacyPolicyDialog = MutableLiveData<DialogEntity.PrivacyPolicyEntity?>()
val syncCertificationDialog = MutableLiveData<CertificationDialogEntity?>()
init {
getHomeNavBar()
@ -100,7 +103,8 @@ class MainWrapperViewModel(application: Application) : AndroidViewModel(applicat
// 全新安装忽略隐私弹窗
if (privacyPolicyDialogEntity != null) {
val id = privacyPolicyDialogEntity.id
val lastAcceptedId = SPUtils.getString(Constants.SP_LAST_ACCEPTED_PRIVACY_DIALOG_ID, "")
val lastAcceptedId =
SPUtils.getString(Constants.SP_LAST_ACCEPTED_PRIVACY_DIALOG_ID, "")
if (HaloApp.getInstance().isBrandNewInstall) {
SPUtils.setString(Constants.SP_LAST_ACCEPTED_PRIVACY_DIALOG_ID, id)
privacyPolicyDialog.postValue(null)
@ -138,9 +142,49 @@ class MainWrapperViewModel(application: Application) : AndroidViewModel(applicat
reserveDialog.postValue(null)
}
})
} else {
showSyncCertificationDialog()
}
}
@SuppressLint("NewApi")
fun showSyncCertificationDialog() {
val uri = Uri.parse("content://com.gh.gamecenter.provider/sync_certification")
runOnIoThread {
val settings = Config.getSettings()
//查询是否已经在光环进行实名认证
val certificationStr = SPUtils.getString(Constants.SP_DEVICE_CERTIFICATION_PREFIX + HaloApp.getInstance().gid)
//后台配置中 开启了同步实名且光环没有进行实名认证才执行
if ((settings?.certificationSyncSwitch ?: "off") == "on" && TextUtils.isEmpty(certificationStr)) {
var realName = ""
var idCard = ""
val cursor = HaloApp.getInstance().contentResolver.query(uri, null, null, null)
if (cursor != null && cursor.count > 0) {
cursor.moveToFirst()
do {
realName = cursor.getString(1)
idCard = cursor.getString(2)
} while (cursor.moveToNext())
cursor.close()
}
if (!TextUtils.isEmpty(realName) && !TextUtils.isEmpty(idCard)) {
//base64解密存储的数据
val finalRealName = String(Base64.decode(realName, Base64.DEFAULT))
val finalIdCard = String(Base64.decode(idCard, Base64.DEFAULT))
val certificationDialogEntity = CertificationDialogEntity()
certificationDialogEntity.realName = finalRealName
certificationDialogEntity.idCard = finalIdCard
syncCertificationDialog.postValue(certificationDialogEntity)
//删除contentprovider数据库中的数据
HaloApp.getInstance().contentResolver.delete(uri, null, null)
}
}
}
}
/**
* 特殊渠道隐藏视频 tab
*/

View File

@ -3,6 +3,7 @@ package com.gh.gamecenter.gamecollection.square
import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.AppExecutor
import com.gh.common.util.TextHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.GameCollectionAmwayContentItemBinding
@ -16,7 +17,9 @@ class GameCollectionAmwayAdapter(context: Context) :
fun setAmwayList(amwayList: List<AmwayCommentEntity>) {
mAmwayList = amwayList
notifyDataSetChanged()
AppExecutor.uiExecutor.execute {
notifyDataSetChanged()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
@ -25,7 +28,7 @@ class GameCollectionAmwayAdapter(context: Context) :
override fun getItemCount() = Int.MAX_VALUE
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameCollectionAmwayContentItemViewHolder) {
if (holder is GameCollectionAmwayContentItemViewHolder && getRealCount() != 0) {
val entity = mAmwayList[getRealPosition(position)]
holder.binding.gameIcon.displayGameIcon(entity.game.toGameEntity())
holder.binding.amwayTv.text = TextHelper.getCommentLabelSpannableStringBuilder(entity.comment.content, R.color.white_alpha_80)

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.AppExecutor
import com.gh.common.exposure.*
import com.gh.common.util.DirectUtils
import com.gh.common.util.ImageUtils
@ -27,7 +28,9 @@ class GameCollectionBannerAdapter(
fun submitList(updateList: List<CarouselEntity>?, amwayList: List<AmwayCommentEntity>? = null) {
mBannerList = if (updateList.isNullOrEmpty()) emptyList() else ArrayList(updateList)
mAmwayListItem = if (amwayList.isNullOrEmpty()) emptyList() else ArrayList(amwayList)
notifyDataSetChanged()
AppExecutor.uiExecutor.execute {
notifyDataSetChanged()
}
}
private fun shouldShowAmway(position: Int) = isHome && getActualPosition(position) == getActualSize() - 1

View File

@ -46,20 +46,16 @@ class GameCollectionSquareAdapter(
ListAdapter<GameCollectionListItemData>(context), IExposable {
fun setAmwayList(amwayList: List<AmwayCommentEntity>) {
if (!mEntityList.isNullOrEmpty()) {
if (mEntityList[0].amwayListItem == null && isHome) {
mEntityList[0].amwayListItem = amwayList
notifyItemChanged(0)
}
if (isHome && mEntityList.isNotEmpty() && mEntityList[0].amwayListItem == null) {
mEntityList[0].amwayListItem = amwayList
notifyItemChanged(0)
}
}
fun setBannerList(bannerList: List<CarouselEntity>) {
if (!mEntityList.isNullOrEmpty()) {
if (mEntityList[0].carouselListItem == null && isHome) {
mEntityList[0].carouselListItem = bannerList
notifyItemChanged(0)
}
if (isHome && mEntityList.isNotEmpty() && mEntityList[0].carouselListItem == null) {
mEntityList[0].carouselListItem = bannerList
notifyItemChanged(0)
}
}

View File

@ -189,7 +189,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
mDefaultBinding.collapsingToolbar.scrimVisibleHeightTrigger = collapsingTrigger
mDefaultBinding.collapsingToolbar.scrimShownAction = {
mIsCollapsed = it
DisplayUtils.setLightStatusBar(requireActivity(), if (mNightMode) false else it)
DisplayUtils.setLightStatusBar(requireActivity(), !mNightMode && it)
changeToolbarStyle(it)
}
@ -492,7 +492,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
setIndicatorBackground(R.drawable.progressbar_game_collection_primary.toDrawable(requireContext()))
setTextColor(ContextCompat.getColorStateList(context, R.color.game_collection_rg_button_selector))
}
DisplayUtils.setLightStatusBar(requireActivity(), if (mNightMode) false else mIsCollapsed)
DisplayUtils.setLightStatusBar(requireActivity(), !mNightMode && mIsCollapsed)
changeToolbarStyle(mIsCollapsed)
}
}

View File

@ -325,11 +325,12 @@ class HomeFragment : LazyFragment() {
override fun onNightModeChange() {
super.onNightModeChange()
mBinding.gameList.setBackgroundColor(R.color.background_white.toColor(requireContext()))
mBinding.gameList.recycledViewPool.clear()
mListAdapter.notifyItemRangeChanged(0, mListAdapter.itemCount)
if (isSupportVisible) {
onScrollChanged()
if (::mBinding.isInitialized) {
mBinding.gameList.recycledViewPool.clear()
if (::mListAdapter.isInitialized) mListAdapter.notifyItemRangeChanged(0, mListAdapter.itemCount)
if (isSupportVisible) {
onScrollChanged()
}
}
}
}

View File

@ -780,9 +780,9 @@ public class NewsDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
public void imageClick(String url) {
if (url.contains("web_load_dfimg_icon.png")) {
editor.post(() -> editor.replaceAllDfImageExcludeGif());
} else if (url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL)) {
}/* else if (url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL)) {
editor.post(() -> editor.replaceDfImageByUrl(url));
} else {
}*/ else {
int current = 0;
for (int i = 0, size = mNewsImgs.size(); i < size; i++) {
if (url.contains(mNewsImgs.get(i))) {

View File

@ -0,0 +1,159 @@
package com.gh.gamecenter.provider
import android.content.ContentProvider
import android.content.ContentUris
import android.content.ContentValues
import android.content.UriMatcher
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.net.Uri
import com.gh.gamecenter.BuildConfig
import com.lightgame.utils.Utils
class GhContentProvider : ContentProvider() {
private var mUriMatcher: UriMatcher = UriMatcher(UriMatcher.NO_MATCH)
private var mSqLiteDatabase: SQLiteDatabase? = null
init {
mUriMatcher.addURI(AUTHORITY, CERTIFICATION_TABLE_NAME, 1)
mUriMatcher.addURI(AUTHORITY, SYNC_CERTIFICATION_TABLE_NAME, 2)
}
override fun onCreate(): Boolean {
val helper: SQLiteOpenHelper =
object : SQLiteOpenHelper(context, CERTIFICATION_DATABASE_NAME, null, 1) {
override fun onCreate(db: SQLiteDatabase) {
// 创建表格
val sql = "CREATE TABLE $CERTIFICATION_TABLE_NAME(" +
"$KEY_PRIMARY_KEY INTEGER PRIMARY KEY AUTOINCREMENT," +
"$KEY_IS_CERTIFICATED BOOL," +
"$KEY_IS_ADULT BOOL" +
")"
db.execSQL(sql)
val syncSql = "CREATE TABLE ${SYNC_CERTIFICATION_TABLE_NAME}(" +
"$KEY_PRIMARY_KEY INTEGER PRIMARY KEY AUTOINCREMENT," +
"$KEY_REAL_NAME TEXT," +
"$KEY_ID_CARD TEXT" +
")"
db.execSQL(syncSql)
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
// do nothing
}
}
mSqLiteDatabase = helper.writableDatabase
return true
}
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?
): Cursor? {
val match = mUriMatcher.match(uri);
when(match){
1 -> return mSqLiteDatabase?.query(
CERTIFICATION_TABLE_NAME,
null,
null,
null,
null,
null,
null
)
2 -> return mSqLiteDatabase?.query(
SYNC_CERTIFICATION_TABLE_NAME,
null,
null,
null,
null,
null,
null
)
}
return null
}
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val context = context ?: return null
if (mUriMatcher.match(uri) == 1) {
// 固定主键(只保留一条数据即可)
values?.put(KEY_PRIMARY_KEY, 1)
// 如果已存在则直接替换
val rowId: Long? = mSqLiteDatabase?.insertWithOnConflict(
CERTIFICATION_TABLE_NAME,
null,
values,
SQLiteDatabase.CONFLICT_REPLACE
)
if (rowId != null && rowId > 0) {
val nameUri = ContentUris.withAppendedId(uri, rowId)
context.contentResolver.notifyChange(nameUri, null)
Utils.log("CertificationContentProvider", "insert success:" + uri.authority + ", status => " + values?.toString())
return nameUri
}
}
else if (mUriMatcher.match(uri) == 2) {
// 固定主键(只保留一条数据即可)
values?.put(KEY_PRIMARY_KEY, 1)
// 如果已存在则直接替换
val rowId: Long? = mSqLiteDatabase?.insertWithOnConflict(
SYNC_CERTIFICATION_TABLE_NAME,
null,
values,
SQLiteDatabase.CONFLICT_REPLACE
)
if (rowId != null && rowId > 0) {
val nameUri = ContentUris.withAppendedId(uri, rowId)
context.contentResolver.notifyChange(nameUri, null)
Utils.log("SyncCertificationContentProvider", "insert success:" + uri.authority + ", status => " + values?.toString())
return nameUri
}
}
return null
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
// delete from outside is forbidden
if (mUriMatcher.match(uri) == 2){
return mSqLiteDatabase?.delete(SYNC_CERTIFICATION_TABLE_NAME,selection,selectionArgs) ?: 0
}
return 0
}
override fun update(
uri: Uri,
values: ContentValues?,
selection: String?,
selectionArgs: Array<out String>?
): Int {
return 0
}
companion object {
private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.provider"
private const val CERTIFICATION_DATABASE_NAME = "gh_certification.db"
private const val CERTIFICATION_TABLE_NAME = "certification"
const val KEY_PRIMARY_KEY = "primary_key"
const val KEY_IS_CERTIFICATED = "is_certificated"
const val KEY_IS_ADULT = "is_adult"
private const val SYNC_CERTIFICATION_TABLE_NAME = "sync_certification"
const val KEY_REAL_NAME = "real_name"
const val KEY_ID_CARD = "id_card"
}
}

View File

@ -1193,7 +1193,7 @@ open class AnswerDetailFragment : NormalFragment() {
fun imageClick(url: String) {
when {
url.contains("web_load_dfimg_icon.png") -> mBaseHandler.post { mBinding.richEditor.replaceAllDfImageExcludeGif() }
url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL) -> mBaseHandler.post { mBinding.richEditor.replaceDfImageByUrl(url) }
//url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL) -> mBaseHandler.post { mBinding.richEditor.replaceDfImageByUrl(url) }
else -> {
var current = 0
var i = 0

View File

@ -237,9 +237,9 @@ class ArticleDetailContentViewHolder(
url.contains("web_load_dfimg_icon.png") -> {
runOnUiThread { binding.richEditor.replaceAllDfImageExcludeGif() }
}
url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL) -> {
runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) }
}
// url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL) -> {
// runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) }
// }
else -> {
clickToastByStatus(status) {
var current = 0

View File

@ -222,9 +222,9 @@ class QuestionDetailContentViewHolder(
url.contains("web_load_dfimg_icon.png") -> {
runOnUiThread { binding.richEditor.replaceAllDfImageExcludeGif() }
}
url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL) -> {
runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) }
}
// url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL) -> {
// runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) }
// }
else -> {
clickToastByStatus(status) {
var current = 0

View File

@ -3534,4 +3534,13 @@ public interface ApiService {
*/
@POST("videos/{video_id}/comments/{comment_id}:unset-top")
Observable<ResponseBody> postVideoCommentUnTop(@Path("video_id") String videoId, @Path("comment_id") String commentId);
/**
* 同步从其他游戏传过来的实名认证
*/
@POST("./certification:sync")
Observable<ResponseBody> postSyncCertification(@Body RequestBody body);
}

View File

@ -55,6 +55,7 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -502,6 +503,37 @@ public class UserRepository {
});
}
/**
* 同步实名信息
*/
@SuppressLint("CheckResult")
public void syncCertificate(final String realName, final String idCard) {
Map<String,Map<String,String>> map = new HashMap<>();
Map<String,String> info = new HashMap<>();
info.put("id",idCard);
info.put("name",realName);
map.put("id_card",info);
RequestBody body = RequestBody.create(
MediaType.parse("application/json"), new JSONObject(map).toString());
RetrofitManager.getInstance().getApi().postSyncCertification(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>(){
@Override
public void onResponse(@Nullable ResponseBody response) {
super.onResponse(response);
DataUtils.getDeviceCertification(HaloApp.getInstance().getGid());
}
@Override
public void onApiFailure(ApiResponse<ResponseBody> e) {
super.onApiFailure(e);
}
});
}
private Response<UserInfoEntity> userInfoResponse(final LoginTag loginTag) {
return new Response<UserInfoEntity>() {
@Override

View File

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

View File

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

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/default_dialog_width"
android:layout_height="wrap_content"
android:background="@drawable/background_shape_white_radius_5"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="4dp"
android:text="实名提示"
android:textColor="@color/text_title"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/contentTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="11dp"
android:lineSpacingExtra="4dp"
android:textColor="@color/text_subtitleDesc"
android:textSize="14sp"
tools:text="@string/dialog_sync_certification_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp">
<TextView
android:id="@+id/refuseTv"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:background="@drawable/button_round_f5f5f5"
android:gravity="center"
android:text="拒绝"
android:textColor="@color/text_title"
android:textSize="14sp" />
<TextView
android:id="@+id/agreeTv"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginLeft="24dp"
android:layout_weight="1"
android:background="@drawable/button_blue_oval"
android:gravity="center"
android:text="同意"
android:textColor="@color/white"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -880,4 +880,7 @@
<string name="attempt_tips_2">该游戏暂时仅提供试玩版本。试玩版可能存在bug或兼容性问题。敬请留意后续相关消息。</string>
<string name="rating_protection">游戏停服更新维护中,为避免情绪化内容对游戏评分带来的影响,因此开启停服保护功能。在停服保护状态期间,所新增及修改发布的评分将不计入总分,所评分评论内容在展示上也会有文字提示告知其他玩家。\n\n感谢您的配合及谅解祝您游戏愉快\n\n光环助手会持续关注产品建议及反馈如您在使用过程中有任何问题欢迎向我们反馈。</string>
<string name="teenager_mode_description">开启青少年模式后,系统将自动关闭所有游戏的下载功能,需要输入密码才能恢复使用\n\n开启青少年模式需要先设置独立密码如忘记密码可联系客服申述重置\n\n青少年模式是光环助手响应国家政策为促进青少年健康成长的一种模式我们优先针对核心场景进行优化也将继续致力于优化更多场景</string>
<string name="dialog_sync_certification_content">您是否同意将您在光环平台游戏内的实名信息与状态同步至光环助手,您的信息将仅用于\n1、部分游戏在助手内无需再次实名即可下载\n2、游戏内使用快速认证方式无需重复实名</string>
</resources>

View File

@ -7,7 +7,7 @@ ext {
targetSdkVersion = 28
// application info (每个大版本之间的 versionCode 增加 20)
versionCode = 531
versionCode = 532
versionName = "5.9.0"
applicationId = "com.gh.gamecenter"