diff --git a/app/build.gradle b/app/build.gradle index ebad8802ce..30387f9df4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,6 +6,8 @@ apply plugin: 'kotlin-kapt' // apkChannelPackage apply plugin: 'channel' +import groovy.xml.XmlUtil + //apply from: 'tinker-support.gradle' android { @@ -18,6 +20,10 @@ android { enabled = true } + viewBinding { + enabled = true + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -125,15 +131,27 @@ android { } } - flavorDimensions "nonsense" + flavorDimensions("env") + + sourceSets { + publish { + java.srcDirs = ['src/main/java'] + } + internal { + java.srcDirs = ['src/main/java'] + } + tea { + java.srcDirs = ['src/main/java', 'src/tea/java'] + } + gdt { + java.srcDirs = ['src/main/java', 'src/gdt/java'] + } + } - /** - * 多渠道打包,渠道请参考"channel.txt"文件,所有渠道值均通过java code设置 - */ productFlavors { // publish release host publish { - dimension "nonsense" + dimension "env" buildConfigField "String", "API_HOST", "\"${API_HOST}\"" buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\"" @@ -144,7 +162,7 @@ android { } // internal test dev host internal { - dimension "nonsense" + dimension "env" versionNameSuffix "-debug" buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\"" @@ -155,6 +173,30 @@ android { buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEV_UMENG_MESSAGE_SECRET}\"" buildConfigField "String", "BUGLY_APPID", "\"${DEV_BUGLY_APPID}\"" } + + tea { + dimension "env" + + buildConfigField "String", "API_HOST", "\"${API_HOST}\"" + + buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\"" + + buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\"" + buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\"" + buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\"" + } + + gdt { + dimension "env" + + buildConfigField "String", "API_HOST", "\"${API_HOST}\"" + + buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\"" + + buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\"" + buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\"" + buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\"" + } } } @@ -184,6 +226,7 @@ repositories { dependencies { implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') + gdtImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/gdt/libs') testImplementation 'junit:junit:4.12' @@ -289,7 +332,7 @@ dependencies { debugImplementation "com.github.nichbar.chucker:library:$chucker" releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker" -// implementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog" + teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog" // implementation "com.bytedance.ies.ugc.aweme:opensdk-china-external:$bytedanceAweme" // implementation "com.bytedance.ies.ugc.aweme:opensdk-common:$bytedanceAweme" @@ -299,6 +342,8 @@ dependencies { implementation "net.lingala.zip4j:zip4j:${zip4j}" + implementation "io.sentry:sentry-android:$sentry" + implementation("com.github.piasy:BigImageViewer:$bigImageViewer", { exclude group: 'com.squareup.okhttp3' exclude group: 'androidx.swiperefreshlayout' @@ -307,7 +352,7 @@ dependencies { implementation "com.github.PhilJay:MPAndroidChart:${chart}" implementation project(':libraries:LGLibrary') -// implementation project(':libraries:MTA') + implementation project(':libraries:MTA') implementation project(':libraries:QQShare') // implementation project(':libraries:TalkingData') // implementation project(':libraries:UmengPush') @@ -371,3 +416,78 @@ if (propFile.exists()) { // task.name.startsWith('merge') && task.name.endsWith('Resources') // }.each { t -> t.dependsOn generateMetaJson } //} + + +project.afterEvaluate { + def variants = null + try { + variants = android.applicationVariants + } catch (Throwable t) { + t.printStackTrace() + try { + variants = android.libraryVariants + } catch (Throwable tt) { + tt.printStackTrace() + } + } + if (variants != null) { + variants.all { variant -> + variant.outputs.each { output -> + def task = output.processManifestProvider.get() + if (task == null) { + return + } + + /** + * 为 Manifest 的 Activity 的 configChanges 添加自己手动处理 configurationChanges 配置 [https://developer.android.com/guide/topics/resources/runtime-changes] + * AGP 4.1.0 从 ProcessManifest task 里拿 manifest 的 API 变更调整可以参考这里 [https://github.com/Tencent/tinker/pull/1476/commits/d71645729b13d545ca4ba6826f93fbf558751434] + * (搞半天还是不会抽离方法,有空再把 gradle 改成用 kotlin 实现吧) + */ + task.doLast { + def manifestFile = new File(multiApkManifestOutputDirectory.get().asFile, "AndroidManifest.xml") + if (manifestFile == null || !manifestFile.exists()) { + return + } + def parser = new XmlSlurper(false, true) + def manifest = parser.parse(manifestFile) + def app = manifest.'application'[0] + app.'activity'.each { act -> + String value = act.attributes()['android:configChanges'] + if (value == null || value.isEmpty()) { + value = "keyboardHidden|orientation|screenSize|screenLayout|density|fontScale|locale" + act.attributes()['androidconfigChanges'] = value + } else { + String[] valueSplit = value.split("\\|") + if (!valueSplit.contains("keyboardHidden")) { + value += "|keyboardHidden" + } + if (!valueSplit.contains("orientation")) { + value += "|orientation" + } + if (!valueSplit.contains("screenSize")) { + value += "|screenSize" + } + if (!valueSplit.contains("screenLayout")) { + value += "|screenLayout" + } + if (!valueSplit.contains("density")) { + value += "|density" + } + if (!valueSplit.contains("fontScale")) { + value += "|fontScale" + } + if (!valueSplit.contains("locale")) { + value += "|locale" + } + act.attributes()['android:configChanges'] = value + } + } + + def tmpManifest = XmlUtil.serialize(manifest).replaceAll("androidconfigChanges", "android:configChanges") + manifest = parser.parseText(tmpManifest) + manifestFile.setText(XmlUtil.serialize(manifest), "utf-8") + } + } + } + } +} \ No newline at end of file diff --git a/app/proguard-rules.txt b/app/proguard-rules.txt index e1d7e29456..be871ae960 100644 --- a/app/proguard-rules.txt +++ b/app/proguard-rules.txt @@ -241,6 +241,13 @@ -dontwarn com.shuyu.gsyvideoplayer.utils.** -keep class tv.danmaku.ijk.** { *; } -dontwarn tv.danmaku.ijk.** +-keep public class * extends android.view.View{ + *** get*(); + void set*(***); + public (android.content.Context); + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); +} #穿山甲 -keep class com.bytedance.sdk.openadsdk.** { *; } @@ -258,4 +265,7 @@ -keep class com.alibaba.sdk.android.**{*;} -keep class com.ut.**{*;} --keep class com.ta.**{*;} \ No newline at end of file +-keep class com.ta.**{*;} + +-keep class com.gh.gamecenter.GdtHelper { *; } +-keep class com.gh.gamecenter.TeaHelper { *; } \ No newline at end of file diff --git a/app/src/gdt/java/com/gh/gamecenter/GdtHelper.kt b/app/src/gdt/java/com/gh/gamecenter/GdtHelper.kt new file mode 100644 index 0000000000..efc5d52491 --- /dev/null +++ b/app/src/gdt/java/com/gh/gamecenter/GdtHelper.kt @@ -0,0 +1,75 @@ +package com.gh.gamecenter + +import android.app.Application +import android.text.TextUtils +import android.util.Log +import com.gh.common.util.ToastUtils +import com.lightgame.utils.Utils +import com.qq.gdt.action.GDTAction +import org.json.JSONObject + +/** + * 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403] + * + * 更换帐号 [https://gitlab.ghzs.com/pm/yunying/issues/893] + */ +object GdtHelper { + + const val NETWORK_TYPE = "NETWORK_TYPE" + const val PAGE_TYPE = "PAGE_TYPE" + const val CONTENT_TYPE = "CONTENT_TYPE" + const val CONTENT_ID = "CONTENT_ID" + const val KEYWORD = "KEYWORD" + const val GAME_ID = "GAME_ID" + const val SCORE = "SCORE" + const val PLATFORM = "PLATFORM" + + @JvmStatic + fun init(application: Application, channel: String) { + if (shouldUseGdtHelper()) { + if (channel == "GH_728") { + GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc") + } else if (channel == "GH_729") { + GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1") + } else { + GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a") + } + } + Utils.log("init GdtHelper") + } + +// fun logAction(type: String) { +// if (shouldUseGdtHelper()) { +// GDTAction.logAction(type) +// Utils.log("GDT", type) +// } +// } + @JvmStatic + fun logAction(type: String, vararg kv: String?) { + try { + val actionParam = JSONObject() + for (i in kv.indices) { + if (i % 2 != 0) { + val key = kv[i - 1] + val value = kv[i] + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { + actionParam.put(key, value) + } + } + } + Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]") + GDTAction.logAction(type, actionParam) + } catch (e: Exception) { + e.printStackTrace() + } + } + + // TODO 确认开启的渠道条件 + private fun shouldUseGdtHelper(): Boolean { + return true +// +// val channel = HaloApp.getInstance().channel +// return !(TextUtils.isEmpty(channel) || channel.contains("GDT".toLowerCase(Locale.CHINA))) + } + +} \ No newline at end of file diff --git a/app/src/gdt/libs/GDTActionSDK.min.1.6.10.aar b/app/src/gdt/libs/GDTActionSDK.min.1.6.10.aar new file mode 100644 index 0000000000..17ddcbc8e3 Binary files /dev/null and b/app/src/gdt/libs/GDTActionSDK.min.1.6.10.aar differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d6cac89074..d82054ae2a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,8 +9,6 @@ - - @@ -25,8 +23,6 @@ - - @@ -35,7 +31,7 @@ tools:ignore="ProtectedPermissions" /> - + @@ -79,6 +75,10 @@ tools:replace="android:allowBackup" tools:targetApi="n"> + + + android:windowSoftInputMode="stateHidden" /> + android:theme="@style/TransparentStatusBarAndNavigationBar" /> - + android:name=".catalog.CatalogActivity" + android:screenOrientation="portrait" /> + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - - - - - - + + + + + + + + - - - + + + - - - + + + diff --git a/app/src/main/assets/emojikf b/app/src/main/assets/emojikf deleted file mode 100644 index 63c97e04a3..0000000000 --- a/app/src/main/assets/emojikf +++ /dev/null @@ -1,40 +0,0 @@ -emoji_kf_1.png,:smile: -emoji_kf_2.png,:smiley: -emoji_kf_3.png,:laughing: -emoji_kf_4.png,:blush: -emoji_kf_5.png,:heart_eyes: -emoji_kf_6.png,:smirk: -emoji_kf_7.png,:flushed: -emoji_kf_8.png,:kissing_heart: -emoji_kf_9.png,:grin: -emoji_kf_10.png,:wink: -emoji_kf_11.png,:stuck_out_tongue_winking_eye: -emoji_kf_12.png,:stuck_out_tongue_closed eyes: -emoji_kf_13.png,:worried: -emoji_kf_14.png,:sleeping: -emoji_kf_15.png,:expressionless: -emoji_kf_16.png,:sweat_smile: -emoji_kf_17.png,:joy: -emoji_kf_18.png,:cold_sweat: -emoji_kf_19.png,:sob: -emoji_kf_20.png,:angry: -emoji_kf_21.png,:mask: -emoji_kf_22.png,:scream: -emoji_kf_23.png,:sunglasses: -emoji_kf_24.png,:heart: -emoji_kf_25.png,:broken_heart: -emoji_kf_26.png,:star: -emoji_kf_27.png,:anger: -emoji_kf_28.png,:exclamation: -emoji_kf_29.png,:question: -emoji_kf_30.png,:zzz: -emoji_kf_31.png,:thumbsup: -emoji_kf_32.png,:thumbsdown: -emoji_kf_33.png,:ok_hand: -emoji_kf_34.png,:punch: -emoji_kf_35.png,:yeah: -emoji_kf_36.png,:clap: -emoji_kf_37.png,:muscle: -emoji_kf_38.png,:pray: -emoji_kf_39.png,:skull: -emoji_kf_40.png,:trollface: diff --git a/app/src/main/assets/iattest.wav b/app/src/main/assets/iattest.wav deleted file mode 100644 index fcee567afa..0000000000 Binary files a/app/src/main/assets/iattest.wav and /dev/null differ diff --git a/app/src/main/assets/like.gif b/app/src/main/assets/like.gif deleted file mode 100644 index 1df9bec736..0000000000 Binary files a/app/src/main/assets/like.gif and /dev/null differ diff --git a/app/src/main/assets/microlog.properties b/app/src/main/assets/microlog.properties deleted file mode 100644 index 1efa6de057..0000000000 --- a/app/src/main/assets/microlog.properties +++ /dev/null @@ -1,5 +0,0 @@ -# This is a simple Microlog configuration file -microlog.level=DEBUG -microlog.appender=LogCatAppender;FileAppender -microlog.formatter=PatternFormatter -microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T \ No newline at end of file diff --git a/app/src/main/java/com/gh/base/AppUncaughtHandler.java b/app/src/main/java/com/gh/base/AppUncaughtHandler.java index df51f1c986..16dc54f472 100644 --- a/app/src/main/java/com/gh/base/AppUncaughtHandler.java +++ b/app/src/main/java/com/gh/base/AppUncaughtHandler.java @@ -26,6 +26,8 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; +import io.sentry.core.Sentry; + public class AppUncaughtHandler implements UncaughtExceptionHandler { private Context mContext; @@ -45,7 +47,9 @@ public class AppUncaughtHandler implements UncaughtExceptionHandler { Looper.loop(); } }); + saveLocalLog(mContext, ex); + Sentry.captureException(ex); restart(mContext); } diff --git a/app/src/main/java/com/gh/base/BaseActivity.java b/app/src/main/java/com/gh/base/BaseActivity.java index d8d129a944..82393324c2 100644 --- a/app/src/main/java/com/gh/base/BaseActivity.java +++ b/app/src/main/java/com/gh/base/BaseActivity.java @@ -32,13 +32,17 @@ import com.gh.common.util.ExtensionsKt; import com.gh.common.util.MtaHelper; import com.gh.common.util.PackageInstaller; import com.gh.common.util.RunningUtils; +import com.gh.common.util.SPUtils; import com.gh.common.util.ShareUtils; import com.gh.common.util.StringUtils; +import com.gh.download.DownloadManager; import com.gh.gamecenter.BuildConfig; import com.gh.gamecenter.LoginActivity; import com.gh.gamecenter.R; +import com.gh.gamecenter.SplashScreenActivity; import com.gh.gamecenter.eventbus.EBShowDialog; import com.lightgame.BaseAppCompatActivity; +import com.lightgame.download.DownloadEntity; import com.lightgame.download.FileUtils; import com.lightgame.utils.Utils; import com.tencent.tauth.Tencent; @@ -122,6 +126,23 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy if (BuildConfig.DEBUG) { Utils.log("ACTIVITY_ENTRANCE -> " + mEntrance); } + + if (savedInstanceState != null) { + String xapkUnzipActivity = SPUtils.getString(Constants.SP_XAPK_UNZIP_ACTIVITY); + String xapkUrl = SPUtils.getString(Constants.SP_XAPK_URL); + Utils.log("页面重建了--" + xapkUnzipActivity + "--" + xapkUrl); + if (this.getClass().getName().equals(SplashScreenActivity.class.getName())) { + SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, ""); + SPUtils.setString(Constants.SP_XAPK_URL, ""); + return; + } + if (this.getClass().getName().equals(xapkUnzipActivity) && !TextUtils.isEmpty(xapkUrl)) { + DownloadEntity downloadEntity = DownloadManager.getInstance(this).getDownloadEntityByUrl(xapkUrl); + PackageInstaller.install(this, downloadEntity, false); + SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, ""); + SPUtils.setString(Constants.SP_XAPK_URL, ""); + } + } } @SuppressWarnings("ConstantConditions") diff --git a/app/src/main/java/com/gh/base/fragment/WaitingDialogFragment.java b/app/src/main/java/com/gh/base/fragment/WaitingDialogFragment.java index 403f92db14..10eff12ffb 100644 --- a/app/src/main/java/com/gh/base/fragment/WaitingDialogFragment.java +++ b/app/src/main/java/com/gh/base/fragment/WaitingDialogFragment.java @@ -81,8 +81,13 @@ public class WaitingDialogFragment extends BaseDialogFragment { @Override public void dismiss() { + dismissAllowingStateLoss(); + } + + @Override + public void dismissAllowingStateLoss() { mBackListener = null; - super.dismiss(); + super.dismissAllowingStateLoss(); } public static class WaitingDialogData { diff --git a/app/src/main/java/com/gh/common/DefaultJsApi.kt b/app/src/main/java/com/gh/common/DefaultJsApi.kt index 879b8615e9..ca42ec55d8 100644 --- a/app/src/main/java/com/gh/common/DefaultJsApi.kt +++ b/app/src/main/java/com/gh/common/DefaultJsApi.kt @@ -252,6 +252,11 @@ class DefaultJsApi(var context: Context) { } } + @JavascriptInterface + fun openInNewWebview(url: Any) { + runOnUiThread { DirectUtils.directToWebView(context, url.toString(), "内部网页") } + } + @Keep internal data class ImageEvent(var imageList: ArrayList = arrayListOf(), var position: Int = 0) diff --git a/app/src/main/java/com/gh/common/constant/Constants.java b/app/src/main/java/com/gh/common/constant/Constants.java index bd14878319..df3c6dd797 100644 --- a/app/src/main/java/com/gh/common/constant/Constants.java +++ b/app/src/main/java/com/gh/common/constant/Constants.java @@ -129,6 +129,11 @@ public class Constants { public static final String SP_IS_USER_ACCEPTED_PRIVACY_STATEMENT = "has_user_accepted_privacy_statement"; public static final String SP_BRAND_NEW_USER = "brand_new_user"; + //包名检测是否点击不再提示 + public static final String SP_PACKAGE_CHECK = "package_check"; + + public static final String SP_XAPK_UNZIP_ACTIVITY = "xapk_unzip_activity"; + public static final String SP_XAPK_URL = "xapk_url"; //手机号码匹配规则 public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$"; 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 76d8cc3c6f..5671d3a8ff 100644 --- a/app/src/main/java/com/gh/common/databind/BindingAdapters.java +++ b/app/src/main/java/com/gh/common/databind/BindingAdapters.java @@ -14,10 +14,17 @@ import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; +import androidx.databinding.BindingAdapter; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + import com.facebook.drawee.view.SimpleDraweeView; import com.gh.base.OnViewClickListener; import com.gh.common.constant.Config; import com.gh.common.dialog.CertificationDialog; +import com.gh.common.dialog.PackageCheckDialogFragment; import com.gh.common.dialog.ReserveDialogFragment; import com.gh.common.exposure.ExposureEvent; import com.gh.common.history.HistoryHelper; @@ -38,7 +45,6 @@ import com.gh.common.util.NewsUtils; import com.gh.common.util.NumberUtils; import com.gh.common.util.PackageInstaller; import com.gh.common.util.PackageUtils; -import com.gh.common.util.PermissionHelper; import com.gh.common.util.PlatformUtils; import com.gh.common.util.ReservationHelper; import com.gh.common.view.DownloadProgressBar; @@ -74,12 +80,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.content.ContextCompat; -import androidx.databinding.BindingAdapter; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - /** * Created by khy on 12/02/18. */ @@ -256,6 +256,14 @@ public class BindingAdapters { } } + /** + * lazy 的 paddingTop + */ + @BindingAdapter("lazyPaddingLeft") + public static void lazyPaddingLeft(View view, int paddingLeftInDp) { + view.setPadding(DisplayUtils.dip2px(paddingLeftInDp), view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); + } + /** * lazy 的 paddingTop */ @@ -448,12 +456,14 @@ public class BindingAdapters { return; } } - DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> { - CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> { - DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> { - DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> { - DialogUtils.checkDownload(v.getContext(), apk.getSize(), - isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location)); + PackageCheckDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity.getPackageDialog(), () -> { + DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> { + CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> { + DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> { + DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> { + DialogUtils.checkDownload(v.getContext(), apk.getSize(), + isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location)); + }); }); }); }); @@ -509,13 +519,11 @@ public class BindingAdapters { break; case RESERVABLE: CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> { - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(progressBar.getContext(), () -> { - ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> { - LogUtils.logReservation(gameEntity, traceEvent); - updateReservation(progressBar, gameEntity); - }); - dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve"); + ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> { + LogUtils.logReservation(gameEntity, traceEvent); + updateReservation(progressBar, gameEntity); }); + dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve"); }); break; case RESERVED: diff --git a/app/src/main/java/com/gh/common/databind/DrawablesBindingAdapter.java b/app/src/main/java/com/gh/common/databind/DrawablesBindingAdapter.java new file mode 100644 index 0000000000..4c65d4dc2b --- /dev/null +++ b/app/src/main/java/com/gh/common/databind/DrawablesBindingAdapter.java @@ -0,0 +1,1000 @@ +package com.gh.common.databind; + +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.InsetDrawable; +import android.graphics.drawable.StateListDrawable; +import android.view.View; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Field; + +import androidx.annotation.ColorInt; +import androidx.annotation.IntDef; +import androidx.databinding.BindingAdapter; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.PARAMETER; + +public class DrawablesBindingAdapter { + private static final String TAG = "Drawables"; + + private static final int INVALID = 0; + private static final int[] TMP_PADDING = new int[4]; + + + // normal, checked, checkable, enabled, focused, pressed, selected + @BindingAdapter(value = { + "drawable_shapeMode", + "drawable_solidColor", + "drawable_strokeColor", + "drawable_strokeWidth", + "drawable_strokeDash", + "drawable_strokeDashGap", + "drawable_radius", + "drawable_radiusLT", + "drawable_radiusLB", + "drawable_radiusRT", + "drawable_radiusRB", + "drawable_startColor", + "drawable_centerColor", + "drawable_endColor", + "drawable_orientation", + "drawable_gradientType", + "drawable_radialCenterX", + "drawable_radialCenterY", + "drawable_radialRadius", + "drawable_width", + "drawable_height", + "drawable_marginLeft", + "drawable_marginTop", + "drawable_marginRight", + "drawable_marginBottom", + "drawable_ringThickness", + "drawable_ringThicknessRatio", + "drawable_ringInnerRadius", + "drawable_ringInnerRadiusRatio", + + "drawable_checked_shapeMode", + "drawable_checked_solidColor", + "drawable_checked_strokeColor", + "drawable_checked_strokeWidth", + "drawable_checked_strokeDash", + "drawable_checked_strokeDashGap", + "drawable_checked_radius", + "drawable_checked_radiusLT", + "drawable_checked_radiusLB", + "drawable_checked_radiusRT", + "drawable_checked_radiusRB", + "drawable_checked_startColor", + "drawable_checked_centerColor", + "drawable_checked_endColor", + "drawable_checked_orientation", + "drawable_checked_gradientType", + "drawable_checked_radialCenterX", + "drawable_checked_radialCenterY", + "drawable_checked_radialRadius", + "drawable_checked_width", + "drawable_checked_height", + "drawable_checked_marginLeft", + "drawable_checked_marginTop", + "drawable_checked_marginRight", + "drawable_checked_marginBottom", + "drawable_checked_ringThickness", + "drawable_checked_ringThicknessRatio", + "drawable_checked_ringInnerRadius", + "drawable_checked_ringInnerRadiusRatio", + + "drawable_checkable_shapeMode", + "drawable_checkable_solidColor", + "drawable_checkable_strokeColor", + "drawable_checkable_strokeWidth", + "drawable_checkable_strokeDash", + "drawable_checkable_strokeDashGap", + "drawable_checkable_radius", + "drawable_checkable_radiusLT", + "drawable_checkable_radiusLB", + "drawable_checkable_radiusRT", + "drawable_checkable_radiusRB", + "drawable_checkable_startColor", + "drawable_checkable_centerColor", + "drawable_checkable_endColor", + "drawable_checkable_orientation", + "drawable_checkable_gradientType", + "drawable_checkable_radialCenterX", + "drawable_checkable_radialCenterY", + "drawable_checkable_radialRadius", + "drawable_checkable_width", + "drawable_checkable_height", + "drawable_checkable_marginLeft", + "drawable_checkable_marginTop", + "drawable_checkable_marginRight", + "drawable_checkable_marginBottom", + "drawable_checkable_ringThickness", + "drawable_checkable_ringThicknessRatio", + "drawable_checkable_ringInnerRadius", + "drawable_checkable_ringInnerRadiusRatio", + + "drawable_enabled_shapeMode", + "drawable_enabled_solidColor", + "drawable_enabled_strokeColor", + "drawable_enabled_strokeWidth", + "drawable_enabled_strokeDash", + "drawable_enabled_strokeDashGap", + "drawable_enabled_radius", + "drawable_enabled_radiusLT", + "drawable_enabled_radiusLB", + "drawable_enabled_radiusRT", + "drawable_enabled_radiusRB", + "drawable_enabled_startColor", + "drawable_enabled_centerColor", + "drawable_enabled_endColor", + "drawable_enabled_orientation", + "drawable_enabled_gradientType", + "drawable_enabled_radialCenterX", + "drawable_enabled_radialCenterY", + "drawable_enabled_radialRadius", + "drawable_enabled_width", + "drawable_enabled_height", + "drawable_enabled_marginLeft", + "drawable_enabled_marginTop", + "drawable_enabled_marginRight", + "drawable_enabled_marginBottom", + "drawable_enabled_ringThickness", + "drawable_enabled_ringThicknessRatio", + "drawable_enabled_ringInnerRadius", + "drawable_enabled_ringInnerRadiusRatio", + + "drawable_focused_shapeMode", + "drawable_focused_solidColor", + "drawable_focused_strokeColor", + "drawable_focused_strokeWidth", + "drawable_focused_strokeDash", + "drawable_focused_strokeDashGap", + "drawable_focused_radius", + "drawable_focused_radiusLT", + "drawable_focused_radiusLB", + "drawable_focused_radiusRT", + "drawable_focused_radiusRB", + "drawable_focused_startColor", + "drawable_focused_centerColor", + "drawable_focused_endColor", + "drawable_focused_orientation", + "drawable_focused_gradientType", + "drawable_focused_radialCenterX", + "drawable_focused_radialCenterY", + "drawable_focused_radialRadius", + "drawable_focused_width", + "drawable_focused_height", + "drawable_focused_marginLeft", + "drawable_focused_marginTop", + "drawable_focused_marginRight", + "drawable_focused_marginBottom", + "drawable_focused_ringThickness", + "drawable_focused_ringThicknessRatio", + "drawable_focused_ringInnerRadius", + "drawable_focused_ringInnerRadiusRatio", + + "drawable_pressed_shapeMode", + "drawable_pressed_solidColor", + "drawable_pressed_strokeColor", + "drawable_pressed_strokeWidth", + "drawable_pressed_strokeDash", + "drawable_pressed_strokeDashGap", + "drawable_pressed_radius", + "drawable_pressed_radiusLT", + "drawable_pressed_radiusLB", + "drawable_pressed_radiusRT", + "drawable_pressed_radiusRB", + "drawable_pressed_startColor", + "drawable_pressed_centerColor", + "drawable_pressed_endColor", + "drawable_pressed_orientation", + "drawable_pressed_gradientType", + "drawable_pressed_radialCenterX", + "drawable_pressed_radialCenterY", + "drawable_pressed_radialRadius", + "drawable_pressed_width", + "drawable_pressed_height", + "drawable_pressed_marginLeft", + "drawable_pressed_marginTop", + "drawable_pressed_marginRight", + "drawable_pressed_marginBottom", + "drawable_pressed_ringThickness", + "drawable_pressed_ringThicknessRatio", + "drawable_pressed_ringInnerRadius", + "drawable_pressed_ringInnerRadiusRatio", + + "drawable_selected_shapeMode", + "drawable_selected_solidColor", + "drawable_selected_strokeColor", + "drawable_selected_strokeWidth", + "drawable_selected_strokeDash", + "drawable_selected_strokeDashGap", + "drawable_selected_radius", + "drawable_selected_radiusLT", + "drawable_selected_radiusLB", + "drawable_selected_radiusRT", + "drawable_selected_radiusRB", + "drawable_selected_startColor", + "drawable_selected_centerColor", + "drawable_selected_endColor", + "drawable_selected_orientation", + "drawable_selected_gradientType", + "drawable_selected_radialCenterX", + "drawable_selected_radialCenterY", + "drawable_selected_radialRadius", + "drawable_selected_width", + "drawable_selected_height", + "drawable_selected_marginLeft", + "drawable_selected_marginTop", + "drawable_selected_marginRight", + "drawable_selected_marginBottom", + "drawable_selected_ringThickness", + "drawable_selected_ringThicknessRatio", + "drawable_selected_ringInnerRadius", + "drawable_selected_ringInnerRadiusRatio", + + // normal, checked, checkable, enabled, focused, pressed, selected + + "drawable", + "drawable_checked", + "drawable_checkable", + "drawable_enabled", + "drawable_focused", + "drawable_pressed", + "drawable_selected", + + }, requireAll = false) + public static void setViewBackground( + View view, + + @ShapeMode int shapeMode, + @ColorInt Integer solidColor, + @ColorInt int strokeColor, + float strokeWidth, + float strokeDash, + float strokeDashGap, + float radius, + float radiusLT, + float radiusLB, + float radiusRT, + float radiusRB, + @ColorInt Integer startColor, + @ColorInt Integer centerColor, + @ColorInt Integer endColor, + @Orientation int orientation, + @GradientType int gradientType, + Float radialCenterX, + Float radialCenterY, + float radialRadius, + float width, + float height, + float marginLeft, + float marginTop, + float marginRight, + float marginBottom, + float ringThickness, + float ringThicknessRatio, + float ringInnerRadius, + float ringInnerRadiusRatio, + + @ShapeMode int checked_shapeMode, + @ColorInt Integer checked_solidColor, + @ColorInt int checked_strokeColor, + float checked_strokeWidth, + float checked_strokeDash, + float checked_strokeDashGap, + float checked_radius, + float checked_radiusLT, + float checked_radiusLB, + float checked_radiusRT, + float checked_radiusRB, + @ColorInt Integer checked_startColor, + @ColorInt Integer checked_centerColor, + @ColorInt Integer checked_endColor, + @Orientation int checked_orientation, + @GradientType int checked_gradientType, + Float checked_radialCenterX, + Float checked_radialCenterY, + float checked_radialRadius, + float checked_width, + float checked_height, + float checked_marginLeft, + float checked_marginTop, + float checked_marginRight, + float checked_marginBottom, + float checked_ringThickness, + float checked_ringThicknessRatio, + float checked_ringInnerRadius, + float checked_ringInnerRadiusRatio, + + @ShapeMode int checkable_shapeMode, + @ColorInt Integer checkable_solidColor, + @ColorInt int checkable_strokeColor, + float checkable_strokeWidth, + float checkable_strokeDash, + float checkable_strokeDashGap, + float checkable_radius, + float checkable_radiusLT, + float checkable_radiusLB, + float checkable_radiusRT, + float checkable_radiusRB, + @ColorInt Integer checkable_startColor, + @ColorInt Integer checkable_centerColor, + @ColorInt Integer checkable_endColor, + @Orientation int checkable_orientation, + @GradientType int checkable_gradientType, + Float checkable_radialCenterX, + Float checkable_radialCenterY, + float checkable_radialRadius, + float checkable_width, + float checkable_height, + float checkable_marginLeft, + float checkable_marginTop, + float checkable_marginRight, + float checkable_marginBottom, + float checkable_ringThickness, + float checkable_ringThicknessRatio, + float checkable_ringInnerRadius, + float checkable_ringInnerRadiusRatio, + + @ShapeMode int enabled_shapeMode, + @ColorInt Integer enabled_solidColor, + @ColorInt int enabled_strokeColor, + float enabled_strokeWidth, + float enabled_strokeDash, + float enabled_strokeDashGap, + float enabled_radius, + float enabled_radiusLT, + float enabled_radiusLB, + float enabled_radiusRT, + float enabled_radiusRB, + @ColorInt Integer enabled_startColor, + @ColorInt Integer enabled_centerColor, + @ColorInt Integer enabled_endColor, + @Orientation int enabled_orientation, + @GradientType int enabled_gradientType, + Float enabled_radialCenterX, + Float enabled_radialCenterY, + float enabled_radialRadius, + float enabled_width, + float enabled_height, + float enabled_marginLeft, + float enabled_marginTop, + float enabled_marginRight, + float enabled_marginBottom, + float enabled_ringThickness, + float enabled_ringThicknessRatio, + float enabled_ringInnerRadius, + float enabled_ringInnerRadiusRatio, + + @ShapeMode int focused_shapeMode, + @ColorInt Integer focused_solidColor, + @ColorInt int focused_strokeColor, + float focused_strokeWidth, + float focused_strokeDash, + float focused_strokeDashGap, + float focused_radius, + float focused_radiusLT, + float focused_radiusLB, + float focused_radiusRT, + float focused_radiusRB, + @ColorInt Integer focused_startColor, + @ColorInt Integer focused_centerColor, + @ColorInt Integer focused_endColor, + @Orientation int focused_orientation, + @GradientType int focused_gradientType, + Float focused_radialCenterX, + Float focused_radialCenterY, + float focused_radialRadius, + float focused_width, + float focused_height, + float focused_marginLeft, + float focused_marginTop, + float focused_marginRight, + float focused_marginBottom, + float focused_ringThickness, + float focused_ringThicknessRatio, + float focused_ringInnerRadius, + float focused_ringInnerRadiusRatio, + + @ShapeMode int pressed_shapeMode, + @ColorInt Integer pressed_solidColor, + @ColorInt int pressed_strokeColor, + float pressed_strokeWidth, + float pressed_strokeDash, + float pressed_strokeDashGap, + float pressed_radius, + float pressed_radiusLT, + float pressed_radiusLB, + float pressed_radiusRT, + float pressed_radiusRB, + @ColorInt Integer pressed_startColor, + @ColorInt Integer pressed_centerColor, + @ColorInt Integer pressed_endColor, + @Orientation int pressed_orientation, + @GradientType int pressed_gradientType, + Float pressed_radialCenterX, + Float pressed_radialCenterY, + float pressed_radialRadius, + float pressed_width, + float pressed_height, + float pressed_marginLeft, + float pressed_marginTop, + float pressed_marginRight, + float pressed_marginBottom, + float pressed_ringThickness, + float pressed_ringThicknessRatio, + float pressed_ringInnerRadius, + float pressed_ringInnerRadiusRatio, + + @ShapeMode int selected_shapeMode, + @ColorInt Integer selected_solidColor, + @ColorInt int selected_strokeColor, + float selected_strokeWidth, + float selected_strokeDash, + float selected_strokeDashGap, + float selected_radius, + float selected_radiusLT, + float selected_radiusLB, + float selected_radiusRT, + float selected_radiusRB, + @ColorInt Integer selected_startColor, + @ColorInt Integer selected_centerColor, + @ColorInt Integer selected_endColor, + @Orientation int selected_orientation, + @GradientType int selected_gradientType, + Float selected_radialCenterX, + Float selected_radialCenterY, + float selected_radialRadius, + float selected_width, + float selected_height, + float selected_marginLeft, + float selected_marginTop, + float selected_marginRight, + float selected_marginBottom, + float selected_ringThickness, + float selected_ringThicknessRatio, + float selected_ringInnerRadius, + float selected_ringInnerRadiusRatio, + + Drawable drawable, + Drawable drawable_checked, + Drawable drawable_checkable, + Drawable drawable_enabled, + Drawable drawable_focused, + Drawable drawable_pressed, + Drawable drawable_selected + ) { + boolean isDefaultNull = false; + int count = 0; + Drawable defaultDrawable = drawable != null ? drawable : create( + shapeMode, + solidColor, + strokeColor, + strokeWidth, + strokeDash, + strokeDashGap, + radius, + radiusLT, + radiusLB, + radiusRT, + radiusRB, + startColor, + centerColor, + endColor, + orientation, + gradientType, + radialCenterX, + radialCenterY, + radialRadius, + width, + height, + marginLeft, + marginTop, + marginRight, + marginBottom, + ringThickness, + ringThicknessRatio, + ringInnerRadius, + ringInnerRadiusRatio + ); + if (defaultDrawable != null) { + count++; + } else { + isDefaultNull = true; + } + Drawable checkedDrawable = drawable_checked != null ? drawable_checked : create( + checked_shapeMode, + checked_solidColor, + checked_strokeColor, + checked_strokeWidth, + checked_strokeDash, + checked_strokeDashGap, + checked_radius, + checked_radiusLT, + checked_radiusLB, + checked_radiusRT, + checked_radiusRB, + checked_startColor, + checked_centerColor, + checked_endColor, + checked_orientation, + checked_gradientType, + checked_radialCenterX, + checked_radialCenterY, + checked_radialRadius, + checked_width, + checked_height, + checked_marginLeft, + checked_marginTop, + checked_marginRight, + checked_marginBottom, + checked_ringThickness, + checked_ringThicknessRatio, + checked_ringInnerRadius, + checked_ringInnerRadiusRatio + ); + if (checkedDrawable != null) { + count++; + } + Drawable checkableDrawable = drawable_checkable != null ? drawable_checkable : create( + checkable_shapeMode, + checkable_solidColor, + checkable_strokeColor, + checkable_strokeWidth, + checkable_strokeDash, + checkable_strokeDashGap, + checkable_radius, + checkable_radiusLT, + checkable_radiusLB, + checkable_radiusRT, + checkable_radiusRB, + checkable_startColor, + checkable_centerColor, + checkable_endColor, + checkable_orientation, + checkable_gradientType, + checkable_radialCenterX, + checkable_radialCenterY, + checkable_radialRadius, + checkable_width, + checkable_height, + checkable_marginLeft, + checkable_marginTop, + checkable_marginRight, + checkable_marginBottom, + checkable_ringThickness, + checkable_ringThicknessRatio, + checkable_ringInnerRadius, + checkable_ringInnerRadiusRatio + ); + if (checkableDrawable != null) { + count++; + } + Drawable enabledDrawable = drawable_enabled != null ? drawable_enabled : create( + enabled_shapeMode, + enabled_solidColor, + enabled_strokeColor, + enabled_strokeWidth, + enabled_strokeDash, + enabled_strokeDashGap, + enabled_radius, + enabled_radiusLT, + enabled_radiusLB, + enabled_radiusRT, + enabled_radiusRB, + enabled_startColor, + enabled_centerColor, + enabled_endColor, + enabled_orientation, + enabled_gradientType, + enabled_radialCenterX, + enabled_radialCenterY, + enabled_radialRadius, + enabled_width, + enabled_height, + enabled_marginLeft, + enabled_marginTop, + enabled_marginRight, + enabled_marginBottom, + enabled_ringThickness, + enabled_ringThicknessRatio, + enabled_ringInnerRadius, + enabled_ringInnerRadiusRatio + ); + if (enabledDrawable != null) { + count++; + } + Drawable focusedDrawable = drawable_focused != null ? drawable_focused : create( + focused_shapeMode, + focused_solidColor, + focused_strokeColor, + focused_strokeWidth, + focused_strokeDash, + focused_strokeDashGap, + focused_radius, + focused_radiusLT, + focused_radiusLB, + focused_radiusRT, + focused_radiusRB, + focused_startColor, + focused_centerColor, + focused_endColor, + focused_orientation, + focused_gradientType, + focused_radialCenterX, + focused_radialCenterY, + focused_radialRadius, + focused_width, + focused_height, + focused_marginLeft, + focused_marginTop, + focused_marginRight, + focused_marginBottom, + focused_ringThickness, + focused_ringThicknessRatio, + focused_ringInnerRadius, + focused_ringInnerRadiusRatio + ); + if (focusedDrawable != null) { + count++; + } + Drawable pressedDrawable = drawable_pressed != null ? drawable_pressed : create( + pressed_shapeMode, + pressed_solidColor, + pressed_strokeColor, + pressed_strokeWidth, + pressed_strokeDash, + pressed_strokeDashGap, + pressed_radius, + pressed_radiusLT, + pressed_radiusLB, + pressed_radiusRT, + pressed_radiusRB, + pressed_startColor, + pressed_centerColor, + pressed_endColor, + pressed_orientation, + pressed_gradientType, + pressed_radialCenterX, + pressed_radialCenterY, + pressed_radialRadius, + pressed_width, + pressed_height, + pressed_marginLeft, + pressed_marginTop, + pressed_marginRight, + pressed_marginBottom, + pressed_ringThickness, + pressed_ringThicknessRatio, + pressed_ringInnerRadius, + pressed_ringInnerRadiusRatio + ); + if (pressedDrawable != null) { + count++; + } + Drawable selectedDrawable = drawable_selected != null ? drawable_selected : create( + selected_shapeMode, + selected_solidColor, + selected_strokeColor, + selected_strokeWidth, + selected_strokeDash, + selected_strokeDashGap, + selected_radius, + selected_radiusLT, + selected_radiusLB, + selected_radiusRT, + selected_radiusRB, + selected_startColor, + selected_centerColor, + selected_endColor, + selected_orientation, + selected_gradientType, + selected_radialCenterX, + selected_radialCenterY, + selected_radialRadius, + selected_width, + selected_height, + selected_marginLeft, + selected_marginTop, + selected_marginRight, + selected_marginBottom, + selected_ringThickness, + selected_ringThicknessRatio, + selected_ringInnerRadius, + selected_ringInnerRadiusRatio + ); + if (selectedDrawable != null) { + count++; + } + //noinspection StatementWithEmptyBody + if (count < 1) { + // impossible,因为该方法被调用说明至少声明了一条属性 + } else { + boolean needReSetPadding = false; + if (isDefaultNull || count == 1) { + // 当设置了margin(非view的margin)时,InsetDrawable会导致view本身的padding失效 + needReSetPadding = true; + TMP_PADDING[0] = view.getPaddingLeft(); + TMP_PADDING[1] = view.getPaddingTop(); + TMP_PADDING[2] = view.getPaddingRight(); + TMP_PADDING[3] = view.getPaddingBottom(); + } + if (count == 1 && !isDefaultNull) { + view.setBackground(defaultDrawable); + } else { + ProxyDrawable listDrawable = new ProxyDrawable(); + if (checkedDrawable != null) { + listDrawable.addState(new int[]{android.R.attr.state_checked}, checkedDrawable); + } + if (checkableDrawable != null) { + listDrawable.addState(new int[]{android.R.attr.state_checkable}, checkableDrawable); + } + if (enabledDrawable != null) { + listDrawable.addState(new int[]{android.R.attr.state_enabled}, enabledDrawable); + } + if (focusedDrawable != null) { + listDrawable.addState(new int[]{android.R.attr.state_focused}, focusedDrawable); + } + if (pressedDrawable != null) { + listDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable); + } + if (selectedDrawable != null) { + listDrawable.addState(new int[]{android.R.attr.state_selected}, selectedDrawable); + } + if (defaultDrawable != null) { + listDrawable.addState(new int[]{0}, defaultDrawable); + } else { + Drawable originDrawable = view.getBackground(); + if (originDrawable != null) { + if (originDrawable instanceof ProxyDrawable) { + originDrawable = ((ProxyDrawable) originDrawable).getOriginDrawable(); + } + listDrawable.addState(new int[]{0}, originDrawable); + } + } + view.setBackground(listDrawable); + } + if (needReSetPadding) { + view.setPadding(TMP_PADDING[0], TMP_PADDING[1], TMP_PADDING[2], TMP_PADDING[3]); + } + } + } + + public static Drawable create( + @ShapeMode int shapeMode, @ColorInt Integer solidColor, + @ColorInt int strokeColor, @DP float strokeWidth, @DP float strokeDash, @DP float strokeDashGap, + @DP float radius, @DP float radiusLT, @DP float radiusLB, @DP float radiusRT, @DP float radiusRB, + @ColorInt Integer startColor, @ColorInt Integer centerColor, @ColorInt Integer endColor, + @Orientation int orientation, @GradientType int gradientType, + Float radialCenterX, Float radialCenterY, float radialRadius, + @DP float width, @DP float height, + @DP float marginLeft, @DP float marginTop, @DP float marginRight, @DP float marginBottom, + @DP float ringThickness, + @DP float ringThicknessRatio, + @DP float ringInnerRadius, + @DP float ringInnerRadiusRatio + ) { + if (shapeMode == INVALID && solidColor == null && strokeColor == INVALID + && strokeWidth == INVALID && strokeDash == INVALID && strokeDashGap == INVALID + && radius == INVALID && radiusLT == INVALID && radiusLB == INVALID + && radiusRT == INVALID && radiusRB == INVALID && startColor == null + && centerColor == null && endColor == null && orientation == INVALID + && gradientType == INVALID && radialCenterX == null && radialCenterY == null + && radialRadius == INVALID && width == INVALID && height == INVALID + && marginLeft == INVALID && marginTop == INVALID && marginRight == INVALID && marginBottom == INVALID + ) { + // 这里需要判断empty,因为有可能只设置了一个state的drawable,那么其他state的就是empty了 + return null; + } + GradientDrawable drawable = new GradientDrawable(); + if (startColor != null && endColor != null) { + int[] colors; + if (centerColor != null) { + colors = new int[3]; + colors[0] = startColor; + colors[1] = centerColor; + colors[2] = endColor; + } else { + colors = new int[2]; + colors[0] = startColor; + colors[1] = endColor; + } + drawable.setColors(colors); + drawable.setOrientation(mapOrientation(orientation)); + drawable.setGradientType(gradientType); + if (gradientType == GradientType.RADIAL) { + drawable.setGradientCenter(radialCenterX == null ? .5f : radialCenterX, + radialCenterY == null ? .5f : radialCenterY); + drawable.setGradientRadius(dip2px(radialRadius)); + } + } else { + if (solidColor != null) { + drawable.setColor(solidColor); + } + } + drawable.setShape(validShapeMode(shapeMode)); + if (shapeMode == ShapeMode.RING) { + // 由于GradientDrawable中没有ring相关的公开API,所以使用反射,若对性能有要求,请注意。 + setRingValue(drawable, ringThickness, ringThicknessRatio, ringInnerRadius, ringInnerRadiusRatio); + } + if (strokeWidth > 0) { + drawable.setStroke(dip2px(strokeWidth), strokeColor, dip2px(strokeDash), dip2px(strokeDashGap)); + } + if (radius <= 0) { + float[] radiusEach = new float[]{dip2px(radiusLT), dip2px(radiusLT), dip2px(radiusRT), dip2px(radiusRT), + dip2px(radiusRB), dip2px(radiusRB), dip2px(radiusLB), dip2px(radiusLB)}; + drawable.setCornerRadii(radiusEach); + } else { + drawable.setCornerRadius(dip2px(radius)); + } + if (width > 0 && height > 0) { + // https://stackoverflow.com/a/29180660/4698946 + drawable.setSize(dip2px(width), dip2px(height)); + } + if (marginLeft != 0 || marginTop != 0 || marginRight != 0 || marginBottom != 0) { + return new InsetDrawable(drawable, + dip2px(marginLeft), + dip2px(marginTop), + dip2px(marginRight), + dip2px(marginBottom)); + } else { + return drawable; + } + } + + private static int validShapeMode(@ShapeMode int shapeMode) { + return shapeMode > ShapeMode.RING || shapeMode < ShapeMode.RECTANGLE + ? GradientDrawable.RECTANGLE : shapeMode; + } + + private static GradientDrawable.Orientation mapOrientation(@Orientation int orientation) { + switch (orientation) { + case Orientation.BL_TR: + return GradientDrawable.Orientation.BL_TR; + case Orientation.BOTTOM_TOP: + return GradientDrawable.Orientation.BOTTOM_TOP; + case Orientation.BR_TL: + return GradientDrawable.Orientation.BR_TL; + case Orientation.LEFT_RIGHT: + return GradientDrawable.Orientation.LEFT_RIGHT; + case Orientation.RIGHT_LEFT: + return GradientDrawable.Orientation.RIGHT_LEFT; + case Orientation.TL_BR: + return GradientDrawable.Orientation.TL_BR; + case Orientation.TOP_BOTTOM: + return GradientDrawable.Orientation.TOP_BOTTOM; + case Orientation.TR_BL: + return GradientDrawable.Orientation.TR_BL; + default: + break; + } + return GradientDrawable.Orientation.TOP_BOTTOM; + } + + private static void setRingValue(GradientDrawable drawable, + Float thickness, Float thicknessRatio, + Float innerRadius, Float innerRadiusRatio) { + try { + Field mGradientState = drawable.getClass().getDeclaredField("mGradientState"); + mGradientState.setAccessible(true); + Class mGradientStateClass = mGradientState.get(drawable).getClass(); + Field mUseLevelForShape = mGradientStateClass.getDeclaredField("mUseLevelForShape"); + mUseLevelForShape.setAccessible(true); + mUseLevelForShape.setBoolean(mGradientState.get(drawable), false); + if (thickness != null) { + Field mThickness = mGradientStateClass.getDeclaredField("mThickness"); + mThickness.setAccessible(true); + mThickness.setInt(mGradientState.get(drawable), dip2px(thickness)); + } + if (thicknessRatio != null) { + Field mThicknessRatio = mGradientStateClass.getDeclaredField("mThicknessRatio"); + mThicknessRatio.setAccessible(true); + mThicknessRatio.setFloat(mGradientState.get(drawable), dip2px(thicknessRatio)); + } + if (innerRadius != null) { + Field mInnerRadius = mGradientStateClass.getDeclaredField("mInnerRadius"); + mInnerRadius.setAccessible(true); + mInnerRadius.setInt(mGradientState.get(drawable), dip2px(innerRadius)); + } + if (innerRadiusRatio != null) { + Field mInnerRadiusRatio = mGradientStateClass.getDeclaredField("mInnerRadiusRatio"); + mInnerRadiusRatio.setAccessible(true); + mInnerRadiusRatio.setFloat(mGradientState.get(drawable), dip2px(innerRadiusRatio)); + } + } catch (NoSuchFieldException | IllegalAccessException t) { + t.printStackTrace(); + } + } + + private static int dip2px(float dipValue) { + final float scale = Resources.getSystem().getDisplayMetrics().density; + return (int) (dipValue * scale + .5f); + } + + + @IntDef({ + ShapeMode.RECTANGLE, + ShapeMode.OVAL, + ShapeMode.LINE, + ShapeMode.RING, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ShapeMode { + int RECTANGLE = GradientDrawable.RECTANGLE; + int OVAL = GradientDrawable.OVAL; + /** + * 画线时,有几点特性必须要知道的: + * 1. 只能画水平线,画不了竖线; + * 2. 线的高度是通过stroke的android:width属性设置的; + * 3. size的android:height属性定义的是整个形状区域的高度; + * 4. size的height必须大于stroke的width,否则,线无法显示; + * 5. 线在整个形状区域中是居中显示的; + * 6. 线左右两边会留有空白间距,线越粗,空白越大; + * 7. 引用虚线的view需要添加属性android:layerType,值设为"software",否则显示不了虚线。 + */ + int LINE = GradientDrawable.LINE; + int RING = GradientDrawable.RING; + } + + @IntDef({ + GradientType.LINEAR, + GradientType.RADIAL, + GradientType.SWEEP + }) + @Retention(RetentionPolicy.SOURCE) + public @interface GradientType { + int LINEAR = 0; + int RADIAL = 1; + int SWEEP = 2; + } + + @IntDef({ + Orientation.TOP_BOTTOM, + Orientation.TR_BL, + Orientation.RIGHT_LEFT, + Orientation.BR_TL, + Orientation.BOTTOM_TOP, + Orientation.BL_TR, + Orientation.LEFT_RIGHT, + Orientation.TL_BR + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Orientation { + int TOP_BOTTOM = 0; + int TR_BL = 1; + int RIGHT_LEFT = 2; + int BR_TL = 3; + int BOTTOM_TOP = 4; + int BL_TR = 5; + int LEFT_RIGHT = 6; + int TL_BR = 7; + } + + @Retention(RetentionPolicy.SOURCE) + @Target({PARAMETER, FIELD}) + @interface DP { + } + + public static class ProxyDrawable extends StateListDrawable { + + private Drawable originDrawable; + + @Override + public void addState(int[] stateSet, Drawable drawable) { + if (stateSet != null && stateSet.length == 1 && stateSet[0] == 0) { + originDrawable = drawable; + } + super.addState(stateSet, drawable); + } + + Drawable getOriginDrawable() { + return originDrawable; + } + } +} diff --git a/app/src/main/java/com/gh/common/dialog/GameOffServiceDialogFragment.kt b/app/src/main/java/com/gh/common/dialog/GameOffServiceDialogFragment.kt index 665fbcf673..61c7047b8b 100644 --- a/app/src/main/java/com/gh/common/dialog/GameOffServiceDialogFragment.kt +++ b/app/src/main/java/com/gh/common/dialog/GameOffServiceDialogFragment.kt @@ -48,7 +48,7 @@ class GameOffServiceDialogFragment siteTv.setOnClickListener { // MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text) DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)") - dismiss() + dismissAllowingStateLoss() } container.addView(siteTv) diff --git a/app/src/main/java/com/gh/common/dialog/InstallPermissionDialogFragment.kt b/app/src/main/java/com/gh/common/dialog/InstallPermissionDialogFragment.kt index 9153c695e6..34bca83c83 100644 --- a/app/src/main/java/com/gh/common/dialog/InstallPermissionDialogFragment.kt +++ b/app/src/main/java/com/gh/common/dialog/InstallPermissionDialogFragment.kt @@ -13,16 +13,19 @@ import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.FragmentTransaction import com.airbnb.lottie.LottieAnimationView import com.gh.common.constant.Config -import com.gh.common.util.MtaHelper -import com.gh.common.util.PermissionHelper -import com.gh.common.util.PermissionHelper.INSTALL_PERMISS_CODE -import com.gh.common.util.goneIf +import com.gh.common.constant.Constants +import com.gh.common.util.* +import com.gh.common.util.PermissionHelper.INSTALL_PERMISSION_CODE +import com.gh.common.xapk.XapkInstaller import com.gh.gamecenter.R +import com.lightgame.download.DownloadEntity import kotlin.random.Random class InstallPermissionDialogFragment : BaseTrackableDialogFragment() { lateinit var mView: View + var isXapk = false + var url: String = "" var mCallBack: (() -> Unit)? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -35,16 +38,26 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() { val closeTv = mView.findViewById(R.id.closeTv) val closeIv = mView.findViewById(R.id.closeIv) val activateTv = mView.findViewById(R.id.activateTv) + val contentTv = mView.findViewById(R.id.contentTv) val switchLottie = mView.findViewById(R.id.switchLottie) + contentTv.text = if (isXapk) "未授权下解压XAPK可能导致解压失败" else "以保证游戏的安装和更新" switchLottie.setAnimation("lottie/install_permission_switch.json") switchLottie.playAnimation() - val randomNumber = Random.nextInt(2) + val randomNumber = if (isXapk) 1 else Random.nextInt(2) closeTv.goneIf(randomNumber == 0) closeIv.goneIf(randomNumber != 0) + if (isXapk) { + closeTv.text = "暂不,尝试解压" + closeIv.visibility = View.VISIBLE + } + closeTv.setOnClickListener { MtaHelper.onEvent(getEvent(), getKey(), "文案样式_点击以后再说") + if (isXapk) { + mCallBack?.invoke() + } dismiss() } closeIv.setOnClickListener { @@ -54,12 +67,18 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() { activateTv.setOnClickListener { MtaHelper.onEvent(getEvent(), getKey(), if (randomNumber == 0) "文案样式_点击立即开启" else "图标样式_点击立即开启") PermissionHelper.toInstallPermissionSetting(requireActivity()) + if (isXapk) { + SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, requireActivity().javaClass.name) + SPUtils.setString(Constants.SP_XAPK_URL, url) + } } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) - if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISS_CODE) { + if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISSION_CODE) { + SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "") + SPUtils.setString(Constants.SP_XAPK_URL, "") mCallBack?.invoke() dismiss() } @@ -71,30 +90,43 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() { companion object { @JvmStatic - fun show(activity: AppCompatActivity, callBack: (() -> Unit)?) { + fun show(activity: AppCompatActivity, downloadEntity: DownloadEntity, callBack: (() -> Unit)?) { + val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == downloadEntity.path.getExtension() if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { callBack?.invoke() return } - if (!Config.isPermissionPopupSwitchOpen()) { - callBack?.invoke() - return - } - val haveInstallPermission = activity.packageManager.canRequestPackageInstalls(); + val haveInstallPermission = activity.packageManager.canRequestPackageInstalls() if (haveInstallPermission) { callBack?.invoke() return - + } + if (isXapk) { + val xapkUnzipVersions = Config.getSettings()?.permissionPopupAppliedVersions?.xapkUnzip + if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) { + callBack?.invoke() + return + } + } else { + val installVersions = Config.getSettings()?.permissionPopupAppliedVersions?.install + if (installVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) { + callBack?.invoke() + return + } } var installPermissionDialogFragment = activity.supportFragmentManager.findFragmentByTag(InstallPermissionDialogFragment::class.java.simpleName) as? InstallPermissionDialogFragment if (installPermissionDialogFragment != null) { installPermissionDialogFragment.mCallBack = callBack + installPermissionDialogFragment.isXapk = isXapk + installPermissionDialogFragment.url = downloadEntity.url val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction() transaction.show(installPermissionDialogFragment) transaction.commit() } else { installPermissionDialogFragment = InstallPermissionDialogFragment().apply { - mCallBack = callBack + this.mCallBack = callBack + this.isXapk = isXapk + this.url = downloadEntity.url } installPermissionDialogFragment.show(activity.supportFragmentManager, InstallPermissionDialogFragment::class.java.simpleName) } diff --git a/app/src/main/java/com/gh/common/dialog/PackageCheckDialogFragment.kt b/app/src/main/java/com/gh/common/dialog/PackageCheckDialogFragment.kt new file mode 100644 index 0000000000..37bf46a287 --- /dev/null +++ b/app/src/main/java/com/gh/common/dialog/PackageCheckDialogFragment.kt @@ -0,0 +1,296 @@ +package com.gh.common.dialog + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.RelativeLayout +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.fragment.app.FragmentTransaction +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.constant.Constants +import com.gh.common.util.* +import com.gh.common.view.CustomLinkMovementMethod +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.FragmentPackageCheckBinding +import com.gh.gamecenter.databinding.PackageCheckItemBinding +import com.gh.gamecenter.entity.DetectionObjectEntity +import com.gh.gamecenter.entity.PackageDialogEntity +import com.gh.gamecenter.eventbus.EBPackage +import com.halo.assistant.HaloApp +import com.lightgame.adapter.BaseRecyclerAdapter +import com.lightgame.dialog.BaseDialogFragment +import io.reactivex.disposables.Disposable +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +/** + * 包名检测弹窗 + */ +class PackageCheckDialogFragment : BaseDialogFragment() { + + private lateinit var binding: FragmentPackageCheckBinding + private var mTotalWidth = 0f + private val mDuration = 3000 + private var mDisposable: Disposable? = null + private var mAdapter: PackageCheckAdapter? = null + var packageDialogEntity: PackageDialogEntity? = null + var callBack: DialogUtils.ConfirmListener? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + EventBus.getDefault().register(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + binding = FragmentPackageCheckBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + packageDialogEntity?.let { + changeParams(it.detectionObjects.size) + + binding.packageRv.layoutManager = LinearLayoutManager(requireContext()) + mAdapter = PackageCheckAdapter(requireContext(), it.detectionObjects) + binding.packageRv.adapter = mAdapter + + binding.titleTv.text = it.title + binding.contentTv.text = it.content + + val spanBuilder = SpanBuilder(it.linkHintText).build() + it.links.forEachIndexed { index, packageLink -> + val linkSpan = SpanBuilder(packageLink.text).click(0, packageLink.text.length, R.color.theme_font, true) { + val linkEntity = packageLink.transform() + DirectUtils.directToLinkPage(requireContext(), linkEntity, "包名检测弹窗", "") + }.build() + spanBuilder.append(linkSpan) + if (index != it.links.size - 1) { + spanBuilder.append("、") + } + } + binding.linkHintTv.text = spanBuilder + binding.linkHintTv.movementMethod = CustomLinkMovementMethod.getInstance() + + when (it.level) { + "HINT_SKIP" -> { + binding.cancelTv.text = "取消" + binding.noRemindAgainCb.visibility = View.GONE + } + "ALWAYS_HINT" -> { + binding.cancelTv.text = "我知道了" + binding.noRemindAgainCb.visibility = View.GONE + } + else -> { + binding.cancelTv.text = "我知道了" + binding.noRemindAgainCb.visibility = View.VISIBLE + } + } + initListener(it) + } + checkPackage() + } + + private fun changeParams(size: Int) { + val params = binding.packageRv.layoutParams as LinearLayout.LayoutParams + params.height = if (size > 3) (28f.dip2px() * 3.5).toInt() else 28f.dip2px() * size + binding.packageRv.layoutParams = params + } + + private fun initListener(entity: PackageDialogEntity) { + binding.downloadBtn.setOnClickListener { + if (binding.noRemindAgainCb.isChecked) { + SPUtils.setBoolean(Constants.SP_PACKAGE_CHECK, true) + } + val isAllPackageInstalled = isAllPackageInstalled(entity) + if (isAllPackageInstalled) { + callBack?.onConfirm() + dismissAllowingStateLoss() + } else { + val packageLink = entity.links.find { it.buttonLink } + if (packageLink != null) { + val linkEntity = packageLink.transform() + DirectUtils.directToLinkPage(requireContext(), linkEntity, "包名检测弹窗", "") + } + } + } + + binding.cancelTv.setOnClickListener { + if (entity.level != "HINT_SKIP") { + callBack?.onConfirm() + } + if (binding.noRemindAgainCb.isChecked) { + SPUtils.setBoolean(Constants.SP_PACKAGE_CHECK, true) + } + dismissAllowingStateLoss() + } + } + + private fun checkPackage() { + var index = 0 + mTotalWidth = (DisplayUtils.getScreenWidth() - 108f.dip2px()).toFloat() + mDisposable = rxTimer(1) { + val width = (mTotalWidth / mDuration) * it + val params = binding.progressView.layoutParams as RelativeLayout.LayoutParams + params.width = width.toInt() + binding.progressView.layoutParams = params + + packageDialogEntity?.detectionObjects?.let { objects -> + if (objects.isNotEmpty()) { + val averageTime = if (objects.size == 1) { + mDuration + } else { + mDuration / objects.size + } + if (it != 0L && it % averageTime == 0L && index < objects.size) { + mAdapter?.notifyPackages() + binding.packageRv.smoothScrollToPosition(index) + index++ + } + } + } + + if (it >= mDuration) { + mDisposable?.dispose() + binding.downloadBtn.isEnabled = true + binding.progressText.text = "检测完成" + binding.progressView.background = ContextCompat.getDrawable(requireContext(), R.drawable.package_check_complete_bg) + } + } + } + + override fun onStart() { + super.onStart() + val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px() + val height = ViewGroup.LayoutParams.WRAP_CONTENT + dialog?.window?.setLayout(width, height) + dialog?.setCanceledOnTouchOutside(true) + } + + override fun onResume() { + super.onResume() + packageDialogEntity?.let { + if (isAllPackageInstalled(it)) { + callBack?.onConfirm() + dismissAllowingStateLoss() + } + } + } + + override fun onDestroyView() { + super.onDestroyView() + EventBus.getDefault().unregister(this) + if (mDisposable?.isDisposed == false) { + mDisposable?.dispose() + } + } + + //安装、卸载事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(busFour: EBPackage) { + if ("安装" == busFour.type || "卸载" == busFour.type) { + mAdapter?.notifyDataSetChanged() + } + } + + class PackageCheckAdapter(val context: Context, val entities: ArrayList) : BaseRecyclerAdapter(context) { + private var index = -1 + + fun notifyPackages() { + index++ + notifyDataSetChanged() + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return PackageCheckViewHolder(PackageCheckItemBinding.bind(LayoutInflater.from(context).inflate(R.layout.package_check_item, parent, false))) + } + + override fun getItemCount(): Int = entities.size + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is PackageCheckViewHolder) { + val entity = entities[position] + holder.binding.entity = entity + if (position <= index) { + var isAllInstalled = true + entity.packages.forEach { + val isInstalled = PackageUtils.isInstalled(context, it) + if (!isInstalled) { + isAllInstalled = false + return@forEach + } + } + if (isAllInstalled) { + holder.binding.statusTv.text = "已安装" + holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font)) + } else { + holder.binding.statusTv.text = "未安装" + holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.text_FF4147)) + } + holder.binding.statusTv.visibility = View.VISIBLE + } else { + holder.binding.statusTv.visibility = View.GONE + } + } + } + } + + class PackageCheckViewHolder(val binding: PackageCheckItemBinding) : BaseRecyclerViewHolder(binding.root) + + companion object { + @JvmStatic + fun show(activity: AppCompatActivity, packageDialogEntity: PackageDialogEntity?, callBack: DialogUtils.ConfirmListener) { + if (packageDialogEntity == null) { + callBack.onConfirm() + return + } + if (isAllPackageInstalled(packageDialogEntity)) { + callBack.onConfirm() + return + } + val isChoose = SPUtils.getBoolean(Constants.SP_PACKAGE_CHECK, false) + if (packageDialogEntity.level == "OPTIONAL_HINT" && isChoose) { + callBack.onConfirm() + return + } + + var dialogFragment = activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.simpleName) as? PackageCheckDialogFragment + if (dialogFragment == null) { + dialogFragment = PackageCheckDialogFragment() + dialogFragment.packageDialogEntity = packageDialogEntity + dialogFragment.callBack = callBack + + dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.simpleName) + } else { + dialogFragment.packageDialogEntity = packageDialogEntity + dialogFragment.callBack = callBack + + val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction() + transaction.show(dialogFragment) + transaction.commit() + } + + } + + fun isAllPackageInstalled(packageDialogEntity: PackageDialogEntity): Boolean { + var isAllInstalled = true + packageDialogEntity.detectionObjects.forEach { obj -> + obj.packages.forEach { + val isInstalled = PackageUtils.isInstalled(HaloApp.getInstance(), it) + if (!isInstalled) { + isAllInstalled = false + return isAllInstalled + } + } + } + return isAllInstalled + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/dialog/PrivacyDialogFragment.kt b/app/src/main/java/com/gh/common/dialog/PrivacyDialogFragment.kt index 9acac07dc2..5b7624eebc 100644 --- a/app/src/main/java/com/gh/common/dialog/PrivacyDialogFragment.kt +++ b/app/src/main/java/com/gh/common/dialog/PrivacyDialogFragment.kt @@ -2,23 +2,27 @@ package com.gh.common.dialog import android.app.Dialog import android.content.DialogInterface -import android.os.Build import android.os.Bundle +import android.text.SpannableStringBuilder +import android.text.Spanned +import android.text.TextPaint +import android.text.method.ScrollingMovementMethod +import android.text.style.ClickableSpan import android.view.* -import android.webkit.WebSettings -import android.webkit.WebView import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.fragment.app.FragmentTransaction import com.gh.base.fragment.BaseDialogFragment +import com.gh.common.util.DirectUtils.directToExternalBrowser import com.gh.common.util.dip2px +import com.gh.common.view.CustomLinkMovementMethod import com.gh.gamecenter.R class PrivacyDialogFragment : BaseDialogFragment() { - private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html" - private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html" +// private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html" +// private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html" var containerView: View? = null var mCallBack: ((isSuccess: Boolean) -> Unit)? = null @@ -30,83 +34,80 @@ class PrivacyDialogFragment : BaseDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val mWebViewPrivacy = containerView?.findViewById(R.id.webView) - val mWebViewRegulation = containerView?.findViewById(R.id.webView2) +// val mWebViewPrivacy = containerView?.findViewById(R.id.webView) +// val mWebViewRegulation = containerView?.findViewById(R.id.webView2) +// +// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false +// mWebViewRegulation?.isHorizontalScrollBarEnabled = false - mWebViewPrivacy?.isHorizontalScrollBarEnabled = false - mWebViewRegulation?.isHorizontalScrollBarEnabled = false + val contentTv = containerView?.findViewById(R.id.contentTv) + val descTv = containerView?.findViewById(R.id.descTv) + contentTv?.movementMethod = ScrollingMovementMethod() - val mTitlePrivacyTv = containerView?.findViewById(R.id.privacyTitleTv) - val mTitleRegulationTv = containerView?.findViewById(R.id.userRegulationTitleTv) - - val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings) - - for (settings in settingsArrayList) { - settings?.javaScriptEnabled = true - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW - } - // 避免提示网页有害信息不能访问 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - settings?.safeBrowsingEnabled = false + val skipText = SpannableStringBuilder("查看完整版的隐私政策和用户协议") + skipText.setSpan(object : ClickableSpan() { + override fun updateDrawState(ds: TextPaint) { + super.updateDrawState(ds) + ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font) + ds.isUnderlineText = false } - // 适配大于屏幕宽度的页面 - settings?.useWideViewPort = true - settings?.loadWithOverviewMode = true - settings?.domStorageEnabled = true - - // 自适应屏幕 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING + override fun onClick(widget: View) { + directToExternalBrowser(context!!, context!!.getString(R.string.privacy_policy_url)) } - } + }, skipText.length - 9, skipText.length - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) -// if (NetworkUtils.isNetworkConnected(requireContext())) { -// mWebViewPrivacy?.loadUrl(requireContext().getString(R.string.privacy_policy_url)) -// mWebViewRegulation?.loadUrl(requireContext().getString(R.string.user_regulation_url)) -// } else { - mWebViewPrivacy?.loadUrl(mLocalPrivacyHtml) - mWebViewRegulation?.loadUrl(mLocalRegulationHtml) -// } + skipText.setSpan(object : ClickableSpan() { + override fun updateDrawState(ds: TextPaint) { + super.updateDrawState(ds) + ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font) + ds.isUnderlineText = false + } -// val client = object : WebViewClient() { -// override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) { -// super.onReceivedError(view, request, error) -// if (view == mWebViewPrivacy) { -// view?.loadUrl(mLocalPrivacyHtml) -// } else { -// view?.loadUrl(mLocalRegulationHtml) -// } + override fun onClick(widget: View) { + directToExternalBrowser(requireContext(), requireContext().getString(R.string.disclaimer_url)) + } + }, skipText.length - 4, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + descTv?.movementMethod = CustomLinkMovementMethod() + descTv?.text = skipText + +// val mWebViewPrivacy = containerView?.findViewById(R.id.webView) +// +// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false +// +// val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings) +// +// for (settings in settingsArrayList) { +// settings?.javaScriptEnabled = true +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { +// settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW +// } +// // 避免提示网页有害信息不能访问 +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { +// settings?.safeBrowsingEnabled = false +// } +// +// // 适配大于屏幕宽度的页面 +// settings?.useWideViewPort = true +// settings?.loadWithOverviewMode = true +// settings?.domStorageEnabled = true +// +// // 自适应屏幕 +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { +// settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING // } // } // mWebViewPrivacy?.webViewClient = client // mWebViewRegulation?.webViewClient = client - mTitlePrivacyTv?.setOnClickListener { - mTitlePrivacyTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white)) - mTitleRegulationTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5)) - - mWebViewPrivacy?.visibility = View.VISIBLE - mWebViewRegulation?.visibility = View.GONE - } - - mTitleRegulationTv?.setOnClickListener { - mTitlePrivacyTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5)) - mTitleRegulationTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white)) - - mWebViewPrivacy?.visibility = View.GONE - mWebViewRegulation?.visibility = View.VISIBLE - } - containerView?.findViewById(R.id.refuseTv)?.setOnClickListener { mCallBack?.invoke(false) - dismiss() + dismissAllowingStateLoss() } containerView?.findViewById(R.id.agreeTv)?.setOnClickListener { mCallBack?.invoke(true) - dismiss() + dismissAllowingStateLoss() } } diff --git a/app/src/main/java/com/gh/common/exposure/meta/MetaUtil.kt b/app/src/main/java/com/gh/common/exposure/meta/MetaUtil.kt index a9f6e6973a..3b4d24a04f 100644 --- a/app/src/main/java/com/gh/common/exposure/meta/MetaUtil.kt +++ b/app/src/main/java/com/gh/common/exposure/meta/MetaUtil.kt @@ -24,6 +24,7 @@ object MetaUtil { private var m: Meta? = null private var imei: String? = null + private var base64EncodedImei: String? = null private var androidId: String? = null fun refreshMeta() { @@ -104,6 +105,20 @@ object MetaUtil { } + @JvmStatic + fun getBase64EncodedIMEI(): String { + if (TextUtils.isEmpty(base64EncodedImei) && imei != null) { + try { + base64EncodedImei = android.util.Base64.encodeToString(getIMEI().trim().toByteArray(), android.util.Base64.NO_WRAP) + } catch (e: java.lang.Exception) { + e.printStackTrace() + return "" + } + } + + return base64EncodedImei ?: "" + } + fun getModel(): String? { return Build.MODEL } diff --git a/app/src/main/java/com/gh/common/history/HistoryHelper.kt b/app/src/main/java/com/gh/common/history/HistoryHelper.kt index 6c7167bc8a..4e19200285 100644 --- a/app/src/main/java/com/gh/common/history/HistoryHelper.kt +++ b/app/src/main/java/com/gh/common/history/HistoryHelper.kt @@ -4,6 +4,7 @@ import com.gh.common.runOnIoThread import com.gh.common.util.clearHtmlFormatCompletely import com.gh.common.util.removeInsertedContent import com.gh.common.util.removeVideoContent +import com.gh.common.util.tryCatchInRelease import com.gh.gamecenter.entity.* import com.gh.gamecenter.qa.entity.AnswerDetailEntity import com.gh.gamecenter.qa.entity.AnswerEntity @@ -14,27 +15,28 @@ object HistoryHelper { fun insertAnswerEntity(answerDetailEntity: AnswerDetailEntity) { val answerEntity = convertAnswerDetailToAnswer(answerDetailEntity) - runOnIoThread { HistoryDatabase.instance.answerDao().addAnswer(answerEntity) } + // 偶尔有设备会出现磁盘满了写不进数据库的问题 database or disk is full 异常,毕竟只是插入个本地历史,这里直接捕抓 + runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.answerDao().addAnswer(answerEntity) } } } fun insertArticleEntity(articleDetailEntity: ArticleDetailEntity) { val articleEntity = convertArticleDetailToArticle(articleDetailEntity) - runOnIoThread { HistoryDatabase.instance.articleDao().addArticle(articleEntity) } + runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.articleDao().addArticle(articleEntity) } } } @JvmStatic fun insertGameEntity(gameEntity: GameEntity) { val historyGameEntity = convertGameEntityToHistoryGameEntity(gameEntity) - runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } + runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } } } @JvmStatic fun insertGameEntity(updateEntity: GameUpdateEntity) { val historyGameEntity = convertGameUpdateEntityToHistoryGameEntity(updateEntity) - runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } + runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } } } - private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity{ + private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity { val historyGame = HistoryGameEntity() historyGame.orderTag = System.currentTimeMillis() diff --git a/app/src/main/java/com/gh/common/observer/VolumeObserver.kt b/app/src/main/java/com/gh/common/observer/VolumeObserver.kt index c2be83d92e..434c10a623 100644 --- a/app/src/main/java/com/gh/common/observer/VolumeObserver.kt +++ b/app/src/main/java/com/gh/common/observer/VolumeObserver.kt @@ -4,6 +4,7 @@ import android.content.Context import android.database.ContentObserver import android.media.AudioManager import android.os.Handler +import com.gh.common.util.tryCatchInRelease class VolumeObserver(var context: Context, handler: Handler, var callback: MuteCallback? = null) : ContentObserver(handler) { @@ -11,7 +12,8 @@ class VolumeObserver(var context: Context, handler: Handler, var callback: MuteC init { val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager - previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC) + // 部分设备的 audioManager getStreamVolume 内部会触发空指针 :( + tryCatchInRelease { previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC) } } override fun onChange(selfChange: Boolean) { diff --git a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt index 7ff7d39acd..5ddb01f1a4 100644 --- a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt +++ b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt @@ -2,6 +2,7 @@ package com.gh.common.simulator import android.app.Dialog import android.content.Context +import android.view.Gravity import android.view.View import android.view.Window import android.widget.ProgressBar @@ -116,8 +117,8 @@ class SimulatorDownloadManager private constructor() { key = if (shouldShowUpdate && isInstalled) "更新弹窗" else "下载弹窗", logShowEvent = true ) - DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, { - if (shouldShowUpdate && isInstalled){ + DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, Gravity.LEFT, { + if (shouldShowUpdate && isInstalled) { cancelCallback?.invoke() MtaHelper.onEvent(trackableEntity.event, trackableEntity.key, "点击下次再说") } diff --git a/app/src/main/java/com/gh/common/util/CommentHelper.kt b/app/src/main/java/com/gh/common/util/CommentHelper.kt index dab37a6303..b85bdeb8d8 100644 --- a/app/src/main/java/com/gh/common/util/CommentHelper.kt +++ b/app/src/main/java/com/gh/common/util/CommentHelper.kt @@ -33,6 +33,7 @@ object CommentHelper { showConversation: Boolean, articleId: String, communityId: String, + isShowTop: Boolean = false, ignoreModerator: Boolean = false, listener: OnCommentOptionClickListener?) { showCommentOptions(view = view, @@ -40,6 +41,7 @@ object CommentHelper { showConversation = showConversation, articleId = articleId, communityId = communityId, + isShowTop = isShowTop, ignoreModerator = ignoreModerator, listener = listener) } @@ -79,11 +81,16 @@ object CommentHelper { communityId: String? = null, answerId: String? = null, videoId: String? = null, + isShowTop: Boolean = false, ignoreModerator: Boolean = false, isVideoAuthor: Boolean = false, listener: OnCommentOptionClickListener? = null) { val context = view.context val dialogOptions = ArrayList() + if (isShowTop && articleId != null && commentEntity.me?.isArticleOrAnswerAuthor == true) { + dialogOptions.add(if (commentEntity.isTop) "取消置顶" else "置顶") + } + dialogOptions.add("复制") if (commentEntity.user.id != UserManager.getInstance().userId) { dialogOptions.add("投诉") diff --git a/app/src/main/java/com/gh/common/util/CommentUtils.java b/app/src/main/java/com/gh/common/util/CommentUtils.java index de8c40c680..7e17331a91 100644 --- a/app/src/main/java/com/gh/common/util/CommentUtils.java +++ b/app/src/main/java/com/gh/common/util/CommentUtils.java @@ -2,7 +2,6 @@ package com.gh.common.util; import android.annotation.SuppressLint; import android.app.Dialog; -import android.content.ClipboardManager; import android.content.Context; import android.graphics.Color; import android.text.TextUtils; @@ -12,6 +11,9 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + import com.gh.gamecenter.CommentDetailActivity; import com.gh.gamecenter.R; import com.gh.gamecenter.adapter.viewholder.CommentViewHolder; @@ -39,8 +41,6 @@ import java.util.Date; import java.util.List; import java.util.Locale; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import okhttp3.ResponseBody; @@ -529,10 +529,7 @@ public class CommentUtils { //复制文字 public static void copyText(String copyContent, Context context) { - ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - cmb.setText(copyContent); - - ToastUtils.INSTANCE.showToast("复制成功"); + ExtensionsKt.copyTextAndToast(copyContent, "复制成功"); } diff --git a/app/src/main/java/com/gh/common/util/DataUtils.java b/app/src/main/java/com/gh/common/util/DataUtils.java index 3a7d54fe4f..5e57ba929d 100644 --- a/app/src/main/java/com/gh/common/util/DataUtils.java +++ b/app/src/main/java/com/gh/common/util/DataUtils.java @@ -3,21 +3,34 @@ package com.gh.common.util; import android.app.Activity; import android.app.Application; import android.content.Context; +import android.os.Build; import android.preference.PreferenceManager; import android.text.TextUtils; +import com.gh.common.constant.Config; import com.gh.common.constant.Constants; import com.gh.common.exposure.meta.MetaUtil; +import com.gh.gamecenter.BuildConfig; +import com.gh.gamecenter.manager.UserManager; import com.gh.gid.GidCallback; import com.gh.gid.GidHelper; import com.halo.assistant.HaloApp; import com.lightgame.config.CommonDebug; import com.lightgame.utils.Utils; +import com.tencent.stat.MtaSDkException; +import com.tencent.stat.StatConfig; +import com.tencent.stat.StatCrashReporter; +import com.tencent.stat.StatReportStrategy; +import com.tencent.stat.StatService; import java.util.HashMap; import java.util.Map; import java.util.Properties; +import io.sentry.android.core.SentryAndroid; +import io.sentry.core.Sentry; +import io.sentry.core.protocol.User; + /** * Created by LGT on 2016/6/15. * 数据收集 工具类 (TalkingData、MTA) @@ -35,6 +48,35 @@ public class DataUtils { if (CommonDebug.IS_DEBUG) { return; } + + SentryAndroid.init(context, options -> { + options.setDebug(BuildConfig.DEBUG); + options.setEnableSessionTracking(true); + options.setEnvironment(BuildConfig.FLAVOR); + options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.ghzs.com/22"); + + options.setBeforeSend((event, hint) -> { + if (BuildConfig.DEBUG) { + return null; + } else { + return event; + } + }); + }); + + Sentry.configureScope(scope -> { + User user = new User(); + user.setId(HaloApp.getInstance().getGid()); + scope.setUser(user); + + if (BuildConfig.BUILD_TIME != 0L) { + scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME + "_" + BuildConfig.BUILD_TIME); + } else { + scope.setTag("alias", "正式版" + BuildConfig.VERSION_NAME); + scope.setTag("channel", channel); + } + }); + //TalkingData // try { // TCAgent.LOG_ON = false; @@ -49,42 +91,42 @@ public class DataUtils { // } //MTA -// try { -// /** -// * -// * 不要启用!!!!全部由{@link com.gh.base.AppUncaughtHandler}处理 -// */ -// StatConfig.setAutoExceptionCaught(false); -// -// StatCrashReporter crashReporter = StatCrashReporter.getStatCrashReporter(context); -// crashReporter.setJavaCrashHandlerStatus(false); -//// crashReporter.setEnableInstantReporting(true); -// -// StatConfig.setDebugEnable(false); -// -// // 设置数据上报策略 -// // 测试渠道的时候即时上传,方便查看日志 -// if (Config.DEFAULT_CHANNEL.equals(HaloApp.getInstance().getChannel())) { -// StatConfig.setStatSendStrategy(StatReportStrategy.INSTANT); -// } else { -// StatConfig.setStatSendStrategy(StatReportStrategy.PERIOD); -// StatConfig.setSendPeriodMinutes(5); -// } -// -// // 设置启用Tlink -// StatConfig.setTLinkStatus(true); -// -// StatConfig.init(context); -// StatConfig.setInstallChannel(channel); -// StatConfig.setAntoActivityLifecycleStat(true); -// StatConfig.setAppVersion(PackageUtils.getVersionName()); -// -// // 开启收集服务 -// StatService.startStatService(context, Config.MTA_APPKEY, com.tencent.stat.common.StatConstants.VERSION); -// StatService.registerActivityLifecycleCallbacks(context); -// } catch (MtaSDkException e) { -// e.printStackTrace(); -// } + try { + /** + * + * 不要启用!!!!全部由{@link com.gh.base.AppUncaughtHandler}处理 + */ + StatConfig.setAutoExceptionCaught(false); + + StatCrashReporter crashReporter = StatCrashReporter.getStatCrashReporter(context); + crashReporter.setJavaCrashHandlerStatus(false); +// crashReporter.setEnableInstantReporting(true); + + StatConfig.setDebugEnable(false); + + // 设置数据上报策略 + // 测试渠道的时候即时上传,方便查看日志 + if (Config.DEFAULT_CHANNEL.equals(HaloApp.getInstance().getChannel())) { + StatConfig.setStatSendStrategy(StatReportStrategy.INSTANT); + } else { + StatConfig.setStatSendStrategy(StatReportStrategy.PERIOD); + StatConfig.setSendPeriodMinutes(5); + } + + // 设置启用Tlink + StatConfig.setTLinkStatus(true); + + StatConfig.init(context); + StatConfig.setInstallChannel(channel); + StatConfig.setAntoActivityLifecycleStat(true); + StatConfig.setAppVersion(PackageUtils.getVersionName()); + + // 开启收集服务 + StatService.startStatService(context, Config.MTA_APPKEY, com.tencent.stat.common.StatConstants.VERSION); + StatService.registerActivityLifecycleCallbacks(context); + } catch (MtaSDkException e) { + e.printStackTrace(); + } // init bugly // try { @@ -141,15 +183,15 @@ public class DataUtils { public static void onEvent(Context var0, String var1, String var2) { Properties prop = new Properties(); prop.setProperty(var1, var2); -// StatService.trackCustomKVEvent(var0, var1, prop); + StatService.trackCustomKVEvent(var0, var1, prop); } public static void onPause(Activity var0) { -// StatService.onPause(var0); + StatService.onPause(var0); } public static void onResume(Activity var0) { -// StatService.onResume(var0); + StatService.onResume(var0); } // 游戏启动 @@ -166,7 +208,7 @@ public class DataUtils { for (String key : var3.keySet()) { prop.setProperty(key, var3.get(key) + ""); } -// StatService.trackCustomKVEvent(var0, var1, prop); + StatService.trackCustomKVEvent(var0, var1, prop); } public static void trackTimeEvent(Context context, String eventId, int costTime, String... kv) { @@ -184,41 +226,41 @@ public class DataUtils { if (prop.size() == 0) return; -// StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop); + StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop); } // 游戏下载 public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status, String method) { -// Map kv = new HashMap<>(); -// -// platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform); -// -// kv.put("版本", platform); -// kv.put("用户机型", Build.MODEL); -// kv.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication())); -// kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication())); -// kv.put("光环助手版本", BuildConfig.VERSION_NAME); -// kv.put("位置", entrance); -// kv.put("类型", method); -// kv.put("厂商", Build.MANUFACTURER); -// kv.put("Android版本", Build.VERSION.RELEASE); -// onEvent(context, "游戏下载", gameName, kv); -// -// Map kv2 = new HashMap<>(); -// kv2.put("状态", status); -// kv2.put("位置", entrance); -// -// if (status.equals("开始")) { -// kv2.put("版本", entrance + "-开始"); -// kv2.put("游戏分平台", gameName + "-" + platform + "-开始"); -// kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始"); -// } else { -// kv2.put("版本", platform); -// kv2.put("游戏分平台", gameName + "-" + platform); -// kv2.put("光环助手版本", BuildConfig.VERSION_NAME); -// } -// -// onEvent(context, "游戏下载位置", gameName, kv2); + Map kv = new HashMap<>(); + + platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform); + + kv.put("版本", platform); + kv.put("用户机型", Build.MODEL); + kv.put("设备IMEI", MetaUtil.getIMEI()); + kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication())); + kv.put("光环助手版本", BuildConfig.VERSION_NAME); + kv.put("位置", entrance); + kv.put("类型", method); + kv.put("厂商", Build.MANUFACTURER); + kv.put("Android版本", Build.VERSION.RELEASE); + onEvent(context, "游戏下载", gameName, kv); + + Map kv2 = new HashMap<>(); + kv2.put("状态", status); + kv2.put("位置", entrance); + + if (status.equals("开始")) { + kv2.put("版本", entrance + "-开始"); + kv2.put("游戏分平台", gameName + "-" + platform + "-开始"); + kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始"); + } else { + kv2.put("版本", platform); + kv2.put("游戏分平台", gameName + "-" + platform); + kv2.put("光环助手版本", BuildConfig.VERSION_NAME); + } + + onEvent(context, "游戏下载位置", gameName, kv2); } // 游戏更新 diff --git a/app/src/main/java/com/gh/common/util/DialogUtils.java b/app/src/main/java/com/gh/common/util/DialogUtils.java index 386bacb999..c6b808faaf 100644 --- a/app/src/main/java/com/gh/common/util/DialogUtils.java +++ b/app/src/main/java/com/gh/common/util/DialogUtils.java @@ -350,7 +350,7 @@ public class DialogUtils { * @param cmListener 确认按钮监听 */ public static Dialog showNewAlertDialog(Context context, String title, CharSequence message - , String negative, String positive, TrackableEntity trackableEntity, final CancelListener clListener, final ConfirmListener cmListener) { + , String negative, String positive, TrackableEntity trackableEntity, int gravity, final CancelListener clListener, final ConfirmListener cmListener) { context = checkDialogContext(context); final Dialog dialog; if (trackableEntity != null) { @@ -373,6 +373,8 @@ public class DialogUtils { TextView cancelBtn = contentView.findViewById(R.id.cancel); TextView confirmBtn = contentView.findViewById(R.id.confirm); View middleLine = contentView.findViewById(R.id.middle_line); + titleTv.setGravity(gravity); + contentTv.setGravity(gravity); titleTv.setText(title); contentTv.setText(message); @@ -411,7 +413,7 @@ public class DialogUtils { public static Dialog showNewAlertDialog(Context context, String title, CharSequence message , String negative, String positive, final CancelListener clListener, final ConfirmListener cmListener) { - return showNewAlertDialog(context, title, message, negative, positive, null, clListener, cmListener); + return showNewAlertDialog(context, title, message, negative, positive, null, Gravity.LEFT, clListener, cmListener); } /** @@ -986,13 +988,13 @@ public class DialogUtils { WindowManager.LayoutParams params = window.getAttributes(); params.horizontalMargin = 0; params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(40); - int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120); - int maxHeight = DisplayUtils.dip2px(446); - if (height > maxHeight) { - params.height = maxHeight; - } else { - params.height = height; - } +// int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120); +// int maxHeight = DisplayUtils.dip2px(446); +// if (height > maxHeight) { +// params.height = maxHeight; +// } else { +// params.height = height; +// } window.setAttributes(params); } @@ -1025,8 +1027,6 @@ public class DialogUtils { hierarchy.setPlaceholderImage(R.drawable.permission_storage); } else if (position == 1) { hierarchy.setPlaceholderImage(R.drawable.permission_phone_state); - } else { - hierarchy.setPlaceholderImage(R.drawable.permission_sdk); } } } 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 3c0baa9aaa..a40ab8e7be 100644 --- a/app/src/main/java/com/gh/common/util/DirectUtils.kt +++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt @@ -22,6 +22,7 @@ import com.gh.common.exposure.ExposureType import com.gh.common.util.EntranceUtils.* import com.gh.gamecenter.* import com.gh.gamecenter.amway.AmwayActivity +import com.gh.gamecenter.catalog.CatalogActivity import com.gh.gamecenter.category.CategoryDirectoryActivity import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE import com.gh.gamecenter.entity.* @@ -57,7 +58,6 @@ import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel import com.gh.gamecenter.video.game.GameVideoActivity import com.gh.gamecenter.video.videomanager.VideoManagerActivity import com.halo.assistant.HaloApp -import com.lightgame.utils.Util_System_ClipboardManager import com.lightgame.utils.Utils import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers @@ -133,7 +133,9 @@ object DirectUtils { "server", "top_game_comment", "wechat_bind", - "video") + "video", + "catalog" + ) fun directToLinkPage(context: Context, linkEntity: LinkEntity, @@ -200,6 +202,8 @@ object DirectUtils { "category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!) + "catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path) + "block", "版块" -> { if (linkEntity.link.isNullOrEmpty()) return directToBlock(context, @@ -575,7 +579,7 @@ object DirectUtils { @JvmStatic fun directToExternalBrowser(context: Context, url: String) { if (url.isEmpty()) return - val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Uri.decode(url))) if (context !is AppCompatActivity) { browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } @@ -606,8 +610,7 @@ object DirectUtils { context.startActivity(intent) } else { // 没有安装QQ 复制账号 - Util_System_ClipboardManager.setText(context, qq) - Utils.toast(context, "已复制 QQ $qq") + qq?.copyTextAndToast("已复制 QQ $qq") } } @@ -889,6 +892,20 @@ object DirectUtils { jumpActivity(context, bundle) } + /** + * 跳转新分类 + */ + @JvmStatic + fun directCatalog(context: Context, catalogId: String, catalogTitle: String, entrance: String? = null, path: String? = "") { + if (catalogId.isEmpty()) return + val bundle = Bundle() + bundle.putString(KEY_TO, CatalogActivity::class.java.name) + bundle.putString(KEY_CATALOG_ID, catalogId) + bundle.putString(KEY_CATALOG_TITLE, catalogTitle) + bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path)) + jumpActivity(context, bundle) + } + /** * 跳转到问题标签详情 */ diff --git a/app/src/main/java/com/gh/common/util/DownloadItemUtils.java b/app/src/main/java/com/gh/common/util/DownloadItemUtils.java index 6dc9eb24ae..fcbfbfd352 100644 --- a/app/src/main/java/com/gh/common/util/DownloadItemUtils.java +++ b/app/src/main/java/com/gh/common/util/DownloadItemUtils.java @@ -8,9 +8,16 @@ import android.text.TextUtils; import android.view.View; import android.widget.TextView; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.collection.ArrayMap; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; + import com.gh.common.constant.Config; import com.gh.common.dialog.CertificationDialog; import com.gh.common.dialog.DeviceRemindDialog; +import com.gh.common.dialog.PackageCheckDialogFragment; import com.gh.common.dialog.ReserveDialogFragment; import com.gh.common.exposure.ExposureEvent; import com.gh.common.history.HistoryHelper; @@ -39,12 +46,6 @@ import com.lightgame.utils.Utils; import java.io.File; import java.util.concurrent.LinkedBlockingQueue; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import androidx.collection.ArrayMap; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.RecyclerView; - /** * todo 下载判断不能以按钮文案为判断条件,否则按钮文案修改时又要修改判断逻辑 */ @@ -419,7 +420,7 @@ public class DownloadItemUtils { } /** - * @param clickCallback 供那些需要知道点击回调的地方使用 + * @param clickCallback 供那些需要知道点击回调的地方使用,触发具体响应才会回调 */ public static void setOnClickListener(final Context context, final TextView downloadBtn, @@ -431,103 +432,13 @@ public class DownloadItemUtils { final ExposureEvent traceEvent, @Nullable final EmptyCallback clickCallback) { - if (gameEntity.isReservable()) { - if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) { - downloadBtn.setOnClickListener(v -> { - CheckLoginUtils.checkLogin(context, entrance, () -> { - if (clickCallback != null) { - clickCallback.onCallback(); - } - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> { - ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance( - gameEntity, - () -> { - LogUtils.logReservation(gameEntity, traceEvent); - adapter.notifyItemChanged(position); - } - ); - dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve"); - }); - }); - }); - } else { - downloadBtn.setOnClickListener(v -> { - if (clickCallback != null) { - clickCallback.onCallback(); - } - if ("download".equals(gameEntity.getReserveStatus())) { - ReservationHelper.showDeleteReservationDialog(context, () -> { - ReservationHelper.deleteReservation(gameEntity, () -> { - adapter.notifyItemChanged(position); - }); - }); - } else { - ReservationHelper.showCancelReservationDialog(context, () -> { - ReservationHelper.cancelReservation(gameEntity, () -> { - adapter.notifyItemChanged(position); - }); - }); - } - }); - } - return; - } - - if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) { - downloadBtn.setOnClickListener(v -> { - MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName()); - - LinkEntity linkEntity = gameEntity.getH5Link(); - - boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩 - if (isPlay) { - HistoryHelper.insertGameEntity(gameEntity); - } - - Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton()); - context.startActivity(i); - }); - } else if (gameEntity.getApk().size() == 1) { - downloadBtn.setOnClickListener(v -> { - EmptyCallback clickRunnable = () -> { - if (clickCallback != null) { - clickCallback.onCallback(); - } - onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent); - }; - - // 启动不需要请求存储权限 - if (downloadBtn.getText().toString().equals(context.getString(R.string.launch))) { - clickRunnable.onCallback(); - } else { - PermissionHelper.checkStoragePermissionBeforeAction(context, clickRunnable); - } - }); - } else { - downloadBtn.setOnClickListener(v -> { - if (clickCallback != null) { - clickCallback.onCallback(); - } - PermissionHelper.checkStoragePermissionBeforeAction(context, () -> { - CertificationDialog.showCertificationDialog(context, gameEntity, () -> { - DialogUtils.showVersionNumberDialog(context, gameEntity, () -> { - DownloadDialog.showDownloadDialog( - v.getContext(), - gameEntity, - traceEvent, - entrance, - location); - }); - }); - }); - }); - } + setOnClickListener(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent, clickCallback, null); } /** - * @param clickCallback 供那些需要知道点击回调的地方使用,只要触发了点击事件就响应回调(未登录状态下点击预约也要响应回调) + * @param allStateClickCallback 供那些需要知道点击回调的地方使用,只要触发点击动作就会回调 */ - public static void setOnClickListenerWithInvokeCallbackForAllState(final Context context, + public static void setOnClickListener(final Context context, final TextView downloadBtn, final GameEntity gameEntity, final int position, @@ -535,29 +446,36 @@ public class DownloadItemUtils { final String entrance, final String location, final ExposureEvent traceEvent, - @Nullable final EmptyCallback clickCallback) { + @Nullable final EmptyCallback clickCallback, + @Nullable final EmptyCallback allStateClickCallback) { if (gameEntity.isReservable()) { if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) { downloadBtn.setOnClickListener(v -> { - if (clickCallback != null) { - clickCallback.onCallback(); + if (allStateClickCallback != null) { + allStateClickCallback.onCallback(); } + CheckLoginUtils.checkLogin(context, entrance, () -> { - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> { - ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance( - gameEntity, - () -> { - LogUtils.logReservation(gameEntity, traceEvent); - adapter.notifyItemChanged(position); - } - ); - dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve"); - }); + if (clickCallback != null) { + clickCallback.onCallback(); + } + ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance( + gameEntity, + () -> { + LogUtils.logReservation(gameEntity, traceEvent); + adapter.notifyItemChanged(position); + } + ); + dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve"); }); }); } else { downloadBtn.setOnClickListener(v -> { + if (allStateClickCallback != null) { + allStateClickCallback.onCallback(); + } + if (clickCallback != null) { clickCallback.onCallback(); } @@ -581,9 +499,10 @@ public class DownloadItemUtils { if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) { downloadBtn.setOnClickListener(v -> { - if (clickCallback != null) { - clickCallback.onCallback(); + if (allStateClickCallback != null) { + allStateClickCallback.onCallback(); } + MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName()); LinkEntity linkEntity = gameEntity.getH5Link(); @@ -599,6 +518,10 @@ public class DownloadItemUtils { } else if (gameEntity.getApk().size() == 1) { downloadBtn.setOnClickListener(v -> { EmptyCallback clickRunnable = () -> { + if (allStateClickCallback != null) { + allStateClickCallback.onCallback(); + } + if (clickCallback != null) { clickCallback.onCallback(); } @@ -614,6 +537,10 @@ public class DownloadItemUtils { }); } else { downloadBtn.setOnClickListener(v -> { + if (allStateClickCallback != null) { + allStateClickCallback.onCallback(); + } + if (clickCallback != null) { clickCallback.onCallback(); } @@ -656,24 +583,27 @@ public class DownloadItemUtils { if (str.equals(context.getString(R.string.download))) { // 先弹下载弹窗(如果需要的话) - DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> { - CertificationDialog.showCertificationDialog(context, gameEntity, () -> { - DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> { - DialogUtils.checkDownload(context, apk.getSize(), - isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent)); + PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> { + DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> { + CertificationDialog.showCertificationDialog(context, gameEntity, () -> { + DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> { + DialogUtils.checkDownload(context, apk.getSize(), + isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent)); + }); }); }); }); - DataLogUtils.uploadGameLog(context, gameEntity.getId(), gameEntity.getName(), entrance); } else if (str.equals(context.getString(R.string.attempt))) { - DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> { - CertificationDialog.showCertificationDialog(context, gameEntity, () -> { - DialogUtils.showVersionNumberDialog(context, gameEntity, () -> { - DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> { - DialogUtils.checkDownload(context, apk.getSize(), - isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent)); + PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> { + DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> { + CertificationDialog.showCertificationDialog(context, gameEntity, () -> { + DialogUtils.showVersionNumberDialog(context, gameEntity, () -> { + DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> { + DialogUtils.checkDownload(context, apk.getSize(), + isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent)); + }); }); }); }); @@ -700,7 +630,7 @@ public class DownloadItemUtils { boolean isInstalled = PackageUtils.isInstalledFromAllPackage(context, gameEntity.getSimulator().getApk().getPackageName()); if (downloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled) { SimulatorDownloadManager.getInstance().showDownloadDialog(context, gameEntity.getSimulator(), - SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(),null); + SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(), null); return; } } diff --git a/app/src/main/java/com/gh/common/util/DownloadObserver.kt b/app/src/main/java/com/gh/common/util/DownloadObserver.kt index a954f36a63..0d8b5749b4 100644 --- a/app/src/main/java/com/gh/common/util/DownloadObserver.kt +++ b/app/src/main/java/com/gh/common/util/DownloadObserver.kt @@ -175,15 +175,15 @@ object DownloadObserver { } // 下载过程分析统计 - val pm = mApplication.packageManager - val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES) - if (packageInfo == null) { +// val pm = mApplication.packageManager +// val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0) +// if (packageInfo == null) { // MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析", // "游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform)) // // MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新", // "游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform)) - } +// } } if (downloadEntity.status == DownloadStatus.done) { diff --git a/app/src/main/java/com/gh/common/util/EntranceUtils.java b/app/src/main/java/com/gh/common/util/EntranceUtils.java index 6a7109b97a..ee48a70945 100644 --- a/app/src/main/java/com/gh/common/util/EntranceUtils.java +++ b/app/src/main/java/com/gh/common/util/EntranceUtils.java @@ -215,6 +215,12 @@ public class EntranceUtils { public static final String KEY_BBS_ID = "bbs_id"; public static final String KEY_DIAGNOSIS = "diagnosis"; public static final String KEY_SIMULATOR = "simulator"; + public static final String KEY_MARKET_DETAILS = "market_details"; + public static final String KEY_CATALOG_ID = "catalogId"; + public static final String KEY_PRIMARY_CATALOG_ID = "primaryCatalogId"; + public static final String KEY_PRIMARY_CATALOG_NAME = "primaryCatalogName"; + public static final String KEY_CATALOG_TITLE = "catalog_title"; + public static final String KEY_CATALOG_INIT_TITLE = "catalog_init_title"; public static void jumpActivity(Context context, Bundle bundle) { bundle.putBoolean(KEY_REQUIRE_REDIRECT, true); diff --git a/app/src/main/java/com/gh/common/util/Extensions.kt b/app/src/main/java/com/gh/common/util/Extensions.kt index 5321198508..2e22840862 100644 --- a/app/src/main/java/com/gh/common/util/Extensions.kt +++ b/app/src/main/java/com/gh/common/util/Extensions.kt @@ -1,6 +1,7 @@ package com.gh.common.util import android.animation.Animator +import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.graphics.drawable.GradientDrawable @@ -43,8 +44,11 @@ import com.halo.assistant.HaloApp import com.lightgame.download.DownloadEntity import com.lightgame.utils.Utils import io.reactivex.Observable +import io.reactivex.ObservableTransformer +import io.reactivex.SingleTransformer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers import okhttp3.MediaType import okhttp3.RequestBody import java.net.URI @@ -124,6 +128,20 @@ fun ViewPager.addOnScrollStateChanged(onStateChanged: ((state: Int) -> Unit)? = addOnPageChangeListener(listener) } + +/** + * Fragment related + */ +inline fun Fragment.fragmentFromActivity() = + parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T + ?: parentFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T + + +inline fun Fragment.fragmentFromParentFragment() = + childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T + ?: childFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T + + /** * RecyclerView Extensions */ @@ -329,6 +347,15 @@ fun throwExceptionInDebug(message: String = "", predicate: Boolean = true) { } } +/** + * 在自动打包的包里弹 toast + */ +fun toastInInternalRelease(content: String) { + if (BuildConfig.BUILD_TIME != 0L) { + Utils.toast(HaloApp.getInstance(), content) + } +} + /** * 主动抛出异常 */ @@ -388,11 +415,25 @@ fun String.getFirstElementDividedByDivider(divider: String): String { return this } +fun String.copyText() { + this.copyTextAndToast("") +} + fun String.copyTextAndToast(toastText: String = "复制成功") { - val application = HaloApp.getInstance().application - val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - cmb.text = this - ToastUtils.showToast(toastText) + try { + val application = HaloApp.getInstance().application + val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clip = ClipData.newPlainText(null, this) + cmb.primaryClip = clip + + if (!TextUtils.isEmpty(toastText)) { + ToastUtils.showToast(toastText) + } + } catch (e: SecurityException) { + // 在一些情况下会报以下这样的错误,可能是以浮动窗口显示然后没有焦点?(https://developer.android.com/about/versions/10/privacy/changes#clipboard-data) + // java.lang.Throwable: java.lang.SecurityException: com.xunmeng.pinduoduo from uid 10317 not allowed to perform READ_CLIPBOARD + ToastUtils.showToast("复制失败,请重试") + } } fun Map.createRequestBody(): RequestBody { @@ -436,6 +477,7 @@ fun Float.sp2px(): Int { return (this * scale + 0.5f).toInt() } + /** * PopupWindow 自动适配方向 * 弹出与锚点右对齐 @@ -559,6 +601,19 @@ fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before }) } +/** + * ArrayList related + */ +fun ArrayList.safelyGetInRelease(index: Int): T? { + return if (index >= size) { + throwExceptionInDebug("这里触发了数组越界,请检查") + toastInInternalRelease("这个操作可能触发闪退,请确定复现方式并联系开发处理") + null + } else { + this[index] + } +} + /** * 拦截 TextView 中的 Url Span,用应用内页面的形式打开链接 * @param shrankText 未展开时的文字 @@ -849,4 +904,18 @@ fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)? onStopTrackingTouch?.invoke() } }) +} + +fun observableToMain(): ObservableTransformer { + return ObservableTransformer { upstream -> + upstream.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + } +} + +fun singleToMain(): SingleTransformer { + return SingleTransformer { upstream -> + upstream.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/GdtHelper.kt b/app/src/main/java/com/gh/common/util/GdtHelper.kt deleted file mode 100644 index f4365cbdb9..0000000000 --- a/app/src/main/java/com/gh/common/util/GdtHelper.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.gh.common.util - -import android.app.Application - -/** - * 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403] - * - * 更换帐号 [https://gitlab.ghzs.com/pm/yunying/issues/893] - */ -object GdtHelper { - - const val NETWORK_TYPE = "NETWORK_TYPE" - const val PAGE_TYPE = "PAGE_TYPE" - const val CONTENT_TYPE = "CONTENT_TYPE" - const val CONTENT_ID = "CONTENT_ID" - const val KEYWORD = "KEYWORD" - const val GAME_ID = "GAME_ID" - const val SCORE = "SCORE" - const val PLATFORM = "PLATFORM" - - fun init(application: Application, channel: String) { -// if (channel == "GH_728") { -// GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc") -// } else if (channel == "GH_729") { -// GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1") -// } else { -// GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a") -// } - } - - fun logAction(type: String) { -// GDTAction.logAction(type) -// Utils.log("GDT", type) - } - - fun logAction(type: String, vararg kv: String?) { -// try { -// val actionParam = JSONObject() -// for (i in kv.indices) { -// if (i % 2 != 0) { -// val key = kv[i - 1] -// val value = kv[i] -// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { -// actionParam.put(key, value) -// } -// } -// } -// Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]") -// GDTAction.logAction(type, actionParam) -// } catch (e: Exception) { -// e.printStackTrace() -// } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/HomePluggableHelper.kt b/app/src/main/java/com/gh/common/util/HomePluggableHelper.kt index 30161814a3..56029d3e03 100644 --- a/app/src/main/java/com/gh/common/util/HomePluggableHelper.kt +++ b/app/src/main/java/com/gh/common/util/HomePluggableHelper.kt @@ -15,7 +15,7 @@ object HomePluggableHelper { if (apkList.isNotEmpty()) { val apk = apkList.first() val tag = if (isNever) "never" else apk.version ?: "" - mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever)) + tryCatchInRelease { mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever)) } } } @@ -44,7 +44,7 @@ object HomePluggableHelper { for (entity in filterList) { entity.active = true } - mHomePluggableFilterDao.addData(filterList) + tryCatchInRelease { mHomePluggableFilterDao.addData(filterList) } } } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/HtmlUtils.java b/app/src/main/java/com/gh/common/util/HtmlUtils.java index 1911c10a9e..ef3cc45db5 100644 --- a/app/src/main/java/com/gh/common/util/HtmlUtils.java +++ b/app/src/main/java/com/gh/common/util/HtmlUtils.java @@ -67,4 +67,15 @@ public class HtmlUtils { return htmlStr.trim(); //返回文本字符串 } + + /** + * 过滤掉标签,保留标签内容 + */ + public static String filterHtmlLabel(String htmlStr) { + String regEx_html = "<[^>]+>([\\s\\S]*?)<\\/[^>]+>"; //定义HTML标签的正则表达式 + Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE); + Matcher m_html = p_html.matcher(htmlStr); + htmlStr = m_html.replaceAll("$1"); //过滤html标签 + return htmlStr.trim(); //返回文本字符串 + } } diff --git a/app/src/main/java/com/gh/common/util/ImageUtils.kt b/app/src/main/java/com/gh/common/util/ImageUtils.kt index e0866f87d6..d55c80552d 100644 --- a/app/src/main/java/com/gh/common/util/ImageUtils.kt +++ b/app/src/main/java/com/gh/common/util/ImageUtils.kt @@ -279,68 +279,74 @@ object ImageUtils { }) } + @JvmStatic + fun display(view: SimpleDraweeView?, url: String?) { + display(view, url, true) + } + /** * 规则 width>0 Wifi/4G:x2 traffic:x1 * 第一种方案:通过LayoutParams获取 可以快速(无延迟)获取宽高,但是无法获取wrap_content和match_parent的View * 第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高 + * @param isAutoPlayGif 是否禁止播放动图 */ @JvmStatic - fun display(view: SimpleDraweeView?, url: String?) { - url?.let { - val width = view?.layoutParams?.width - val height = view?.layoutParams?.height + fun display(view: SimpleDraweeView?, url: String?, isAutoPlayGif: Boolean = true) { + if (url == null) return - var lowResUrl = "" - var highResUrl = "" + val width = view?.layoutParams?.width + val height = view?.layoutParams?.height - // 找同一图片地址已加载过的图片作为低质量预览图 - // TODO 根据实际请求大小(w_width)来避免小图用大图作为低质量图片 - for (cachedImageUrl in mImageUrlCacheSet) { - if (cachedImageUrl.contains(url)) { - lowResUrl = cachedImageUrl - break - } + var lowResUrl = "" + var highResUrl = "" + + // 找同一图片地址已加载过的图片作为低质量预览图 + // TODO 根据实际请求大小(w_width)来避免小图用大图作为低质量图片 + for (cachedImageUrl in mImageUrlCacheSet) { + if (url.isNotEmpty() && cachedImageUrl.contains(url)) { + lowResUrl = cachedImageUrl + break } + } - val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl -> - view?.controller = Fresco.newDraweeControllerBuilder() - .setImageRequest(ImageRequest.fromUri(hUrl)) - .apply { - if (lUrl.isNotEmpty() - && lUrl != hUrl - && hUrl != view?.getTag(R.string.highResImageTag)) { - lowResImageRequest = ImageRequest.fromUri(lUrl) - } - autoPlayAnimations = autoPlay + val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl -> + view?.controller = Fresco.newDraweeControllerBuilder() + .setImageRequest(ImageRequest.fromUri(hUrl)) + .apply { + if (lUrl.isNotEmpty() + && lUrl != hUrl + && hUrl != view?.getTag(R.string.highResImageTag)) { + lowResImageRequest = ImageRequest.fromUri(lUrl) } - .build() + autoPlayAnimations = autoPlay + } + .build() - view?.setTag(R.string.highResImageTag, highResUrl) + view?.setTag(R.string.highResImageTag, highResUrl) + } + + val shouldLoadAsGif = url.endsWith(".gif") && isAutoPlayGif && view?.getTag(R.id.tag_show_gif) != false + + if (shouldLoadAsGif && view?.tag == url) return + + if (width != null && width > 0) { + highResUrl = if (shouldLoadAsGif) { + resizeGif(url, width, height ?: 0) + } else { + getTransformLimitUrl(url, width, view.context) ?: "" } - - val shouldLoadAsGif = it.endsWith(".gif") && view?.getTag(R.id.tag_show_gif) != false - - if (shouldLoadAsGif && view?.tag == url) return - - if (width != null && width > 0) { + loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl) + } else { + view?.post { highResUrl = if (shouldLoadAsGif) { - resizeGif(url, width, height ?: 0) + resizeGif(url, view.width, height ?: 0) } else { - getTransformLimitUrl(url, width, view.context) ?: "" + getTransformLimitUrl(url, view.width, view.context) ?: "" } loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl) - } else { - view?.post { - highResUrl = if (shouldLoadAsGif) { - resizeGif(url, view.width, height ?: 0) - } else { - getTransformLimitUrl(url, view.width, view.context) ?: "" - } - loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl) - } } - view?.tag = url } + view?.tag = url } // Wifi/4G:x2 traffic:x1 diff --git a/app/src/main/java/com/gh/common/util/InstallUtils.java b/app/src/main/java/com/gh/common/util/InstallUtils.java index a23f1c0be5..4e8fb3fd42 100644 --- a/app/src/main/java/com/gh/common/util/InstallUtils.java +++ b/app/src/main/java/com/gh/common/util/InstallUtils.java @@ -48,7 +48,7 @@ public class InstallUtils { public void handleMessage(Message msg) { if (msg.what == INSTALL_WHAT && packageManager != null) { ArrayList list = new ArrayList<>(); - List packageInfos = packageManager.getInstalledPackages(0); + List packageInfos = PackageUtils.getInstalledPackages(context, 0); for (PackageInfo packageInfo : packageInfos) { if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { list.add(packageInfo.packageName); diff --git a/app/src/main/java/com/gh/common/util/LibaoUtils.java b/app/src/main/java/com/gh/common/util/LibaoUtils.java index fc532d8921..fd438070a6 100644 --- a/app/src/main/java/com/gh/common/util/LibaoUtils.java +++ b/app/src/main/java/com/gh/common/util/LibaoUtils.java @@ -1,7 +1,6 @@ package com.gh.common.util; import android.app.Dialog; -import android.content.ClipboardManager; import android.content.Context; import android.content.pm.PackageInfo; import android.graphics.Color; @@ -11,6 +10,8 @@ import android.text.TextUtils; import android.util.Log; import android.widget.TextView; +import androidx.core.content.ContextCompat; + import com.gh.gamecenter.BuildConfig; import com.gh.gamecenter.R; import com.gh.gamecenter.adapter.LibaoDetailAdapter; @@ -36,7 +37,6 @@ import org.json.JSONObject; import java.util.ArrayList; import java.util.List; -import androidx.core.content.ContextCompat; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; @@ -237,85 +237,160 @@ public class LibaoUtils { // 领取限制 CheckLoginUtils.checkLogin(context, "礼包详情-[" + btnStatus + "]", () -> { - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> { - if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) { - if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) { - String platform; - if (TextUtils.isEmpty(libaoEntity.getPlatform())) { - platform = ""; - } else { - platform = PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform()); - } + if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) { + if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) { + String platform; + if (TextUtils.isEmpty(libaoEntity.getPlatform())) { + platform = ""; + } else { + platform = PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform()); + } - boolean isExistPlatform = false; - ArrayList apk = adapter.getGameEntity().getApk(); - for (ApkEntity apkEntity : apk) { - if (TextUtils.isEmpty(libaoEntity.getPlatform())) break; - if (libaoEntity.getPlatform().equals(apkEntity.getPlatform())) { - isExistPlatform = true; - break; - } + boolean isExistPlatform = false; + ArrayList apk = adapter.getGameEntity().getApk(); + for (ApkEntity apkEntity : apk) { + if (TextUtils.isEmpty(libaoEntity.getPlatform())) break; + if (libaoEntity.getPlatform().equals(apkEntity.getPlatform())) { + isExistPlatform = true; + break; } + } - String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform); - boolean finalIsExistPlatform = isExistPlatform; - DialogUtils.showWarningDialog(context, "条件不符", - Html.fromHtml(dialogContent), isExistPlatform ? "关闭" : null, - isExistPlatform ? "立即安装" : "关闭", - () -> { - if (finalIsExistPlatform) { - adapter.openDownload(libaoEntity.getPlatform()); - } - }, null); + String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform); + boolean finalIsExistPlatform = isExistPlatform; + DialogUtils.showWarningDialog(context, "条件不符", + Html.fromHtml(dialogContent), isExistPlatform ? "关闭" : null, + isExistPlatform ? "立即安装" : "关闭", + () -> { + if (finalIsExistPlatform) { + adapter.openDownload(libaoEntity.getPlatform()); + } + }, null); + return; + } + } + + switch (btnStatus) { + case "未开始": + Utils.toast(context, "还没到开始领取时间"); + break; + case "查看": + if (!TextUtils.isEmpty(libaoEntity.getDes())) { + DialogUtils.showAlertDialog(v.getContext(), "使用说明", + Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null); + } + break; + case "再领一个": + case "领取": + if ("repeatLing".equals(status)) { + DialogUtils.showWarningDialog(context, "礼包刷新提醒" + , "礼包每天0点刷新,换新区或者换新角色需要继续领取礼包的童鞋,请于明天0点之后回来即可[再领一个]" + , null, "知道了", null, null); + } else { + libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance); + } + break; + case "再淘一个": + case "淘号": + if ("repeatTao".equals(status)) { + Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新"); return; } - } + final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中..."); + postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() { + @Override + public void postSucceed(Object response) { - switch (btnStatus) { - case "未开始": - Utils.toast(context, "还没到开始领取时间"); - break; - case "查看": - if (!TextUtils.isEmpty(libaoEntity.getDes())) { - DialogUtils.showAlertDialog(v.getContext(), "使用说明", - Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null); - } - break; - case "再领一个": - case "领取": - if ("repeatLing".equals(status)) { - DialogUtils.showWarningDialog(context, "礼包刷新提醒" - , "礼包每天0点刷新,换新区或者换新角色需要继续领取礼包的童鞋,请于明天0点之后回来即可[再领一个]" - , null, "知道了", null, null); - } else { - libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance); - } - break; - case "再淘一个": - case "淘号": - if ("repeatTao".equals(status)) { - Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新"); - return; - } - final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中..."); - postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() { - @Override - public void postSucceed(Object response) { + if (loadingDialog != null) loadingDialog.dismiss(); - if (loadingDialog != null) loadingDialog.dismiss(); + JSONObject responseBody = (JSONObject) response; + String libaoCode = null; + try { + libaoCode = responseBody.getString("code"); + } catch (JSONException e) { + e.printStackTrace(); + } - JSONObject responseBody = (JSONObject) response; - String libaoCode = null; + if (TextUtils.isEmpty(libaoCode)) { try { - libaoCode = responseBody.getString("code"); + String detail = responseBody.getString("detail"); + switch (detail) { + case "maintaining": + Utils.toast(context, "网络状态异常,请稍后再试"); + break; + case "fail to compete": + Utils.toast(context, "淘号失败,稍后重试"); + break; + default: + Utils.toast(context, "淘号异常"); + break; + } } catch (JSONException e) { e.printStackTrace(); } + return; + } - if (TextUtils.isEmpty(libaoCode)) { + Utils.toast(context, "淘号成功"); + + libaoEntity.setStatus("taoed"); + + EventBus.getDefault().post(new EBReuse("libaoChanged")); + + adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context))); + + final String finalLibaoCode = libaoCode; + + DialogUtils.showWarningDialog(context, "淘号成功" + , Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode)) + , "关闭", " 复制礼包码" + , () -> { + copyLink(finalLibaoCode, context); + if (isInstallRequired) { + libaoBtn.postDelayed(() -> { + Spanned msg = Html.fromHtml( + context.getString(R.string.taoed_copy_dialog + , finalLibaoCode)); + lunningAppDialog(context + , msg, libaoEntity); + }, 300); + } + }, null); + } + + @Override + public void postFailed(Throwable error) { + Utils.log("---" + error.toString()); + + if (loadingDialog != null) loadingDialog.dismiss(); + + if (error instanceof HttpException) { + HttpException exception = (HttpException) error; + if (exception.code() == 403) { try { - String detail = responseBody.getString("detail"); + JSONObject errorJson = new JSONObject(exception.response().errorBody().string()); + String detail = errorJson.getString("detail"); +// Utils.toast(context, "返回::" + detail); switch (detail) { + case "coming": + Utils.toast(context, "礼包领取时间未开始"); + break; + case "finish": + Utils.toast(context, "礼包领取时间已结束"); + break; + case "fetched": + Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号"); + + libaoBtn.setText("已淘号"); + libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style); + libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector)); + libaoEntity.setStatus("taoed"); + break; + case "try tao": + case "used up": + DialogUtils.showHintDialog(context, "礼包已领光" + , "手速不够快,礼包已经被抢光了,十分抱歉", "知道了"); + break; case "maintaining": Utils.toast(context, "网络状态异常,请稍后再试"); break; @@ -323,101 +398,24 @@ public class LibaoUtils { Utils.toast(context, "淘号失败,稍后重试"); break; default: - Utils.toast(context, "淘号异常"); + Utils.toast(context, "操作失败"); break; + } - } catch (JSONException e) { - e.printStackTrace(); + } catch (Exception ex) { + ex.printStackTrace(); + Utils.toast(context, "礼包处理异常" + ex.toString()); } return; + } else if (exception.code() == 401) { + return; } - - Utils.toast(context, "淘号成功"); - - libaoEntity.setStatus("taoed"); - - EventBus.getDefault().post(new EBReuse("libaoChanged")); - - adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context))); - - final String finalLibaoCode = libaoCode; - - DialogUtils.showWarningDialog(context, "淘号成功" - , Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode)) - , "关闭", " 复制礼包码" - , () -> { - copyLink(finalLibaoCode, context); - if (isInstallRequired) { - libaoBtn.postDelayed(() -> { - Spanned msg = Html.fromHtml( - context.getString(R.string.taoed_copy_dialog - , finalLibaoCode)); - lunningAppDialog(context - , msg, libaoEntity); - }, 300); - } - }, null); } - - @Override - public void postFailed(Throwable error) { - Utils.log("---" + error.toString()); - - if (loadingDialog != null) loadingDialog.dismiss(); - - if (error instanceof HttpException) { - HttpException exception = (HttpException) error; - if (exception.code() == 403) { - try { - JSONObject errorJson = new JSONObject(exception.response().errorBody().string()); - String detail = errorJson.getString("detail"); -// Utils.toast(context, "返回::" + detail); - switch (detail) { - case "coming": - Utils.toast(context, "礼包领取时间未开始"); - break; - case "finish": - Utils.toast(context, "礼包领取时间已结束"); - break; - case "fetched": - Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号"); - - libaoBtn.setText("已淘号"); - libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style); - libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector)); - libaoEntity.setStatus("taoed"); - break; - case "try tao": - case "used up": - DialogUtils.showHintDialog(context, "礼包已领光" - , "手速不够快,礼包已经被抢光了,十分抱歉", "知道了"); - break; - case "maintaining": - Utils.toast(context, "网络状态异常,请稍后再试"); - break; - case "fail to compete": - Utils.toast(context, "淘号失败,稍后重试"); - break; - default: - Utils.toast(context, "操作失败"); - break; - - } - } catch (Exception ex) { - ex.printStackTrace(); - Utils.toast(context, "礼包处理异常" + ex.toString()); - } - return; - } else if (exception.code() == 401) { - return; - } - } - Utils.toast(context, "发生异常"); - } - }); - break; - } - }); + Utils.toast(context, "发生异常"); + } + }); + break; + } }); }); } @@ -458,7 +456,7 @@ public class LibaoUtils { adapter.notifyDataSetChanged(); final String finalLibaoCode = libaoCode; NotificationHelper.showNotificationHintDialog(NotificationUgc.GIFT, isShow -> { - if (!isShow){ + if (!isShow) { DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, finalLibaoCode)) , "关闭", " 复制礼包码" , () -> { @@ -547,8 +545,7 @@ public class LibaoUtils { } public static boolean isAppInstalled(Context context, String packageName) { - final android.content.pm.PackageManager packageManager = context.getPackageManager(); - List pinfo = packageManager.getInstalledPackages(0); + List pinfo = PackageUtils.getInstalledPackages(context, 0); if (pinfo != null) { for (int i = 0; i < pinfo.size(); i++) { String pn = pinfo.get(i).packageName; @@ -576,10 +573,7 @@ public class LibaoUtils { //复制文字 public static void copyLink(String copyContent, Context context) { - ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - cmb.setText(copyContent); - - Utils.toast(context, copyContent + " 复制成功"); + ExtensionsKt.copyTextAndToast(copyContent, copyContent + " 复制成功"); } diff --git a/app/src/main/java/com/gh/common/util/LogUtils.java b/app/src/main/java/com/gh/common/util/LogUtils.java index df059a3c37..66e4bf82fc 100644 --- a/app/src/main/java/com/gh/common/util/LogUtils.java +++ b/app/src/main/java/com/gh/common/util/LogUtils.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.List; import androidx.annotation.Nullable; + import io.reactivex.schedulers.Schedulers; import okhttp3.MediaType; import okhttp3.RequestBody; @@ -637,4 +638,49 @@ public class LogUtils { } LoghubUtils.log(object, "event", false); } + + public static void logNewCatalogAppearanceEvent(String entrance, String key) { + logCatalogEvent("access_to_classification", entrance, key, -1, -1, -1, -1); + } + + public static void logSubCatalogClickEvent(String entrance, String key, int seq1) { + logCatalogEvent("click_first_classification", entrance, key, seq1, -1, -1, -1); + } + + public static void logSubCatalogContentClickEvent(String entrance, String key, int seq1, int seq2) { + logCatalogEvent("click_secondary_classification", entrance, key, seq1, seq2, -1, -1); + } + + public static void logSpecialCatalogContentClickEvent(String entrance, String key, int seq1, int seqContent) { + logCatalogEvent("click_content", entrance, key, seq1, -1, seqContent, -1); + } + + public static void logSpecialCatalogSpecificContentClickEvent(String entrance, String key, int seq1, int seqContent, int seqContentList) { + logCatalogEvent("click_content_list", entrance, key, seq1, -1, seqContent, seqContentList); + } + + private static void logCatalogEvent(String event, String entrance, String key, int seq1, int seq2, int seqContent, int seqContentList) { + JSONObject object = new JSONObject(); + JSONObject payload = new JSONObject(); + try { + object.put("event", event); + object.put("meta", getMetaObject()); + object.put("timestamp", System.currentTimeMillis() / 1000); + + payload.put("entrance", entrance); //入口分类, 分为 首页或版块, + payload.put("key", key); //搜索类型, 有四种取值 默认搜索/历史搜索/自动搜索/主动搜索 + payload.put("seq_1st", seq1); //从0开始,默认-1表示没有 + payload.put("seq_2nd", seq2); //从0开始,默认-1表示没有 + payload.put("seq_content", seqContent); //精选页上 图片、专题-全部按钮、专题合集-全部按钮 的排序;从0开始,默认-1表示没有 + payload.put("seq_content_list", seqContentList); + object.put("payload", payload); + } catch (JSONException e) { + e.printStackTrace(); + } + + if (BuildConfig.DEBUG) { + Utils.log("LogUtils->" + object.toString()); + } + LoghubUtils.log(object, "event", false); + } } diff --git a/app/src/main/java/com/gh/common/util/MtaHelper.kt b/app/src/main/java/com/gh/common/util/MtaHelper.kt index ce50fd36fa..2bd37b063c 100644 --- a/app/src/main/java/com/gh/common/util/MtaHelper.kt +++ b/app/src/main/java/com/gh/common/util/MtaHelper.kt @@ -1,52 +1,61 @@ package com.gh.common.util +import android.os.Build +import android.text.TextUtils +import com.gh.common.exposure.meta.MetaUtil +import com.gh.gamecenter.BuildConfig +import com.halo.assistant.HaloApp +import com.lightgame.utils.Utils +import com.tencent.stat.StatService +import java.util.* + object MtaHelper { @JvmStatic fun onEvent(eventId: String, vararg kv: String?) { -// val prop = Properties() -// -// if (kv.size == 1) { -// prop.setProperty(kv[0], kv[0]) -// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop) -// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]") -// return -// } -// -// for (i in kv.indices) { -// if (i % 2 != 0) { -// val key = kv[i - 1] -// val value = kv[i] -// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { -// prop.setProperty(key, value) -// } -// } -// } -// -// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]") -// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop) + val prop = Properties() + + if (kv.size == 1) { + prop.setProperty(kv[0], kv[0]) + StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop) + Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]") + return + } + + for (i in kv.indices) { + if (i % 2 != 0) { + val key = kv[i - 1] + val value = kv[i] + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { + prop.setProperty(key, value) + } + } + } + + Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]") + StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop) } @JvmStatic fun onEventWithTime(eventId: String, time: Int, vararg kv: String?) { -// val prop = Properties() -// for (i in kv.indices) { -// if (i % 2 != 0 || i != 0) { -// val key = kv[i - 1] -// val value = kv[i] -// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { -// prop.setProperty(key, value) -// } -// } -// } -// -// if (prop.size == 0 && kv.size == 1) { -// prop.setProperty(kv[0], kv[0]) -// } -// -// if (prop.size == 0) return -// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}] + last $time seconds") -// StatService.trackCustomKVTimeIntervalEvent(HaloApp.getInstance().application, time, eventId, prop) + val prop = Properties() + for (i in kv.indices) { + if (i % 2 != 0 || i != 0) { + val key = kv[i - 1] + val value = kv[i] + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { + prop.setProperty(key, value) + } + } + } + + if (prop.size == 0 && kv.size == 1) { + prop.setProperty(kv[0], kv[0]) + } + + if (prop.size == 0) return + Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}] + last $time seconds") + StatService.trackCustomKVTimeIntervalEvent(HaloApp.getInstance().application, time, eventId, prop) } /** @@ -54,29 +63,29 @@ object MtaHelper { */ @JvmStatic fun onEventWithBasicDeviceInfo(eventId: String, vararg kv: String) { -// val prop = Properties() -// for (i in kv.indices) { -// if (i % 2 != 0) { -// val key = kv[i - 1] -// val value = kv[i] -// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { -// prop.setProperty(key, value) -// } -// } -// } -// -// prop.setProperty("光环版本", BuildConfig.VERSION_NAME) -// prop.setProperty("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application)) -// prop.setProperty("IMEI", MetaUtil.getIMEI()) -// prop.setProperty("机型", Build.MODEL) -// prop.setProperty("厂商", Build.MANUFACTURER) -// prop.setProperty("Android版本", Build.VERSION.RELEASE) -// if (!TextUtils.isEmpty(HaloApp.getInstance().gid)) { -// prop.setProperty("GID", HaloApp.getInstance().gid) -// } -// -// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]") -// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop) + val prop = Properties() + for (i in kv.indices) { + if (i % 2 != 0) { + val key = kv[i - 1] + val value = kv[i] + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { + prop.setProperty(key, value) + } + } + } + + prop.setProperty("光环版本", BuildConfig.VERSION_NAME) + prop.setProperty("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application)) + prop.setProperty("IMEI", MetaUtil.getIMEI()) + prop.setProperty("机型", Build.MODEL) + prop.setProperty("厂商", Build.MANUFACTURER) + prop.setProperty("Android版本", Build.VERSION.RELEASE) + if (!TextUtils.isEmpty(HaloApp.getInstance().gid)) { + prop.setProperty("GID", HaloApp.getInstance().gid) + } + + Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]") + StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop) } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/PackageHelper.kt b/app/src/main/java/com/gh/common/util/PackageHelper.kt index b488d89970..9cbda1952d 100644 --- a/app/src/main/java/com/gh/common/util/PackageHelper.kt +++ b/app/src/main/java/com/gh/common/util/PackageHelper.kt @@ -63,7 +63,7 @@ object PackageHelper { private fun getAllPackageName(context: Context): HashSet { val set = HashSet() return try { - val packageInfos = context.applicationContext.packageManager.getInstalledPackages(0) + val packageInfos = PackageUtils.getInstalledPackages(context, 0) for (packageInfo in packageInfos) { if (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0) { if (context.packageName != packageInfo.packageName) { diff --git a/app/src/main/java/com/gh/common/util/PackageInstaller.kt b/app/src/main/java/com/gh/common/util/PackageInstaller.kt index 02b8ea9a84..e59488d77c 100644 --- a/app/src/main/java/com/gh/common/util/PackageInstaller.kt +++ b/app/src/main/java/com/gh/common/util/PackageInstaller.kt @@ -1,5 +1,6 @@ package com.gh.common.util +import android.app.Activity import android.app.Application import android.content.Context import android.content.Intent @@ -38,13 +39,14 @@ object PackageInstaller { */ @JvmStatic fun install(context: Context, downloadEntity: DownloadEntity, showUnzipToast: Boolean) { - InstallPermissionDialogFragment.show(AppManager.getInstance().currentActivity() as AppCompatActivity) { + val pkgPath = downloadEntity.path + val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension() + InstallPermissionDialogFragment.show(AppManager.getInstance().currentActivity() as AppCompatActivity, downloadEntity) { // 取消状态栏下载完成的通知,若存在 downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES" DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity) - val pkgPath = downloadEntity.path - if (XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()) { + if (isXapk) { XapkInstaller.install(context, downloadEntity, showUnzipToast) } else { install(context, downloadEntity.path) @@ -113,6 +115,9 @@ object PackageInstaller { val uninstallIntent = Intent() uninstallIntent.action = Intent.ACTION_DELETE uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT) + if (context !is Activity) { + uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } val packageName = PackageUtils.getPackageNameByPath(context, path) uninstallIntent.data = Uri.parse("package:$packageName") InstallUtils.getInstance(context).addUninstall(packageName) diff --git a/app/src/main/java/com/gh/common/util/PackageUtils.java b/app/src/main/java/com/gh/common/util/PackageUtils.java index 3524812c24..791c8b2eb5 100644 --- a/app/src/main/java/com/gh/common/util/PackageUtils.java +++ b/app/src/main/java/com/gh/common/util/PackageUtils.java @@ -30,8 +30,11 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -286,7 +289,7 @@ public class PackageUtils { */ public static String getPackageNameByPath(Context context, String path) { PackageManager packageManager = context.getApplicationContext().getPackageManager(); - PackageInfo info = packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES); + PackageInfo info = packageManager.getPackageArchiveInfo(path, 0); if (info != null) { ApplicationInfo appInfo = info.applicationInfo; return appInfo.packageName; @@ -370,7 +373,7 @@ public class PackageUtils { */ public static ArrayList getAllPackageName(Context context) { ArrayList list = new ArrayList<>(); - List packageInfos = context.getApplicationContext().getPackageManager().getInstalledPackages(0); + List packageInfos = getInstalledPackages(context, 0); for (PackageInfo packageInfo : packageInfos) { if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { if (!context.getPackageName().equals(packageInfo.packageName)) { @@ -385,7 +388,7 @@ public class PackageUtils { JSONArray jsonArray = new JSONArray(); try { PackageManager pm = context.getPackageManager(); - List packageInfos = pm.getInstalledPackages(0); + List packageInfos = getInstalledPackages(context, 0); for (PackageInfo packageInfo : packageInfos) { if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { JSONObject jsonObject = new JSONObject(); @@ -557,4 +560,42 @@ public class PackageUtils { } + /** + * 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常 + * https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-to-get-a-list-of-applications-installed/30062632#30062632 + */ + public static List getInstalledPackages(Context context, int flags) { + final PackageManager pm = context.getPackageManager(); + try { + return pm.getInstalledPackages(flags); + } catch (Exception ignored) { + //we don't care why it didn't succeed. We'll do it using an alternative way instead + } + // use fallback: + Process process; + List result = new ArrayList<>(); + BufferedReader bufferedReader = null; + try { + process = Runtime.getRuntime().exec("pm list packages"); + bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = bufferedReader.readLine()) != null) { + final String packageName = line.substring(line.indexOf(':') + 1); + final PackageInfo packageInfo = pm.getPackageInfo(packageName, flags); + result.add(packageInfo); + } + process.waitFor(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (bufferedReader != null) + try { + bufferedReader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return result; + } + } diff --git a/app/src/main/java/com/gh/common/util/PermissionHelper.kt b/app/src/main/java/com/gh/common/util/PermissionHelper.kt index cddd88a41d..e8419933cf 100644 --- a/app/src/main/java/com/gh/common/util/PermissionHelper.kt +++ b/app/src/main/java/com/gh/common/util/PermissionHelper.kt @@ -13,7 +13,7 @@ import com.tbruyelle.rxpermissions2.RxPermissions object PermissionHelper { - const val INSTALL_PERMISS_CODE = 100 + const val INSTALL_PERMISSION_CODE = 100 @JvmStatic fun requestReadPhoneStateAndStoragePermissionFromStartUp(context: Context) { @@ -232,7 +232,7 @@ object PermissionHelper { } else { val packageURI = Uri.fromParts("package", activity.packageName, null) val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI) - activity.startActivityForResult(intent, INSTALL_PERMISS_CODE) + activity.startActivityForResult(intent, INSTALL_PERMISSION_CODE) } } diff --git a/app/src/main/java/com/gh/common/util/SentryHelper.kt b/app/src/main/java/com/gh/common/util/SentryHelper.kt new file mode 100644 index 0000000000..7a7b4a728b --- /dev/null +++ b/app/src/main/java/com/gh/common/util/SentryHelper.kt @@ -0,0 +1,47 @@ +package com.gh.common.util + +import android.text.TextUtils +import com.lightgame.utils.Utils +import io.sentry.core.Sentry +import io.sentry.core.SentryEvent +import io.sentry.core.SentryLevel +import io.sentry.core.protocol.Message + +object SentryHelper { + + /** + * 注意 tag-key 不支持中文 + */ + fun onEvent(eventId: String, vararg kv: String?) { + val sentryEvent = SentryEvent() + val message = Message() + message.message = eventId + sentryEvent.message = message + sentryEvent.level = SentryLevel.LOG + + for (i in kv.indices) { + if (i % 2 != 0) { + val key = kv[i - 1] + val value = kv[i] + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { + sentryEvent.setTag(key, value) + debugOnly { + throwExceptionInDebug("tag-key 不支持中文", isContainChinese(key)) + } + } + } + } + + Utils.log("Sentry", "$eventId + [${kv.joinToString(" , ")}]") + Sentry.captureEvent(sentryEvent) + } + + // 判断一个字符串是否含有中文 + private fun isContainChinese(str: String?): Boolean { + if (str == null) return false + for (c in str.toCharArray()) { + if (c.toInt() in 0x4E00..0x9FA5) return true + } + return false + } +} diff --git a/app/src/main/java/com/gh/common/util/ShareUtils.java b/app/src/main/java/com/gh/common/util/ShareUtils.java index a368384c1e..eecfbc8605 100644 --- a/app/src/main/java/com/gh/common/util/ShareUtils.java +++ b/app/src/main/java/com/gh/common/util/ShareUtils.java @@ -1,11 +1,9 @@ package com.gh.common.util; import android.app.Activity; -import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -24,6 +22,9 @@ import android.widget.PopupWindow; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.gh.common.constant.Config; import com.gh.gamecenter.R; import com.gh.gamecenter.WeiBoShareActivity; @@ -50,9 +51,6 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - import static com.gh.common.util.LoginHelper.WEIBO_SCOPE; /** @@ -159,8 +157,7 @@ public class ShareUtils { //检查是否安装手机QQ public static boolean isQQClientAvailable(Context context) { - final PackageManager packageManager = context.getPackageManager(); - List pinfo = packageManager.getInstalledPackages(0); + List pinfo = PackageUtils.getInstalledPackages(context, 0); if (pinfo != null) { for (int i = 0; i < pinfo.size(); i++) { String pn = pinfo.get(i).packageName; @@ -634,13 +631,11 @@ public class ShareUtils { private void copyLink(String copyContent) { shareType = "copy_link"; LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId); - ClipboardManager cmb = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE); - cmb.setText(copyContent); if (mShareEntrance != ShareEntrance.shareGh) { - Utils.toast(mContext, "复制成功"); + ExtensionsKt.copyTextAndToast(copyContent, "复制成功"); safelyDismiss(); } else { - Utils.toast(mContext, "复制成功,请到微信/QQ粘贴分享"); + ExtensionsKt.copyTextAndToast(copyContent, "复制成功,请到微信/QQ粘贴分享"); } } diff --git a/app/src/main/java/com/gh/common/util/SpanBuilder.kt b/app/src/main/java/com/gh/common/util/SpanBuilder.kt index 7e081e2221..dec35a5c5f 100644 --- a/app/src/main/java/com/gh/common/util/SpanBuilder.kt +++ b/app/src/main/java/com/gh/common/util/SpanBuilder.kt @@ -13,7 +13,7 @@ import androidx.core.content.ContextCompat import com.gh.common.view.CenterImageSpan import com.halo.assistant.HaloApp -class SpanBuilder(content: String) { +class SpanBuilder(content: CharSequence) { private var spannableString: SpannableStringBuilder = SpannableStringBuilder(content) fun color(context: Context, start: Int, end: Int, colorRes: Int): SpanBuilder { @@ -70,12 +70,12 @@ class SpanBuilder(content: String) { return this } - fun click(start: Int, end: Int, colorRes: Int, onClick: () -> Unit): SpanBuilder { + fun click(start: Int, end: Int, colorRes: Int, isUnderlineText: Boolean = false, onClick: () -> Unit): SpanBuilder { val clickSpan = object : ClickableSpan() { override fun updateDrawState(ds: TextPaint) { super.updateDrawState(ds) ds.color = ContextCompat.getColor(HaloApp.getInstance().application, colorRes) - ds.isUnderlineText = false + ds.isUnderlineText = isUnderlineText } override fun onClick(widget: View) { diff --git a/app/src/main/java/com/gh/common/util/TeaHelper.kt b/app/src/main/java/com/gh/common/util/TeaHelper.kt deleted file mode 100644 index 6363b729e2..0000000000 --- a/app/src/main/java/com/gh/common/util/TeaHelper.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.gh.common.util - -import android.content.Context - -/** - * 今日头条的激活统计 SDK https://gitlab.ghzs.com/pm/halo-app-issues/issues/567 - * - * 更新 SDK https://gitlab.ghzs.com/pm/halo-app-issues/issues/743 - */ -object TeaHelper { - - @JvmStatic - fun init(context: Context, channel: String) { -// val config = InitConfig("163824", channel) -// config.setUriConfig(UriConfig.DEFAULT) -// config.appName = "guanghuan1" -// config.setEnablePlay(true) -// AppLog.setEnableLog(false) -// AppLog.init(context, config) -// -// AppLog.setOaidObserver { -// HaloApp.getInstance().oaid = it.id -// Utils.log("oaid is $it.id") -// MetaUtil.refreshMeta() -// } -// -// // gameReportHelper ?! -// GameReportHelper.onEventRegister("wechat", true) -// GameReportHelper.onEventPurchase("gift", "flower", "008", 1, "wechat", "¥", true, 1) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/view/AdBannerView.kt b/app/src/main/java/com/gh/common/view/AdBannerView.kt index 26dde9c6c0..48d75974bb 100644 --- a/app/src/main/java/com/gh/common/view/AdBannerView.kt +++ b/app/src/main/java/com/gh/common/view/AdBannerView.kt @@ -3,7 +3,6 @@ package com.gh.common.view import android.content.Context import android.util.AttributeSet import android.view.* -import android.widget.ImageView import android.widget.LinearLayout import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView @@ -14,7 +13,6 @@ import com.gh.common.util.ImageUtils import com.gh.common.util.rxTimer import com.gh.gamecenter.R import com.gh.gamecenter.entity.SettingsEntity -import com.squareup.picasso.Picasso import io.reactivex.disposables.Disposable import kotlin.math.abs diff --git a/app/src/main/java/com/gh/common/view/CatalogFilterView.kt b/app/src/main/java/com/gh/common/view/CatalogFilterView.kt new file mode 100644 index 0000000000..19a5f4c742 --- /dev/null +++ b/app/src/main/java/com/gh/common/view/CatalogFilterView.kt @@ -0,0 +1,301 @@ +package com.gh.common.view + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.PopupWindow +import android.widget.TextView +import androidx.core.content.ContextCompat +import com.gh.common.util.toColor +import com.gh.common.util.visibleIf +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.entity.SubjectSettingEntity +import com.google.android.flexbox.FlexboxLayout + +class CatalogFilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) { + + private var mTypeTv: TextView + private var mCatalogTv: TextView + private var mSizeTv: TextView + private var mTypeContainer: View + private var mCatalogContainer: View + private var mSizeContainer: View + + private var mTypeFilterArray = ArrayList() + private var mCatalogFilterArray = ArrayList() + private var sizeFilterArray: ArrayList? = null + + private var mOnCatalogFilterSetupListener: OnCatalogFilterSetupListener? = null + + init { + View.inflate(context, R.layout.layout_catalog_filter, this) + + mTypeTv = findViewById(R.id.type_tv) + mCatalogTv = findViewById(R.id.catalog_tv) + mSizeTv = findViewById(R.id.size_tv) + mTypeContainer = findViewById(R.id.container_type) + mCatalogContainer = findViewById(R.id.container_catalog) + mSizeContainer = findViewById(R.id.container_size) + + mTypeContainer.setOnClickListener { + showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString()) + } + + mCatalogContainer.setOnClickListener { + showSelectCatalogPopupWindow(this, mCatalogTv, mCatalogTv.text.toString()) + } + + mSizeContainer.setOnClickListener { + showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString()) + } + } + + fun setTypeList(switch: CatalogEntity.CatalogSwitch) { + switch.run { + if ("on" == hotSort) mTypeFilterArray.add(SortType.RECOMMENDED) + if ("on" == newSort) mTypeFilterArray.add(SortType.NEWEST) + if ("on" == starSort) mTypeFilterArray.add(SortType.RATING) + } + if (mTypeFilterArray.isNotEmpty()) mTypeTv.text = mTypeFilterArray[0].value + } + + fun setCatalogList(subCatalogList: List, initCatalogName: String) { + mCatalogFilterArray = ArrayList(subCatalogList) + mCatalogTv.text = initCatalogName + } + + fun setOnConfigSetupListener(onCatalogFilterSetupListener: OnCatalogFilterSetupListener) { + mOnCatalogFilterSetupListener = onCatalogFilterSetupListener + } + + private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) { + if (highlightIt) { + targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text) + targetTextView.setTextColor(Color.WHITE) + } else { + targetTextView.background = null + targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575)) + } + } + + private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) { + val drawableUp = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_up) + val drawableDown = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_down) + drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight) + drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight) + + typeTv.setTextColor(R.color.theme_font.toColor()) + typeTv.setCompoundDrawables(null, null, drawableUp, null) + + val inflater = LayoutInflater.from(typeTv.context) + val layout = inflater.inflate(R.layout.layout_filter_size, null) + val popupWindow = PopupWindow( + layout, + LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT) + + val flexboxLayout = layout.findViewById(R.id.flexbox) + val backgroundView = layout.findViewById(R.id.background) + + backgroundView.setOnClickListener { + popupWindow.dismiss() + } + + for (type in mTypeFilterArray) { + val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false) + + // 单列 3 个,强行设置宽度为屏幕的 1/3 + val width = typeTv.context.resources.displayMetrics.widthPixels / 3 + val height = item.layoutParams.height + + item.layoutParams = ViewGroup.LayoutParams(width, height) + flexboxLayout.addView(item) + + val tv = item.findViewById(R.id.size_tv) + tv.text = type.value + + toggleHighlightedTextView(tv, typeText == type.value) + + tv.tag = type.value + + item.setOnClickListener { + toggleHighlightedTextView(tv, true) + popupWindow.dismiss() + typeTv.text = type.value + + mOnCatalogFilterSetupListener?.onSetupSortType(type) + } + } + + popupWindow.setOnDismissListener { + typeTv.setTextColor(R.color.text_757575.toColor()) + typeTv.setCompoundDrawables(null, null, drawableDown, null) + } + + popupWindow.isTouchable = true + popupWindow.isFocusable = true + popupWindow.animationStyle = 0 + popupWindow.showAsDropDown(containerView, 0, 0) + } + + private fun showSelectCatalogPopupWindow(containerView: View, catalogTv: TextView, catalogText: String) { + val drawableUp = ContextCompat.getDrawable(catalogTv.context, R.drawable.ic_filter_arrow_up) + val drawableDown = ContextCompat.getDrawable(catalogTv.context, R.drawable.ic_filter_arrow_down) + drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight) + drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight) + + catalogTv.setTextColor(R.color.theme_font.toColor()) + catalogTv.setCompoundDrawables(null, null, drawableUp, null) + + val inflater = LayoutInflater.from(catalogTv.context) + val layout = inflater.inflate(R.layout.layout_filter_size, null) + val popupWindow = PopupWindow( + layout, + LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT) + + val flexboxLayout = layout.findViewById(R.id.flexbox) + val backgroundView = layout.findViewById(R.id.background) + + backgroundView.setOnClickListener { + popupWindow.dismiss() + } + + for (entity in mCatalogFilterArray) { + val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false) + + // 单列 3 个,强行设置宽度为屏幕的 1/3 + val width = catalogTv.context.resources.displayMetrics.widthPixels / 3 + val height = item.layoutParams.height + + item.layoutParams = ViewGroup.LayoutParams(width, height) + flexboxLayout.addView(item) + + val tv = item.findViewById(R.id.size_tv) + val iv = item.findViewById(R.id.recommend_iv) + tv.text = entity.name + iv.visibleIf(entity.recommended) + + toggleHighlightedTextView(tv, catalogText == entity.name) + + tv.tag = entity.name + + item.setOnClickListener { + toggleHighlightedTextView(tv, true) + popupWindow.dismiss() + catalogTv.text = entity.name + + mOnCatalogFilterSetupListener?.onSetupSortCatalog(entity) + } + } + + popupWindow.setOnDismissListener { + catalogTv.setTextColor(R.color.text_757575.toColor()) + catalogTv.setCompoundDrawables(null, null, drawableDown, null) + } + + popupWindow.isTouchable = true + popupWindow.isFocusable = true + popupWindow.animationStyle = 0 + popupWindow.showAsDropDown(containerView, 0, 0) + } + + private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) { + val drawableUp = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_up) + val drawableDown = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_down) + drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight) + drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight) + + sizeTv.setTextColor(R.color.theme_font.toColor()) + sizeTv.setCompoundDrawables(null, null, drawableUp, null) + + val inflater = LayoutInflater.from(sizeTv.context) + val layout = inflater.inflate(R.layout.layout_filter_size, null) + val popupWindow = PopupWindow( + layout, + LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT) + + val flexboxLayout = layout.findViewById(R.id.flexbox) + val backgroundView = layout.findViewById(R.id.background) + + sizeFilterArray = if (sizeFilterArray == null) { + getDefaultSizeFilterArray() + } else { + sizeFilterArray?.apply { + if (firstOrNull()?.text != "全部大小") { + add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小")) + } + } + } + + backgroundView.setOnClickListener { + popupWindow.dismiss() + } + + for (size in sizeFilterArray!!) { + val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false) + + // 单列 3 个,强行设置宽度为屏幕的 1/3 + val width = sizeTv.context.resources.displayMetrics.widthPixels / 3 + val height = item.layoutParams.height + + item.layoutParams = ViewGroup.LayoutParams(width, height) + flexboxLayout.addView(item) + + val tv = item.findViewById(R.id.size_tv) + tv.text = size.text + + toggleHighlightedTextView(tv, sizeText == size.text) + + tv.tag = size.text + + item.setOnClickListener { + toggleHighlightedTextView(tv, true) + popupWindow.dismiss() + sizeTv.text = size.text + + mOnCatalogFilterSetupListener?.onSetupSortSize(size) + } + } + + popupWindow.setOnDismissListener { + sizeTv.setTextColor(R.color.text_757575.toColor()) + sizeTv.setCompoundDrawables(null, null, drawableDown, null) + } + + popupWindow.isTouchable = true + popupWindow.isFocusable = true + popupWindow.animationStyle = 0 + popupWindow.showAsDropDown(containerView, 0, 0) + } + + private fun getDefaultSizeFilterArray(): ArrayList { + return arrayListOf().apply { + add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小")) + add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下")) + add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M")) + add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M")) + add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G")) + add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上")) + } + } + + interface OnCatalogFilterSetupListener { + fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) + fun onSetupSortType(sortType: SortType) + fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity) + } + + enum class SortType(val value: String) { + RECOMMENDED("热门推荐"), + NEWEST("最新上线"), + RATING("最高评分") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/view/ConfigFilterView.kt b/app/src/main/java/com/gh/common/view/ConfigFilterView.kt index cec37b79a6..f79a458896 100644 --- a/app/src/main/java/com/gh/common/view/ConfigFilterView.kt +++ b/app/src/main/java/com/gh/common/view/ConfigFilterView.kt @@ -12,7 +12,7 @@ import android.widget.PopupWindow import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat -import com.gh.common.util.DisplayUtils +import com.gh.common.util.toColor import com.gh.gamecenter.R import com.gh.gamecenter.entity.SubjectSettingEntity import com.google.android.flexbox.FlexboxLayout @@ -69,16 +69,13 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib mOnConfigFilterSetupListener = onConfigFilterSetupListener } - fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) { + private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) { if (highlightIt) { - targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.text_blue_background) + targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text) targetTextView.setTextColor(Color.WHITE) } else { - val colorDrawable = GradientDrawable() - colorDrawable.setColor(Color.WHITE) - colorDrawable.cornerRadius = DisplayUtils.dip2px(1.5f).toFloat() - targetTextView.background = colorDrawable - targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_3a3a3a)) + targetTextView.background = null + targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575)) } } @@ -88,8 +85,8 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight) drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight) + sizeTv.setTextColor(R.color.theme_font.toColor()) sizeTv.setCompoundDrawables(null, null, drawableUp, null) - sizeTv.text = "收起" val inflater = LayoutInflater.from(sizeTv.context) val layout = inflater.inflate(R.layout.layout_filter_size, null) @@ -146,25 +143,24 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib } popupWindow.setOnDismissListener { + sizeTv.setTextColor(R.color.text_757575.toColor()) sizeTv.setCompoundDrawables(null, null, drawableDown, null) - if (sizeTv.text == "收起") { - sizeTv.text = sizeText - } } popupWindow.isTouchable = true popupWindow.isFocusable = true + popupWindow.animationStyle = 0 popupWindow.showAsDropDown(containerView, 0, 0) } private fun getDefaultSizeFilterArray(): ArrayList { return arrayListOf().apply { add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小")) - add(SubjectSettingEntity.Size(min = -1, max = 20, text = "20M以下")) - add(SubjectSettingEntity.Size(min = 20, max = 50, text = "20-50M")) - add(SubjectSettingEntity.Size(min = 50, max = 100, text = "50-100M")) - add(SubjectSettingEntity.Size(min = 100, max = 500, text = "100-500M")) - add(SubjectSettingEntity.Size(min = 500, max = -1, text = "500M以上")) + add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下")) + add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M")) + add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M")) + add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G")) + add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上")) } } diff --git a/app/src/main/java/com/gh/common/view/GameIconView.kt b/app/src/main/java/com/gh/common/view/GameIconView.kt index 3f1c207b0d..7600e2f767 100644 --- a/app/src/main/java/com/gh/common/view/GameIconView.kt +++ b/app/src/main/java/com/gh/common/view/GameIconView.kt @@ -5,6 +5,7 @@ import android.text.TextUtils import android.util.AttributeSet import android.view.View import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat import com.facebook.drawee.generic.RoundingParams import com.facebook.drawee.view.SimpleDraweeView import com.gh.common.util.DisplayUtils @@ -18,6 +19,7 @@ class GameIconView : ConstraintLayout { private var mCornerRadius = 10 private var mBorderColor = 0 + private var mGameIconOverlayColor = 0 private var mBorderWidth = 1 private var mFadeDuration = -1 @@ -36,11 +38,15 @@ class GameIconView : ConstraintLayout { val ta = context.obtainStyledAttributes(attrs, R.styleable.GameIconView) mCornerRadius = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconCornerRadius, DisplayUtils.dip2px(10F)) mBorderColor = ta.getColor(R.styleable.GameIconView_gameIconBorderColor, 0) + mGameIconOverlayColor = ta.getColor(R.styleable.GameIconView_gameIconOverlayColor, 0) mBorderWidth = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconBorderWidth, 1) mFadeDuration = ta.getInt(R.styleable.GameIconView_gameIconFadeDuration, -1) ta.recycle() val roundingParams = RoundingParams.fromCornersRadius(mCornerRadius.toFloat()) + if (mGameIconOverlayColor != 0) { + roundingParams.overlayColor = mGameIconOverlayColor + } if (mBorderColor != 0) { roundingParams.setBorder(mBorderColor, mBorderWidth.toFloat()) diff --git a/app/src/main/java/com/gh/common/view/ReserveDialog.kt b/app/src/main/java/com/gh/common/view/ReserveDialog.kt index 46afcdb1eb..d1311428b7 100644 --- a/app/src/main/java/com/gh/common/view/ReserveDialog.kt +++ b/app/src/main/java/com/gh/common/view/ReserveDialog.kt @@ -32,7 +32,7 @@ class ReserveDialog : BaseDialogFragment() { binding.more.setOnClickListener { val intent = MyGameActivity.getIntentWithConfig(requireContext(), 2) startActivity(intent) - dismiss() + dismissAllowingStateLoss() } binding.recyclerView.layoutManager = if (mReserveList.size > 4) { GridLayoutManager(context, 4) @@ -54,7 +54,7 @@ class ReserveDialog : BaseDialogFragment() { holder.binding.game = entity holder.itemView.setOnClickListener { GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(预约弹窗)") - dismiss() + dismissAllowingStateLoss() } } } diff --git a/app/src/main/java/com/gh/common/view/UrlInterceptedLinkMovementMethod.kt b/app/src/main/java/com/gh/common/view/UrlInterceptedLinkMovementMethod.kt new file mode 100644 index 0000000000..5e15f51857 --- /dev/null +++ b/app/src/main/java/com/gh/common/view/UrlInterceptedLinkMovementMethod.kt @@ -0,0 +1,70 @@ +package com.gh.common.view + +import android.text.Selection +import android.text.Spannable +import android.text.method.LinkMovementMethod +import android.text.style.ClickableSpan +import android.text.style.URLSpan +import android.view.MotionEvent +import android.view.ViewGroup +import android.view.ViewParent +import android.widget.TextView +import com.gh.common.DefaultUrlHandler + +/** + * 拦截处理以 "ghzhushou://" 起始的 URLSpan + */ +class UrlInterceptedLinkMovementMethod : LinkMovementMethod() { + + override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean { + val action = event.action + var isTouchEventConsumed = false + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { + var x = event.x.toInt() + var y = event.y.toInt() + x -= widget.totalPaddingLeft + y -= widget.totalPaddingTop + x += widget.scrollX + y += widget.scrollY + val layout = widget.layout + val line = layout.getLineForVertical(y) + val off = layout.getOffsetForHorizontal(line, x.toFloat()) + val links = buffer.getSpans(off, off, ClickableSpan::class.java) + if (links.size != 0) { + val link = links[0] + if (action == MotionEvent.ACTION_UP) { + if (link is URLSpan && link.url.contains("ghzhushou")) { + DefaultUrlHandler.interceptUrl(widget.context, link.url, "") + } else { + link.onClick(widget) + } + } else if (action == MotionEvent.ACTION_DOWN) { + // do nothing + } + isTouchEventConsumed = true + } else { + Selection.removeSelection(buffer) + } + } + + //解决点击事件冲突问题 + if (!isTouchEventConsumed && event.action == MotionEvent.ACTION_UP) { + val parent: ViewParent? = iterateViewParentForClicking(widget.parent) //处理widget的父控件点击事件 + if (parent is ViewGroup) { + return parent.performClick() + } + } + return false + } + + private fun iterateViewParentForClicking(parent: ViewParent): ViewParent? { + return if (parent is ViewGroup) { + if (parent.hasOnClickListeners()) { + parent + } else { + iterateViewParentForClicking(parent.getParent()) + } + } else null + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/view/WelcomeDialog.kt b/app/src/main/java/com/gh/common/view/WelcomeDialog.kt index f67ca9ddd8..66b602483c 100644 --- a/app/src/main/java/com/gh/common/view/WelcomeDialog.kt +++ b/app/src/main/java/com/gh/common/view/WelcomeDialog.kt @@ -86,7 +86,7 @@ class WelcomeDialog : BaseDialogFragment() { mDismissByClickImage = true - dismiss() + dismissAllowingStateLoss() } binding.ivOpeningCover.loadingCallback = object : WrapContentDraweeView.LoadingCallback { @@ -102,15 +102,24 @@ class WelcomeDialog : BaseDialogFragment() { } binding.ivCloseBackup.setOnClickListener { - dismiss() + dismissAllowingStateLoss() } binding.ivClose.setOnClickListener { - dismiss() + dismissAllowingStateLoss() } binding.welcome = mWelcomeEntity return binding.root } + override fun dismissAllowingStateLoss() { + try { + mDismissByClickImage = false + super.dismissAllowingStateLoss() + } catch (e: Exception) { + e.printStackTrace() + } + } + override fun dismiss() { try { mDismissByClickImage = false diff --git a/app/src/main/java/com/gh/common/xapk/XapkInstaller.kt b/app/src/main/java/com/gh/common/xapk/XapkInstaller.kt index b8bb3d3ab9..d6892ca4ea 100644 --- a/app/src/main/java/com/gh/common/xapk/XapkInstaller.kt +++ b/app/src/main/java/com/gh/common/xapk/XapkInstaller.kt @@ -1,12 +1,9 @@ package com.gh.common.xapk import android.content.Context -import android.os.Build import com.gh.common.AppExecutor -import com.gh.common.exposure.meta.MetaUtil import com.gh.common.util.* import com.gh.download.DownloadManager -import com.gh.gamecenter.BuildConfig import com.halo.assistant.HaloApp import com.lightgame.download.DataChanger import com.lightgame.download.DownloadEntity @@ -124,14 +121,9 @@ object XapkInstaller : IXapkUnzipListener { DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity) } - MtaHelper.onEvent("解压失败" - , "安卓版本", Build.VERSION.RELEASE - , "IMEI", MetaUtil.getIMEI() - , "光环版本", BuildConfig.VERSION_NAME - , "厂商", Build.MANUFACTURER - , "机型", Build.MODEL - , "游戏", downloadEntity.name - , "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application)) + SentryHelper.onEvent("XAPK_UNZIP_ERROR", + "gameName", downloadEntity.name, + "errorDigest", exception.localizedMessage) debugOnly { Utils.log("unzip", "onFailure->$exception") @@ -142,7 +134,14 @@ object XapkInstaller : IXapkUnzipListener { mXapkUnzipThreadMap.remove(downloadEntity.path) AppExecutor.uiExecutor.execute { - val pkgPath = checkNotNull(downloadEntity.meta[XAPK_PACKAGE_PATH_TAG]) + val pkgPath = downloadEntity.meta[XAPK_PACKAGE_PATH_TAG] + + if (pkgPath == null) { + Utils.toast(mContext, "下载出错,请重新下载!") + + return@execute + } + PackageInstaller.install(mContext, pkgPath) downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0" diff --git a/app/src/main/java/com/gh/download/DownloadDataHelper.kt b/app/src/main/java/com/gh/download/DownloadDataHelper.kt index cefe309eee..b6532fd73a 100644 --- a/app/src/main/java/com/gh/download/DownloadDataHelper.kt +++ b/app/src/main/java/com/gh/download/DownloadDataHelper.kt @@ -56,7 +56,7 @@ object DownloadDataHelper { return "下载完成" } val pm = HaloApp.getInstance().application.applicationContext.packageManager - val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES) + val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0) if (packageInfo == null && XapkInstaller.PACKAGE_EXTENSION_NAME == downloadEntity.path.getExtension()) { "解析包错误" } else { diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java index 6ba8c339d4..9ed07f5a5a 100644 --- a/app/src/main/java/com/gh/download/DownloadManager.java +++ b/app/src/main/java/com/gh/download/DownloadManager.java @@ -150,6 +150,8 @@ public class DownloadManager implements DownloadStatusListener { // 只有下载模块需要这坨东西,因此移动到这里初始化 ConnectionUtils.initHttpsUrlConnection(context); + updateMetaMap(); + // DownloadNotification.showDownloadingNotification(mContext); lastTimeMap = new ArrayMap<>(); @@ -292,8 +294,6 @@ public class DownloadManager implements DownloadStatusListener { downloadEntity.setUpdate(true); } - updateMetaMap(); - downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion())); ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId()); @@ -340,6 +340,8 @@ public class DownloadManager implements DownloadStatusListener { * @param downloadEntity */ public void add(DownloadEntity downloadEntity) { + updateMetaMap(); + if (downloadEntity != null) { String url = downloadEntity.getUrl(); checkDownloadEntryRecordValidate(url); @@ -397,6 +399,8 @@ public class DownloadManager implements DownloadStatusListener { * @param downloadEntity */ public void subscribe(DownloadEntity downloadEntity) { + updateMetaMap(); + if (downloadEntity != null) { String url = downloadEntity.getUrl(); checkDownloadEntryRecordValidate(url); @@ -992,7 +996,7 @@ public class DownloadManager implements DownloadStatusListener { map.put(HttpDnsManager.GID, HaloApp.getInstance().getGid()); map.put(HttpDnsManager.OAID, HaloApp.getInstance().getOAID()); map.put(HttpDnsManager.USER_ID, UserManager.getInstance().getUserId()); - map.put(HttpDnsManager.IMEI, MetaUtil.INSTANCE.getIMEI()); + map.put(HttpDnsManager.IMEI, MetaUtil.getBase64EncodedIMEI()); HttpDnsManager.metaMap = map; } diff --git a/app/src/main/java/com/gh/download/PackageObserver.kt b/app/src/main/java/com/gh/download/PackageObserver.kt new file mode 100644 index 0000000000..1ef2fedc79 --- /dev/null +++ b/app/src/main/java/com/gh/download/PackageObserver.kt @@ -0,0 +1,201 @@ +package com.gh.download + +import android.annotation.SuppressLint +import android.app.NotificationManager +import android.content.Context +import android.preference.PreferenceManager +import android.text.TextUtils +import com.gh.common.constant.Constants +import com.gh.common.loghub.LoghubUtils +import com.gh.common.util.* +import com.gh.gamecenter.entity.GameDigestEntity +import com.gh.gamecenter.eventbus.EBPackage +import com.gh.gamecenter.manager.UserManager +import com.gh.gamecenter.packagehelper.PackageRepository +import com.gh.gamecenter.packagehelper.PackageViewModel +import com.gh.gamecenter.retrofit.EmptyResponse +import com.gh.gamecenter.retrofit.Response +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import com.halo.assistant.fragment.SettingsFragment +import com.lightgame.download.DownloadEntity +import com.lightgame.utils.Utils +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import okhttp3.MediaType +import okhttp3.RequestBody +import org.json.JSONException +import org.json.JSONObject +import java.util.* + +object PackageObserver { + + private val mPackageViewModel: PackageViewModel + by lazy { PackageViewModel(HaloApp.getInstance().application, PackageRepository) } + + @JvmStatic + fun onPackageChanged(busFour: EBPackage) { + val application = HaloApp.getInstance().application + val packageName = busFour.packageName + val versionName = busFour.versionName + var gameId = "" + var mDownloadEntity: DownloadEntity? = null + val sp = PreferenceManager.getDefaultSharedPreferences(application) + + for (downloadEntity in DownloadManager.getInstance(application).allDownloadEntity) { + if (packageName == downloadEntity.packageName) { + mDownloadEntity = downloadEntity + gameId = mDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER) + if (TextUtils.isEmpty(busFour.versionName)) { + // 没有版本号的事件直接选用第一个找到的 downloadEntity + break + } else { + // 有版本号的事件直接尽量找到版本一致的 downloadEntity + if (versionName == downloadEntity.versionName) { + break + } + } + } + } + if ("安装" == busFour.type) { + mPackageViewModel.addInstalledGame(packageName) + + // TODO 这个取消通知栏看起来没什么用,没在其它地方看到它,暂且保留一个版本 + // 删除下载完成 弹窗 + val nManager = application.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + nManager.cancel(packageName.hashCode()) + + if (mDownloadEntity != null) { + if (mDownloadEntity.isPluggable) { + val kv6: MutableMap = HashMap() + kv6["安装或卸载"] = "安装完成" + DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6) + +// DataUtils.onMtaEvent(this, +// "插件化_新", +// "位置", mDownloadEntity.getEntrance(), +// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(), +// "操作", "安装完成", +// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication())); + } + + // 没有光环 ID 的都记录一下游戏 ID,供'我的游戏'区分同包名不同插件用 + val gh_id = PackageUtils.getMetaData(application, mDownloadEntity.packageName, "gh_id") + if (gh_id == null) { + ThirdPartyPackageHelper.saveGameId(mDownloadEntity.packageName, mDownloadEntity.gameId) + } + DownloadManager.getInstance(application).cancel( + mDownloadEntity.url, false, true) // 默认不删除安装包 mSp.getBoolean("autodelete", true) + } + if (sp.getBoolean(SettingsFragment.CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注 + // 安装后关注游戏 + val finalDownloadEntity = mDownloadEntity + RetrofitManager.getInstance(application).sensitiveApi + .getGameDigestByPackageName(UrlFilterUtils.getFilterQuery("package", packageName)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response?>() { + override fun onResponse(response: List?) { + for (gameDigestEntity in response!!) { + if (!TextUtils.isEmpty(gameDigestEntity?.id)) { // 关注游戏 + if (finalDownloadEntity != null && gameDigestEntity?.id == finalDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)) { + ConcernUtils.postConcernGameId(application, gameDigestEntity?.id ?: "", null, false) + } + } + } + } + }) + } + postNewlyInstalledApp(gameId, packageName) + } + + if ("卸载" == busFour.type) { + mPackageViewModel.addUninstalledGame(packageName) + if (mDownloadEntity != null && mDownloadEntity.isPluggable) { + val kv6: MutableMap = HashMap() + kv6["安装或卸载"] = "卸载完成" + DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6) + +// DataUtils.onMtaEvent(this, +// "插件化_新", +// "位置", mDownloadEntity.getEntrance(), +// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(), +// "操作", "卸载完成", +// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication())); + PackageInstaller.install(application, mDownloadEntity) + } + + // 更新已安装游戏 + deleteInstalledPackage(packageName) + } + DataCollectionUtils.uploadInorunstall(application, busFour.type, busFour.packageName) + } + + @SuppressLint("CheckResult") + private fun postNewlyInstalledApp(gameId: String, packageName: String) { + + // 发送应用变更前都检查一下是否需要把所有应用都上传 + PackageRepository.checkAndUploadAppList() + + // 更新已安装游戏 + val packageObject = PackageUtils.getAppBasicInfoByPackageName(packageName) + val dataObject = JSONObject() + val wrapperObject = JSONObject() + try { + dataObject.put("type", "POST") + dataObject.put("device_id", HaloApp.getInstance().gid) + dataObject.put("app", packageObject) + dataObject.put("time", Utils.getTime(HaloApp.getInstance().application)) + wrapperObject.put("content", dataObject.toString()) + } catch (e: JSONException) { + e.printStackTrace() + } + LoghubUtils.log(wrapperObject, "halo-api-device-installed", true) + val requestBody = RequestBody.create(MediaType.parse("application/json"), + packageObject.toString()) + // 更新已安装游戏 + RetrofitManager.getInstance(HaloApp.getInstance().application).api + .postNewlyInstalledApp(HaloApp.getInstance().gid, requestBody) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .subscribe(EmptyResponse()) + if (!TextUtils.isEmpty(gameId) && UserManager.getInstance().isLoggedIn) { + val jsonObject = JSONObject() + try { + jsonObject.put("game_id", gameId) + jsonObject.put("package", packageName) + val rBody = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString()) + RetrofitManager.getInstance(HaloApp.getInstance().application).api + .postPlayedGame(UserManager.getInstance().userId, rBody) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .subscribe(EmptyResponse()) + } catch (e: JSONException) { + e.printStackTrace() + } + } + + } + + @SuppressLint("CheckResult") + private fun deleteInstalledPackage(packageName: String) { + + // 发送应用变更前都检查一下是否需要把所有应用都上传 + PackageRepository.checkAndUploadAppList() + + // 删除已安装游戏 + val dataObject = JSONObject() + val wrapperObject = JSONObject() + try { + dataObject.put("type", "DELETE") + dataObject.put("device_id", HaloApp.getInstance().gid) + dataObject.put("package", packageName) + dataObject.put("time", Utils.getTime(HaloApp.getInstance().application)) + wrapperObject.put("content", dataObject.toString()) + } catch (e: JSONException) { + e.printStackTrace() + } + LoghubUtils.log(wrapperObject, "halo-api-device-installed", true) + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/download/dialog/DownloadDialog.kt b/app/src/main/java/com/gh/download/dialog/DownloadDialog.kt index d546bae775..fc90821205 100644 --- a/app/src/main/java/com/gh/download/dialog/DownloadDialog.kt +++ b/app/src/main/java/com/gh/download/dialog/DownloadDialog.kt @@ -140,7 +140,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener { } }) mViewModel.dismissLiveData.observe(this, Observer { - dismiss() + dismissAllowingStateLoss() }) mElapsedHelper = TimeElapsedHelper() @@ -173,7 +173,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener { postBrowseMta() mViewModel.collectionLiveData.postValue(null) } else { - dismiss() + dismissAllowingStateLoss() } } mGestureDetector = GestureDetector(requireContext(), SingleTapConfirm()) @@ -332,7 +332,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener { MotionEvent.ACTION_UP, MotionEvent.ACTION_OUTSIDE -> { if (mBinding.root.y >= mBinding.root.height / 2) { - dismiss() + dismissAllowingStateLoss() } else { resetDialogPosition(300) } diff --git a/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt b/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt index 63fce2a68e..797df214ca 100644 --- a/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt +++ b/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt @@ -2,11 +2,13 @@ package com.gh.download.dialog import android.content.Context import android.view.View +import androidx.appcompat.app.AppCompatActivity import com.gh.base.BaseActivity import com.gh.base.BaseRecyclerViewHolder import com.gh.common.constant.Config import com.gh.common.dialog.CertificationDialog import com.gh.common.dialog.DeviceRemindDialog +import com.gh.common.dialog.PackageCheckDialogFragment import com.gh.common.exposure.ExposureEvent import com.gh.common.util.* import com.gh.common.util.DirectUtils.directToLinkPage @@ -24,6 +26,7 @@ import com.lightgame.download.DownloadStatus import com.lightgame.download.FileUtils import com.lightgame.utils.AppManager import com.lightgame.utils.Utils +import io.sentry.core.protocol.App class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : BaseRecyclerViewHolder(binding.root) { @@ -278,19 +281,21 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas if (msg.isNullOrEmpty()) { DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback { override fun onCallback() { - CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener { - DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe -> - DownloadManager.createDownload( - context, - apkEntity, - gameEntity, - downloadMethod, - entrance, - location, - isSubscribe, traceEvent) + PackageCheckDialogFragment.show(context as AppCompatActivity, gameEntity.packageDialog, DialogUtils.ConfirmListener { + CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener { + DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe -> + DownloadManager.createDownload( + context, + apkEntity, + gameEntity, + downloadMethod, + entrance, + location, + isSubscribe, traceEvent) - DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity) - } + DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity) + } + }) }) } }) diff --git a/app/src/main/java/com/gh/download/dialog/DownloadLinkDialog.kt b/app/src/main/java/com/gh/download/dialog/DownloadLinkDialog.kt index de97247f69..2c854bd651 100644 --- a/app/src/main/java/com/gh/download/dialog/DownloadLinkDialog.kt +++ b/app/src/main/java/com/gh/download/dialog/DownloadLinkDialog.kt @@ -28,7 +28,7 @@ class DownloadLinkDialog : BaseDialogFragment() { mLinkEntity.content, "text/html", "utf-8", null) binding.confirm.setOnClickListener { - dismiss() + dismissAllowingStateLoss() } return binding.root } diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index 159afbed88..4f2d0ebbb5 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -19,6 +19,7 @@ import android.util.Log; import android.view.KeyEvent; import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; import androidx.lifecycle.ViewModelProviders; import com.gh.base.AppUncaughtHandler; @@ -71,6 +72,7 @@ import com.gh.gamecenter.eventbus.EBPackage; import com.gh.gamecenter.eventbus.EBReuse; import com.gh.gamecenter.eventbus.EBSkip; import com.gh.gamecenter.fragment.MainWrapperFragment; +import com.gh.gamecenter.gamedetail.GameDetailFragment; import com.gh.gamecenter.manager.DataCollectionManager; import com.gh.gamecenter.manager.UpdateManager; import com.gh.gamecenter.manager.UserManager; @@ -78,12 +80,14 @@ import com.gh.gamecenter.normal.NormalFragment; import com.gh.gamecenter.packagehelper.PackageRepository; import com.gh.gamecenter.packagehelper.PackageViewModel; import com.gh.gamecenter.qa.CommunityFragment; +import com.gh.gamecenter.retrofit.BiResponse; import com.gh.gamecenter.retrofit.EmptyResponse; import com.gh.gamecenter.retrofit.Response; import com.gh.gamecenter.retrofit.RetrofitManager; import com.gh.gamecenter.suggest.SuggestSelectFragment; import com.gh.gamecenter.suggest.SuggestType; import com.google.gson.Gson; +import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; import com.halo.assistant.HaloApp; import com.halo.assistant.fragment.SettingsFragment; @@ -96,6 +100,7 @@ import com.lightgame.utils.Utils; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; @@ -125,9 +130,11 @@ import static com.gh.common.util.EntranceUtils.HOST_QQ; import static com.gh.common.util.EntranceUtils.HOST_QQ_GROUP; import static com.gh.common.util.EntranceUtils.HOST_WEB; import static com.gh.common.util.EntranceUtils.KEY_DATA; +import static com.gh.common.util.EntranceUtils.KEY_MARKET_DETAILS; import static com.gh.common.util.EntranceUtils.KEY_NEXT_TO; import static com.gh.common.util.EntranceUtils.KEY_TO; import static com.gh.common.util.EntranceUtils.KEY_TYPE; +import static com.gh.common.util.ExtensionsKt.singleToMain; import static com.gh.gamecenter.fragment.MainWrapperFragment.INDEX_PERSONAL; import static com.gh.gamecenter.personal.PersonalFragment.LOGIN_TAG; import static com.gh.gamecenter.personal.PersonalFragment.LOGOUT_TAG; @@ -399,6 +406,9 @@ public class MainActivity extends BaseActivity { SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity); } break; + case KEY_MARKET_DETAILS: + redirectGameDetail(bundle.getString(KEY_DATA)); + break; } } } @@ -412,6 +422,28 @@ public class MainActivity extends BaseActivity { }, 500); } + /** + * 应用跳转 + * @param packageName + */ + @SuppressLint("CheckResult") + private void redirectGameDetail(String packageName) { + RetrofitManager.getInstance(this).getApi().redirectGameDetail(packageName) + .compose(singleToMain()) + .subscribe(new BiResponse() { + @Override + public void onSuccess(JsonObject data) { + String gameId = data.get("game_id").getAsString(); + DirectUtils.directToGameDetail(MainActivity.this, gameId, GameDetailFragment.INDEX_DESC, "应用跳转"); + } + + @Override + public void onFailure(@NotNull Exception exception) { + super.onFailure(exception); + } + }); + } + private void checkNotificationPermission() { // 仅登录后再启动光环时请求一次权限 if (UserManager.getInstance().isLoggedIn()) { @@ -713,184 +745,6 @@ public class MainActivity extends BaseActivity { } } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(EBPackage busFour) { - final String packageName = busFour.getPackageName(); - final String versionName = busFour.getVersionName(); - String gameId = ""; - - DownloadEntity mDownloadEntity = null; - for (DownloadEntity downloadEntity : DownloadManager.getInstance(getApplicationContext()).getAllDownloadEntity()) { - if (packageName.equals(downloadEntity.getPackageName())) { - mDownloadEntity = downloadEntity; - gameId = mDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER); - if (TextUtils.isEmpty(busFour.getVersionName())) { - // 没有版本号的事件直接选用第一个找到的 downloadEntity - break; - } else { - // 有版本号的事件直接尽量找到版本一致的 downloadEntity - if (versionName.equals(downloadEntity.getVersionName())) { - break; - } - } - } - } - - if ("安装".equals(busFour.getType())) { - mPackageViewModel.addInstalledGame(packageName); - - // 删除下载完成 弹窗 - NotificationManager nManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - nManager.cancel(packageName.hashCode()); - - if (mDownloadEntity != null) { - if (mDownloadEntity.isPluggable()) { - Map kv6 = new HashMap<>(); - kv6.put("安装或卸载", "安装完成"); - DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6); - -// DataUtils.onMtaEvent(this, -// "插件化_新", -// "位置", mDownloadEntity.getEntrance(), -// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(), -// "操作", "安装完成", -// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication())); - } - - // 没有光环 ID 的都记录一下游戏 ID,供'我的游戏'区分同包名不同插件用 - Object gh_id = PackageUtils.getMetaData(this, mDownloadEntity.getPackageName(), "gh_id"); - if (gh_id == null) { - ThirdPartyPackageHelper.saveGameId(mDownloadEntity.getPackageName(), mDownloadEntity.getGameId()); - } - DownloadManager.getInstance(getApplicationContext()).cancel( - mDownloadEntity.getUrl(), false, true); // 默认不删除安装包 mSp.getBoolean("autodelete", true) - } - - - if (mSp.getBoolean(SettingsFragment.CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注 - // 安装后关注游戏 - DownloadEntity finalDownloadEntity = mDownloadEntity; - RetrofitManager.getInstance(this).getSensitiveApi().getGameDigestByPackageName(UrlFilterUtils.getFilterQuery("package", packageName)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response>() { - @Override - public void onResponse(List response) { - for (GameDigestEntity gameDigestEntity : response) { - if (!TextUtils.isEmpty(gameDigestEntity.getId())) { // 关注游戏 - if (finalDownloadEntity != null && gameDigestEntity.getId().equals(finalDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER))) { - ConcernUtils.INSTANCE.postConcernGameId(MainActivity.this, gameDigestEntity.getId(), null, false); - } - } - } - } - }); - } - - postNewlyInstalledApp(gameId, packageName); - } - if ("卸载".equals(busFour.getType())) { - mPackageViewModel.addUninstalledGame(packageName); - - if (mDownloadEntity != null && mDownloadEntity.isPluggable()) { - Map kv6 = new HashMap<>(); - kv6.put("安装或卸载", "卸载完成"); - DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6); - -// DataUtils.onMtaEvent(this, -// "插件化_新", -// "位置", mDownloadEntity.getEntrance(), -// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(), -// "操作", "卸载完成", -// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication())); - - PackageInstaller.install(this, mDownloadEntity); - } - - // 更新已安装游戏 - deleteInstalledPackage(packageName); - } - - DataCollectionUtils.uploadInorunstall(this, busFour.getType(), busFour.getPackageName()); - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - @SuppressLint("CheckResult") - private void postNewlyInstalledApp(String gameId, String packageName) { - - // 发送应用变更前都检查一下是否需要把所有应用都上传 - PackageRepository.checkAndUploadAppList(); - - // 更新已安装游戏 - JSONObject packageObject = PackageUtils.getAppBasicInfoByPackageName(packageName); - JSONObject dataObject = new JSONObject(); - JSONObject wrapperObject = new JSONObject(); - try { - dataObject.put("type", "POST"); - dataObject.put("device_id", HaloApp.getInstance().getGid()); - dataObject.put("app", packageObject); - dataObject.put("time", Utils.getTime(getApplicationContext())); - wrapperObject.put("content", dataObject.toString()); - } catch (JSONException e) { - e.printStackTrace(); - } - LoghubUtils.log(wrapperObject, "halo-api-device-installed", true); - - RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), - packageObject.toString()); - // 更新已安装游戏 - RetrofitManager.getInstance(MainActivity.this).getApi() - .postNewlyInstalledApp(HaloApp.getInstance().getGid(), requestBody) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) - .subscribe(new EmptyResponse<>()); - - if (!TextUtils.isEmpty(gameId) && UserManager.getInstance().isLoggedIn()) { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("game_id", gameId); - jsonObject.put("package", packageName); - RequestBody rBody = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString()); - - RetrofitManager.getInstance(MainActivity.this).getApi() - .postPlayedGame(UserManager.getInstance().getUserId(), rBody) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) - .subscribe(new EmptyResponse<>()); - } catch (JSONException e) { - e.printStackTrace(); - } - } - } - - @SuppressLint("CheckResult") - private void deleteInstalledPackage(String packageName) { - - // 发送应用变更前都检查一下是否需要把所有应用都上传 - PackageRepository.checkAndUploadAppList(); - - // 删除已安装游戏 - JSONObject dataObject = new JSONObject(); - JSONObject wrapperObject = new JSONObject(); - try { - dataObject.put("type", "DELETE"); - dataObject.put("device_id", HaloApp.getInstance().getGid()); - dataObject.put("package", packageName); - dataObject.put("time", Utils.getTime(getApplicationContext())); - wrapperObject.put("content", dataObject.toString()); - } catch (JSONException e) { - e.printStackTrace(); - } - LoghubUtils.log(wrapperObject, "halo-api-device-installed", true); - - // 删除已安装游戏 - RetrofitManager.getInstance(MainActivity.this).getApi() - .deleteInstalledApp(HaloApp.getInstance().getGid(), packageName) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) - .subscribe(new EmptyResponse<>()); - } - // 接收登录和登出更新事件统计的 Meta @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(EBReuse reuse) { diff --git a/app/src/main/java/com/gh/gamecenter/SearchActivity.kt b/app/src/main/java/com/gh/gamecenter/SearchActivity.kt index c9f50a1f7a..a024fb45b6 100644 --- a/app/src/main/java/com/gh/gamecenter/SearchActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/SearchActivity.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.text.TextUtils import android.view.View import android.view.inputmethod.EditorInfo +import android.widget.EditText import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doOnTextChanged import com.gh.base.BaseActivity @@ -21,12 +22,15 @@ import com.lightgame.utils.Util_System_Keyboard import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.subjects.PublishSubject import kotlinx.android.synthetic.main.toolbar_search.* +import kotterknife.bindView import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import java.util.concurrent.TimeUnit open class SearchActivity : BaseActivity() { + private val searchEt by bindView(R.id.searchEt) + private var mDao: SearchHistoryDao? = null protected var mSearchKey: String? = null @@ -53,6 +57,7 @@ open class SearchActivity : BaseActivity() { super.onCreate(savedInstanceState) val hint = intent.getStringExtra(EntranceUtils.KEY_HINT) val searchImmediately = intent.getBooleanExtra(KEY_SEARCH_IMMEDIATELY, false) + var ignoreTextChanges = savedInstanceState != null mDao = SearchHistoryDao(this) mPublishSubject = PublishSubject.create() @@ -62,21 +67,27 @@ open class SearchActivity : BaseActivity() { .distinctUntilChanged() .observeOn(AndroidSchedulers.mainThread()) .subscribe { - if (searchEt.text.isNotEmpty()) { + if (searchEt.text.isNotEmpty() + && searchEt.text != searchEt.hint + && !ignoreTextChanges) { search(SearchType.AUTO, it) } + + ignoreTextChanges = false } initSearchBar() - if (savedInstanceState != null) { - mDisplayType = DisplayType.fromInt(savedInstanceState.getInt(KEY_DISPLAY_TYPE, 0)) - mSearchKey = savedInstanceState.getString(EntranceUtils.KEY_SEARCHKEY, null) - mSearchType = SearchType.fromString(savedInstanceState.getString(KEY_SEARCH_TYPE, null)) - if (mDisplayType != DisplayType.DEFAULT && !TextUtils.isEmpty(mSearchKey)) { - search(mSearchType, mSearchKey) - } - } else if (!TextUtils.isEmpty(hint)) { + // 子 Fragment 自己恢复状态 +// if (savedInstanceState != null) { +// mDisplayType = DisplayType.fromInt(savedInstanceState.getInt(KEY_DISPLAY_TYPE, 0)) +// mSearchKey = savedInstanceState.getString(EntranceUtils.KEY_SEARCHKEY, null) +// mSearchType = SearchType.fromString(savedInstanceState.getString(KEY_SEARCH_TYPE, null)) +// if (mDisplayType != DisplayType.DEFAULT && !TextUtils.isEmpty(mSearchKey)) { +// search(mSearchType, mSearchKey) +// } +// } else + if (!TextUtils.isEmpty(hint)) { searchEt.hint = hint if (searchImmediately) { mDisplayType = GAME_DETAIL @@ -87,7 +98,8 @@ open class SearchActivity : BaseActivity() { searchEt.hint = "搜索游戏..." } - if (mDisplayType == DisplayType.DEFAULT) { + if (savedInstanceState == null + && mDisplayType == DisplayType.DEFAULT) { updateDisplayType(DisplayType.DEFAULT) } } @@ -233,7 +245,7 @@ open class SearchActivity : BaseActivity() { } companion object { - private const val KEY_SEARCH_TYPE = "search_type" + const val KEY_SEARCH_TYPE = "search_type" private const val KEY_DISPLAY_TYPE = "display_type" private const val KEY_SEARCH_IMMEDIATELY = "search_immediately" @@ -274,11 +286,13 @@ enum class SearchType(var value: String) { * [DEFAULT] 默认搜索页 * [GAME_DIGEST] 游戏为部分文字样式的列表 * [GAME_DETAIL] 游戏全为标准样式的列表 + * [FORUM_OR_USER] 论坛内容和用户 */ enum class DisplayType(var value: Int) { DEFAULT(0), GAME_DIGEST(1), - GAME_DETAIL(2); + GAME_DETAIL(2), + FORUM_OR_USER(3); companion object { fun fromInt(typeInt: Int) = values().find { typeInt == it.value } ?: DEFAULT diff --git a/app/src/main/java/com/gh/gamecenter/ShareGhActivity.java b/app/src/main/java/com/gh/gamecenter/ShareGhActivity.java index f2685599d7..cc53b812b1 100644 --- a/app/src/main/java/com/gh/gamecenter/ShareGhActivity.java +++ b/app/src/main/java/com/gh/gamecenter/ShareGhActivity.java @@ -1,6 +1,5 @@ package com.gh.gamecenter; -import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -10,15 +9,16 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.annotation.NonNull; + import com.gh.base.ToolBarActivity; +import com.gh.common.util.ExtensionsKt; import com.gh.common.util.MessageShareUtils; import com.gh.common.util.MtaHelper; import com.gh.common.util.QRCodeUtils; import com.gh.common.util.ShareUtils; -import com.lightgame.utils.Utils; import com.tencent.tauth.Tencent; -import androidx.annotation.NonNull; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; @@ -73,9 +73,6 @@ public class ShareGhActivity extends ToolBarActivity { @OnClick(R.id.gh_address_tv) public void copyAddress() { MtaHelper.onEvent("我的光环_新", "分享光环", "复制官网"); - ClipboardManager cmb = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); - cmb.setText(getString(R.string.gh_website_url_100)); - - Utils.toast(this, "网址复制成功,请到微信/QQ粘贴分享"); + ExtensionsKt.copyTextAndToast(getString(R.string.gh_website_url_100), "网址复制成功,请到微信/QQ粘贴分享"); } } diff --git a/app/src/main/java/com/gh/gamecenter/SkipActivity.java b/app/src/main/java/com/gh/gamecenter/SkipActivity.java index e2e0af420f..0f7231a3e1 100644 --- a/app/src/main/java/com/gh/gamecenter/SkipActivity.java +++ b/app/src/main/java/com/gh/gamecenter/SkipActivity.java @@ -80,310 +80,325 @@ public class SkipActivity extends BaseActivity { Uri uri = getIntent().getData(); Bundle bundle; if (uri != null) { - if (CommonDebug.IS_DEBUG) { - Utils.log("SkipActivity:: Uri=>" + uri.toString()); - } - String host = uri.getHost(); - String path = uri.getPath(); + if ("ghzhushou".equals(uri.getScheme())) { + if (CommonDebug.IS_DEBUG) { + Utils.log("SkipActivity:: Uri=>" + uri.toString()); + } + String host = uri.getHost(); + String path = uri.getPath(); - String to = uri.getQueryParameter("to"); - String type = uri.getQueryParameter("type"); - String name = uri.getQueryParameter("name"); - String referer = uri.getQueryParameter("referer"); - String id = uri.getQueryParameter("id"); - if (!TextUtils.isEmpty(path)) { - path = path.substring(1); - } + String to = uri.getQueryParameter("to"); + String type = uri.getQueryParameter("type"); + String name = uri.getQueryParameter("name"); + String referer = uri.getQueryParameter("referer"); + String id = uri.getQueryParameter("id"); + if (!TextUtils.isEmpty(path)) { + path = path.substring(1); + } - if (host != null) { - Intent intent; - switch (host) { - case HOST_ARTICLE: - DirectUtils.directToArticle(this, path, ENTRANCE_BROWSER); - break; - case HOST_GAME: - DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, "true".equals(uri.getQueryParameter("auto_download")), to, null); - break; - case HOST_COLUMN: - DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER); - break; - case HOST_SUGGESTION: - String platform = uri.getQueryParameter(KEY_PLATFORM); - String platformName = PlatformUtils.getInstance(this).getPlatformName(platform); - String gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID); - String packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5); - String content = (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) ? - String.format("%s-%s-V%s,", - uri.getQueryParameter(KEY_GAME_NAME), - TextUtils.isEmpty(platformName) ? platform : platformName, - uri.getQueryParameter(KEY_VERSION)) : - String.format("%s-%s-V%s\n游戏ID:%s\n游戏包MD5:%s\n", - uri.getQueryParameter(KEY_GAME_NAME), - TextUtils.isEmpty(platformName) ? platform : platformName, - uri.getQueryParameter(KEY_VERSION), gameId, packageMd5); - String qaId = uri.getQueryParameter("qa_id"); - String qaTitle = uri.getQueryParameter(EntranceUtils.KEY_QA_TITLE); - if (!TextUtils.isEmpty(qaId)) { - DirectUtils.directToQa(this, qaTitle, qaId); - } else { - DirectUtils.directToFeedback(this, content, ENTRANCE_BROWSER); - } - break; - case HOST_DOWNLOAD: - DirectUtils.directToDownloadManagerAndStartUpdate(this, path, uri.getQueryParameter(KEY_PACKAGENAME), ENTRANCE_BROWSER); - break; - case HOST_ANSWER: - DirectUtils.directToAnswerDetail(this, path, ENTRANCE_BROWSER, "浏览器"); - break; - case HOST_QUESTION: - DirectUtils.directToQuestionDetail(this, path, ENTRANCE_BROWSER, "浏览器"); - break; - case HOST_TOOLBOX: - DirectUtils.directToToolbox(this, uri.getQueryParameter("gameId"), uri.getQueryParameter("toolboxUrl"), ENTRANCE_BROWSER); - break; - case HOST_COMMUNITY: - UserManager.getInstance().setCommunityData(new CommunityEntity(path, name)); - // 把切换放到 MainActivity 处理 - if (RunningUtils.isRunning(this) - && MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) { - intent = new Intent(this, MainActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtra(MainActivity.SWITCH_TO_COMMUNITY, true); - } else { - bundle = new Bundle(); - bundle.putBoolean(MainActivity.SWITCH_TO_COMMUNITY, true); - intent = SplashScreenActivity.getSplashScreenIntent(this, bundle); - } - startActivity(intent); - break; - // 社区文章格式一 - case "community.article": - DirectUtils.directToCommunityArticle(this, uri.getQueryParameter("articleId"), uri.getQueryParameter("communityId"), ENTRANCE_BROWSER, "浏览器"); - break; - // 社区文章格式二 - case "communities": - String communityId = ""; - String typeId = ""; - String[] split = path.split("/"); - for (String text : split) { - if (TextUtils.isEmpty(communityId)) { - communityId = text; - continue; - } - if (TextUtils.isEmpty(type)) { - type = text; - continue; - } - if (TextUtils.isEmpty(typeId)) { - typeId = text; - } - } - if ("articles".equals(type)) { - DirectUtils.directToCommunityArticle(this, typeId, communityId, ENTRANCE_BROWSER, "浏览器"); + if (host != null) { + Intent intent; + switch (host) { + case HOST_ARTICLE: + DirectUtils.directToArticle(this, path, ENTRANCE_BROWSER); break; - } - break; - case HOST_VIDEO: - DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.HOTTEST_GAME_VIDEO.getValue(), - false, id, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer); - break; - case HOST_UPLOAD_VIDEO://跳转上传视频 - String titleParameter = uri.getQueryParameter("title"); - String title = TextUtils.isEmpty(titleParameter) ? "" : "#" + titleParameter + "#"; - String categoryId = uri.getQueryParameter("category_id"); - String link = uri.getQueryParameter("link"); - gameId = uri.getQueryParameter("gameId"); - String gameName = uri.getQueryParameter("gameName"); - String tagActivityId = uri.getQueryParameter("tagActivityId"); - String tagActivityName = uri.getQueryParameter("tagActivityName"); - VideoLinkEntity linkEntity = new VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName); - - SimpleGameEntity simpleGameEntity = new SimpleGameEntity(gameId != null ? gameId : "", gameName != null ? gameName : "", ""); - Bundle nextToBundle = VideoManagerActivity.getVideoManagerBundle(linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, ""); - CheckLoginUtils.checkLogin(this, nextToBundle, true, EntranceUtils.ENTRANCE_BROWSER, () -> - DirectUtils.directToVideoManager(SkipActivity.this, linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "浏览器")); - break; - case HOST_VIDEO_SINGLE: - DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.getValue(), - false, "", ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer); - break; - case HOST_VIDEO_MORE: - gameId = uri.getQueryParameter("gameId"); - String act = uri.getQueryParameter("act"); - String fieldId = uri.getQueryParameter("fieldId"); - String sectionName = uri.getQueryParameter("sectionName"); - String paginationType = uri.getQueryParameter("paginationType");//活动分页方式 page filter - String location; - if (!TextUtils.isEmpty(act)) { - location = VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.getValue(); - } else if (!TextUtils.isEmpty(fieldId)) { - location = VideoDetailContainerViewModel.Location.GAME_ZONE.getValue(); - } else { - location = path; - } - DirectUtils.directToVideoDetail(this, path, location, - false, TextUtils.isEmpty(gameId) ? "" : gameId, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer, - TextUtils.isEmpty(type) ? "" : type, TextUtils.isEmpty(act) ? "" : act, TextUtils.isEmpty(paginationType) ? "page" : paginationType, TextUtils.isEmpty(fieldId) ? "" : fieldId, - TextUtils.isEmpty(sectionName) ? "" : sectionName); - break; - case HOST_VIDEO_STREAMING_HOME: - // 把切换放到 MainActivity 处理 - if (RunningUtils.isRunning(this) - && MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) { - intent = new Intent(this, MainActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true); - } else { - bundle = new Bundle(); - bundle.putBoolean(MainActivity.SWITCH_TO_VIDEO, true); - intent = SplashScreenActivity.getSplashScreenIntent(this, bundle); - } - startActivity(intent); - break; - case HOST_VIDEO_STREAMING_DESC: - DirectUtils.directToGameDetailVideoStreaming(this, path, ENTRANCE_BROWSER); - break; - case HOST_VIDEO_COLLECTION: - DirectUtils.directToGameVideo(this, path, ENTRANCE_BROWSER, "浏览器"); - break; - case HOST_QQ: - bundle = new Bundle(); - bundle.putString(KEY_TO, HOST_QQ); - bundle.putString(KEY_DATA, path); - EntranceUtils.jumpActivity(this, bundle); - break; - case HOST_QQ_GROUP: - bundle = new Bundle(); - bundle.putString(KEY_TO, HOST_QQ_GROUP); - bundle.putString(KEY_DATA, path); - EntranceUtils.jumpActivity(this, bundle); - break; - case HOST_QQ_QUN: - String key = uri.getQueryParameter("key"); - bundle = new Bundle(); - bundle.putString(KEY_TO, HOST_QQ_GROUP); - bundle.putString(KEY_DATA, key); - EntranceUtils.jumpActivity(this, bundle); - break; - case HOST_WEB: - bundle = new Bundle(); - bundle.putString(KEY_TO, HOST_WEB); - bundle.putString(KEY_DATA, to); - bundle.putString(KEY_TYPE, type); - EntranceUtils.jumpActivity(this, bundle); - break; - case HOST_LIBAO: - DirectUtils.directToGiftDetail(this, path, ENTRANCE_BROWSER); - break; - case HOST_USERHOME: - String position = uri.getQueryParameter("position"); - DirectUtils.directToHomeActivity(this, path, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器"); - break; - case HOST_COMMUNITY_COLUMN: - CommunityEntity community = new CommunityEntity(); - community.setId(uri.getQueryParameter("community_id")); - community.setName(uri.getQueryParameter("community_name")); - String columnId = uri.getQueryParameter("column_id"); - DirectUtils.directToCommunityColumn(this, community, columnId, ENTRANCE_BROWSER, ""); - break; - - case HOST_CATEGORY: - title = uri.getQueryParameter("title"); - DirectUtils.directCategoryDirectory(this, path, title, ENTRANCE_BROWSER, "浏览器"); - break; - case HOST_COLUMN_COLLECTION: - DirectUtils.directToColumnCollection(this, path, -1, ENTRANCE_BROWSER, "浏览器"); - break; - case HOST_COMMUNITY_QUESTION_LABEL_DETAIL: - community = new CommunityEntity(); - community.setId(uri.getQueryParameter("community_id")); - community.setName(uri.getQueryParameter("community_name")); - String tag = uri.getQueryParameter("tag"); - DirectUtils.directAskColumnLabelDetail(this, tag, community, ENTRANCE_BROWSER, "浏览器"); - break; - case HOST_COMMUNITY_COLUMN_DETAIL: - community = new CommunityEntity(); - community.setId(uri.getQueryParameter("community_id")); - community.setName(uri.getQueryParameter("community_name")); - columnId = uri.getQueryParameter("column_id"); - DirectUtils.directAskColumnDetail(this, columnId, community, ENTRANCE_BROWSER, "浏览器"); - break; - case EntranceUtils.HOST_BLOCK: - name = uri.getQueryParameter("name"); - SubjectRecommendEntity entity = new SubjectRecommendEntity(); - entity.setLink(path); - entity.setName(name); - entity.setText(name); - DirectUtils.directToBlock(this, entity, mEntrance); - break; - - case EntranceUtils.HOST_SERVER_BLOCK: - DirectUtils.directToGameServers(this, ENTRANCE_BROWSER, "浏览器"); - break; - - case EntranceUtils.HOST_AMWAY_BLOCK: - DirectUtils.directToAmway(this, null, ENTRANCE_BROWSER, "浏览器"); - break; - - case EntranceUtils.HOST_HELP: - name = uri.getQueryParameter("name"); - DirectUtils.directToQa(this, name, path); - break; - - case EntranceUtils.HOST_HELP_COLLECTION: - name = uri.getQueryParameter("name"); - DirectUtils.directToQaCollection(this, name, path); - break; - case EntranceUtils.HOST_GAME_UPLOAD: - DirectUtils.directGameUpload(this, ENTRANCE_BROWSER, "浏览器"); - break; - case EntranceUtils.HOST_GAME_ZONE: - String zoneUrl = uri.getQueryParameter("url"); - DirectUtils.directGameZone(this, path, zoneUrl, ENTRANCE_BROWSER); - break; - case EntranceUtils.HOST_LINK: - try { - String dataString = uri.getQueryParameter("data"); - if (!TextUtils.isEmpty(dataString)) { - byte[] linkData = Base64.decode(dataString, Base64.DEFAULT); - String linkDataString = new String(linkData, "UTF-8"); - LinkEntity le = GsonUtils.INSTANCE.getGson().fromJson(linkDataString, LinkEntity.class); - DirectUtils.directToLinkPage(this, le, ENTRANCE_BROWSER, ""); + case HOST_GAME: + DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, "true".equals(uri.getQueryParameter("auto_download")), to, null); + break; + case HOST_COLUMN: + DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER); + break; + case HOST_SUGGESTION: + String platform = uri.getQueryParameter(KEY_PLATFORM); + String platformName = PlatformUtils.getInstance(this).getPlatformName(platform); + String gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID); + String packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5); + String content = (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) ? + String.format("%s-%s-V%s,", + uri.getQueryParameter(KEY_GAME_NAME), + TextUtils.isEmpty(platformName) ? platform : platformName, + uri.getQueryParameter(KEY_VERSION)) : + String.format("%s-%s-V%s\n游戏ID:%s\n游戏包MD5:%s\n", + uri.getQueryParameter(KEY_GAME_NAME), + TextUtils.isEmpty(platformName) ? platform : platformName, + uri.getQueryParameter(KEY_VERSION), gameId, packageMd5); + String qaId = uri.getQueryParameter("qa_id"); + String qaTitle = uri.getQueryParameter(EntranceUtils.KEY_QA_TITLE); + if (!TextUtils.isEmpty(qaId)) { + DirectUtils.directToQa(this, qaTitle, qaId); + } else { + DirectUtils.directToFeedback(this, content, ENTRANCE_BROWSER); } - } catch (Exception e) { - e.printStackTrace(); - toast(e.getMessage()); - } - break; - case EntranceUtils.HOST_GAME_NEWS: - DirectUtils.directToGameNews( - this, - uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), - uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME), - EntranceUtils.ENTRANCE_BROWSER); - break; - case EntranceUtils.HOST_GAME_CALENDAR: - DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID)); - break; - case EntranceUtils.HOST_HISTORY_APK: - DirectUtils.directToHistoryApk(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID)); - break; - case EntranceUtils.HOST_FORUM_DETAIL: - DirectUtils.directForumDetail(this, id, ENTRANCE_BROWSER); - break; - case EntranceUtils.HOST_GAME_RATING_DETAIL: - DirectUtils.directToGameRatingDetail(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), ENTRANCE_BROWSER); - break; - case EntranceUtils.HOST_FORUM: - DirectUtils.directToForum(this); - break; - case EntranceUtils.HOST_HELP_AND_FEEDBACK: - position = uri.getQueryParameter("position"); - DirectUtils.directToHelpAndFeedback(this, TextUtils.isEmpty(position) ? 0 : Integer.parseInt(position)); - break; - default: + break; + case HOST_DOWNLOAD: + DirectUtils.directToDownloadManagerAndStartUpdate(this, path, uri.getQueryParameter(KEY_PACKAGENAME), ENTRANCE_BROWSER); + break; + case HOST_ANSWER: + DirectUtils.directToAnswerDetail(this, path, ENTRANCE_BROWSER, "浏览器"); + break; + case HOST_QUESTION: + DirectUtils.directToQuestionDetail(this, path, ENTRANCE_BROWSER, "浏览器"); + break; + case HOST_TOOLBOX: + DirectUtils.directToToolbox(this, uri.getQueryParameter("gameId"), uri.getQueryParameter("toolboxUrl"), ENTRANCE_BROWSER); + break; + case HOST_COMMUNITY: + UserManager.getInstance().setCommunityData(new CommunityEntity(path, name)); + // 把切换放到 MainActivity 处理 + if (RunningUtils.isRunning(this) + && MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) { + intent = new Intent(this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.putExtra(MainActivity.SWITCH_TO_COMMUNITY, true); + } else { + bundle = new Bundle(); + bundle.putBoolean(MainActivity.SWITCH_TO_COMMUNITY, true); + intent = SplashScreenActivity.getSplashScreenIntent(this, bundle); + } + startActivity(intent); + break; + // 社区文章格式一 + case "community.article": + DirectUtils.directToCommunityArticle(this, uri.getQueryParameter("articleId"), uri.getQueryParameter("communityId"), ENTRANCE_BROWSER, "浏览器"); + break; + // 社区文章格式二 + case "communities": + String communityId = ""; + String typeId = ""; + String[] split = path.split("/"); + for (String text : split) { + if (TextUtils.isEmpty(communityId)) { + communityId = text; + continue; + } + if (TextUtils.isEmpty(type)) { + type = text; + continue; + } + if (TextUtils.isEmpty(typeId)) { + typeId = text; + } + } + if ("articles".equals(type)) { + DirectUtils.directToCommunityArticle(this, typeId, communityId, ENTRANCE_BROWSER, "浏览器"); + break; + } + break; + case HOST_VIDEO: + DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.HOTTEST_GAME_VIDEO.getValue(), + false, id, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer); + break; + case HOST_UPLOAD_VIDEO://跳转上传视频 + String titleParameter = uri.getQueryParameter("title"); + String title = TextUtils.isEmpty(titleParameter) ? "" : "#" + titleParameter + "#"; + String categoryId = uri.getQueryParameter("category_id"); + String link = uri.getQueryParameter("link"); + gameId = uri.getQueryParameter("gameId"); + String gameName = uri.getQueryParameter("gameName"); + String tagActivityId = uri.getQueryParameter("tagActivityId"); + String tagActivityName = uri.getQueryParameter("tagActivityName"); + VideoLinkEntity linkEntity = new VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName); + + SimpleGameEntity simpleGameEntity = new SimpleGameEntity(gameId != null ? gameId : "", gameName != null ? gameName : "", ""); + Bundle nextToBundle = VideoManagerActivity.getVideoManagerBundle(linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, ""); + CheckLoginUtils.checkLogin(this, nextToBundle, true, EntranceUtils.ENTRANCE_BROWSER, () -> + DirectUtils.directToVideoManager(SkipActivity.this, linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "浏览器")); + break; + case HOST_VIDEO_SINGLE: + DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.getValue(), + false, "", ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer); + break; + case HOST_VIDEO_MORE: + gameId = uri.getQueryParameter("gameId"); + String act = uri.getQueryParameter("act"); + String fieldId = uri.getQueryParameter("fieldId"); + String sectionName = uri.getQueryParameter("sectionName"); + String paginationType = uri.getQueryParameter("paginationType");//活动分页方式 page filter + String location; + if (!TextUtils.isEmpty(act)) { + location = VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.getValue(); + } else if (!TextUtils.isEmpty(fieldId)) { + location = VideoDetailContainerViewModel.Location.GAME_ZONE.getValue(); + } else { + location = path; + } + DirectUtils.directToVideoDetail(this, path, location, + false, TextUtils.isEmpty(gameId) ? "" : gameId, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer, + TextUtils.isEmpty(type) ? "" : type, TextUtils.isEmpty(act) ? "" : act, TextUtils.isEmpty(paginationType) ? "page" : paginationType, TextUtils.isEmpty(fieldId) ? "" : fieldId, + TextUtils.isEmpty(sectionName) ? "" : sectionName); + break; + case HOST_VIDEO_STREAMING_HOME: + // 把切换放到 MainActivity 处理 + if (RunningUtils.isRunning(this) + && MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) { + intent = new Intent(this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true); + } else { + bundle = new Bundle(); + bundle.putBoolean(MainActivity.SWITCH_TO_VIDEO, true); + intent = SplashScreenActivity.getSplashScreenIntent(this, bundle); + } + startActivity(intent); + break; + case HOST_VIDEO_STREAMING_DESC: + DirectUtils.directToGameDetailVideoStreaming(this, path, ENTRANCE_BROWSER); + break; + case HOST_VIDEO_COLLECTION: + DirectUtils.directToGameVideo(this, path, ENTRANCE_BROWSER, "浏览器"); + break; + case HOST_QQ: + bundle = new Bundle(); + bundle.putString(KEY_TO, HOST_QQ); + bundle.putString(KEY_DATA, path); + EntranceUtils.jumpActivity(this, bundle); + break; + case HOST_QQ_GROUP: + bundle = new Bundle(); + bundle.putString(KEY_TO, HOST_QQ_GROUP); + bundle.putString(KEY_DATA, path); + EntranceUtils.jumpActivity(this, bundle); + break; + case HOST_QQ_QUN: + String key = uri.getQueryParameter("key"); + bundle = new Bundle(); + bundle.putString(KEY_TO, HOST_QQ_GROUP); + bundle.putString(KEY_DATA, key); + EntranceUtils.jumpActivity(this, bundle); + break; + case HOST_WEB: + bundle = new Bundle(); + bundle.putString(KEY_TO, HOST_WEB); + bundle.putString(KEY_DATA, to); + bundle.putString(KEY_TYPE, type); + EntranceUtils.jumpActivity(this, bundle); + break; + case HOST_LIBAO: + DirectUtils.directToGiftDetail(this, path, ENTRANCE_BROWSER); + break; + case HOST_USERHOME: + String position = uri.getQueryParameter("position"); + DirectUtils.directToHomeActivity(this, path, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器"); + break; + case HOST_COMMUNITY_COLUMN: + CommunityEntity community = new CommunityEntity(); + community.setId(uri.getQueryParameter("community_id")); + community.setName(uri.getQueryParameter("community_name")); + String columnId = uri.getQueryParameter("column_id"); + DirectUtils.directToCommunityColumn(this, community, columnId, ENTRANCE_BROWSER, ""); + break; + + case HOST_CATEGORY: + title = uri.getQueryParameter("title"); + DirectUtils.directCategoryDirectory(this, path, title, ENTRANCE_BROWSER, "浏览器"); + break; + case HOST_COLUMN_COLLECTION: + DirectUtils.directToColumnCollection(this, path, -1, ENTRANCE_BROWSER, "浏览器"); + break; + case HOST_COMMUNITY_QUESTION_LABEL_DETAIL: + community = new CommunityEntity(); + community.setId(uri.getQueryParameter("community_id")); + community.setName(uri.getQueryParameter("community_name")); + String tag = uri.getQueryParameter("tag"); + DirectUtils.directAskColumnLabelDetail(this, tag, community, ENTRANCE_BROWSER, "浏览器"); + break; + case HOST_COMMUNITY_COLUMN_DETAIL: + community = new CommunityEntity(); + community.setId(uri.getQueryParameter("community_id")); + community.setName(uri.getQueryParameter("community_name")); + columnId = uri.getQueryParameter("column_id"); + DirectUtils.directAskColumnDetail(this, columnId, community, ENTRANCE_BROWSER, "浏览器"); + break; + case EntranceUtils.HOST_BLOCK: + name = uri.getQueryParameter("name"); + SubjectRecommendEntity entity = new SubjectRecommendEntity(); + entity.setLink(path); + entity.setName(name); + entity.setText(name); + DirectUtils.directToBlock(this, entity, mEntrance); + break; + + case EntranceUtils.HOST_SERVER_BLOCK: + DirectUtils.directToGameServers(this, ENTRANCE_BROWSER, "浏览器"); + break; + + case EntranceUtils.HOST_AMWAY_BLOCK: + DirectUtils.directToAmway(this, null, ENTRANCE_BROWSER, "浏览器"); + break; + + case EntranceUtils.HOST_HELP: + name = uri.getQueryParameter("name"); + DirectUtils.directToQa(this, name, path); + break; + + case EntranceUtils.HOST_HELP_COLLECTION: + name = uri.getQueryParameter("name"); + DirectUtils.directToQaCollection(this, name, path); + break; + case EntranceUtils.HOST_GAME_UPLOAD: + DirectUtils.directGameUpload(this, ENTRANCE_BROWSER, "浏览器"); + break; + case EntranceUtils.HOST_GAME_ZONE: + String zoneUrl = uri.getQueryParameter("url"); + DirectUtils.directGameZone(this, path, zoneUrl, ENTRANCE_BROWSER); + break; + case EntranceUtils.HOST_LINK: + try { + String dataString = uri.getQueryParameter("data"); + if (!TextUtils.isEmpty(dataString)) { + byte[] linkData = Base64.decode(dataString, Base64.DEFAULT); + String linkDataString = new String(linkData, "UTF-8"); + LinkEntity le = GsonUtils.INSTANCE.getGson().fromJson(linkDataString, LinkEntity.class); + DirectUtils.directToLinkPage(this, le, ENTRANCE_BROWSER, ""); + } + } catch (Exception e) { + e.printStackTrace(); + toast(e.getMessage()); + } + break; + case EntranceUtils.HOST_GAME_NEWS: + DirectUtils.directToGameNews( + this, + uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), + uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME), + EntranceUtils.ENTRANCE_BROWSER); + break; + case EntranceUtils.HOST_GAME_CALENDAR: + DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID)); + break; + case EntranceUtils.HOST_HISTORY_APK: + DirectUtils.directToHistoryApk(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID)); + break; + case EntranceUtils.HOST_FORUM_DETAIL: + DirectUtils.directForumDetail(this, id, ENTRANCE_BROWSER); + break; + case EntranceUtils.HOST_GAME_RATING_DETAIL: + DirectUtils.directToGameRatingDetail(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), ENTRANCE_BROWSER); + break; + case EntranceUtils.HOST_FORUM: + DirectUtils.directToForum(this); + break; + case EntranceUtils.HOST_HELP_AND_FEEDBACK: + position = uri.getQueryParameter("position"); + DirectUtils.directToHelpAndFeedback(this, TextUtils.isEmpty(position) ? 0 : Integer.parseInt(position)); + break; + default: + EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页 + return; + } + } + } else if ("market".equals(uri.getScheme())) { + String host = uri.getHost(); + String id = uri.getQueryParameter("id"); + if (host != null) { + if ("details".equals(host)) { + bundle = new Bundle(); + bundle.putString(KEY_TO, EntranceUtils.KEY_MARKET_DETAILS); + bundle.putString(KEY_DATA, id); + EntranceUtils.jumpActivity(this, bundle); + } else { EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页 - return; + } } } } diff --git a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java index e846cf6cbb..6ddb9be05c 100644 --- a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java +++ b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java @@ -2,6 +2,7 @@ package com.gh.gamecenter; import android.Manifest; import android.annotation.SuppressLint; +import android.app.Application; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -15,6 +16,12 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; + import com.g00fy2.versioncompare.Version; import com.gh.base.BaseActivity; import com.gh.common.AppExecutor; @@ -23,6 +30,7 @@ import com.gh.common.constant.Constants; import com.gh.common.dialog.PrivacyDialogFragment; import com.gh.common.util.DataUtils; import com.gh.common.util.DeviceTokenUtils; +import com.gh.common.util.DeviceUtils; import com.gh.common.util.DialogUtils; import com.gh.common.util.EmptyCallback; import com.gh.common.util.GameSubstituteRepositoryHelper; @@ -32,7 +40,6 @@ import com.gh.common.util.PackageUtils; import com.gh.common.util.PlatformUtils; import com.gh.common.util.SPUtils; import com.gh.common.util.TagUtils; -import com.gh.common.util.TeaHelper; import com.gh.common.util.UsageStatsHelper; import com.gh.download.DownloadManager; import com.gh.gamecenter.entity.AuthDialogEntity; @@ -50,17 +57,14 @@ import org.jetbrains.annotations.NotNull; import org.json.JSONObject; import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.app.ActivityCompat; -import androidx.viewpager.widget.PagerAdapter; -import androidx.viewpager.widget.ViewPager; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import okhttp3.ResponseBody; @@ -74,7 +78,8 @@ public class SplashScreenActivity extends BaseActivity { private SharedPreferences mSharedPreferences; - private boolean isNewFirstLaunch; + private boolean mIsNewForThisVersion; + private boolean mStartMainActivityDirectly = false; // 是否不需要用户点击立即体验就直接跳转首页 private static final int REQUEST_PERMISSION_TAG = 30001; private String[] mPermissions = { @@ -94,7 +99,7 @@ public class SplashScreenActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - isNewFirstLaunch = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true); + mIsNewForThisVersion = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true); super.onCreate(savedInstanceState); @@ -105,13 +110,14 @@ public class SplashScreenActivity extends BaseActivity { } // 判断是不是这个版本的新用户 - if (isNewFirstLaunch) { + if (mIsNewForThisVersion) { mContentView.setPadding(0, 0, 0, 0); ViewPager guideLayout = findViewById(R.id.splash_intro_vp_guide); guideLayout.setAdapter(new GuidePagerAdapter()); // 判断是不是光环的新用户 if (SPUtils.getBoolean(Constants.SP_BRAND_NEW_USER, true)) { + mStartMainActivityDirectly = true; SPUtils.setLong(Constants.SP_INITIAL_USAGE_TIME, System.currentTimeMillis()); HaloApp.getInstance().isBrandNewInstall = true; showPrivacyDialog(guideLayout); @@ -124,6 +130,9 @@ public class SplashScreenActivity extends BaseActivity { } else { launchMainActivity(); } + + SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, ""); + SPUtils.setString(Constants.SP_XAPK_URL, ""); } private void showPrivacyDialog(ViewPager guideLayout) { @@ -136,7 +145,7 @@ public class SplashScreenActivity extends BaseActivity { requestPermission(); }); } else { - DialogUtils.showPrivacyPolicyDisallowDialog(this, PrivacyPolicyEntity.createDefaultData(),()->{ + DialogUtils.showPrivacyPolicyDisallowDialog(this, PrivacyPolicyEntity.createDefaultData(), () -> { showPrivacyDialog(guideLayout); }); } @@ -245,7 +254,7 @@ public class SplashScreenActivity extends BaseActivity { @Override protected int getLayoutId() { - if (isNewFirstLaunch) { + if (mIsNewForThisVersion) { return R.layout.activity_splash_intro; } else { return 0; @@ -255,7 +264,7 @@ public class SplashScreenActivity extends BaseActivity { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { - if (isNewFirstLaunch && EasyPermissions.hasPermissions(this, mPermissions)) { + if (mIsNewForThisVersion && EasyPermissions.hasPermissions(this, mPermissions)) { launchMainActivity(); } else { return true; @@ -282,9 +291,7 @@ public class SplashScreenActivity extends BaseActivity { prefetchData(); - // 在可能获取了相关权限后才初始化SDK/发送激活数据 - TeaHelper.init(getApplication(), HaloApp.getInstance().getChannel()); -// GdtHelper.INSTANCE.logAction(ActionType.START_APP, GdtHelper.NETWORK_TYPE, DeviceUtils.getNetwork(this)); + uploadTeaAndGdtData(); Bundle bundle = getIntent().getExtras(); Intent intent = new Intent(SplashScreenActivity.this, MainActivity.class); @@ -293,6 +300,33 @@ public class SplashScreenActivity extends BaseActivity { finish(); } + private void uploadTeaAndGdtData(){ + // 在可能获取了相关权限后才初始化SDK/发送激活数据 +// TeaHelper.init(getApplication(), HaloApp.getInstance().getChannel()); + try { + Class clazz = Class.forName("com.gh.gamecenter.TeaHelper"); + Method method = clazz.getMethod("init", Context.class, String.class); + method.invoke(null, getApplication(), HaloApp.getInstance().getChannel()); + } catch (Exception e) { + e.printStackTrace(); + } +// GdtHelper.INSTANCE.logAction(ActionType.START_APP, GdtHelper.NETWORK_TYPE, DeviceUtils.getNetwork(this)); + try { + Class clazz = Class.forName("com.gh.gamecenter.GdtHelper"); + Field field = clazz.getDeclaredField("NETWORK_TYPE"); + String type = (String) field.get(null); + Method method = clazz.getMethod("logAction", String.class, String[].class); + + Class actionTypeClazz = Class.forName("com.qq.gdt.action.ActionType"); + Field typeField = actionTypeClazz.getDeclaredField("START_APP"); + String actionType = (String) typeField.get(null); + + method.invoke(null, actionType, new String[]{type, DeviceUtils.getNetwork(this)}); + } catch (Exception e) { + e.printStackTrace(); + } + } + private void getUniqueId() { DataUtils.getGid(); } @@ -336,6 +370,9 @@ public class SplashScreenActivity extends BaseActivity { MtaHelper.onEvent("授权情况", "启动授权", "都授权"); // 检查是否有旧版本光环,有就删掉 AppExecutor.getIoExecutor().execute(this::deleteOutdatedUpdatePackage); + if (mStartMainActivityDirectly) { + launchMainActivity(); + } } else { ActivityCompat.requestPermissions(this, mPermissions, REQUEST_PERMISSION_TAG); } @@ -350,12 +387,22 @@ public class SplashScreenActivity extends BaseActivity { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); - }, () -> logGrantedPermission(perms)); + }, () -> { + logGrantedPermission(perms); + if (mStartMainActivityDirectly) { + launchMainActivity(); + } + }); } else { DialogUtils.showPermissionDialog(this, "权限申请", "在设置-应用-光环助手-权限中开启存储和手机信息权限,以保证能正常使用相关功能", "重试", "放弃", this::checkAndRequestPermission, - () -> logGrantedPermission(perms)); + () -> { + logGrantedPermission(perms); + if (mStartMainActivityDirectly) { + launchMainActivity(); + } + }); } } diff --git a/app/src/main/java/com/gh/gamecenter/adapter/CleanApkAdapter.java b/app/src/main/java/com/gh/gamecenter/adapter/CleanApkAdapter.java index f646c2130d..6a1e888f7b 100644 --- a/app/src/main/java/com/gh/gamecenter/adapter/CleanApkAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/adapter/CleanApkAdapter.java @@ -17,6 +17,7 @@ import androidx.core.content.ContextCompat; import com.gh.common.util.BitmapUtils; import com.gh.common.util.MtaHelper; import com.gh.common.util.PackageInstaller; +import com.gh.common.util.PackageUtils; import com.gh.gamecenter.R; import com.gh.gamecenter.adapter.viewholder.KcSelectGameViewHolder; import com.gh.gamecenter.entity.InstallGameEntity; @@ -106,7 +107,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter for (String apk_path : mApkPath) { InstallGameEntity apkEntity = new InstallGameEntity(); PackageManager pm = mContext.getApplicationContext().getPackageManager(); - PackageInfo packageInfo = pm.getPackageArchiveInfo(apk_path, PackageManager.GET_ACTIVITIES); + PackageInfo packageInfo = pm.getPackageArchiveInfo(apk_path, 0); if (packageInfo == null) continue; ApplicationInfo appInfo = packageInfo.applicationInfo; @@ -132,7 +133,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter /**安装处理类型*/ /** 得到包名 */ String packageName = packageInfo.packageName; - int type = doType(pm, packageName); + int type = doType(packageName); apkEntity.setInstallStatus(type); mApkList.add(apkEntity); @@ -176,8 +177,8 @@ public class CleanApkAdapter extends BaseRecyclerAdapter } } - private int doType(PackageManager pm, String packageName) { - List pakageinfos = pm.getInstalledPackages(0); + private int doType(String packageName) { + List pakageinfos = PackageUtils.getInstalledPackages(mContext, 0); for (PackageInfo pi : pakageinfos) { if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { String pi_packageName = pi.packageName; diff --git a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java index 31091abb59..bb8a9dc043 100644 --- a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java +++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java @@ -5,9 +5,14 @@ import android.content.Intent; import android.text.TextUtils; import android.view.View; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.FragmentActivity; + import com.gh.common.dialog.CertificationDialog; import com.gh.common.dialog.DeviceRemindDialog; import com.gh.common.dialog.GameOffServiceDialogFragment; +import com.gh.common.dialog.PackageCheckDialogFragment; import com.gh.common.dialog.ReserveDialogFragment; import com.gh.common.exposure.ExposureEvent; import com.gh.common.history.HistoryHelper; @@ -39,16 +44,13 @@ import com.gh.gamecenter.eventbus.EBReuse; import com.gh.gamecenter.gamedetail.GameDetailFragment; import com.lightgame.download.DownloadEntity; import com.lightgame.download.FileUtils; +import com.lightgame.utils.AppManager; import com.lightgame.utils.Utils; import org.greenrobot.eventbus.EventBus; import java.io.File; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.FragmentActivity; - /** * Created by khy on 27/06/17. * 详情页面下载ViewHolder @@ -165,16 +167,18 @@ public class DetailViewHolder { PermissionHelper.checkStoragePermissionBeforeAction(mViewHolder.context, () -> { if (mGameEntity.getApk().size() == 1) { ApkEntity apk = mGameEntity.getApk().get(0); - DownloadDialogHelper.findAvailableDialogAndShow(mViewHolder.context, mGameEntity, apk, - () -> { - CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> { - DialogUtils.showVersionNumberDialog(mViewHolder.context, mGameEntity, () -> { - DialogUtils.showOverseaDownloadDialog(mViewHolder.context, mGameEntity, () -> { - DialogUtils.checkDownload(mViewHolder.context, apk.getSize(), this::download); - }); + PackageCheckDialogFragment.show((AppCompatActivity) mViewHolder.context, mGameEntity.getPackageDialog(), () -> { + DownloadDialogHelper.findAvailableDialogAndShow(mViewHolder.context, mGameEntity, apk, () -> { + CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> { + DialogUtils.showVersionNumberDialog(mViewHolder.context, mGameEntity, () -> { + DialogUtils.showOverseaDownloadDialog(mViewHolder.context, mGameEntity, () -> { + DialogUtils.checkDownload(mViewHolder.context, apk.getSize(), this::download); }); }); }); + }); + }); + } else { CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> { DialogUtils.showVersionNumberDialog(mViewHolder.context, mGameEntity, () -> { @@ -248,15 +252,13 @@ public class DetailViewHolder { break; case RESERVABLE: CheckLoginUtils.checkLogin(mViewHolder.context, mEntrance, () -> { - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(mViewHolder.context, () -> { - ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance( - mGameEntity, - () -> { - LogUtils.logReservation(mGameEntity, mTraceEvent); - DetailDownloadUtils.detailInitDownload(mViewHolder, false); - }); - dialogFragment.show(((AppCompatActivity) mViewHolder.context).getSupportFragmentManager(), "reserve"); - }); + ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance( + mGameEntity, + () -> { + LogUtils.logReservation(mGameEntity, mTraceEvent); + DetailDownloadUtils.detailInitDownload(mViewHolder, false); + }); + dialogFragment.show(((AppCompatActivity) mViewHolder.context).getSupportFragmentManager(), "reserve"); }); break; case RESERVED: diff --git a/app/src/main/java/com/gh/gamecenter/amway/search/AmwaySearchActivity.kt b/app/src/main/java/com/gh/gamecenter/amway/search/AmwaySearchActivity.kt index 3a46fb5b6a..22d5eb787e 100644 --- a/app/src/main/java/com/gh/gamecenter/amway/search/AmwaySearchActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/amway/search/AmwaySearchActivity.kt @@ -63,7 +63,7 @@ class AmwaySearchActivity : SearchActivity() { val transaction = supportFragmentManager.beginTransaction() when (type) { DisplayType.DEFAULT -> { - val fragment = supportFragmentManager.findFragmentByTag(AmwaySearchDefaultFragment::class.java.simpleName) + val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.simpleName) ?: AmwaySearchDefaultFragment() transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.simpleName) } diff --git a/app/src/main/java/com/gh/gamecenter/amway/search/AmwaySearchViewHolder.kt b/app/src/main/java/com/gh/gamecenter/amway/search/AmwaySearchViewHolder.kt index eaf0dca196..e8f0d81c33 100644 --- a/app/src/main/java/com/gh/gamecenter/amway/search/AmwaySearchViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/amway/search/AmwaySearchViewHolder.kt @@ -44,14 +44,10 @@ class AmwaySearchViewHolder(var binding: AmwaySearchItemBinding, val mViewModel: it.context.showRegulationTestDialogIfNeeded { val installPackageName = mViewModel.canUserCommentThisGame(gameEntity) if (gameEntity.directComment || !installPackageName.isNullOrEmpty()) { - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(activity, object : EmptyCallback { - override fun onCallback() { - MtaHelper.onEvent("发表评论", "进入", "选中游戏_${gameEntity.name}") - val intent = RatingEditActivity.getIntent(binding.root.context, gameEntity, 0.0F, installPackageName, true) - activity.startActivity(intent) - activity.finish() - } - }) + MtaHelper.onEvent("发表评论", "进入", "选中游戏_${gameEntity.name}") + val intent = RatingEditActivity.getIntent(binding.root.context, gameEntity, 0.0F, installPackageName, true) + activity.startActivity(intent) + activity.finish() } else { Utils.toast(activity, "安装游戏后才能评论哦") } diff --git a/app/src/main/java/com/gh/gamecenter/catalog/CatalogActivity.kt b/app/src/main/java/com/gh/gamecenter/catalog/CatalogActivity.kt new file mode 100644 index 0000000000..798c478567 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/CatalogActivity.kt @@ -0,0 +1,34 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.gh.common.util.EntranceUtils +import com.gh.gamecenter.NormalActivity +import com.gh.gamecenter.R + +class CatalogActivity : NormalActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setToolbarMenu(R.menu.menu_download) + } + + override fun showDownloadMenu(): Boolean { + return true + } + + override fun provideNormalIntent(): Intent { + return getTargetIntent(this, CatalogActivity::class.java, CatalogFragment::class.java) + } + + companion object { + fun getIntent(context: Context, catalogId: String, catalogTitle: String, entrance: String): Intent { + val bundle = Bundle() + bundle.putString(EntranceUtils.KEY_CATALOG_ID, catalogId) + bundle.putString(EntranceUtils.KEY_CATALOG_TITLE, catalogTitle) + bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance) + return getTargetIntent(context, CatalogActivity::class.java, CatalogFragment::class.java, bundle) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/CatalogAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/CatalogAdapter.kt new file mode 100644 index 0000000000..5e8a7987fa --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/CatalogAdapter.kt @@ -0,0 +1,51 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.util.toColor +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.CatalogItemBinding +import com.gh.gamecenter.entity.CatalogEntity +import com.lightgame.adapter.BaseRecyclerAdapter + +class CatalogAdapter(context: Context, + private val mFragment: CatalogFragment, + private val mViewModel: CatalogViewModel, + private val mList: List) + : BaseRecyclerAdapter(context) { + + override fun getItemCount() = mList.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = + CatalogItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_item,parent, false)) + + override fun onBindViewHolder(holder: CatalogItemViewHolder, position: Int) { + holder.binding.run { + val catalogEntity = mList[position] + entity = catalogEntity + executePendingBindings() + if (catalogEntity.name == mViewModel.selectedCatalogName) { + selectedTag.visibility = View.VISIBLE + catalogName.setTextColor(R.color.theme_font.toColor()) + root.setBackgroundColor(R.color.white.toColor()) + } else { + selectedTag.visibility = View.GONE + catalogName.setTextColor(R.color.text_333333.toColor()) + root.setBackgroundColor(R.color.text_F5F5F5.toColor()) + } + root.setOnClickListener { + if (catalogEntity.name != mViewModel.selectedCatalogName) { + mViewModel.selectedCatalogName = catalogEntity.name + mViewModel.logSubCatalogClick(position) + mFragment.changeCatalog(position) + notifyDataSetChanged() + } + } + } + } + + class CatalogItemViewHolder(val binding: CatalogItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/CatalogFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/CatalogFragment.kt new file mode 100644 index 0000000000..567fd541a0 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/CatalogFragment.kt @@ -0,0 +1,116 @@ +package com.gh.gamecenter.catalog + +import android.os.Bundle +import android.view.View +import androidx.core.os.bundleOf +import androidx.lifecycle.Observer +import com.gh.common.util.EntranceUtils +import com.gh.common.util.viewModelProviderFromParent +import com.gh.common.view.FixLinearLayoutManager +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.FragmentCatalogBinding +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.normal.NormalFragment + +class CatalogFragment : NormalFragment() { + + private lateinit var mBinding: FragmentCatalogBinding + private lateinit var mViewModel: CatalogViewModel + private lateinit var mEntity: CatalogEntity + private lateinit var mSpecialCatalogFragment: SpecialCatalogFragment + private lateinit var mSubCatalogFragment: SubCatalogFragment + + private var mCatalogId: String = "" + private var mCatalogTitle: String = "" + + override fun getLayoutId() = 0 + + override fun getInflatedLayout() = FragmentCatalogBinding.inflate(layoutInflater).apply { mBinding = this }.root + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: "" + mCatalogTitle = arguments?.getString(EntranceUtils.KEY_CATALOG_TITLE) ?: "" + mViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, mCatalogTitle)) + + mViewModel.validEntranceName = if (mEntrance.contains("首页")) "首页" else "板块" + mViewModel.logAppearance() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setNavigationTitle(mCatalogTitle) + mViewModel.catalogs.observe(viewLifecycleOwner, Observer { + mBinding.run { + reuseLoading.root.visibility = View.GONE + if (it != null) { + reuseNoConnection.root.visibility = View.GONE + if (it.subCatalog.isNotEmpty()) { + containerCatalog.visibility = View.VISIBLE + reuseNoneData.root.visibility = View.GONE + mEntity = it + if (mEntity.hasSpecial) { + val specialEntity = CatalogEntity.SubCatalogEntity(name = "精选") + (mEntity.subCatalog as ArrayList).add(0, specialEntity) + } + initView() + } else { + containerCatalog.visibility = View.GONE + reuseNoneData.root.visibility = View.VISIBLE + } + } else { + containerCatalog.visibility = View.GONE + reuseNoneData.root.visibility = View.GONE + reuseNoConnection.root.visibility = View.VISIBLE + reuseNoConnection.root.setOnClickListener { + reuseLoading.root.visibility = View.VISIBLE + mViewModel.getCatalogs() + } + } + } + }) + } + + private fun initView() { + mEntity.run { + if (subCatalog.isNotEmpty()) { + mViewModel.selectedCatalogName = subCatalog[0].name + mBinding.rvCatalog.layoutManager = FixLinearLayoutManager(requireContext()) + mBinding.rvCatalog.adapter = CatalogAdapter(requireContext(), this@CatalogFragment, mViewModel, subCatalog) + + if (hasSpecial) { + mSpecialCatalogFragment = childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.simpleName) as? SpecialCatalogFragment ?: SpecialCatalogFragment() + mSpecialCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id) + childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSpecialCatalogFragment, SpecialCatalogFragment::class.java.simpleName).commitAllowingStateLoss() + } else { + mSubCatalogFragment = childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.simpleName) as? SubCatalogFragment ?: SubCatalogFragment() + mSubCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id, EntranceUtils.KEY_PRIMARY_CATALOG_ID to subCatalog[0].id) + childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSubCatalogFragment, SubCatalogFragment::class.java.simpleName).commitAllowingStateLoss() + } + } + } + } + + fun changeCatalog(position: Int) { + mEntity.run { + if (hasSpecial) { + if (mViewModel.selectedCatalogPosition == 0) { + mSubCatalogFragment = childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.simpleName) as? SubCatalogFragment ?: SubCatalogFragment() + mSubCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id, EntranceUtils.KEY_PRIMARY_CATALOG_ID to subCatalog[position].id) + childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSubCatalogFragment, SubCatalogFragment::class.java.simpleName).commitAllowingStateLoss() + } else { + if (position == 0) { + mSpecialCatalogFragment = childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.simpleName) as? SpecialCatalogFragment ?: SpecialCatalogFragment() + mSpecialCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id) + childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSpecialCatalogFragment, SpecialCatalogFragment::class.java.simpleName).commitAllowingStateLoss() + } else { + mSubCatalogFragment.changeSubCatalog(subCatalog[position].id) + } + } + } else { + mSubCatalogFragment.changeSubCatalog(subCatalog[position].id) + } + mViewModel.selectedCatalogPosition = position + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/CatalogViewModel.kt b/app/src/main/java/com/gh/gamecenter/catalog/CatalogViewModel.kt new file mode 100644 index 0000000000..0d01d0e915 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/CatalogViewModel.kt @@ -0,0 +1,77 @@ +package com.gh.gamecenter.catalog + +import android.annotation.SuppressLint +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.gh.common.exposure.ExposureSource +import com.gh.common.util.LogUtils +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +class CatalogViewModel(application: Application, private val catalogId: String, val catalogTitle: String) + : AndroidViewModel(application) { + + private val api = RetrofitManager.getInstance(getApplication()).api + var catalogs = MutableLiveData() + + var selectedCatalogName: String = "" + var selectedCatalogPosition: Int = 0 + + var validEntranceName: String = "" + + val basicExposureSource by lazy { ExposureSource("分类", catalogTitle) } + + init { + getCatalogs() + } + + @SuppressLint("CheckResult") + fun getCatalogs() { + api.getCatalogs(catalogId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: CatalogEntity) { + catalogs.postValue(data) + } + + override fun onFailure(exception: Exception) { + super.onFailure(exception) + catalogs.postValue(null) + } + }) + } + + fun logAppearance() { + LogUtils.logNewCatalogAppearanceEvent(validEntranceName, catalogTitle) + } + + fun logSubCatalogClick(position: Int) { + LogUtils.logSubCatalogClickEvent(validEntranceName, "${catalogTitle}_${selectedCatalogName}", position) + } + + fun logSubCatalogContentClick(itemName: String, listPosition: Int) { + LogUtils.logSubCatalogContentClickEvent(validEntranceName, "${catalogTitle}_${selectedCatalogName}_${itemName}", selectedCatalogPosition, listPosition) + } + + fun logSpecialCatalogContentClick(contentType: String, contentName: String, listPosition: Int) { + LogUtils.logSpecialCatalogContentClickEvent(validEntranceName, "${catalogTitle}_${contentType}_${contentName}", selectedCatalogPosition, listPosition) + } + + fun logSpecialCatalogSpecificContentClick(contentType: String, contentName: String, targetName: String, listPosition: Int, specificListPosition: Int) { + LogUtils.logSpecialCatalogSpecificContentClickEvent(validEntranceName, "${catalogTitle}_${contentType}_${contentName}_${targetName}", selectedCatalogPosition, listPosition, specificListPosition) + } + + class Factory(private val catalogId: String, private val catalogTitle: String) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return CatalogViewModel(HaloApp.getInstance().application, catalogId, catalogTitle) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListActivity.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListActivity.kt new file mode 100644 index 0000000000..52a3e2d2ec --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListActivity.kt @@ -0,0 +1,38 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.gh.common.util.EntranceUtils +import com.gh.gamecenter.NormalActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.CatalogEntity + +class NewCatalogListActivity : NormalActivity() { + + companion object { + fun getIntent(context: Context, + primaryCatalogName: String, // 一级分类名 + catalogTitle: String, + catalog: CatalogEntity, + initTitle: String): Intent { + val bundle = Bundle() + bundle.putParcelable(EntranceUtils.KEY_DATA, catalog) + bundle.putString(EntranceUtils.KEY_PRIMARY_CATALOG_NAME, primaryCatalogName) + bundle.putString(EntranceUtils.KEY_NAME, catalog.name) + bundle.putString(EntranceUtils.KEY_CATALOG_TITLE, catalogTitle) + bundle.putString(EntranceUtils.KEY_CATALOG_INIT_TITLE, initTitle) + return getTargetIntent(context, NewCatalogListActivity::class.java, NewCatalogListFragment::class.java, bundle) + } + } + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setToolbarMenu(R.menu.menu_download) + } + + override fun showDownloadMenu(): Boolean { + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt new file mode 100644 index 0000000000..a9b71798dc --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt @@ -0,0 +1,173 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.util.SparseArray +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.constant.ItemViewType +import com.gh.common.exposure.ExposureEvent +import com.gh.common.exposure.ExposureSource +import com.gh.common.exposure.ExposureType +import com.gh.common.exposure.IExposable +import com.gh.common.util.DownloadItemUtils +import com.gh.common.util.GameViewUtils +import com.gh.common.util.StringUtils +import com.gh.common.util.dip2px +import com.gh.gamecenter.GameDetailActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.adapter.viewholder.GameViewHolder +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.baselist.LoadType +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.eventbus.EBDownloadStatus +import com.gh.gamecenter.game.GameItemViewHolder +import com.lightgame.download.DownloadEntity +import java.util.* + +class NewCatalogListAdapter(context: Context, + private val mBaseExposureSource: ExposureSource, + private val mViewModel: NewCatalogListViewModel, + private val mEntrance: String?) : ListAdapter(context), IExposable { + + private val mExposureEventSparseArray: SparseArray = SparseArray() + + val positionAndPackageMap = HashMap() + + override fun setListData(updateData: MutableList?) { + // 记录游戏位置 + if (updateData != null) { + for (i in 0 until updateData.size) { + val gameEntity = updateData[i] + var packages = gameEntity.id + for (apkEntity in gameEntity.getApk()) { + packages += apkEntity.packageName + } + positionAndPackageMap[packages + i] = i + } + } + super.setListData(updateData) + } + + fun clearPositionAndPackageMap() { + positionAndPackageMap.clear() + } + + override fun areItemsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean { + return oldItem?.id == newItem?.id + } + + override fun getItemViewType(position: Int): Int { + if (position == itemCount - 1) { + return ItemViewType.ITEM_FOOTER + } + return ItemViewType.GAME_NORMAL + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + ItemViewType.GAME_NORMAL -> { + GameItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.game_item, parent, false)) + } + else -> { + FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)) + } + } + } + + override fun getItemCount(): Int { + return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1 + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is GameItemViewHolder) { + val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px() + holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px()) + + val gameEntity = mEntityList[position] + + holder.binding.game = gameEntity + holder.initServerType(gameEntity) + holder.binding.hideSize = true + holder.binding.executePendingBindings() + + GameViewUtils.setLabelList(mContext, holder.binding.labelList, gameEntity.tagStyle) + + gameEntity.sequence = position + 1 + + val sortType = mViewModel.sortType.value + val sortSize = mViewModel.sortSize.text + val toolbarTitle = mViewModel.title + val selectedCatalogName = mViewModel.selectedCatalog.name + + val exposureSources = ArrayList() + exposureSources.add(mBaseExposureSource) + exposureSources.add(ExposureSource(toolbarTitle)) + exposureSources.add(ExposureSource("二级分类详情", "$selectedCatalogName+$sortType+$sortSize")) + gameEntity.sequence = position + 1 + + val event = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE) + mExposureEventSparseArray.put(position, event) + + holder.itemView.setOnClickListener { + GameDetailActivity.startGameDetailActivity( + mContext, + gameEntity, + StringUtils.buildString(mEntrance, "+(", toolbarTitle, ":列表[", selectedCatalogName, "=", sortType, "=", (position + 1).toString(), "])"), + event) + } + DownloadItemUtils.setOnClickListener(mContext, + holder.binding.downloadBtn, + gameEntity, + position, + this, + StringUtils.buildString(StringUtils.buildString(mEntrance, "+(", toolbarTitle, ":列表[", selectedCatalogName, "=", sortType, "=", (position + 1).toString(), "])")), + StringUtils.buildString(selectedCatalogName, ":", gameEntity.name), + event) + + DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding), true, "star&brief") + } else if (holder is FooterViewHolder) { + holder.initItemPadding() + holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint) + holder.itemView.setOnClickListener { + if (mIsNetworkError) { + mViewModel.load(LoadType.RETRY) + } + } + } + } + + fun notifyItemByDownload(download: DownloadEntity) { + for (key in positionAndPackageMap.keys) { + if (key.contains(download.packageName) && key.contains(download.gameId)) { + val position = positionAndPackageMap[key] + if (position != null && mEntityList != null && position < mEntityList.size) { + mEntityList[position].getEntryMap()[download.platform] = download + notifyItemChanged(position) + } + } + } + } + + fun notifyItemAndRemoveDownload(status: EBDownloadStatus) { + for (key in positionAndPackageMap.keys) { + if (key.contains(status.packageName) && key.contains(status.gameId)) { + val position = positionAndPackageMap[key] + if (position != null && mEntityList != null && position < mEntityList.size) { + mEntityList[position].getEntryMap().remove(status.platform) + notifyItemChanged(position) + } + } + } + } + + override fun getEventByPosition(pos: Int): ExposureEvent? { + return mExposureEventSparseArray.get(pos) + } + + override fun getEventListByPosition(pos: Int): List? { + return null + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt new file mode 100644 index 0000000000..3c18aa2c59 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt @@ -0,0 +1,182 @@ +package com.gh.gamecenter.catalog + +import android.os.Bundle +import android.view.View +import com.ethanhua.skeleton.Skeleton +import com.gh.common.constant.Constants +import com.gh.common.exposure.ExposureListener +import com.gh.common.exposure.ExposureSource +import com.gh.common.util.DialogUtils +import com.gh.common.util.EntranceUtils +import com.gh.common.util.observeNonNull +import com.gh.common.util.viewModelProvider +import com.gh.common.view.CatalogFilterView +import com.gh.common.xapk.XapkInstaller +import com.gh.common.xapk.XapkUnzipStatus +import com.gh.download.DownloadManager +import com.gh.gamecenter.R +import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.databinding.FragmentCatalogListBinding +import com.gh.gamecenter.entity.* +import com.gh.gamecenter.eventbus.EBDownloadStatus +import com.gh.gamecenter.eventbus.EBPackage +import com.lightgame.download.DataWatcher +import com.lightgame.download.DownloadEntity +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class NewCatalogListFragment : ListFragment() { + + private var mPrimaryCatalogName: String = "" // 一级分类名 + private var mPrimeCatalog: CatalogEntity? = null + private var mSubCatalogList = arrayListOf() + private var mInitCatalogName = "" + private var mAdapter: NewCatalogListAdapter? = null + private val mDataWatcher = object : DataWatcher() { + override fun onDataChanged(downloadEntity: DownloadEntity) { + mAdapter?.notifyItemByDownload(downloadEntity) + + if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) { + showUnzipFailureDialog(downloadEntity) + } + } + } + + private lateinit var mBinding: FragmentCatalogListBinding + private lateinit var mExposureListener: ExposureListener + private lateinit var mViewModel: NewCatalogListViewModel + + override fun getLayoutId() = 0 + + override fun getInflatedLayout() = FragmentCatalogListBinding.inflate(layoutInflater).apply { mBinding = this }.root + + override fun provideListViewModel() = viewModelProvider() + + override fun provideListAdapter() = mAdapter + ?: NewCatalogListAdapter( + requireContext(), + ExposureSource(mPrimaryCatalogName), + mViewModel, + mEntrance).apply { mAdapter = this } + + override fun getItemDecoration() = null + + override fun onCreate(savedInstanceState: Bundle?) { + mViewModel = provideListViewModel() + + mViewModel.title = arguments?.getString(EntranceUtils.KEY_NAME) ?: "" + mViewModel.categoryTitle = arguments?.getString(EntranceUtils.KEY_CATALOG_TITLE) ?: "" + mEntrance = arguments?.getString(EntranceUtils.KEY_ENTRANCE) ?: Constants.ENTRANCE_UNKNOWN + mPrimeCatalog = arguments?.getParcelable(EntranceUtils.KEY_DATA) + mSubCatalogList = mPrimeCatalog?.subCatalog as ArrayList + + mInitCatalogName = arguments?.getString(EntranceUtils.KEY_CATALOG_INIT_TITLE) ?: "" + mPrimaryCatalogName = arguments?.getString(EntranceUtils.KEY_PRIMARY_CATALOG_NAME) ?: "" + + mViewModel.selectedCatalog = mSubCatalogList.find { entity -> entity.name == mInitCatalogName } + ?: CatalogEntity.SubCatalogEntity() + initSortType() + + super.onCreate(savedInstanceState) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setNavigationTitle(mViewModel.title) + + initFilterView() + + mViewModel.refresh.observeNonNull(this) { onRefresh() } + + mExposureListener = ExposureListener(this, mAdapter!!) + mListRv.addOnScrollListener(mExposureListener) + + mSkeletonScreen = Skeleton.bind(mBinding.listSkeleton).shimmer(false).load(R.layout.fragment_subject_skeleton).show() + } + + private fun initSortType() { + mPrimeCatalog?.switch?.run { + if (hotSort == "on") { + mViewModel.sortType = CatalogFilterView.SortType.RECOMMENDED + return@run + } + if (newSort == "on") { + mViewModel.sortType = CatalogFilterView.SortType.NEWEST + return@run + } + if (starSort == "on") { + mViewModel.sortType = CatalogFilterView.SortType.RATING + return@run + } + } + } + + private fun initFilterView() { + mBinding.filterContainer.run { + visibility = View.VISIBLE + setTypeList(mPrimeCatalog?.switch ?: CatalogEntity.CatalogSwitch()) + setCatalogList(mSubCatalogList, mInitCatalogName) + setOnConfigSetupListener(object : CatalogFilterView.OnCatalogFilterSetupListener { + override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) { + mViewModel.updateSortConfig(sortSize = sortSize) + } + + override fun onSetupSortType(sortType: CatalogFilterView.SortType) { + mViewModel.updateSortConfig(sortType = sortType) + } + + override fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity) { + mViewModel.updateSortConfig(sortCatalog = sortCatalog) + } + }) + } + + } + + override fun onResume() { + if (isEverPause && mAdapter != null) mAdapter?.notifyDataSetChanged() + super.onResume() + DownloadManager.getInstance(context).addObserver(mDataWatcher) + } + + override fun onPause() { + super.onPause() + DownloadManager.getInstance(context).removeObserver(mDataWatcher) + } + + override fun onRefresh() { + mAdapter?.clearPositionAndPackageMap() + + super.onRefresh() + } + + // 下载被删除事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(status: EBDownloadStatus) { + if ("delete" == status.status) { + mAdapter?.notifyItemAndRemoveDownload(status) + } + } + + // 安装/卸载 事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(busFour: EBPackage) { + if ("安装" == busFour.type || "卸载" == busFour.type) { + mAdapter?.notifyDataSetChanged() + } + } + + fun showUnzipFailureDialog(downloadEntity: DownloadEntity) { + val data = mAdapter?.positionAndPackageMap ?: return + for (gameAndPosition in data) { + if (gameAndPosition.key.contains(downloadEntity.packageName)) { + val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value) + if (targetView != null) { + DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity) + return + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt new file mode 100644 index 0000000000..0b7f06ecf0 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt @@ -0,0 +1,82 @@ +package com.gh.gamecenter.catalog + +import android.app.Application +import androidx.lifecycle.MutableLiveData +import com.gh.common.util.UrlFilterUtils +import com.gh.common.view.CatalogFilterView +import com.gh.gamecenter.baselist.ListViewModel +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.entity.SubjectSettingEntity +import com.gh.gamecenter.retrofit.RetrofitManager +import io.reactivex.Observable +import io.reactivex.Single + +class NewCatalogListViewModel(application: Application) : ListViewModel(application) { + + var title = "" // 显示在 Toolbar 的标题 + var categoryTitle = "" // 跳转进来的分类的标题 + + val refresh = MutableLiveData() + + var selectedCatalog = CatalogEntity.SubCatalogEntity() + var sortType = CatalogFilterView.SortType.RECOMMENDED + var sortSize = SubjectSettingEntity.Size() + private val api = RetrofitManager.getInstance(getApplication()).api + + override fun provideDataObservable(page: Int): Observable>? = null + + override fun provideDataSingle(page: Int): Single> { + return if (selectedCatalog.link.type == "column") { // column(专题)/tag(标签) + api.getColumn(selectedCatalog.link.link, getSortType(), getSortSize(), page) // 专题 + } else { + api.getGamesWithSpecificTag(getSortSize(), getSortType(), page) // 标签 + } + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) } + } + + fun updateSortConfig(sortSize: SubjectSettingEntity.Size? = null, + sortType: CatalogFilterView.SortType? = null, + sortCatalog: CatalogEntity.SubCatalogEntity? = null) { + when { + sortSize != null && sortSize != this.sortSize -> { + this.sortSize = sortSize + refresh.postValue(true) + } + + sortType != null && sortType != this.sortType -> { + this.sortType = sortType + refresh.postValue(true) + } + + sortCatalog != null && sortCatalog != selectedCatalog -> { + selectedCatalog = sortCatalog + refresh.postValue(true) + } + } + } + + private fun getSortSize(): String? { + return if (selectedCatalog.link.type == "column") { + UrlFilterUtils.getFilterQuery( + "min_size", sortSize.min.toString(), + "max_size", sortSize.max.toString()) + } else { + UrlFilterUtils.getFilterQuery( + "tag_id", selectedCatalog.link.link, + "min_size", sortSize.min.toString(), + "max_size", sortSize.max.toString()) + } + } + + private fun getSortType(): String? { + return when (sortType) { + CatalogFilterView.SortType.RECOMMENDED -> if (selectedCatalog.link.type == "column") "position:1" else "download:-1" + CatalogFilterView.SortType.NEWEST -> "publish:-1" + CatalogFilterView.SortType.RATING -> "star:-1" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogAdapter.kt new file mode 100644 index 0000000000..385cc629e3 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogAdapter.kt @@ -0,0 +1,239 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.util.SparseArray +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.constant.ItemViewType +import com.gh.common.exposure.ExposureEvent +import com.gh.common.exposure.ExposureSource +import com.gh.common.exposure.IExposable +import com.gh.common.util.DirectUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.databinding.CatalogHeaderItemBinding +import com.gh.gamecenter.databinding.CatalogImageItemBinding +import com.gh.gamecenter.databinding.CatalogSubjectCollectionItemBinding +import com.gh.gamecenter.databinding.CatalogSubjectItemBinding +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.subject.SubjectActivity.Companion.startSubjectActivity + +class SpecialCatalogAdapter(context: Context, private val mCatalogViewModel: CatalogViewModel) + : ListAdapter(context), IExposable { + + private val mExposureEventSparseArray: SparseArray = SparseArray() + + override fun getItemCount() = if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT + + override fun areItemsTheSame(oldItem: SpecialCatalogItemData?, newItem: SpecialCatalogItemData?): Boolean { + return when { + oldItem?.header != null && newItem?.header != null -> { + oldItem.header.id == newItem.header.id + } + + oldItem?.bigImage != null && newItem?.bigImage != null -> { + oldItem.bigImage.id == newItem.bigImage.id + } + + oldItem?.subject != null && newItem?.subject != null -> { + oldItem.subject.id == newItem.subject.id + } + + oldItem?.subjectCollection != null && newItem?.subjectCollection != null -> { + oldItem.subjectCollection.id == newItem.subjectCollection.id + } + + else -> super.areItemsTheSame(oldItem, newItem) + } + } + + override fun areContentsTheSame(oldItem: SpecialCatalogItemData?, newItem: SpecialCatalogItemData?): Boolean { + return when { + oldItem?.header != null && newItem?.header != null -> { + oldItem.header.id == newItem.header.id + } + + oldItem?.bigImage != null && newItem?.bigImage != null -> { + oldItem.bigImage.id == newItem.bigImage.id + } + + oldItem?.subject != null && newItem?.subject != null -> { + oldItem.subject.id == newItem.subject.id + } + + oldItem?.subjectCollection != null && newItem?.subjectCollection != null -> { + oldItem.subjectCollection.id == newItem.subjectCollection.id + } + + else -> super.areItemsTheSame(oldItem, newItem) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val view: View + return when (viewType) { + ItemViewType.ITEM_FOOTER -> { + view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false) + FooterViewHolder(view) + } + + TYPE_HEADER -> CatalogHeaderItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_header_item, parent, false)) + + TYPE_BIG_IMAGE -> CatalogImageItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_image_item, parent, false)) + + TYPE_SUBJECT -> CatalogSubjectItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_item, parent, false)) + + TYPE_SUBJECT_COLLECTION -> CatalogSubjectCollectionItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_collection_item, parent, false)) + + else -> throw NullPointerException() + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (holder) { + is CatalogImageItemHolder -> { + val imageEntity = mEntityList[position].bigImage!! + holder.binding.run { + entity = imageEntity.image + + var exposureEvent: ExposureEvent? = null + if (imageEntity.link.type == "game") { + exposureEvent = ExposureEvent.createEvent( + GameEntity(id = imageEntity.link.link), + listOf(mCatalogViewModel.basicExposureSource, ExposureSource("精选页图片", ""))) + mExposureEventSparseArray.append(position, exposureEvent) + } + root.setOnClickListener { + DirectUtils.directToLinkPage(mContext, imageEntity.link, "新分类-精选分类", "图片", exposureEvent) + mCatalogViewModel.logSpecialCatalogContentClick("图片", imageEntity.image.title, mEntityList[position].position) + } + } + } + + is CatalogHeaderItemHolder -> { + val entity = mEntityList[position].header!! + val specialLink = entity.link + holder.binding.run { + link = specialLink + headMore.setOnClickListener { + if (entity.type == "专题合集") { + DirectUtils.directToColumnCollection(mContext, specialLink.link + ?: "", -1, "(游戏-专题:" + specialLink.text + "-全部)") + } else { + startSubjectActivity(mContext, specialLink.link, specialLink.text, false, "(游戏-专题:" + specialLink.text + "-全部)") + } + mCatalogViewModel.logSpecialCatalogContentClick(entity.type, specialLink.text + ?: "", mEntityList[position].position) + } + } + } + + is CatalogSubjectItemHolder -> { + val subject = mEntityList[position].subject!! + + val exposureList = arrayListOf() + for (game in subject.link.data) { + val exposureEvent = ExposureEvent.createEvent(game, + listOf(mCatalogViewModel.basicExposureSource, ExposureSource("精选页专题", subject.link.text ?: ""))) + exposureList.add(exposureEvent) + game.exposureEvent = exposureEvent + game.subjectName = subject.link.text + } + mEntityList[position].exposureEventList = exposureList + + holder.bindSubject(subject.link.data, mEntityList[position].position) + } + + is CatalogSubjectCollectionItemHolder -> { + val subjectCollection = mEntityList[position].subjectCollection!! + + for (subject in subjectCollection.link.data) { + subject.subjectName = subjectCollection.link.text + } + + holder.bindSubjectCollection(subjectCollection.link.data, mEntityList[position].position) + } + + is FooterViewHolder -> { + holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint) + } + } + } + + override fun getItemViewType(position: Int): Int { + return if (position == itemCount - 1) { + ItemViewType.ITEM_FOOTER + } else { + val item = mEntityList[position] + when { + item.header != null -> TYPE_HEADER + item.bigImage != null -> TYPE_BIG_IMAGE + item.subject != null -> TYPE_SUBJECT + item.subjectCollection != null -> TYPE_SUBJECT_COLLECTION + else -> TYPE_SUBJECT_COLLECTION + } + } + } + + override fun getEventByPosition(pos: Int): ExposureEvent? = mExposureEventSparseArray.get(pos) + + override fun getEventListByPosition(pos: Int): List? = mEntityList[pos].exposureEventList + + class CatalogImageItemHolder(val binding: CatalogImageItemBinding) : BaseRecyclerViewHolder(binding.root) + + class CatalogHeaderItemHolder(val binding: CatalogHeaderItemBinding) : BaseRecyclerViewHolder(binding.root) + + inner class CatalogSubjectItemHolder(val binding: CatalogSubjectItemBinding) : BaseRecyclerViewHolder(binding.root) { + + fun bindSubject(gameList: List, position: Int) { + binding.gameList.run { + var subjectAdapter = adapter + if (subjectAdapter is SpecialCatalogSubjectAdapter) { + subjectAdapter.checkResetData(gameList) + subjectAdapter.updatePosition(position) + return + } + subjectAdapter = SpecialCatalogSubjectAdapter(context, mCatalogViewModel, gameList).apply { + updatePosition(position) + } + layoutManager = GridLayoutManager(context, 3) + adapter = subjectAdapter + } + } + } + + inner class CatalogSubjectCollectionItemHolder(val binding: CatalogSubjectCollectionItemBinding) : BaseRecyclerViewHolder(binding.root) { + + fun bindSubjectCollection(subjectCollection: List, position: Int) { + binding.subjectCollectionList.run { + var collectionAdapter = adapter + if (collectionAdapter is SpecialCatalogSubjectCollectionAdapter) { + collectionAdapter.checkResetData(subjectCollection) + collectionAdapter.updatePosition(position) + return + } + collectionAdapter = SpecialCatalogSubjectCollectionAdapter(context, mCatalogViewModel, subjectCollection).apply { + updatePosition(position) + } + layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + adapter = collectionAdapter + } + } + } + + companion object { + private const val TYPE_HEADER = 900 + + private const val TYPE_BIG_IMAGE = 901 + + private const val TYPE_SUBJECT = 902 + + private const val TYPE_SUBJECT_COLLECTION = 903 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt new file mode 100644 index 0000000000..07acba124d --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt @@ -0,0 +1,45 @@ +package com.gh.gamecenter.catalog + +import android.graphics.Color +import android.os.Bundle +import android.view.View +import com.gh.common.exposure.ExposureListener +import com.gh.common.util.EntranceUtils +import com.gh.common.util.viewModelProvider +import com.gh.common.util.viewModelProviderFromParent +import com.gh.gamecenter.baselist.ListFragment + +class SpecialCatalogFragment : ListFragment() { + + private var mCatalogId = "" + + private var mAdapter: SpecialCatalogAdapter? = null + + private lateinit var mCatalogViewModel: CatalogViewModel + + private lateinit var mExposureListener: ExposureListener + + override fun provideListViewModel() = viewModelProvider(SpecialCatalogViewModel.Factory(mCatalogId)) + + override fun provideListAdapter() = mAdapter ?: SpecialCatalogAdapter(requireContext(), mCatalogViewModel).apply { + mAdapter = this + mExposureListener = ExposureListener(this@SpecialCatalogFragment, this) + } + + override fun getItemDecoration() = null + + override fun onCreate(savedInstanceState: Bundle?) { + mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: "" + // 按理来说在这里获取不需要再传值给构造函数,但保守起见还是传了 + mCatalogViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, "")) + + super.onCreate(savedInstanceState) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mListRv.setBackgroundColor(Color.WHITE) + mListRv.addOnScrollListener(mExposureListener) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogItemData.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogItemData.kt new file mode 100644 index 0000000000..2e8edfeb59 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogItemData.kt @@ -0,0 +1,14 @@ +package com.gh.gamecenter.catalog + +import com.gh.common.exposure.ExposureEvent +import com.gh.gamecenter.entity.SpecialCatalogEntity + +data class SpecialCatalogItemData( + val header: SpecialCatalogEntity? = null, + val bigImage: SpecialCatalogEntity? = null, + val subject: SpecialCatalogEntity? = null, + val subjectCollection: SpecialCatalogEntity? = null, + + var position: Int = 0, + var exposureEventList: ArrayList? = null +) diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectAdapter.kt new file mode 100644 index 0000000000..d5b6617644 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectAdapter.kt @@ -0,0 +1,82 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.util.dip2px +import com.gh.gamecenter.GameDetailActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.CatalogSubjectGameItemBinding +import com.gh.gamecenter.entity.GameEntity +import com.lightgame.adapter.BaseRecyclerAdapter + +class SpecialCatalogSubjectAdapter(context: Context, + private val mCatalogViewModel: CatalogViewModel, + private var mList: List) + : BaseRecyclerAdapter(context) { + + private val mEntrance = "精选分类" + private var countAndKey: Pair? = null + private var mPosition: Int = -1 + + init { + var dataIds = "" + mList.forEach { + dataIds += it.id + } + if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds) + } + + override fun getItemCount() = mList.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) + = CatalogSubjectGameItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_game_item, parent, false)) + + override fun onBindViewHolder(holder: CatalogSubjectGameItemViewHolder, position: Int) { + holder.binding.run { + root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply { + topMargin = if (position > 2) 24F.dip2px() else 16F.dip2px() + } + + val entity = mList[position] + game = entity + executePendingBindings() + + if (!gameName.isSelected) { + gameName.postDelayed({ gameName.isSelected = true }, 500) + } + + root.setOnClickListener { + GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(${mEntrance})", entity.exposureEvent) + mCatalogViewModel.logSpecialCatalogSpecificContentClick( + "专题", + game?.subjectName ?: "", + game?.name ?: "", + mPosition, + position) + } + } + } + + fun checkResetData(update: List) { + var dataIds = "" + mList.forEach { dataIds += it.id } + + mList = update + if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变 + notifyItemRangeChanged(0, itemCount) + } else if (countAndKey?.first != update.size) { // 数量发生改变 + notifyDataSetChanged() + } + + // 重新刷新数据标识 + countAndKey = Pair(update.size, dataIds) + } + + fun updatePosition(position: Int) { + mPosition = position + } + + class CatalogSubjectGameItemViewHolder(val binding: CatalogSubjectGameItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectCollectionAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectCollectionAdapter.kt new file mode 100644 index 0000000000..5b9edf0045 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogSubjectCollectionAdapter.kt @@ -0,0 +1,77 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.util.DirectUtils +import com.gh.common.util.ImageUtils +import com.gh.common.util.dip2px +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.CatalogSubjectCollectionListItemBinding +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.entity.LinkEntity +import com.lightgame.adapter.BaseRecyclerAdapter + +class SpecialCatalogSubjectCollectionAdapter(context: Context, + private val mCatalogViewModel: CatalogViewModel, + private var mList: List) + : BaseRecyclerAdapter(context) { + + private var countAndKey: Pair? = null + private var mPosition: Int = -1 + + init { + var dataIds = "" + mList.forEach { + dataIds += it.id + } + if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds) + } + + override fun getItemCount() = mList.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) + = CatalogSubjectCollectionListItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_collection_list_item, parent, false)) + + + override fun onBindViewHolder(holder: CatalogSubjectCollectionListItemViewHolder, position: Int) { + holder.binding.run { + root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply { + leftMargin = if (position == 0) 16F.dip2px() else 0 + } + val entity = mList[position] + ImageUtils.display(subjectCollectionImage, entity.image) + root.setOnClickListener { + DirectUtils.directToLinkPage(mContext, LinkEntity(link = entity.link, type = entity.type), "精选分类", "专题合集") + mCatalogViewModel.logSpecialCatalogSpecificContentClick( + "专题合集", + entity.subjectName ?: "", + entity.name ?: "", + mPosition, + position) + } + } + } + + fun checkResetData(update: List) { + var dataIds = "" + mList.forEach { dataIds += it.id } + + mList = update + if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变 + notifyItemRangeChanged(0, itemCount) + } else if (countAndKey?.first != update.size) { // 数量发生改变 + notifyDataSetChanged() + } + + // 重新刷新数据标识 + countAndKey = Pair(update.size, dataIds) + } + + fun updatePosition(position: Int) { + mPosition = position + } + + class CatalogSubjectCollectionListItemViewHolder(val binding: CatalogSubjectCollectionListItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogViewModel.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogViewModel.kt new file mode 100644 index 0000000000..5b8dc232b3 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogViewModel.kt @@ -0,0 +1,50 @@ +package com.gh.gamecenter.catalog + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.gh.gamecenter.baselist.ListViewModel +import com.gh.gamecenter.entity.SpecialCatalogEntity +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.Observable +import io.reactivex.Single + +class SpecialCatalogViewModel(application: Application, private val catalogId: String) : ListViewModel(application) { + + override fun provideDataObservable(page: Int): Observable>? = null + + override fun provideDataSingle(page: Int): Single> { + return RetrofitManager.getInstance(getApplication()) + .sensitiveApi + .getSpecialCatalogs(catalogId, page) + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { list -> + val itemDataList = arrayListOf() + list.forEachIndexed { index, it -> + when (it.type) { + "图片" -> itemDataList.add(SpecialCatalogItemData(bigImage = it).apply { position = index }) + + "专题" -> { + itemDataList.add(SpecialCatalogItemData(header = it).apply { position = index }) + itemDataList.add(SpecialCatalogItemData(subject = it).apply { position = index }) + } + + "专题合集" -> { + itemDataList.add(SpecialCatalogItemData(header = it).apply { position = index }) + itemDataList.add(SpecialCatalogItemData(subjectCollection = it).apply { position = index }) + } + } + } + mResultLiveData.postValue(itemDataList) + } + } + + class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return SpecialCatalogViewModel(HaloApp.getInstance().application, catalogId) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogAdapter.kt new file mode 100644 index 0000000000..111ca593d5 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogAdapter.kt @@ -0,0 +1,43 @@ +package com.gh.gamecenter.catalog + +import android.content.Context +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.util.DialogUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.SubCatalogItemBinding +import com.gh.gamecenter.entity.CatalogEntity +import com.lightgame.adapter.BaseRecyclerAdapter + +class SubCatalogAdapter(context: Context, + private val mCatalogViewModel: CatalogViewModel, + private val mPrimaryCatalog: CatalogEntity, + private var mList: List) + : BaseRecyclerAdapter(context) { + + private val mTypes = listOf("专题", "标签") + + override fun getItemCount() = mList.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = + SubCatalogItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.sub_catalog_item, parent, false)) + + override fun onBindViewHolder(holder: SubCatalogItemViewHolder, position: Int) { + holder.binding.run { + val catalogEntity = mList[position] + entity = catalogEntity + executePendingBindings() + root.setOnClickListener { + mCatalogViewModel.logSubCatalogContentClick(catalogEntity.name, position) + if (mTypes.contains(catalogEntity.type)) { + root.context.startActivity(NewCatalogListActivity.getIntent(mContext, mCatalogViewModel.catalogTitle, catalogEntity.name, mPrimaryCatalog, catalogEntity.name)) + } else { + DialogUtils.showLowVersionDialog(mContext) + } + } + } + } + + class SubCatalogItemViewHolder(val binding: SubCatalogItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogFragment.kt new file mode 100644 index 0000000000..3ccd022080 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogFragment.kt @@ -0,0 +1,84 @@ +package com.gh.gamecenter.catalog + +import android.os.Bundle +import android.view.View +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.GridLayoutManager +import com.gh.common.util.EntranceUtils +import com.gh.common.util.viewModelProvider +import com.gh.common.util.viewModelProviderFromParent +import com.gh.gamecenter.databinding.FragmentSubCatalogBinding +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.normal.NormalFragment + +class SubCatalogFragment : NormalFragment() { + + private lateinit var mBinding: FragmentSubCatalogBinding + private lateinit var mViewModel: SubCatalogViewModel + private lateinit var mCatalogViewModel: CatalogViewModel + private lateinit var mEntity: CatalogEntity + private var mCatalogId: String = "" + private var mPrimaryCatalogId: String = "" + + override fun getLayoutId() = 0 + + override fun getInflatedLayout() = FragmentSubCatalogBinding.inflate(layoutInflater).apply { mBinding = this }.root + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: "" + mPrimaryCatalogId = arguments?.getString(EntranceUtils.KEY_PRIMARY_CATALOG_ID) ?: "" + mViewModel = viewModelProvider(SubCatalogViewModel.Factory(mCatalogId)) + mCatalogViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, "")) + mViewModel.getSubCatalogs(mPrimaryCatalogId) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mViewModel.catalogs.observe(viewLifecycleOwner, Observer { + mBinding.run { + reuseLoading.root.visibility = View.GONE + if (it != null) { + reuseNoConnection.root.visibility = View.GONE + if (it.subCatalog.isNotEmpty()) { + rvSubCatalog.visibility = View.VISIBLE + reuseNoneData.root.visibility = View.GONE + mEntity = it + initView() + } else { + rvSubCatalog.visibility = View.GONE + reuseNoneData.root.visibility = View.VISIBLE + } + } else { + rvSubCatalog.visibility = View.GONE + reuseNoneData.root.visibility = View.GONE + reuseNoConnection.root.visibility = View.VISIBLE + reuseNoConnection.root.setOnClickListener { + reuseLoading.root.visibility = View.VISIBLE + mViewModel.getSubCatalogs(mPrimaryCatalogId) + } + } + } + }) + } + + private fun initView() { + mEntity.run { + mBinding.rvSubCatalog.layoutManager = GridLayoutManager(requireContext(), 3) + mBinding.rvSubCatalog.adapter = SubCatalogAdapter(requireContext(), mCatalogViewModel, mEntity, subCatalog) + } + } + + fun changeSubCatalog(primaryCatalogId: String) { + mBinding.run { + mPrimaryCatalogId = primaryCatalogId + rvSubCatalog.visibility = View.GONE + reuseNoneData.root.visibility = View.GONE + reuseNoConnection.root.visibility = View.GONE + reuseLoading.root.visibility = View.VISIBLE + mViewModel.getSubCatalogs(mPrimaryCatalogId) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogViewModel.kt b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogViewModel.kt new file mode 100644 index 0000000000..12acf47463 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/catalog/SubCatalogViewModel.kt @@ -0,0 +1,44 @@ +package com.gh.gamecenter.catalog + +import android.annotation.SuppressLint +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.gh.gamecenter.entity.CatalogEntity +import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +class SubCatalogViewModel(application: Application, private val catalogId: String): AndroidViewModel(application) { + + private val api = RetrofitManager.getInstance(getApplication()).api + var catalogs = MutableLiveData() + + + @SuppressLint("CheckResult") + fun getSubCatalogs(primaryCatalogId: String) { + api.getSubCatalogs(catalogId, primaryCatalogId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: CatalogEntity) { + catalogs.postValue(data) + } + + override fun onFailure(exception: Exception) { + super.onFailure(exception) + catalogs.postValue(null) + } + }) + } + + class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return SubCatalogViewModel(HaloApp.getInstance().application, catalogId) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/category/CategoryDirectoryActivity.kt b/app/src/main/java/com/gh/gamecenter/category/CategoryDirectoryActivity.kt index faf8d247c3..e528b19922 100644 --- a/app/src/main/java/com/gh/gamecenter/category/CategoryDirectoryActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/category/CategoryDirectoryActivity.kt @@ -4,7 +4,6 @@ import android.content.Context import android.content.Intent import android.os.Bundle import com.gh.common.util.EntranceUtils -import com.gh.download.DownloadManager import com.gh.gamecenter.NormalActivity import com.gh.gamecenter.R diff --git a/app/src/main/java/com/gh/gamecenter/category/NewCategoryHorizontalAdapter.kt b/app/src/main/java/com/gh/gamecenter/category/NewCategoryHorizontalAdapter.kt index 430bdfd80b..cd078096e8 100644 --- a/app/src/main/java/com/gh/gamecenter/category/NewCategoryHorizontalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/category/NewCategoryHorizontalAdapter.kt @@ -27,21 +27,16 @@ class NewCategoryHorizontalAdapter(context: Context, override fun onBindViewHolder(holder: TagsViewHolder, position: Int) { val categoryEntity = mCategoryList[position] - val gradientDrawable = GradientDrawable() - gradientDrawable.shape = GradientDrawable.RECTANGLE if (mViewModel.selectedCategory.name == categoryEntity.name) { - gradientDrawable.setColor(ContextCompat.getColor(mContext, R.color.theme)) - gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat() + holder.tagTv.background = ContextCompat.getDrawable(mContext, R.drawable.bg_tag_text) holder.tagTv.setTextColor(Color.WHITE) } else { - gradientDrawable.setColor(Color.WHITE) - gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat() - holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_3a3a3a)) + holder.tagTv.background = null + holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_757575)) } holder.tagTv.text = categoryEntity.name - holder.tagTv.background = gradientDrawable holder.tagTv.setOnClickListener { mViewModel.changeSelectedCategory(categoryEntity) notifyDataSetChanged() diff --git a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListAdapter.kt b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListAdapter.kt index affa700591..6143b0e9cb 100644 --- a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListAdapter.kt @@ -11,6 +11,7 @@ import com.gh.common.exposure.ExposureType import com.gh.common.exposure.IExposable import com.gh.common.util.DownloadItemUtils import com.gh.common.util.StringUtils +import com.gh.common.util.dip2px import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder @@ -85,6 +86,9 @@ class NewCategoryListAdapter(context: Context, holder.initServerType(gameEntity) holder.binding.executePendingBindings() + val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px() + holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px()) + gameEntity.sequence = position + 1 val sortType = if ("download:-1" == mViewModel.getSortType()) "最热" else "最新" diff --git a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt index c0be80e13e..b40ef98c2f 100644 --- a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt @@ -114,6 +114,8 @@ class NewCategoryListFragment : ListFragment findByType(String type) { try { return dao.queryForEq("type", type); - } catch (SQLException e) { + } catch (SQLException | IllegalStateException e) { e.printStackTrace(); } return null; @@ -40,7 +40,8 @@ public class DataCollectionDao { public void add(DataCollectionInfo entity) { try { dao.create(entity); - } catch (SQLException e) { + } catch (SQLException | IllegalStateException e) { + // java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: e.printStackTrace(); } } @@ -51,7 +52,8 @@ public class DataCollectionDao { public void delete(String id) { try { dao.deleteById(id); - } catch (SQLException e) { + } catch (SQLException | IllegalStateException e) { + // java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: e.printStackTrace(); } } @@ -62,7 +64,7 @@ public class DataCollectionDao { public void delete(List ids) { try { dao.deleteIds(ids); - } catch (SQLException e) { + } catch (SQLException | IllegalStateException e) { e.printStackTrace(); } } @@ -73,7 +75,7 @@ public class DataCollectionDao { public DataCollectionInfo find(String id) { try { return dao.queryForId(id); - } catch (SQLException e) { + } catch (SQLException | IllegalStateException e) { e.printStackTrace(); } return null; @@ -85,7 +87,7 @@ public class DataCollectionDao { public List getAll() { try { return dao.queryForAll(); - } catch (SQLException e) { + } catch (SQLException | IllegalStateException e) { e.printStackTrace(); } return null; @@ -97,7 +99,7 @@ public class DataCollectionDao { public List getClickData() { try { return dao.queryForEq("type", "click-item"); - } catch (SQLException e) { + } catch (SQLException | IllegalStateException e) { e.printStackTrace(); } return null; @@ -109,7 +111,7 @@ public class DataCollectionDao { public void update(DataCollectionInfo entity) { try { dao.update(entity); - } catch (SQLException e) { + } catch (SQLException | IllegalStateException e) { e.printStackTrace(); } } diff --git a/app/src/main/java/com/gh/gamecenter/db/FilterDao.java b/app/src/main/java/com/gh/gamecenter/db/FilterDao.java index cced0beb3f..6b4579782f 100644 --- a/app/src/main/java/com/gh/gamecenter/db/FilterDao.java +++ b/app/src/main/java/com/gh/gamecenter/db/FilterDao.java @@ -1,6 +1,7 @@ package com.gh.gamecenter.db; import android.content.Context; +import android.database.sqlite.SQLiteException; import com.gh.gamecenter.db.info.PackageInfo; import com.j256.ormlite.dao.Dao; @@ -18,7 +19,7 @@ public class FilterDao { try { helper = DatabaseHelper.getHelper(context); dao = helper.getDao(PackageInfo.class); - } catch (SQLException e) { + } catch (SQLiteException | SQLException e) { e.printStackTrace(); } } @@ -31,7 +32,7 @@ public class FilterDao { if (list != null && list.size() != 0) { return list.get(0).getTime(); } - } catch (SQLException e) { + } catch (SQLiteException | SQLException e) { e.printStackTrace(); } return 0; @@ -43,7 +44,7 @@ public class FilterDao { if (filterEntity != null) { return true; } - } catch (SQLException e) { + } catch (SQLiteException | SQLException e) { e.printStackTrace(); } return false; @@ -55,7 +56,7 @@ public class FilterDao { public void add(PackageInfo entity) { try { dao.create(entity); - } catch (SQLException e) { + } catch (SQLiteException | SQLException e) { e.printStackTrace(); } } @@ -67,7 +68,7 @@ public class FilterDao { public void addAll(List list) { try { dao.create(list); - } catch (SQLException e) { + } catch (SQLiteException | SQLException e) { e.printStackTrace(); } } @@ -75,7 +76,7 @@ public class FilterDao { public void deleteAll(List list) { try { dao.delete(list); - } catch (SQLException e) { + } catch (SQLiteException | SQLException e) { e.printStackTrace(); } } @@ -86,7 +87,7 @@ public class FilterDao { public void delete(String packageName) { try { dao.deleteById(packageName); - } catch (SQLException e) { + } catch (SQLiteException | SQLException e) { e.printStackTrace(); } } @@ -97,7 +98,7 @@ public class FilterDao { public List getAll() { try { return dao.queryForAll(); - } catch (SQLException e) { + } catch (SQLiteException | SQLException e) { e.printStackTrace(); } return null; @@ -109,7 +110,7 @@ public class FilterDao { public long getCount() { try { return dao.countOf(); - } catch (SQLException e) { + } catch (SQLiteException | SQLException e) { e.printStackTrace(); } return 0; diff --git a/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java index 5de7aedcca..fc4a12916e 100644 --- a/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java @@ -541,8 +541,6 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter implemen GameEntity gameEntity = new GameEntity(updateEntity.getId(), updateEntity.getName()); gameEntity.setGameVersion(updateEntity.getVersion()); - DownloadManager.updateMetaMap(); - ExposureEvent event = ExposureUtils.logADownloadExposureEvent(gameEntity, updateEntity.getPlatform(), updateEntity.getExposureEvent(), downloadType); downloadEntity.setExposureTrace(GsonUtils.toJson(event)); diff --git a/app/src/main/java/com/gh/gamecenter/entity/CatalogEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/CatalogEntity.kt new file mode 100644 index 0000000000..01560db574 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/entity/CatalogEntity.kt @@ -0,0 +1,63 @@ +package com.gh.gamecenter.entity + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class CatalogEntity( + @SerializedName("_id") + var id: String = "", + var name: String = "", + var switch: CatalogSwitch = CatalogSwitch(), + @SerializedName("has_special") + var hasSpecial: Boolean = false, + @SerializedName("sub_catalogs") + var subCatalog: List = emptyList() +): Parcelable { + + @Parcelize + data class SubCatalogEntity( + @SerializedName("_id") + var id: String = "", + var name: String = "", + var icon: String = "", + var type: String = "", + var link: LinkEntity = LinkEntity(), + var recommended: Boolean = false + ): Parcelable + + @Parcelize + data class CatalogSwitch( + @SerializedName("sort_hot") + var hotSort: String = "", + @SerializedName("sort_new") + var newSort: String = "", + @SerializedName("sort_star") + var starSort: String = "" + ): Parcelable +} + + +@Parcelize +data class SpecialCatalogEntity( + @SerializedName("_id") + var id: String = "", + var type: String = "", + var link: SpecialLink = SpecialLink(), + var image: Image = Image() +): Parcelable { + + @Parcelize + data class SpecialLink( + @SerializedName("_id") + var id: String = "", + var data: List = emptyList() + ): LinkEntity(), Parcelable + + @Parcelize + data class Image( + var url: String = "", + var title: String = "" + ): Parcelable +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt index 635b618be4..9dce2abf99 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt @@ -22,13 +22,15 @@ data class CommentEntity(@SerializedName("_id") var priority: Int = 0, @SerializedName("me") var me: MeEntity? = null, + @SerializedName("is_top") + var isTop: Boolean = false,//是否置顶 // 楼数,本地字段 var floor: Int = 0, @SerializedName("attached") // 楼中楼 var subCommentList: ArrayList? = null) : Parcelable { - fun clone() : CommentEntity { - return CommentEntity(id, user, parent, parentUser, content, vote, reply, time, priority, me, floor, subCommentList) + fun clone(): CommentEntity { + return CommentEntity(id, user, parent, parentUser, content, vote, reply, time, priority, me, isTop, floor, subCommentList) } companion object { diff --git a/app/src/main/java/com/gh/gamecenter/entity/FollowersOrFansEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/FollowersOrFansEntity.kt index 2a7c5f589c..17bb46ef11 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/FollowersOrFansEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/FollowersOrFansEntity.kt @@ -17,7 +17,8 @@ data class FollowersOrFansEntity( data class Count( val vote: Int = 0, - val answer: Int = 0) + val answer: Int = 0, + val fans :Int= 0) } diff --git a/app/src/main/java/com/gh/gamecenter/entity/ForumEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ForumEntity.kt index 58f5fa4a37..2761bfc5f5 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/ForumEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/ForumEntity.kt @@ -8,8 +8,9 @@ data class ForumEntity( var game: SimpleGame = SimpleGame(), var name: String = "", @SerializedName("is_follow") - var isFollow: Boolean = false - + var isFollow: Boolean = false, + //本地字段,判断是否是推荐论坛 + var isRecommend: Boolean = false ) data class ForumCategoryEntity( diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt index d097349bf6..7eb7e27f47 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt @@ -223,8 +223,10 @@ data class GameEntity( @SerializedName("is_recently_played") var isRecentlyPlayed: Boolean = false, var active: Boolean = true, + @SerializedName("package_dialog") + val packageDialog: PackageDialogEntity? = null, - // 本地字段,使用镜像信息 + // 本地字段,使用镜像信息 var useMirrorInfo: Boolean = false, // 从启动弹窗跳转到对应游戏列表时候记录的启动弹窗数据 (ugly ugly ugly) var welcomeDialogId: String? = null, diff --git a/app/src/main/java/com/gh/gamecenter/entity/MessageUnreadEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/MessageUnreadEntity.kt index b0a20134a5..c83116e377 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/MessageUnreadEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/MessageUnreadEntity.kt @@ -65,6 +65,18 @@ class MessageUnreadEntity { @SerializedName("game_comment_reply_vote") var gameCommentReplyVote = 0 + @SerializedName("activity_comment") + var activityComment = 0 + + @SerializedName("reply_activity_comment") + var replyActivityComment = 0 + + @SerializedName("activity_comment_vote") + var activityCommentVote = 0 + + @SerializedName("activity_comment_reply_vote") + var activityCommentReplyVote = 0 + var fans: Int = 0 // 与其他未读区分 用于我的主页 var meta: Meta? = null @@ -84,8 +96,7 @@ class MessageUnreadEntity { tryWithDefaultCatch { val fields = this.javaClass.declaredFields for (field in fields) { - // TODO 处理 vote 可能不是 int 的情况 - if (field.name.toLowerCase(Locale.getDefault()).contains("vote")) { + if (field.name.toLowerCase(Locale.getDefault()).contains("vote") && field.type == Integer.TYPE) { voteCount += field.getInt(this) } } @@ -99,8 +110,7 @@ class MessageUnreadEntity { tryWithDefaultCatch { for (field in fields) { - // TODO 处理 vote 可能不是 int 的情况 - if (field.name.toLowerCase(Locale.getDefault()).contains("vote")) { + if (field.name.toLowerCase(Locale.getDefault()).contains("vote") && field.type == Integer.TYPE) { field.setInt(this, 0) } } diff --git a/app/src/main/java/com/gh/gamecenter/entity/PackageDialogEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/PackageDialogEntity.kt new file mode 100644 index 0000000000..2462a17888 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/entity/PackageDialogEntity.kt @@ -0,0 +1,44 @@ +package com.gh.gamecenter.entity + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class PackageDialogEntity( + val title: String = "", + val content: String = "", + @SerializedName("detection_objects") + val detectionObjects: ArrayList = arrayListOf(), + @SerializedName("link_hint_text") + val linkHintText: String = "", + val links: ArrayList = arrayListOf(), + val level: String = "HINT_SKIP"// 弹窗级别,HINT_SKIP(提示且跳转)、ALWAYS_HINT(仅提示(每次提示))、OPTIONAL_HINT(仅提示(可不再提示)) +) : Parcelable + +@Parcelize +data class DetectionObjectEntity( + val text: String = "", + val packages: ArrayList = arrayListOf() +) : Parcelable + +@Parcelize +data class PackageLink( + val text: String = "", + @SerializedName("link_type") + val linkType: String = "", + @SerializedName("link_id") + val linkId: String = "", + @SerializedName("link_text") + val linkText: String = "", + @SerializedName("button_link") + val buttonLink: Boolean = false +) : Parcelable { + fun transform(): LinkEntity { + val entity = LinkEntity() + entity.linkText = linkText + entity.type = linkType + entity.link = linkId + return entity + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/PersonalHistoryEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/PersonalHistoryEntity.kt index b5ff015bf0..0745b9b656 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/PersonalHistoryEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/PersonalHistoryEntity.kt @@ -29,7 +29,10 @@ data class PersonalHistoryEntity( val images: List = ArrayList(), val me: MeEntity = MeEntity(), var comment: Comment = Comment(), - var commentable: Boolean = true) : Parcelable { + var commentable: Boolean = true, + @SerializedName("is_edit") + var isEdit: Boolean = false +) : Parcelable { fun getPassVideos(): List { val passVideos = arrayListOf() diff --git a/app/src/main/java/com/gh/gamecenter/entity/PrivacyPolicyEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/PrivacyPolicyEntity.kt index ceda1fc35d..4b970d2035 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/PrivacyPolicyEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/PrivacyPolicyEntity.kt @@ -26,7 +26,7 @@ data class PrivacyPolicyEntity( permissions.add(PermissionsEntity( icon = "res:///" + R.drawable.permission_phone_state, name = "设备信息", - intro = "获取设备型号等信息,保证功能的适配与完整性")) + intro = "为保障您的账号安全及使用软件与服务可安全运行")) // permissions.add(PermissionsEntity( // icon = "res:///" + R.drawable.permission_sdk, // name = "第三方SDK使用信息提醒", diff --git a/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt index 028b7af135..c3ce229984 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt @@ -32,7 +32,9 @@ data class SettingsEntity( @SerializedName("game_dome_switch") var gameDomeSwitch: String = "",//试玩显示开关,on打开 @SerializedName("permission_popup_switch") - var permissionPopupSwitch: String = "off"//权限引导弹窗开关,on/off + var permissionPopupSwitch: String = "off",//权限引导弹窗开关,on/off + @SerializedName("permission_popup_applied_versions") + var permissionPopupAppliedVersions: PermissionPopupAppliedVersions = PermissionPopupAppliedVersions() ) { fun setCommunityEntrance(communityEntrance: String) { @@ -211,4 +213,10 @@ data class SettingsEntity( var display: Display? = Display() ) + data class PermissionPopupAppliedVersions( + val install: ArrayList = arrayListOf(), + @SerializedName("xapk_unzip") + val xapkUnzip: ArrayList = arrayListOf() + ) + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/SubjectSettingEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SubjectSettingEntity.kt index afc10d941c..3108bf59c2 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/SubjectSettingEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/SubjectSettingEntity.kt @@ -43,7 +43,7 @@ data class SubjectSettingEntity( @Parcelize data class Size(var min: Int? = -1, var max: Int? = -1, - var text: String? = "") : Parcelable + var text: String? = "全部大小") : Parcelable } diff --git a/app/src/main/java/com/gh/gamecenter/eventbus/EBCommentSuccess.java b/app/src/main/java/com/gh/gamecenter/eventbus/EBCommentSuccess.java new file mode 100644 index 0000000000..7be696adf1 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/eventbus/EBCommentSuccess.java @@ -0,0 +1,5 @@ +package com.gh.gamecenter.eventbus; + +public class EBCommentSuccess { + +} diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListAdapter.kt index 88f7cb9870..d62c2f4f90 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListAdapter.kt @@ -66,11 +66,11 @@ class ForumArticleAskListAdapter(context: Context, val bbsId: String, val mEntra val binding = answerViewHolder.binding binding.forumNameLl.visibility = View.GONE - val params = binding.includeVoteAndComment.layoutParams as LinearLayout.LayoutParams + val params = binding.includeVoteAndComment.root.layoutParams as LinearLayout.LayoutParams params.width = LinearLayout.LayoutParams.MATCH_PARENT params.leftMargin = 0 params.rightMargin = 0 - binding.includeVoteAndComment.layoutParams = params + binding.includeVoteAndComment.root.layoutParams = params answerViewHolder.bindForumAnswerItem(answer, mEntrance, path) answerViewHolder.itemView.setOnClickListener { diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt index 5349744947..a669d8a981 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt @@ -29,14 +29,17 @@ import com.gh.common.util.* import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.databinding.FragmentForumDetailBinding -import com.gh.gamecenter.entity.* +import com.gh.gamecenter.entity.CommunityEntity +import com.gh.gamecenter.entity.ForumDetailEntity +import com.gh.gamecenter.entity.ForumEntity +import com.gh.gamecenter.entity.UserEntity import com.gh.gamecenter.eventbus.EBForumFollowChange import com.gh.gamecenter.eventbus.EBTypeChange import com.gh.gamecenter.forum.moderator.ModeratorListActivity +import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity import com.gh.gamecenter.gamedetail.GameDetailFragment import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.mvvm.Status -import com.gh.gamecenter.personalhome.UserHomeActivity import com.gh.gamecenter.qa.article.edit.ArticleEditActivity import com.gh.gamecenter.qa.questions.edit.QuestionEditActivity import com.google.android.material.appbar.AppBarLayout @@ -215,9 +218,12 @@ class ForumDetailFragment : BaseLazyTabFragment() { } } - @OnClick(R.id.filterContainer, R.id.community_edit, R.id.moderatorTv, R.id.reuse_no_connection, R.id.gameZoneTv, R.id.followTv, R.id.forumThumbBig) + @OnClick(R.id.filterContainer, R.id.community_edit, R.id.moderatorTv, R.id.reuse_no_connection, R.id.gameZoneTv, R.id.followTv, R.id.forumThumbBig, R.id.searchIv) fun onViewClick(view: View) { when (view.id) { + R.id.searchIv -> { + requireContext().startActivity(ForumOrUserSearchActivity.getIntent(requireContext(), bbsId, "论坛详情")) + } R.id.filterContainer -> { MtaHelper.onEvent("论坛详情", "全部Tab", "过滤选项") showFilterPopupWindow { @@ -289,9 +295,11 @@ class ForumDetailFragment : BaseLazyTabFragment() { if (isToolbarWhite) { DisplayUtils.setLightStatusBar(requireActivity(), true) mBinding.toolbar.setNavigationIcon(R.drawable.ic_back_gamedetail) + mBinding.searchIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_forum_detail_search)) } else { DisplayUtils.setLightStatusBar(requireActivity(), false) mBinding.toolbar.setNavigationIcon(R.drawable.ic_back_gamedetail_white) + mBinding.searchIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_forum_detail_search_light)) } } } @@ -389,7 +397,7 @@ class ForumDetailFragment : BaseLazyTabFragment() { dialog.show() contentView.findViewById(R.id.community_edit_article).setOnClickListener { context?.ifLogin("论坛详情", action = { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { MtaHelper.onEvent("论坛详情", "发布", "发帖子") startActivity(ArticleEditActivity.getIntent(requireContext(), CommunityEntity(mForumDetail?.id ?: "", mForumDetail?.name ?: ""))) @@ -399,7 +407,7 @@ class ForumDetailFragment : BaseLazyTabFragment() { } contentView.findViewById(R.id.community_edit_question).setOnClickListener { context?.ifLogin("论坛详情", action = { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { MtaHelper.onEvent("论坛详情", "发布", "提问") startActivity(QuestionEditActivity.getIntent(requireContext(), CommunityEntity(mForumDetail?.id ?: "", mForumDetail?.name ?: ""))) diff --git a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowAdapter.kt index 9b9de767e3..f5f9a4ea8b 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowAdapter.kt @@ -1,6 +1,7 @@ package com.gh.gamecenter.forum.follow import android.content.Context +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -68,10 +69,12 @@ class ForumMyFollowAdapter(context: Context, val mViewModel: ForumMyFollowViewMo popupWindow.dismiss() when (text) { "取消关注" -> { - MtaHelper.onEvent("论坛首页", "我关注的论坛", "取消关注") - mViewModel.unFollowForum(entity.id) { - EventBus.getDefault().post(EBForumFollowChange(entity, false)) - } + DialogUtils.showNewAlertDialog(mContext, "提示", "确定取消关注", "暂不", "确定", null, Gravity.CENTER, {}, { + MtaHelper.onEvent("论坛首页", "我关注的论坛", "取消关注") + mViewModel.unFollowForum(entity.id) { + EventBus.getDefault().post(EBForumFollowChange(entity, false)) + } + }) } } } diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt index 4c3e6c576e..f7036b5f51 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt @@ -8,6 +8,7 @@ import com.gh.common.util.* import com.gh.gamecenter.R import com.gh.gamecenter.databinding.CommunityAnswerItemBinding import com.gh.gamecenter.entity.CommunityEntity +import com.gh.gamecenter.forum.detail.ForumDetailActivity import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.qa.answer.BaseAnswerOrArticleItemViewHolder import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity @@ -34,7 +35,7 @@ class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : B binding.entity = entity binding.executePendingBindings() - binding.userIcon.display(entity.user.border,entity.user.icon,entity.user.auth?.icon) + binding.userIcon.display(entity.user.border, entity.user.icon, entity.user.auth?.icon) binding.forumNameTv.text = entity.bbs.name if (entity.type == "question") { binding.content.visibility = View.GONE @@ -84,6 +85,11 @@ class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : B voteCount.text = "邀请回答" voteIcon.setImageDrawable(ContextCompat.getDrawable(itemView.context, R.drawable.community_invite_follow)) } + forumNameTv.setOnClickListener { + MtaHelper.onEvent(getEventId(entrance), getKey(entrance), if (entity.bbs.name.isEmpty()) entity.bbs.name else entity.bbs.name) + itemView.context.startActivity(ForumDetailActivity.getIntent(itemView.context, entity.bbs.id, entrance)) + LogUtils.uploadAccessToBbs(entity.bbs.id, "文章外所属论坛") + } commentCountContainer.setOnClickListener { if (filterIllegalCommentStatus(entity.commentable, entity.active)) return@setOnClickListener diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumFollowAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumFollowAdapter.kt index 153ae161f1..0d4097be7a 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumFollowAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumFollowAdapter.kt @@ -29,6 +29,7 @@ class ForumFollowAdapter(context: Context) : BaseRecyclerAdapter) mForumFollowAdapter?.setListData(it) } else { mViewPager.currentItem = TAB_TITLE_RECOMMEND_POS @@ -106,7 +104,7 @@ class ForumHomeFragment : BaseLazyTabFragment() { super.onViewCreated(view, savedInstanceState) refreshLayout.setOnRefreshListener { mViewModel?.loadSlide() - if (UserManager.getInstance().isLoggedIn) mViewModel?.loadFollowsForum() + mViewModel?.loadForums() if (mFollowForumArticleListFragment != null && mViewPager.currentItem == TAB_TITLE_FOLLOW_POS) { if (UserManager.getInstance().isLoggedIn) { mFollowForumArticleListFragment?.onRefresh() @@ -140,9 +138,7 @@ class ForumHomeFragment : BaseLazyTabFragment() { if (!UserManager.getInstance().isLoggedIn) { mViewPager.currentItem = TAB_TITLE_RECOMMEND_POS } - if (UserManager.getInstance().isLoggedIn) { - mViewModel?.loadFollowsForum() - } + mViewModel?.loadForums() mViewModel?.loadSlide() showGuideMask() } @@ -154,7 +150,7 @@ class ForumHomeFragment : BaseLazyTabFragment() { mForumFollowRv.getLocationOnScreen(location) mGuideMaskView.visibility = View.VISIBLE val params = mGuideContainer.layoutParams as RelativeLayout.LayoutParams - params.topMargin = location[1] - 18f.dip2px() + params.topMargin = location[1] - 12f.dip2px() mGuideContainer.layoutParams = params mGuideMaskView.setOnClickListener { /*do nothing*/ } mGuideIv.setOnClickListener { @@ -165,13 +161,13 @@ class ForumHomeFragment : BaseLazyTabFragment() { } private fun initViewPager(slide: List) { - mContainerLl.removeViewAt(0) + mContainerLl.removeViewAt(1) val pageAdapter = ForumBannerPageAdapter(context, slide) mBannerView.pageMargin = DisplayUtils.dip2px(10f) mBannerView.offscreenPageLimit = 3 mBannerView.adapter = pageAdapter mBannerView.setCurrentItem(pageAdapter.actualFirstPositionInCenter, false) - mContainerLl.addView(mBannerView, 0) + mContainerLl.addView(mBannerView, 1) mBannerView.addOnScrollStateChanged(onStateChanged = { pageAdapter.setScrollState(it) }) @@ -227,9 +223,12 @@ class ForumHomeFragment : BaseLazyTabFragment() { tabTitleList.add(TAB_TITLE_RECOMMEND) } - @OnClick(R.id.community_edit, R.id.forumFollowTv, R.id.filterContainer) + @OnClick(R.id.actionbar_search_rl, R.id.community_edit, R.id.forumFollowTv, R.id.filterContainer) fun onViewClicked(view: View) { when (view.id) { + R.id.actionbar_search_rl -> { + requireContext().startActivity(ForumOrUserSearchActivity.getIntent(requireContext(), "", "论坛首页")) + } R.id.filterContainer -> { showFilterPopupWindow { mFilter = it @@ -257,6 +256,8 @@ class ForumHomeFragment : BaseLazyTabFragment() { override fun onResume() { super.onResume() sendScrollMessage() + ForumVisitDao.getInstance().sortForumList(mForumFollowAdapter?.entityList) + mForumFollowAdapter?.notifyDataSetChanged() DisplayUtils.setLightStatusBar(requireActivity(), true) } @@ -331,7 +332,7 @@ class ForumHomeFragment : BaseLazyTabFragment() { dialog.show() contentView.findViewById(R.id.community_edit_article).setOnClickListener { context?.ifLogin("论坛首页", action = { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { showRegulationTestDialogIfNeeded { MtaHelper.onEvent("论坛首页", "发布", "发帖子") startActivity(ArticleEditActivity.getIntent(requireContext(), null)) @@ -342,7 +343,7 @@ class ForumHomeFragment : BaseLazyTabFragment() { } contentView.findViewById(R.id.community_edit_question).setOnClickListener { context?.ifLogin("论坛首页", action = { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { showRegulationTestDialogIfNeeded { MtaHelper.onEvent("论坛首页", "发布", "提问") startActivity(QuestionEditActivity.getIntent(requireContext())) @@ -381,13 +382,16 @@ class ForumHomeFragment : BaseLazyTabFragment() { fun onFollowForumChange(forumFollowChange: EBForumFollowChange) { val entityList = mForumFollowAdapter?.entityList ?: arrayListOf() if (forumFollowChange.isFollow) { - entityList.add(forumFollowChange.forumEntity) - mForumFollowAdapter?.notifyDataSetChanged() +// entityList.add(forumFollowChange.forumEntity) +// mForumFollowAdapter?.notifyDataSetChanged() + mViewModel?.loadForums() mFollowForumArticleListFragment?.onRefresh() } else { val findEntity = entityList.find { it.id == forumFollowChange.forumEntity.id } - entityList.remove(findEntity) - mForumFollowAdapter?.notifyDataSetChanged() +// entityList.remove(findEntity) +// mForumFollowAdapter?.notifyDataSetChanged() + ForumVisitDao.getInstance().delete(findEntity?.id ?: "") + mViewModel?.loadForums() mFollowForumArticleListFragment?.onRefresh() } } diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumHomeViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumHomeViewModel.kt index 2383a604fc..861f9f34f7 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumHomeViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumHomeViewModel.kt @@ -1,14 +1,21 @@ package com.gh.gamecenter.forum.home +import android.annotation.SuppressLint import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MediatorLiveData +import com.gh.common.util.observableToMain +import com.gh.common.util.toRequestBody import com.gh.gamecenter.entity.ForumEntity import com.gh.gamecenter.entity.LinkEntity +import com.gh.gamecenter.manager.PackagesManager import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager +import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.functions.BiFunction +import io.reactivex.functions.Function import io.reactivex.schedulers.Schedulers import retrofit2.HttpException @@ -16,7 +23,7 @@ class ForumHomeViewModel(application: Application) : AndroidViewModel(applicatio val slideLiveData = MediatorLiveData>() val forumData = MediatorLiveData>() - fun loadSlide() { + fun loadSlide() { RetrofitManager.getInstance(getApplication()).api .forumSlide .subscribeOn(Schedulers.io()) @@ -34,11 +41,16 @@ class ForumHomeViewModel(application: Application) : AndroidViewModel(applicatio }) } - fun loadFollowsForum(){ - RetrofitManager.getInstance(getApplication()).api - .getFollowsForum(UserManager.getInstance().userId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) + fun loadForums() { + Observable.zip(loadFollowsForum(), getRecommendForum(), BiFunction, List, ArrayList> { t1, t2 -> + val list = arrayListOf() + list.addAll(t1) + t2.forEach { + it.isRecommend = true + list.add(it) + } + list + }).compose(observableToMain()) .subscribe(object : Response>() { override fun onResponse(response: List?) { super.onResponse(response) @@ -50,5 +62,32 @@ class ForumHomeViewModel(application: Application) : AndroidViewModel(applicatio forumData.postValue(null) } }) + + } + + + private fun loadFollowsForum(): Observable> { + return if (UserManager.getInstance().isLoggedIn) { + RetrofitManager.getInstance(getApplication()).api + .getFollowsForum(UserManager.getInstance().userId) + } else { + Observable.create> { + it.onNext(listOf()) + } + } + } + + private fun getRecommendForum(): Observable> { + val installedList = PackagesManager.filterSameApk(PackagesManager.filterDownloadBlackPackage(PackagesManager.getInstalledList())) + val gameIds = installedList.map { it.id }.toList() + val requestMap = hashMapOf() + requestMap["game_ids"] = gameIds + return if (UserManager.getInstance().isLoggedIn) { + RetrofitManager.getInstance(getApplication()).api + .getRecommendForum(UserManager.getInstance().userId, requestMap.toRequestBody()) + } else { + RetrofitManager.getInstance(getApplication()).api.getRecommendForumNotLoggedIn(requestMap.toRequestBody()) + } + } } diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumVisitDao.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumVisitDao.kt new file mode 100644 index 0000000000..5bbc52040b --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumVisitDao.kt @@ -0,0 +1,80 @@ +package com.gh.gamecenter.forum.home + +import com.gh.common.util.SPUtils +import com.gh.gamecenter.entity.ForumEntity + +class ForumVisitDao { + fun add(id: String) { + val originString = SPUtils.getString(SP_KEY) + + if (originString.isEmpty()) { + SPUtils.setString(SP_KEY, id) + } else { + getAll()?.let { + if (it.contains(id)) { + it.remove(id) + } + it.add(0, id) + save(it) + } + } + } + + fun delete(id: String) { + val originString = SPUtils.getString(SP_KEY) + if (originString.isNotEmpty()) { + getAll()?.let { + if (it.contains(id)) { + it.remove(id) + } + save(it) + } + } + } + + private fun save(it: ArrayList) { + val builder = StringBuilder() + for ((index, key) in it.withIndex()) { + builder.append(key) + if (index != it.size - 1) { + builder.append(DIVIDER) + } + } + SPUtils.setString(SP_KEY, builder.toString()) + } + + fun sortForumList(originalForums: ArrayList?) { + if (originalForums.isNullOrEmpty()) return + val visitRecords = getAll() + val tempList = arrayListOf() + visitRecords?.forEach { id -> + val index = originalForums.indexOfFirst { it.id == id } + if (index >= 0) { + tempList.add(originalForums.removeAt(index)) + } + } + tempList.addAll(originalForums) + originalForums.clear() + originalForums.addAll(tempList) + } + + fun getAll(): ArrayList? { + val list = SPUtils.getString(SP_KEY).split(DIVIDER) + + return if (list.size == 1 && list[0].isEmpty()) null else ArrayList(list) + } + + companion object { + private const val SP_KEY = "forum_visit_key" + private const val DIVIDER = "<-||->" + + @Volatile + private var instance: ForumVisitDao? = null + + fun getInstance(): ForumVisitDao { + return instance ?: synchronized(this) { + instance ?: ForumVisitDao().also { instance = it } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt new file mode 100644 index 0000000000..85d51fe658 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt @@ -0,0 +1,178 @@ +package com.gh.gamecenter.forum.search + +import android.content.Context +import android.text.SpannableStringBuilder +import android.text.Spanned +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import com.gh.base.BaseActivity +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.constant.ItemViewType +import com.gh.common.syncpage.ISyncAdapterHandler +import com.gh.common.util.ImageUtils +import com.gh.common.util.MtaHelper +import com.gh.common.util.dip2px +import com.gh.common.util.fromHtml +import com.gh.common.view.CenterImageSpan +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.databinding.CommunityAnswerItemBinding +import com.gh.gamecenter.databinding.ForumSearchContentListBinding +import com.gh.gamecenter.entity.CommunityEntity +import com.gh.gamecenter.entity.RatingComment +import com.gh.gamecenter.forum.home.ForumArticleAskItemViewHolder +import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity +import com.gh.gamecenter.qa.entity.AnswerEntity +import com.gh.gamecenter.qa.entity.Questions +import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity + +class ForumContentSearchListAdapter(context: Context, val mListViewModel: ForumContentSearchListViewModel, val mEntrance: String) : ListAdapter(context), ISyncAdapterHandler { + + override fun setListData(updateData: MutableList) { + var oldSize = 0 + if (mEntityList != null && mEntityList.size > 0) { + oldSize += mEntityList.size + } + mEntityList = ArrayList(updateData) + if (oldSize == 0 || oldSize > updateData.size || mListViewModel.getLinkPageSize() == 2 /* 第一页 */) { + notifyDataSetChanged() + } else { + notifyItemRangeInserted(oldSize, updateData.size - oldSize) + } + } + + override fun getItemViewType(position: Int): Int { + if (position == itemCount - 1) return ItemViewType.ITEM_FOOTER + return ItemViewType.ITEM_BODY + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + ItemViewType.ITEM_FOOTER -> { + FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)) + } + else -> { + if (mEntrance == "论坛首页+(搜索)") { + ForumArticleAskItemViewHolder(CommunityAnswerItemBinding.bind(mLayoutInflater.inflate(R.layout.community_answer_item, parent, false))) + } else { + ForumSearchContentListViewHolder(ForumSearchContentListBinding.bind(mLayoutInflater.inflate(R.layout.forum_search_content_list, parent, false))) + } + } + } + } + + override fun getItemCount(): Int { + return if (mEntityList.isNotEmpty()) mEntityList.size + FOOTER_ITEM_COUNT else 0 + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (getItemViewType(position)) { + ItemViewType.ITEM_BODY -> { + val answer = mEntityList[position] + val questions = Questions() + questions.id = answer.id ?: "" + questions.title = answer.articleTitle + questions.answerCount = answer.answerCount + answer.questions = questions + + if (mEntrance == "论坛首页+(搜索)") { + val answerViewHolder = holder as ForumArticleAskItemViewHolder + answerViewHolder.bindForumAnswerItem(answer, mEntrance, "") + if (answer.type == "question") { + answerViewHolder.binding.content.visibility = View.GONE + val title = answer.questions.title ?: "" + val spannableStringBuilder = SpannableStringBuilder(" ") + spannableStringBuilder.setSpan(CenterImageSpan(mContext, R.drawable.ic_ask_label), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + spannableStringBuilder.append(title.fromHtml()) + answerViewHolder.binding.title.text = spannableStringBuilder + } else { + answerViewHolder.binding.content.visibility = View.VISIBLE + answerViewHolder.binding.title.text = answer.questions.title?.fromHtml() + } + answerViewHolder.binding.content.text = answer.brief?.fromHtml() + answerViewHolder.itemView.setOnClickListener { + val entrance = BaseActivity.mergeEntranceAndPath(mEntrance, "") + if ("community_article" == answer.type) { + MtaHelper.onEvent(holder.getEventId(entrance), holder.getKey(entrance), "${answer.articleTitle}(${answer.id})") + mContext.startActivity(ArticleDetailActivity.getIntent(mContext, CommunityEntity(answer.bbs.id), answer.id!!, mEntrance, "")) + } else { + MtaHelper.onEvent(holder.getEventId(entrance), holder.getKey(entrance), "${answer.articleTitle}(${answer.id})") + mContext.startActivity(QuestionsDetailActivity.getIntent(mContext, answer.id, mEntrance, "")) + } + } + if (answer.type != "community_article") { + if (answer.questions.answerCount > 0) { + answerViewHolder.commentCount.text = answer.questions.answerCount.toString() + } else { + answerViewHolder.commentCount.text = "回答" + } + answerViewHolder.voteCountContainer.visibility = View.GONE + val params = answerViewHolder.binding.includeVoteAndComment.root.layoutParams as LinearLayout.LayoutParams + params.width = 80f.dip2px() + answerViewHolder.binding.includeVoteAndComment.root.layoutParams = params + } + + } else { + val forumSearchHolder = holder as ForumSearchContentListViewHolder + forumSearchHolder.binding.entity = answer + if (answer.type == "question") { + forumSearchHolder.binding.content.visibility = View.GONE + val title = answer.questions.title ?: "" + val spannableStringBuilder = SpannableStringBuilder(" ") + spannableStringBuilder.setSpan(CenterImageSpan(mContext, R.drawable.ic_ask_label), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + spannableStringBuilder.append(title.fromHtml()) + forumSearchHolder.binding.title.text = spannableStringBuilder + } else { + forumSearchHolder.binding.content.visibility = View.VISIBLE + forumSearchHolder.binding.title.text = answer.questions.title?.fromHtml() + } + when { + answer.getPassVideos().isNotEmpty() -> { + val poster = answer.getPassVideos()[0].poster + ImageUtils.display(forumSearchHolder.binding.image, poster, false) + forumSearchHolder.binding.image.visibility = View.VISIBLE + } + answer.images.isNotEmpty() -> { + forumSearchHolder.binding.image.visibility = View.VISIBLE + ImageUtils.display(forumSearchHolder.binding.image, answer.images[0], false) + } + else -> { + forumSearchHolder.binding.image.visibility = View.GONE + } + } + + forumSearchHolder.binding.content.text = answer.brief?.fromHtml() + forumSearchHolder.itemView.setOnClickListener { + if ("community_article" == answer.type) { + mContext.startActivity(ArticleDetailActivity.getIntent(mContext, CommunityEntity(answer.bbs.id), answer.id!!, mEntrance, "")) + } else { + mContext.startActivity(QuestionsDetailActivity.getIntent(mContext, answer.id, mEntrance, "")) + } + } + } + } + ItemViewType.ITEM_FOOTER -> { + val footerViewHolder = holder as FooterViewHolder + footerViewHolder.initItemPadding() + footerViewHolder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_content_hint) + footerViewHolder.itemView.setPadding(0, 18f.dip2px(), 0, 18f.dip2px()) + footerViewHolder.hint.textSize = 12f + footerViewHolder.hint.setTextColor(ContextCompat.getColor(mContext, R.color.aaaaaa)) + footerViewHolder.lineLeft.visibility = View.GONE + footerViewHolder.lineRight.visibility = View.GONE + } + } + } + + class ForumSearchContentListViewHolder(val binding: ForumSearchContentListBinding) : BaseRecyclerViewHolder(binding.root) + + override fun getSyncData(position: Int): Pair? { + if (position >= mEntityList.size) return null + val entity = mEntityList[position] + return Pair(entity.id ?: "", entity) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListFragment.kt new file mode 100644 index 0000000000..1754c8a20d --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListFragment.kt @@ -0,0 +1,66 @@ +package com.gh.gamecenter.forum.search + +import android.os.Bundle +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.DisplayUtils +import com.gh.common.util.EntranceUtils +import com.gh.common.util.viewModelProvider +import com.gh.common.view.divider.HorizontalDividerItemDecoration +import com.gh.gamecenter.R +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.qa.entity.AnswerEntity + +class ForumContentSearchListFragment : ListFragment() { + + private var bbsId = "" + private var mSearchKey = "" + private var mAdapter: ForumContentSearchListAdapter? = null + + override fun provideListAdapter(): ListAdapter<*> { + return mAdapter + ?: ForumContentSearchListAdapter(requireContext(), mListViewModel, "${mEntrance}+(搜索)").apply { mAdapter = this } + } + + override fun provideListViewModel(): ForumContentSearchListViewModel { + val factory = ForumContentSearchListViewModel.Factory(bbsId) + return viewModelProvider(factory) + } + + override fun isAutomaticLoad(): Boolean = false + + fun setSearchKey(searchKey: String) { + mSearchKey = searchKey + mListViewModel?.updateSearchKey(mSearchKey) + } + + override fun onCreate(savedInstanceState: Bundle?) { + bbsId = arguments?.getString(EntranceUtils.KEY_BBS_ID) ?: "" + super.onCreate(savedInstanceState) + mListRv.overScrollMode = View.OVER_SCROLL_NEVER + mListRv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white)) + mReuseNoData?.findViewById(R.id.reuseNoneDataIv)?.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.pic_no_data)) + mReuseNoData?.findViewById(R.id.reuse_tv_none_data)?.text = "搜索结果为空,换个搜索词试试" + mReuseNoData?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white)) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mListViewModel?.updateSearchKey(mSearchKey) + } + + override fun getItemDecoration(): RecyclerView.ItemDecoration? { + return HorizontalDividerItemDecoration.Builder(requireContext()) + .size(DisplayUtils.dip2px(0.5f)) + .margin(DisplayUtils.dip2px(20f)) + .color(ContextCompat.getColor(requireContext(), R.color.text_f5f5f5)).build() + } + + override fun addSyncPageObserver(): Boolean = true + + override fun provideSyncAdapter(): ForumContentSearchListAdapter = mAdapter!! +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListViewModel.kt new file mode 100644 index 0000000000..3c2836d59d --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListViewModel.kt @@ -0,0 +1,45 @@ +package com.gh.gamecenter.forum.search + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.gh.common.util.UrlFilterUtils +import com.gh.gamecenter.baselist.ListViewModel +import com.gh.gamecenter.baselist.LoadType +import com.gh.gamecenter.qa.article.detail.ArticleDetailViewModel +import com.gh.gamecenter.qa.entity.AnswerEntity +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.Observable + +class ForumContentSearchListViewModel(application: Application, val bbsId: String) : ListViewModel(application) { + var searchKey = "" + + override fun provideDataObservable(page: Int): Observable>? { + val map = hashMapOf("keyword" to searchKey) + if (bbsId.isNotEmpty()) { + map["bbs_id"] = bbsId + } + return RetrofitManager.getInstance(getApplication()).api.searchForumContent(map, page) + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) } + } + + fun updateSearchKey(searchKey: String) { + this.searchKey = searchKey + load(LoadType.REFRESH) + } + + fun getLinkPageSize(): Int { + return mCurLoadParams.loadOffset + } + + class Factory(private val bbsId: String) : ViewModelProvider.NewInstanceFactory() { + + override fun create(modelClass: Class): T { + return ForumContentSearchListViewModel(HaloApp.getInstance().application, bbsId) as T + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchActivity.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchActivity.kt new file mode 100644 index 0000000000..6b3945f73b --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchActivity.kt @@ -0,0 +1,101 @@ +package com.gh.gamecenter.forum.search + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.text.TextUtils +import androidx.core.os.bundleOf +import com.gh.common.constant.Constants +import com.gh.common.util.DirectUtils +import com.gh.common.util.EntranceUtils +import com.gh.common.util.showKeyBoard +import com.gh.gamecenter.DisplayType +import com.gh.gamecenter.R +import com.gh.gamecenter.SearchActivity +import com.gh.gamecenter.SearchType +import com.gh.gamecenter.search.SearchDefaultFragment +import kotlinx.android.synthetic.main.toolbar_search.* + +class ForumOrUserSearchActivity : SearchActivity() { + + private val mSearchHistoryDao by lazy { ForumSearchDao() } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + searchEt.hint = if (mEntrance == "论坛首页") { + "搜索论坛内容、用户" + } else { + "搜索此论坛中的内容" + } + searchEt.showKeyBoard() + } + + override fun search(type: SearchType, key: String?) { + mSearchType = type + mIsAutoSearchDisabled = true + + when (type) { + SearchType.AUTO -> { + mSearchKey = key + updateDisplayType(DisplayType.FORUM_OR_USER) + } + + SearchType.HISTORY -> { + mSearchKey = key + searchEt.setText(key) + searchEt.setSelection(searchEt.text.length) + updateDisplayType(DisplayType.FORUM_OR_USER) + } + else -> { + val newSearchKey = searchEt.text.toString().trim { it <= ' ' } + if (newSearchKey != mSearchKey || mDisplayType != DisplayType.GAME_DETAIL) { + mSearchKey = newSearchKey + if (!TextUtils.isEmpty(mSearchKey)) { + mSearchHistoryDao.add(mSearchKey!!) + updateDisplayType(DisplayType.FORUM_OR_USER) + } else { + toast("请先输入搜索内容再搜索~") + } + } + } + } + + mIsAutoSearchDisabled = false + } + + override fun updateDisplayType(type: DisplayType) { + val transaction = supportFragmentManager.beginTransaction() + when (type) { + DisplayType.DEFAULT -> { + val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.simpleName) + ?: ForumOrUserSearchDefaultFragment() + transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.simpleName) + } + else -> { + if (mEntrance == "论坛首页") { + val fragment = supportFragmentManager.findFragmentByTag(ForumOrUserSearchFragment::class.java.simpleName) as? ForumOrUserSearchFragment + ?: ForumOrUserSearchFragment() + fragment.setSearchKey(mSearchKey ?: "") + transaction.replace(R.id.search_result, fragment, ForumOrUserSearchFragment::class.java.simpleName) + } else { + val fragment = supportFragmentManager.findFragmentByTag(ForumContentSearchListFragment::class.java.simpleName) as? ForumContentSearchListFragment + ?: ForumContentSearchListFragment() + fragment.setSearchKey(mSearchKey ?: "") + fragment.arguments = intent.extras + transaction.replace(R.id.search_result, fragment, ForumContentSearchListFragment::class.java.simpleName) + } + } + } + mDisplayType = type + transaction.commitAllowingStateLoss() + } + + companion object { + fun getIntent(context: Context, bbsId: String, mEntrance: String): Intent { + val intent = Intent(context, ForumOrUserSearchActivity::class.java) + intent.putExtra(EntranceUtils.KEY_BBS_ID, bbsId) + intent.putExtra(EntranceUtils.KEY_ENTRANCE, mEntrance) + return intent + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultFragment.kt new file mode 100644 index 0000000000..535cce6ac7 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultFragment.kt @@ -0,0 +1,49 @@ +package com.gh.gamecenter.forum.search + +import android.view.View +import androidx.constraintlayout.widget.ConstraintLayout +import com.gh.common.util.DialogUtils +import com.gh.common.util.dip2px +import com.gh.gamecenter.databinding.FragmentSearchDefaultBinding +import com.gh.gamecenter.eventbus.EBSearch +import com.gh.gamecenter.search.SearchDefaultFragment +import com.lightgame.utils.Util_System_Keyboard +import org.greenrobot.eventbus.EventBus + +class ForumOrUserSearchDefaultFragment : SearchDefaultFragment() { + + private lateinit var mSearchDao: ForumSearchDao + + override fun initDao() { + mSearchDao = ForumSearchDao() + mHistoryList = mSearchDao.getAll() + } + + override fun initView() { + mBinding = FragmentSearchDefaultBinding.bind(mCachedView) + mBinding.hotTagTitle.visibility = View.GONE + mBinding.hotTagFlexContainer.visibility = View.GONE + mBinding.hotTitle.visibility = View.GONE + mBinding.hotList.visibility = View.GONE + val params = mBinding.historyTitle.layoutParams as ConstraintLayout.LayoutParams + params.topMargin = 0.5f.dip2px() + mBinding.historyTitle.layoutParams = params + + + mBinding.isExistHistory = mHistoryList?.isNotEmpty() + mBinding.historyFlexContainer.setLimitHeight(mHistoryFlexMaxHeight) + createFlexContent(mBinding.historyFlex, mHistoryList, true, clickListener = { + val key = mHistoryList!![it] + mSearchDao.add(key) + EventBus.getDefault().post(EBSearch("history", key)) + Util_System_Keyboard.hideSoftKeyboardByIBinder(context, mBinding.historyFlex.windowToken) + }) + + mBinding.historyClear.setOnClickListener { + DialogUtils.showWarningDialog(activity, "清空记录", "确定清空历史搜索记录?") { + mSearchDao.deleteAll() + mBinding.isExistHistory = false + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchFragment.kt new file mode 100644 index 0000000000..5fbdfd8520 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchFragment.kt @@ -0,0 +1,56 @@ +package com.gh.gamecenter.forum.search + +import android.os.Bundle +import android.view.View +import android.widget.LinearLayout +import android.widget.RelativeLayout +import androidx.fragment.app.Fragment +import com.gh.base.fragment.BaseFragment_TabLayout +import com.gh.common.util.dip2px +import com.google.android.material.tabs.TabLayout + +class ForumOrUserSearchFragment : BaseFragment_TabLayout() { + private var mSearchKey = "" + + override fun initFragmentList(fragments: MutableList) { + fragments.add(ForumContentSearchListFragment()) + fragments.add(UserSearchListFragment()) + } + + override fun initTabTitleList(tabTitleList: MutableList) { + tabTitleList.add("帖子") + tabTitleList.add("用户") + } + + fun setSearchKey(searchKey: String) { + mSearchKey = searchKey + if (mFragmentsList != null) { + setSearchKeyToChildFragment() + } + } + + private fun setSearchKeyToChildFragment() { + mFragmentsList.forEach { + if (it is ForumContentSearchListFragment) { + it.setSearchKey(mSearchKey) + } + if (it is UserSearchListFragment) { + it.setSearchKey(mSearchKey) + } + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mTabLayout.tabMode = TabLayout.MODE_AUTO + val tabLayoutParams = mTabLayout.layoutParams as RelativeLayout.LayoutParams + tabLayoutParams.width = RelativeLayout.LayoutParams.WRAP_CONTENT + mTabLayout.layoutParams = tabLayoutParams + + val viewpagerParams = mViewPager.layoutParams as LinearLayout.LayoutParams + viewpagerParams.topMargin = 0.5f.dip2px() + mViewPager.layoutParams = viewpagerParams + + setSearchKeyToChildFragment() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumSearchDao.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumSearchDao.kt new file mode 100644 index 0000000000..801c14cbf7 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumSearchDao.kt @@ -0,0 +1,45 @@ +package com.gh.gamecenter.forum.search + +import com.gh.common.util.SPUtils + +class ForumSearchDao { + fun add(keyword: String) { + val originString = SPUtils.getString(SP_KEY) + + if (originString.isEmpty()) { + // Insert keyword only for the very first time. + SPUtils.setString(SP_KEY, keyword) + } else { + getAll()?.let { + // Move keyword to the very front if it exists. + if (it.contains(keyword)) { + it.remove(keyword) + } + it.add(0, keyword) + val builder = StringBuilder() + for ((index, key) in it.withIndex()) { + builder.append(key) + if (index != it.size - 1) { + builder.append(SEARCH_KEY_DIVIDER) + } + } + SPUtils.setString(SP_KEY, builder.toString()) + } + } + } + + fun getAll(): ArrayList? { + val list = SPUtils.getString(SP_KEY).split(SEARCH_KEY_DIVIDER) + + return if (list.size == 1 && list[0].isEmpty()) null else ArrayList(list) + } + + fun deleteAll() { + SPUtils.setString(SP_KEY, "") + } + + companion object { + const val SP_KEY = "forum_key" + const val SEARCH_KEY_DIVIDER = "<-||->" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListAdapter.kt new file mode 100644 index 0000000000..4fdec90c2b --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListAdapter.kt @@ -0,0 +1,109 @@ +package com.gh.gamecenter.forum.search + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.constant.ItemViewType +import com.gh.common.util.* +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.databinding.UserSearchListItemBinding +import com.gh.gamecenter.entity.FollowersOrFansEntity +import com.gh.gamecenter.manager.UserManager +import java.util.* + +class UserSearchListAdapter(context: Context, val mEntrance: String, val mViewModel: UserSearchListViewModel) : ListAdapter(context) { + + override fun setListData(updateData: MutableList) { + var oldSize = 0 + if (mEntityList != null && mEntityList.size > 0) { + oldSize += mEntityList.size + } + mEntityList = ArrayList(updateData) + if (oldSize == 0 || oldSize > updateData.size || mViewModel.getLinkPageSize() == 2 /* 第一页 */) { + notifyDataSetChanged() + } else { + notifyItemRangeInserted(oldSize, updateData.size - oldSize) + } + } + + override fun getItemViewType(position: Int): Int { + if (position == itemCount - 1) return ItemViewType.ITEM_FOOTER + return ItemViewType.ITEM_BODY + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + ItemViewType.ITEM_FOOTER -> { + FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)) + } + else -> { + UserSearchListViewHolder(UserSearchListItemBinding.bind(mLayoutInflater.inflate(R.layout.user_search_list_item, parent, false))) + } + } + } + + override fun getItemCount(): Int { + return if (mEntityList.isNotEmpty()) mEntityList.size + FOOTER_ITEM_COUNT else 0 + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (getItemViewType(position)) { + ItemViewType.ITEM_BODY -> { + val binding = (holder as UserSearchListViewHolder).binding + val entity = mEntityList[position] + binding.entity = entity + binding.executePendingBindings() + if (entity.id == UserManager.getInstance().userId) { + binding.attentionTv.text = "自己" + binding.attentionTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_999999)) + binding.attentionTv.background = ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f5_radius_999) + binding.attentionTv.isEnabled = false + } + holder.itemView.setOnClickListener { + DirectUtils.directToHomeActivity(mContext, entity.id, mEntrance, "用户搜索") + } + binding.userBadgeName.setOnClickListener { binding.userBadgeIcon.performClick() } + binding.userBadgeIcon.setOnClickListener { + DialogUtils.showViewBadgeDialog(binding.root.context, entity.badge) { + MtaHelper.onEvent("进入徽章墙_用户记录", "用户搜索", entity.name + "(" + entity.id + ")") + MtaHelper.onEvent("徽章中心", "进入徽章中心", "用户搜索") + DirectUtils.directToBadgeWall(binding.root.context, entity.id, entity.name, entity.icon) + } + } + holder.binding.attentionTv.setOnClickListener { + CheckLoginUtils.checkLogin(mContext, "用户搜索") { + if (entity.me.isFollower) { + mViewModel.unFollow(entity.id) { + entity.me.isFollower = false + notifyItemChanged(position) + } + } else { + mViewModel.follow(entity.id) { + entity.me.isFollower = true + notifyItemChanged(position) + } + } + } + } + } + ItemViewType.ITEM_FOOTER -> { + val footerViewHolder = holder as FooterViewHolder + footerViewHolder.initItemPadding() + footerViewHolder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_content_hint) + footerViewHolder.itemView.setPadding(0, 18f.dip2px(), 0, 18f.dip2px()) + footerViewHolder.hint.textSize = 12f + footerViewHolder.hint.setTextColor(ContextCompat.getColor(mContext, R.color.aaaaaa)) + footerViewHolder.lineLeft.visibility = View.GONE + footerViewHolder.lineRight.visibility = View.GONE + } + } + } + + + class UserSearchListViewHolder(val binding: UserSearchListItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListFragment.kt new file mode 100644 index 0000000000..5a89c45a9f --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListFragment.kt @@ -0,0 +1,56 @@ +package com.gh.gamecenter.forum.search + +import android.os.Bundle +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import com.gh.gamecenter.R +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.entity.FollowersOrFansEntity +import com.gh.gamecenter.eventbus.EBUserFollow +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class UserSearchListFragment : ListFragment() { + + private var mSearchKey = "" + private var mAdapter: UserSearchListAdapter? = null + + override fun provideListAdapter(): ListAdapter<*> { + return mAdapter + ?: UserSearchListAdapter(requireContext(), mEntrance, mListViewModel).apply { mAdapter = this } + } + + override fun isAutomaticLoad(): Boolean = false + + fun setSearchKey(searchKey: String) { + mSearchKey = searchKey + mListViewModel?.updateSearchKey(mSearchKey) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mListRv.overScrollMode = View.OVER_SCROLL_NEVER + mListRv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white)) + mReuseNoData?.findViewById(R.id.reuseNoneDataIv)?.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.pic_no_data)) + mReuseNoData?.findViewById(R.id.reuse_tv_none_data)?.text = "搜索结果为空,换个搜索词试试" + mReuseNoData?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white)) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mListViewModel?.updateSearchKey(mSearchKey) + } + + override fun getItemDecoration(): RecyclerView.ItemDecoration? = null + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(follow: EBUserFollow?) { + val index = mAdapter?.entityList?.indexOfFirst { it.id == follow?.userId } ?: 0 + mAdapter?.entityList?.get(index)?.me?.isFollower = follow?.isFollow ?: false + mAdapter?.notifyItemChanged(index) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListViewModel.kt new file mode 100644 index 0000000000..0585b50a74 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListViewModel.kt @@ -0,0 +1,72 @@ +package com.gh.gamecenter.forum.search + +import android.app.Application +import com.gh.gamecenter.R +import com.gh.gamecenter.baselist.ListViewModel +import com.gh.gamecenter.baselist.LoadType +import com.gh.gamecenter.entity.FollowersOrFansEntity +import com.gh.gamecenter.eventbus.EBUserFollow +import com.gh.gamecenter.retrofit.Response +import com.gh.gamecenter.retrofit.RetrofitManager +import com.lightgame.utils.Utils +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import okhttp3.ResponseBody +import org.greenrobot.eventbus.EventBus +import retrofit2.HttpException + +class UserSearchListViewModel(application: Application) : ListViewModel(application) { + var searchKey = "" + override fun provideDataObservable(page: Int): Observable> { + return RetrofitManager.getInstance(getApplication()).api.searchUsers(searchKey, page) + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) } + } + + fun updateSearchKey(searchKey: String) { + this.searchKey = searchKey + load(LoadType.REFRESH) + } + + fun follow(userId: String, callback: () -> Unit) { + followingCommand(true, userId, callback) + } + + fun unFollow(userId: String, callback: () -> Unit) { + followingCommand(false, userId, callback) + } + + private fun followingCommand(isFollow: Boolean, userId: String, callback: () -> Unit) { + val observable = if (isFollow) { + RetrofitManager.getInstance(getApplication()).api.postFollowing(userId) + } else { + RetrofitManager.getInstance(getApplication()).api.deleteFollowing(userId) + } + observable + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + if (isFollow) { + Utils.toast(getApplication(), R.string.concern_success) + } else { + Utils.toast(getApplication(), R.string.concern_already_cancel) + } + callback.invoke() + } + + override fun onFailure(e: HttpException?) { + super.onFailure(e) + Utils.toast(getApplication(), R.string.loading_failed_hint) + } + }) + } + + fun getLinkPageSize(): Int { + return mCurLoadParams.loadOffset + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/select/ForumAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/select/ForumAdapter.kt index 32974813a3..cb175c8904 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/select/ForumAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/select/ForumAdapter.kt @@ -1,6 +1,7 @@ package com.gh.gamecenter.forum.select import android.content.Context +import android.view.Gravity import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView @@ -11,6 +12,7 @@ import com.gh.gamecenter.databinding.ForumItemBinding import com.gh.gamecenter.entity.ForumEntity import com.gh.gamecenter.eventbus.EBForumFollowChange import com.gh.gamecenter.forum.detail.ForumDetailActivity +import com.gh.gamecenter.forum.home.ForumVisitDao import com.gh.gamecenter.qa.entity.CommunitySelectEntity import com.lightgame.adapter.BaseRecyclerAdapter import org.greenrobot.eventbus.EventBus @@ -37,7 +39,7 @@ class ForumAdapter(context: Context, val mViewModel: ForumSelectViewModel?) : Ba if (holder is ForumItemViewHolder) { val forumEntity = datas[position] holder.binding.entity = forumEntity - holder.binding.forumIcon.displayGameIcon(forumEntity.game.getIcon(),forumEntity.game.iconSubscript) + holder.binding.forumIcon.displayGameIcon(forumEntity.game.getIcon(), forumEntity.game.iconSubscript) holder.itemView.setOnClickListener { MtaHelper.onEvent("论坛首页", "选择论坛", forumEntity.name) mContext.startActivity(ForumDetailActivity.getIntent(mContext, forumEntity.id, "论坛-选择论坛")) @@ -46,7 +48,7 @@ class ForumAdapter(context: Context, val mViewModel: ForumSelectViewModel?) : Ba mContext.ifLogin("论坛-选择论坛") { debounceActionWithInterval(it.id) { if (forumEntity.isFollow) { - DialogUtils.showAlertDialog(mContext, "提示", "取消关注论坛", "确定", "暂不", { + DialogUtils.showNewAlertDialog(mContext, "提示", "确定取消关注", "暂不", "确定", null, Gravity.CENTER, {}, { mViewModel?.unFollowForum(forumEntity.id) { MtaHelper.onEvent("论坛首页", "选择论坛", "关注") forumEntity.isFollow = false @@ -56,7 +58,7 @@ class ForumAdapter(context: Context, val mViewModel: ForumSelectViewModel?) : Ba holder.binding.followTv.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font)) EventBus.getDefault().post(EBForumFollowChange(forumEntity, false)) } - }, {}) + }) } else { mViewModel?.followForum(forumEntity.id) { diff --git a/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java index 4fa86e3813..b684a15b9c 100644 --- a/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java +++ b/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.List; import butterknife.BindView; +import kotlin.text.StringsKt; /** @@ -310,7 +311,12 @@ public class SearchToolbarFragment extends BaseLazyFragment implements View.OnCl @Override public void setHint(ArrayList hint) { if (hint != null && hint.size() > 0) { - mHintList = hint; + mHintList = new ArrayList<>(); + + for (String h : hint) { + mHintList.add(StringsKt.removeSuffix(h,".")); + } + if (hint.size() == 1 && mSearchHintTv != null) { mSearchHintTv.setHint(mHintList.get(0)); } else if (mAlphaAnimation != null && mSearchHintTv != null) { diff --git a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt index cd18696a01..446b77a862 100644 --- a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt @@ -24,6 +24,7 @@ import com.gh.gamecenter.R import com.gh.gamecenter.adapter.ImagePagerAdapter import com.gh.gamecenter.adapter.viewholder.* import com.gh.gamecenter.baselist.LoadStatus +import com.gh.gamecenter.catalog.CatalogActivity import com.gh.gamecenter.category.CategoryDirectoryActivity import com.gh.gamecenter.databinding.* import com.gh.gamecenter.entity.CommunityEntity @@ -235,7 +236,7 @@ class GameFragmentAdapter(context: Context, DataCollectionUtils.uploadClick(mContext, subjectData?.name + "-列表", "游戏-专题", gameEntity.name) GameDetailActivity.startGameDetailActivity(mContext, gameEntity, StringUtils.buildString("(游戏-专题:", subjectData?.name, "-列表[", (subjectData?.position).toString(), "])"), - listExposureEventList[snapPosition]) + gameEntity.exposureEvent) } val verticalSlide = mItemDataList[position].verticalSlide!! @@ -261,6 +262,7 @@ class GameFragmentAdapter(context: Context, source = listOf(mBasicExposureSource, ExposureSource("专题", verticalSlide.name!!)), eTrace = null, event = ExposureType.EXPOSURE) + gameList[i].exposureEvent = event listExposureEventList.add(event) } exposureEventList.addAll(listExposureEventList) @@ -419,6 +421,7 @@ class GameFragmentAdapter(context: Context, entity.type == "column_collection" -> DirectUtils.directToColumnCollection(mContext, entity.link!!, -1, "(推荐入口)") entity.type == "block" -> mContext.startActivity(BlockActivity.getIntent(mContext, entity, "(推荐入口)")) entity.type == "category" -> mContext.startActivity(CategoryDirectoryActivity.getIntent(mContext, entity.link!!, entity.text!!)) + entity.type == "catalog" -> mContext.startActivity(CatalogActivity.getIntent(mContext, entity.link!!, entity.text!!, "(推荐入口)")) entity.type == "column" -> { SubjectActivity.startSubjectActivity(mContext, entity.link, entity.text, entity.order , StringUtils.buildString("(游戏-专题:", entity.name, "[1-", (data + 1).toString(), "]", ")")) diff --git a/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt b/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt index 612413c89e..e670db7d1c 100644 --- a/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt @@ -61,12 +61,12 @@ class GameResourcePolicyDialogFragment : BaseDialogFragment() { mVebView?.loadUrl(requireContext().getString(R.string.upload_game_policy_url)) containerView?.findViewById(R.id.refuseTv)?.setOnClickListener { MtaHelper.onEvent("游戏上传", "开发者弹窗", "不同意") - dismiss() + dismissAllowingStateLoss() requireActivity().finish() } containerView?.findViewById(R.id.agreeTv)?.setOnClickListener { MtaHelper.onEvent("游戏上传", "开发者弹窗", "同意") - dismiss() + dismissAllowingStateLoss() } } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt index 17a99ad49e..c80cc165a3 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt @@ -242,13 +242,11 @@ class GameDetailFragment : NormalFragment() { } R.id.menu_concern -> { - checkReadPhoneStatePermissionBeforeAction { - ifLogin("游戏详情-[关注]") { - if (mNewGameDetailEntity != null && mNewGameDetailEntity!!.me.isGameConcerned) { - DialogUtils.showCancelDialog(requireContext(), { mViewModel.concernCommand(false) }, null) - } else { - mViewModel.concernCommand(true) - } + ifLogin("游戏详情-[关注]") { + if (mNewGameDetailEntity != null && mNewGameDetailEntity!!.me.isGameConcerned) { + DialogUtils.showCancelDialog(requireContext(), { mViewModel.concernCommand(false) }, null) + } else { + mViewModel.concernCommand(true) } } } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameDetailInfoItemAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameDetailInfoItemAdapter.kt index bd9f255719..bed03a4461 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameDetailInfoItemAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameDetailInfoItemAdapter.kt @@ -4,17 +4,21 @@ import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.databinding.DataBindingUtil import androidx.recyclerview.widget.RecyclerView import com.gh.common.util.* import com.gh.gamecenter.R import com.gh.gamecenter.databinding.ItemGameInfoBinding import com.gh.gamecenter.entity.TrackableEntity +import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment import com.gh.gamecenter.gamedetail.entity.GameInfo import com.gh.gamecenter.gamedetail.entity.GameInfoItemData +import com.gh.gamecenter.gamedetail.entity.Permission import com.halo.assistant.HaloApp -class GameDetailInfoItemAdapter(val context: Context, gameInfo: GameInfo, private val mViewModel: DescViewModel, val gameName: String) : RecyclerView.Adapter() { +class GameDetailInfoItemAdapter(val context: Context, val gameInfo: GameInfo, private val mViewModel: DescViewModel, val gameName: String) : RecyclerView.Adapter() { var datas = ArrayList() init { @@ -34,6 +38,9 @@ class GameDetailInfoItemAdapter(val context: Context, gameInfo: GameInfo, privat if (gameInfo.manufacturer.isNotEmpty()) { datas.add(GameInfoItemData(title = "厂商", info = gameInfo.manufacturer)) } + if (!gameInfo.permissions.isNullOrEmpty()) { + datas.add(GameInfoItemData(title = "权限", info = "查看详情")) + } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { @@ -52,6 +59,12 @@ class GameDetailInfoItemAdapter(val context: Context, gameInfo: GameInfo, privat holder.binding.actionTv.visibility = View.VISIBLE holder.binding.actionTv.text = gameInfoItemData.actionStr } + if (gameInfoItemData.title == "权限") { + holder.binding.infoTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font)) + holder.binding.infoTv.setOnClickListener { + GamePermissionDialogFragment.show(context as AppCompatActivity, mViewModel.game, gameInfo) + } + } holder.binding.actionTv.setOnClickListener { when (gameInfoItemData.actionStr) { "求更新" -> { diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GamePermissionAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GamePermissionAdapter.kt new file mode 100644 index 0000000000..a38a20e027 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GamePermissionAdapter.kt @@ -0,0 +1,51 @@ +package com.gh.gamecenter.gamedetail.dialog + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import com.gh.base.BaseRecyclerViewHolder +import com.gh.common.util.dip2px +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.GamePermissionItemBinding +import com.gh.gamecenter.gamedetail.entity.Permission +import com.lightgame.adapter.BaseRecyclerAdapter + +class GamePermissionAdapter(context: Context, val permissions: List) : BaseRecyclerAdapter(context) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return GamePermissionViewHolder(GamePermissionItemBinding.bind(LayoutInflater.from(mContext).inflate(R.layout.game_permission_item, parent, false))) + } + + override fun getItemCount(): Int = permissions.size + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is GamePermissionViewHolder) { + val permission = permissions[position] + holder.binding.permissionNameTV.text = permission.name + holder.binding.permissionDetailLl.removeAllViews() + permission.details.forEach { + holder.binding.permissionDetailLl.addView(createDetailView(it)) + } + } + } + + private fun createDetailView(detail: String): View { + return TextView(mContext).apply { + val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + params.topMargin = 12f.dip2px() + layoutParams = params + textSize = 13f + setTextColor(ContextCompat.getColor(mContext, R.color.text_999999)) + setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(mContext, R.drawable.bg_circle_permission_detail), null, null, null) + compoundDrawablePadding = 5f.dip2px() + text = detail + } + } + + class GamePermissionViewHolder(val binding: GamePermissionItemBinding) : BaseRecyclerViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GamePermissionDialogFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GamePermissionDialogFragment.kt new file mode 100644 index 0000000000..a16ab46347 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GamePermissionDialogFragment.kt @@ -0,0 +1,72 @@ +package com.gh.gamecenter.gamedetail.dialog + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.core.os.bundleOf +import androidx.fragment.app.FragmentTransaction +import androidx.recyclerview.widget.LinearLayoutManager +import com.gh.base.fragment.BaseDialogFragment +import com.gh.common.util.dip2px +import com.gh.common.view.VerticalItemDecoration +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.GamePermissionDialogBinding +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.gamedetail.entity.GameInfo +import com.gh.gamecenter.gamedetail.entity.Permission + +class GamePermissionDialogFragment : BaseDialogFragment() { + + lateinit var binding: GamePermissionDialogBinding + var game: GameEntity? = null + var gameInfo: GameInfo? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + binding = GamePermissionDialogBinding.bind(inflater.inflate(R.layout.game_permission_dialog, container, false)) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + game?.let { + binding.gameIconView.displayGameIcon(it) + binding.gameNameTv.text = it.name + binding.gameVersionTv.text = "版本号:${gameInfo?.version}" + } + gameInfo?.permissions?.let { + binding.permissionsRv.layoutManager = LinearLayoutManager(requireContext()) + binding.permissionsRv.adapter = GamePermissionAdapter(requireContext(), it) + } + } + + override fun onStart() { + super.onStart() + val width = requireContext().resources.displayMetrics.widthPixels - 40F.dip2px() + val height = ViewGroup.LayoutParams.WRAP_CONTENT + dialog?.window?.setLayout(width, height) + dialog?.setCanceledOnTouchOutside(true) + } + + companion object { + fun show(activity: AppCompatActivity, game: GameEntity?, gameInfo: GameInfo) { + var permissionDialogFragment = activity.supportFragmentManager.findFragmentByTag(GamePermissionDialogFragment::class.java.simpleName) as? GamePermissionDialogFragment + if (permissionDialogFragment == null) { + permissionDialogFragment = GamePermissionDialogFragment() + permissionDialogFragment.game = game + permissionDialogFragment.gameInfo = gameInfo + + permissionDialogFragment.show(activity.supportFragmentManager, GamePermissionDialogFragment::class.java.simpleName) + } else { + permissionDialogFragment.game = game + permissionDialogFragment.gameInfo = gameInfo + + val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction() + transaction.show(permissionDialogFragment) + transaction.commit() + } + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/entity/DetailEntity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/DetailEntity.kt index b9fb16433f..cea04823f1 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/entity/DetailEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/DetailEntity.kt @@ -128,7 +128,8 @@ data class GameInfo( var updateTime: Long = 0, var size: String = "", var contact: Contact? = null, - var manufacturer: String = "" + var manufacturer: String = "", + var permissions: List? = null ) @Keep @@ -147,4 +148,10 @@ data class UpdateContent( var historyApkStatus: String = "", @SerializedName("update_des") val updateDes: String = "" +) + +@Keep +data class Permission( + var name: String = "", + var details: List = arrayListOf() ) \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarActivity.kt index 94f2a111dc..26107165fd 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/kaifu/ServersCalendarActivity.kt @@ -82,9 +82,9 @@ class ServersCalendarActivity : ToolBarActivity() { postButton.text = "反馈" mBinding = DataBindingUtil.bind(mContentView)!! - mBinding.includeNoConnection.setOnClickListener { - mBinding.includeLoading.visibility = View.VISIBLE - mBinding.includeNoConnection.visibility = View.GONE + mBinding.includeNoConnection.root.setOnClickListener { + mBinding.includeLoading.root.visibility = View.VISIBLE + mBinding.includeNoConnection.root.visibility = View.GONE mViewModel.loadServerData() } @@ -112,8 +112,8 @@ class ServersCalendarActivity : ToolBarActivity() { mViewModel.initDate() initView() } else { - mBinding.includeLoading.visibility = View.GONE - mBinding.includeNoConnection.visibility = View.VISIBLE + mBinding.includeLoading.root.visibility = View.GONE + mBinding.includeNoConnection.root.visibility = View.VISIBLE } }) } @@ -132,7 +132,7 @@ class ServersCalendarActivity : ToolBarActivity() { fun initView() { mBinding.contentContainer.visibility = View.VISIBLE - mBinding.includeLoading.visibility = View.GONE + mBinding.includeLoading.root.visibility = View.GONE val serversDes = mViewModel.gameServer.des if (serversDes.isNotEmpty()) { diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingAdapter.kt index 8bc397ee32..2934b8c554 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingAdapter.kt @@ -279,12 +279,8 @@ class RatingAdapter(context: Context, if (mContext is Activity) { val installPackageName = mListViewModel.canUserCommentThisGame() if (mDirectComment || !installPackageName.isNullOrEmpty()) { - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(mContext, object : EmptyCallback { - override fun onCallback() { - val intent = RatingEditActivity.getIntent(mContext, mListViewModel.game, starCount, installPackageName, fromAmway, isSkipSuccessPage) - (mContext as Activity).startActivityForResult(intent, RatingFragment.RATING_EDIT_REQUEST) - } - }) + val intent = RatingEditActivity.getIntent(mContext, mListViewModel.game, starCount, installPackageName, fromAmway, isSkipSuccessPage) + (mContext as Activity).startActivityForResult(intent, RatingFragment.RATING_EDIT_REQUEST) } else { Utils.toast(mContext, "安装游戏后才能评论哦") } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt index 3a4b89c288..eb834c5265 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt @@ -170,19 +170,17 @@ class RatingReplyActivity : ListActivity(R.id.reuse_tv_none_data).setText(R.string.content_delete_hint) + mBinding.includeNoneData.root.findViewById(R.id.reuse_tv_none_data).setText(R.string.content_delete_hint) toast(R.string.comment_failed_unable) } }) @@ -116,9 +116,9 @@ class HelpContainerFragment : NormalFragment() { } false } - mBinding.includeNoConnection.setOnClickListener { + mBinding.includeNoConnection.root.setOnClickListener { mBinding.content.visibility = View.VISIBLE - mBinding.includeNoConnection.visibility = View.GONE + mBinding.includeNoConnection.root.visibility = View.GONE mViewModel.initData() } } diff --git a/app/src/main/java/com/gh/gamecenter/help/HelpQaCategoryFragment.kt b/app/src/main/java/com/gh/gamecenter/help/HelpQaCategoryFragment.kt index f7ffb3da28..931d630c3b 100644 --- a/app/src/main/java/com/gh/gamecenter/help/HelpQaCategoryFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/help/HelpQaCategoryFragment.kt @@ -41,26 +41,26 @@ class HelpQaCategoryFragment : NormalFragment() { val factory = HelpQaCategoryViewModel.Factory(mQaCollectionId) mViewModel = viewModelProvider(factory) mViewModel?.categoryLiveData?.observe(this, Observer { - mBinding.includeLoading.visibility = View.GONE + mBinding.includeLoading.root.visibility = View.GONE if (it.status == Status.SUCCESS) { if (it.data.isNullOrEmpty()) { - mBinding.includeNoneData.findViewById(R.id.reuse_tv_none_data).setText(R.string.game_empty) - mBinding.includeNoneData.visibility = View.VISIBLE + mBinding.includeNoneData.root.findViewById(R.id.reuse_tv_none_data).setText(R.string.game_empty) + mBinding.includeNoneData.root.visibility = View.VISIBLE } else { - mBinding.includeNoneData.visibility = View.GONE + mBinding.includeNoneData.root.visibility = View.GONE mAdapter?.setListData(it.data) } - mBinding.includeNoConnection.visibility = View.GONE + mBinding.includeNoConnection.root.visibility = View.GONE } else { val errorEntity = it.exception?.response()?.errorBody()?.string()?.toObject() if (errorEntity?.code == 403083) { // 隐藏 - mBinding.includeNoneData.visibility = View.VISIBLE - mBinding.includeNoConnection.visibility = View.GONE - mBinding.includeNoneData.findViewById(R.id.reuse_tv_none_data).setText(R.string.content_delete_hint) + mBinding.includeNoneData.root.visibility = View.VISIBLE + mBinding.includeNoConnection.root.visibility = View.GONE + mBinding.includeNoneData.root.findViewById(R.id.reuse_tv_none_data).setText(R.string.content_delete_hint) toast(R.string.comment_failed_unable) } else { - mBinding.includeNoneData.visibility = View.GONE - mBinding.includeNoConnection.visibility = View.VISIBLE + mBinding.includeNoneData.root.visibility = View.GONE + mBinding.includeNoConnection.root.visibility = View.VISIBLE } } @@ -78,9 +78,9 @@ class HelpQaCategoryFragment : NormalFragment() { adapter = mAdapter } - mBinding.includeNoConnection.setOnClickListener { - mBinding.includeLoading.visibility = View.VISIBLE - mBinding.includeNoConnection.visibility = View.GONE + mBinding.includeNoConnection.root.setOnClickListener { + mBinding.includeLoading.root.visibility = View.VISIBLE + mBinding.includeNoConnection.root.visibility = View.GONE mViewModel?.initData() } } diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt index 55235470d8..7c66859295 100644 --- a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt @@ -48,6 +48,10 @@ class HomeFragmentAdapter(context: Context, if (oldItem.slides != null && newItem.slides != null) return true if (oldItem.recommends != null && newItem.recommends != null) return true if (oldItem.pluginList != null && newItem.pluginList != null) return true + if (oldItem.verticalSlide != null && newItem.verticalSlide != null) return true + if (oldItem.horizontalColumn != null && newItem.horizontalColumn != null) return true + if (oldItem.columnHead != null && newItem.columnHead != null) return true + if (oldItem.horizontalSlide != null && newItem.horizontalSlide != null) return true return super.areItemsTheSame(oldItem, newItem) } @@ -56,6 +60,10 @@ class HomeFragmentAdapter(context: Context, if (oldItem.recommends != null && newItem.recommends != null) return false if (oldItem.pluginList != null && newItem.pluginList != null) return false if (oldItem.game?.id != newItem.game?.id) return false + if (oldItem.verticalSlide != null && newItem.verticalSlide != null) return false + if (oldItem.horizontalColumn != null && newItem.horizontalColumn != null) return false + if (oldItem.columnHead != null && newItem.columnHead != null) return false + if (oldItem.horizontalSlide != null && newItem.horizontalSlide != null) return false return super.areContentsTheSame(oldItem, newItem) } diff --git a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt index 8c0dfba0a9..b819069be7 100644 --- a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt +++ b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt @@ -34,6 +34,7 @@ import com.gh.gamecenter.game.horizontal.GameHorizontalSlideListViewHolder import com.gh.gamecenter.game.imageslide.GameImageSlideViewHolder import com.gh.gamecenter.game.vertical.GameVerticalAdapter import com.gh.gamecenter.game.vertical.GameVerticalSlideViewHolder +import com.gh.gamecenter.game.vertical.OnPagerSnapScrollListener import com.gh.gamecenter.subject.SubjectActivity import com.halo.assistant.fragment.game.GamePluginAdapter import com.halo.assistant.fragment.game.GamePluginViewHolder @@ -239,10 +240,10 @@ class LegacyHomeFragmentAdapterAssistant(private var mContext: Context, DataCollectionUtils.uploadClick(mContext, subjectData?.name + "-列表", "游戏-专题", gameEntity.name) GameDetailActivity.startGameDetailActivity(mContext, gameEntity, StringUtils.buildString("(游戏-专题:", subjectData?.name, "-列表[", (subjectData?.position).toString(), "])"), - listExposureEventList[snapPosition]) + gameEntity.exposureEvent) } - holder.bindVerticalSlide(verticalSlide, clickClosure, mMakeItemBackgroundTransparent) + val snapHelper = holder.bindVerticalSlide(verticalSlide, clickClosure, mMakeItemBackgroundTransparent) val exposureClosure: (Int) -> Unit = { val adapter = binding.recyclerView.adapter as GameVerticalAdapter @@ -267,9 +268,15 @@ class LegacyHomeFragmentAdapterAssistant(private var mContext: Context, } exposureClosure(0) + binding.recyclerView.addOnScrollListener(OnPagerSnapScrollListener(snapHelper) { + exposureClosure(it) + }) + if (mOuterType == OuterType.AMWAY) { holder.binding.recyclerView.isNestedScrollingEnabled = false } + + item.exposureEventList = exposureEventList } private fun bindGameImageSlide(holder: GameImageSlideViewHolder, item: LegacyHomeItemData) { diff --git a/app/src/main/java/com/gh/gamecenter/manager/PackagesManager.kt b/app/src/main/java/com/gh/gamecenter/manager/PackagesManager.kt index 394e431b4a..f45c9265c2 100644 --- a/app/src/main/java/com/gh/gamecenter/manager/PackagesManager.kt +++ b/app/src/main/java/com/gh/gamecenter/manager/PackagesManager.kt @@ -27,7 +27,7 @@ object PackagesManager { */ val updateListSize: Int get() = updateAndPluginList.size - fun initInstallPkgList(list: ArrayList) { + fun initInstallPkgList(list: List) { installedPkgList.clear() installedPkgList.addAll(list) } diff --git a/app/src/main/java/com/gh/gamecenter/message/KeFuFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/message/KeFuFragmentAdapter.java index 997483bedb..2a94ed0255 100644 --- a/app/src/main/java/com/gh/gamecenter/message/KeFuFragmentAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/message/KeFuFragmentAdapter.java @@ -41,7 +41,6 @@ import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity; import com.gh.gamecenter.subject.SubjectActivity; import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel; import com.google.android.flexbox.FlexboxLayout; -import com.lightgame.utils.Util_System_ClipboardManager; import com.lightgame.utils.Utils; import java.util.ArrayList; @@ -147,16 +146,14 @@ public class KeFuFragmentAdapter extends ListAdapter { ExtensionsKt.goneIf(viewHolder.copyIdContainer, !shouldShouldUserId); if (shouldShouldUserId) { viewHolder.copyIdContainer.setOnClickListener((view) -> { - Util_System_ClipboardManager.setText(mContext, UserManager.getInstance().getUserId()); - Utils.toast(mContext, "已复制"); + ExtensionsKt.copyTextAndToast(UserManager.getInstance().getUserId(), "已复制"); }); } viewHolder.content.setText(Html.fromHtml(keFuEntity.getMessage())); viewHolder.content.setOnSpannableClickListener(spannableText -> { - Util_System_ClipboardManager.setText(mContext, spannableText); - Utils.toast(mContext, "已复制:" + spannableText); + ExtensionsKt.copyTextAndToast(spannableText, "已复制:" + spannableText); }); viewHolder.setClickData(keFuEntity); diff --git a/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java b/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java index 2d83212afc..dd6e4fb008 100644 --- a/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java +++ b/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java @@ -15,6 +15,10 @@ import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.gh.common.constant.Config; import com.gh.common.util.CheckLoginUtils; import com.gh.common.util.DialogUtils; @@ -24,7 +28,6 @@ import com.gh.common.util.ErrorHelper; import com.gh.common.util.GsonUtils; import com.gh.common.util.KeyboardHeightObserver; import com.gh.common.util.KeyboardHeightProvider; -import com.gh.common.util.PermissionHelper; import com.gh.common.util.PostCommentUtils; import com.gh.common.util.TextHelper; import com.gh.common.util.TimestampUtils; @@ -59,9 +62,6 @@ import org.json.JSONObject; import java.util.List; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; import butterknife.OnClick; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -317,114 +317,111 @@ public class MessageDetailFragment extends NormalFragment implements OnCommentCa } } - @OnClick({R.id.answer_comment_send_btn,R.id.shadowView}) + @OnClick({R.id.answer_comment_send_btn, R.id.shadowView}) public void OnSendCommentListener(View view) { - switch (view.getId()){ + switch (view.getId()) { case R.id.answer_comment_send_btn: - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(requireContext(), () -> { - final String content = mMessageDetailEt.getText().toString(); + final String content = mMessageDetailEt.getText().toString(); - if (content.length() == 0) { - Utils.toast(getContext(), "评论内容不能为空!"); + if (content.length() == 0) { + Utils.toast(getContext(), "评论内容不能为空!"); + return; + } + + CheckLoginUtils.checkLogin(requireContext(), "资讯文章详情-评论详情-写评论", () -> { + mSendingDialog = DialogUtils.showWaitDialog(getActivity(), getString(R.string.post_dialog_hint)); + + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("content", content); + } catch (JSONException e) { + e.printStackTrace(); + } + if (newsId == null && mConcernEntity == null || newsId == null && mConcernEntity.getId() == null) { + Utils.toast(getContext(), "评论异常 id null"); + mSendingDialog.cancel(); return; + } else if (newsId == null) { + newsId = mConcernEntity.getId(); } - CheckLoginUtils.checkLogin(requireContext(), "资讯文章详情-评论详情-写评论", () -> { - mSendingDialog = DialogUtils.showWaitDialog(getActivity(), getString(R.string.post_dialog_hint)); + PostCommentUtils.addCommentData(getContext(), newsId, jsonObject, mCommentEntity, new PostCommentUtils.PostCommentListener() { + @Override + public void postSuccess(JSONObject response) { + mSendingDialog.dismiss(); + toast("发表成功"); + mMessageDetailEt.setText(""); - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("content", content); - } catch (JSONException e) { - e.printStackTrace(); - } - if (newsId == null && mConcernEntity == null || newsId == null && mConcernEntity.getId() == null) { - Utils.toast(getContext(), "评论异常 id null"); - mSendingDialog.cancel(); - return; - } else if (newsId == null) { - newsId = mConcernEntity.getId(); - } + try { + JSONObject cacheObject = new JSONObject(); + JSONObject cacheUser = new JSONObject(); + JSONObject userData = new JSONObject(); + JSONObject badgeData = new JSONObject(); + cacheUser.put("_id", mUserInfo.getUserId()); + cacheUser.put("icon", mUserInfo.getIcon()); + cacheUser.put("name", mUserInfo.getName()); - PostCommentUtils.addCommentData(getContext(), newsId, jsonObject, mCommentEntity, new PostCommentUtils.PostCommentListener() { - @Override - public void postSuccess(JSONObject response) { - mSendingDialog.dismiss(); - toast("发表成功"); - mMessageDetailEt.setText(""); - - try { - JSONObject cacheObject = new JSONObject(); - JSONObject cacheUser = new JSONObject(); - JSONObject userData = new JSONObject(); - JSONObject badgeData = new JSONObject(); - cacheUser.put("_id", mUserInfo.getUserId()); - cacheUser.put("icon", mUserInfo.getIcon()); - cacheUser.put("name", mUserInfo.getName()); - - if (mUserInfo.getBadge() != null) { - badgeData.put("name", mUserInfo.getBadge().getName()); - badgeData.put("icon", mUserInfo.getBadge().getIcon()); - cacheUser.put("badge", badgeData); - } - - userData.put("is_comment_own", true); - cacheObject.put("_id", response.getString("_id")); - cacheObject.put("content", content); - cacheObject.put("time", System.currentTimeMillis() / 1000); - cacheObject.put("vote", 0); - cacheObject.put("user", cacheUser); - cacheObject.put("me", userData); - - if (mCommentEntity != null) { - JSONObject cacheParent = new JSONObject(); - cacheParent.put("user", new JSONObject(GsonUtils.toJson(mCommentEntity.getUser()))); - cacheParent.put("comment", mCommentEntity.getContent()); - cacheObject.put("parent", cacheParent); - } - - CommentEntity commentEntity = new Gson().fromJson(cacheObject.toString(), CommentEntity.class); - if (mConcernEntity != null) { - adapter.addNormalComment(commentEntity); - } - - modifyNewsCommentOkhttpCache(adapter.findTheLastPriorComment(), cacheObject, newsId); - } catch (JSONException e) { - e.printStackTrace(); + if (mUserInfo.getBadge() != null) { + badgeData.put("name", mUserInfo.getBadge().getName()); + badgeData.put("icon", mUserInfo.getBadge().getIcon()); + cacheUser.put("badge", badgeData); } + userData.put("is_comment_own", true); + cacheObject.put("_id", response.getString("_id")); + cacheObject.put("content", content); + cacheObject.put("time", System.currentTimeMillis() / 1000); + cacheObject.put("vote", 0); + cacheObject.put("user", cacheUser); + cacheObject.put("me", userData); + + if (mCommentEntity != null) { + JSONObject cacheParent = new JSONObject(); + cacheParent.put("user", new JSONObject(GsonUtils.toJson(mCommentEntity.getUser()))); + cacheParent.put("comment", mCommentEntity.getContent()); + cacheObject.put("parent", cacheParent); + } + + CommentEntity commentEntity = new Gson().fromJson(cacheObject.toString(), CommentEntity.class); if (mConcernEntity != null) { - // 完成评论操作,添加评论数 - adapter.addCommentCount(); - //修改评论缓存 - CommentManager.updateOkhttpCacheForId(getContext(), newsId); - CommentManager.updateOkhttpCache(getContext(), newsId); - adapter.notifyItemInserted(adapter.getHotCommentListSize() + 2); - adapter.notifyItemChanged(adapter.getItemCount() - 1); //刷新脚布局高度 - } else { - showNoConnection(false); + adapter.addNormalComment(commentEntity); } - setSoftInput(false); - + modifyNewsCommentOkhttpCache(adapter.findTheLastPriorComment(), cacheObject, newsId); + } catch (JSONException e) { + e.printStackTrace(); } - @Override - public void postFailed(Throwable e) { - mSendingDialog.dismiss(); - String errorString = null; - if (e instanceof HttpException) { - try { - errorString = ((HttpException) e).response().errorBody().string(); - } catch (Exception e1) { - e1.printStackTrace(); - } + if (mConcernEntity != null) { + // 完成评论操作,添加评论数 + adapter.addCommentCount(); + //修改评论缓存 + CommentManager.updateOkhttpCacheForId(getContext(), newsId); + CommentManager.updateOkhttpCache(getContext(), newsId); + adapter.notifyItemInserted(adapter.getHotCommentListSize() + 2); + adapter.notifyItemChanged(adapter.getItemCount() - 1); //刷新脚布局高度 + } else { + showNoConnection(false); + } + + setSoftInput(false); + + } + + @Override + public void postFailed(Throwable e) { + mSendingDialog.dismiss(); + String errorString = null; + if (e instanceof HttpException) { + try { + errorString = ((HttpException) e).response().errorBody().string(); + } catch (Exception e1) { + e1.printStackTrace(); } - ErrorHelper.handleError(requireContext(), errorString, false); } - }); + ErrorHelper.handleError(requireContext(), errorString, false); + } }); - }); break; case R.id.shadowView: @@ -507,7 +504,7 @@ public class MessageDetailFragment extends NormalFragment implements OnCommentCa } private void popInputLayout(boolean isPopup, int height) { - if(requireActivity() instanceof MessageDetailActivity){ + if (requireActivity() instanceof MessageDetailActivity) { View shadowView = ((MessageDetailActivity) requireActivity()).shadowView; shadowView.setVisibility(isPopup ? View.VISIBLE : View.GONE); shadowView.setOnClickListener(v -> Util_System_Keyboard.hideSoftKeyboard(getActivity())); @@ -529,7 +526,7 @@ public class MessageDetailFragment extends NormalFragment implements OnCommentCa RelativeLayout.LayoutParams mLayoutParams = (RelativeLayout.LayoutParams) mReplyEditorContainer.getLayoutParams(); mLayoutParams.height = isPopup ? DisplayUtils.dip2px(130f) : LinearLayout.LayoutParams.WRAP_CONTENT; - mLayoutParams.bottomMargin = isPopup? height + mOffset - DisplayUtils.dip2px(12f) : 0; + mLayoutParams.bottomMargin = isPopup ? height + mOffset - DisplayUtils.dip2px(12f) : 0; mReplyEditorContainer.setLayoutParams(mLayoutParams); } diff --git a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt index 3df09a7932..ae1fce55c8 100644 --- a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt @@ -33,6 +33,8 @@ import okhttp3.ResponseBody import org.json.JSONException import org.json.JSONObject import retrofit2.HttpException +import java.util.* +import kotlin.collections.ArrayList /** * 该类存储的是已安装的所有游戏(助手后台已收录的)和所有更新(包括插件化)数据 @@ -54,7 +56,7 @@ object PackageRepository { private const val LAST_UPLOAD_APPLIST_TIME = "last_upload_applist_time" - private val mInstalledPkgList = ArrayList() + private val mInstalledPkgList = Collections.synchronizedList(ArrayList()) val gameUpdateLiveData = MutableLiveData>() val gameInstalledLiveData = MutableLiveData>() diff --git a/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.java b/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.java index b83eedab95..95a72872be 100644 --- a/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.java +++ b/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.java @@ -2,10 +2,10 @@ package com.gh.gamecenter.personal; import android.annotation.SuppressLint; import android.content.Intent; +import android.database.sqlite.SQLiteException; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; @@ -13,6 +13,14 @@ import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.ContextCompat; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + import com.facebook.drawee.view.SimpleDraweeView; import com.gh.base.fragment.BaseLazyFragment; import com.gh.common.databind.BindingAdapters; @@ -84,13 +92,6 @@ import java.util.ArrayList; import java.util.Locale; import java.util.concurrent.TimeUnit; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.Toolbar; -import androidx.core.content.ContextCompat; -import androidx.lifecycle.ViewModelProviders; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; @@ -622,7 +623,11 @@ public class PersonalFragment extends BaseLazyFragment { signEntity.setId(UserManager.getInstance().getUserId()); if (mDatabase.signDao().updateSignEntity(signEntity) <= 0) { - mDatabase.signDao().addSignEntity(signEntity); + try { + mDatabase.signDao().addSignEntity(signEntity); + } catch (SQLiteException e) { + e.printStackTrace(); + } } } diff --git a/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt b/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt index b41578ef7c..193e3312dd 100644 --- a/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt @@ -253,7 +253,7 @@ class PersonalFunctionAdapter(val context: Context, val groupName: String, var m "游戏投稿" -> { if (UserManager.getInstance().isLoggedIn) { MtaHelper.onEvent("我的光环", "游戏投稿") - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(context, object : EmptyCallback { + PermissionHelper.checkStoragePermissionBeforeAction(context, object : EmptyCallback { override fun onCallback() { context.startActivity(GameSubmissionActivity.getIntent(context, "(我的光环)", "")) } diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt index d215037396..1c16c419c0 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt @@ -273,7 +273,7 @@ class UserHomeFragment : NormalFragment() { ?: UserVideoHistoryFragment.getInstance(mUserHomeViewModel.userId, count) val fragmentList = listOf(commentFragment, qaFragment, videoFragment) - val titleList = listOf("游戏评论", "问答", "视频") + val titleList = listOf("游戏评论", "我的论坛", "视频") val countList = listOf(count.gameComment, count.getQaCount(), count.video) viewpager.offscreenPageLimit = fragmentList.size @@ -352,7 +352,7 @@ class UserHomeFragment : NormalFragment() { ImageUtils.getBitmap(personalData.background?.url ?: "", object : BiCallback { override fun onFirst(first: Bitmap) { userBackground.postDelayed({ - if (!requireActivity().isFinishing && !isStateSaved) { + if (activity?.isFinishing == false && !isStateSaved) { val statusBarHeight = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) 0 else DisplayUtils.getStatusBarHeight(resources) val bitmap = getBitmapFromView(userBackground) bitmap?.let { diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryAdapter.kt b/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryAdapter.kt index 089d5032b3..87aec43490 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryAdapter.kt @@ -4,7 +4,6 @@ import android.content.Context import android.util.SparseBooleanArray import android.view.View import android.view.ViewGroup -import androidx.constraintlayout.widget.ConstraintSet import androidx.recyclerview.widget.RecyclerView import com.gh.common.constant.ItemViewType import com.gh.common.util.* @@ -16,14 +15,8 @@ import com.gh.gamecenter.baselist.ListAdapter import com.gh.gamecenter.databinding.PersonalHomeItemBinding import com.gh.gamecenter.databinding.PersonalHomeRatingBinding import com.gh.gamecenter.entity.PersonalHistoryEntity -import com.gh.gamecenter.forum.detail.ForumDetailActivity -import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity import com.gh.gamecenter.personalhome.PersonalItemViewHolder -import com.gh.gamecenter.personalhome.rating.MyRating -import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity -import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity -import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity import java.util.regex.Pattern class UserHistoryAdapter(context: Context, @@ -82,8 +75,8 @@ class UserHistoryAdapter(context: Context, forumNameTv.text = entity?.community?.name userIcon.display(historyEntity.user?.border, historyEntity.user?.icon, historyEntity.user?.auth?.icon) executePendingBindings() - val command = getUserCommand(historyEntity.type, historyEntity.time) - userCommand.text = if (!command.isEmpty()) command else historyEntity?.user?.name + "" + val command = getUserCommand(historyEntity.type, historyEntity.time, historyEntity.isEdit) + userCommand.text = if (command.isNotEmpty()) command else historyEntity?.user?.name + "" questionTitle.setOnClickListener { holder.itemView.performClick() @@ -156,14 +149,14 @@ class UserHistoryAdapter(context: Context, } companion object { - fun getUserCommand(type: String, time: Long): String { + fun getUserCommand(type: String, time: Long, isEdit: Boolean = false): String { return when (type) { - "answer" -> NewsUtils.getFormattedTime(time) + " 发布了回答" - "question" -> NewsUtils.getFormattedTime(time) + " 提交了问题" + "answer" -> NewsUtils.getFormattedTime(time) + if (isEdit) " 修改了回答" else " 发布了回答" + "question" -> NewsUtils.getFormattedTime(time) + if (isEdit) " 修改了问题" else " 提交了问题" "answer_vote" -> NewsUtils.getFormattedTime(time) + " 赞同了回答" "follow_question" -> NewsUtils.getFormattedTime(time) + " 关注了问题" "community_article_vote" -> NewsUtils.getFormattedTime(time) + " 赞同了帖子" - "community_article" -> NewsUtils.getFormattedTime(time) + " 发布了帖子" + "community_article" -> NewsUtils.getFormattedTime(time) + if (isEdit) " 修改了帖子" else " 发布了帖子" "update-answer" -> NewsUtils.getFormattedTime(time) + " 更新了回答" else -> "" } diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryFragment.kt index 40a5399732..4673bb0fde 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryFragment.kt @@ -7,7 +7,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout -import android.widget.RelativeLayout import android.widget.TextView import androidx.core.content.ContextCompat import androidx.core.os.bundleOf @@ -204,27 +203,35 @@ class UserHistoryFragment : ListFragment { val resultData = data.getParcelableExtra(ArticleDetailEntity::class.java.simpleName) historyEntity?.apply { - count.vote = resultData?.count?.vote ?: 0 - count.comment = resultData?.count?.comment ?: 0 - title = resultData?.title ?: "" - brief = HtmlUtils.stripHtmlCode(resultData?.content ?: "") + if (title != resultData?.title || brief != HtmlUtils.stripHtmlCode(resultData.content)) { + onLoadRefresh() + return + } + count.vote = resultData.count.vote + count.comment = resultData.count.comment me.isCommunityArticleVote = resultData.me.isCommunityArticleVote } } 102 -> { val resultData = data.getParcelableExtra(AnswerDetailEntity::class.java.simpleName) historyEntity?.apply { + if (brief != HtmlUtils.stripHtmlCode(resultData?.content ?: "")) { + onLoadRefresh() + return + } count.vote = resultData?.vote ?: 0 count.comment = resultData?.commentCount ?: 0 - brief = HtmlUtils.stripHtmlCode(resultData?.content ?: "") question.title = resultData?.question?.title ?: "" } } 103 -> { val resultData = data.getParcelableExtra(QuestionsDetailEntity::class.java.simpleName) historyEntity?.apply { - title = resultData?.title ?: "" - count.answer = resultData.answersCount + if (title != resultData?.title ?: "" || description != resultData?.description ?: "") { + onLoadRefresh() + return + } + count.answer = resultData?.answersCount ?: 0 } } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/CommunityFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/CommunityFragment.kt index e2fc91fa6f..c337e74242 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/CommunityFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/CommunityFragment.kt @@ -21,7 +21,6 @@ import androidx.lifecycle.ViewModelProviders import androidx.viewpager.widget.PagerAdapter import butterknife.OnClick import com.gh.base.fragment.BaseLazyTabFragment -import com.gh.common.databind.BindingAdapters import com.gh.common.dialog.TrackableDialog import com.gh.common.util.* import com.gh.common.view.GameIconView @@ -469,7 +468,7 @@ class CommunityFragment : BaseLazyTabFragment() { dialog.show() contentView.findViewById(R.id.community_edit_article).setOnClickListener { context?.ifLogin("(首页-问答)", action = { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { MtaHelper.onEvent("问答页面", UserManager.getInstance().community.name, "发布-发文章") startActivity(ArticleEditActivity.getIntent(requireContext(), UserManager.getInstance().community)) dialog.dismiss() @@ -478,7 +477,7 @@ class CommunityFragment : BaseLazyTabFragment() { } contentView.findViewById(R.id.community_edit_question).setOnClickListener { context?.ifLogin("(首页-问答)", action = { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { MtaHelper.onEvent("问答页面", UserManager.getInstance().community.name, "发布-提问题") startActivity(QuestionEditActivity.getIntent(requireContext())) dialog.dismiss() diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/CommunityAnswerItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/CommunityAnswerItemViewHolder.kt index 73eca0a0a7..d52ff24afd 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/CommunityAnswerItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/CommunityAnswerItemViewHolder.kt @@ -5,22 +5,12 @@ import android.view.View import android.widget.LinearLayout import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat -import com.gh.base.BaseRecyclerViewHolder import com.gh.common.util.* import com.gh.gamecenter.CollectionActivity import com.gh.gamecenter.R import com.gh.gamecenter.databinding.CommunityAnswerItemBinding -import com.gh.gamecenter.entity.VoteEntity -import com.gh.gamecenter.manager.UserManager -import com.gh.gamecenter.qa.comment.CommentActivity import com.gh.gamecenter.qa.entity.AnswerEntity import com.gh.gamecenter.qa.entity.ArticleEntity -import com.gh.gamecenter.retrofit.Response -import com.gh.gamecenter.retrofit.RetrofitManager -import com.lightgame.utils.Utils -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.schedulers.Schedulers -import retrofit2.HttpException /** * 因为社区回答和社区文章的样式完全一样,所以就统一处理吧!有需要时可以直接复制一份作为单独的社区文章样式 @@ -55,11 +45,11 @@ class CommunityAnswerItemViewHolder(val binding: CommunityAnswerItemBinding) : B private fun changeVoteAndCommentStyle() { binding.forumNameLl.visibility = View.GONE - val params = binding.includeVoteAndComment.layoutParams as LinearLayout.LayoutParams + val params = binding.includeVoteAndComment.root.layoutParams as LinearLayout.LayoutParams params.width = LinearLayout.LayoutParams.MATCH_PARENT params.leftMargin = 0 params.rightMargin = 0 - binding.includeVoteAndComment.layoutParams = params + binding.includeVoteAndComment.root.layoutParams = params } private fun changeToAlternativeStyle() { diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt index 9d64f58ecf..2902124ed4 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt @@ -457,7 +457,7 @@ class AnswerDetailFragment : NormalFragment() { DrawableView.setTextDrawable( mBinding.statusTv, R.drawable.community_question_edit_my_answer, - "编辑回答") + "修改回答") } ANSWERED_NOT_MY_ANSWER -> { mBinding.statusTv.setTextColor(R.color.text_999999.toColor()) @@ -825,14 +825,14 @@ class AnswerDetailFragment : NormalFragment() { } NOT_ANSWERED_YET -> ifLogin("回答详情-[我来回答]") { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { val question = mViewModel.answerDetail!!.question startActivityForResult(AnswerEditActivity.getIntent(requireContext(), question, true, question.communityName), ANSWER_POST_REQUEST) } } NOT_ANSWERED_BUT_HAVE_DRAFT -> ifLogin("回答详情-[继续回答]") { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { val question = mViewModel.answerDetail!!.question startActivityForResult(AnswerEditActivity.getIntent(requireContext(), question, true, question.communityName), ANSWER_POST_REQUEST) } @@ -980,7 +980,7 @@ class AnswerDetailFragment : NormalFragment() { if (answerDetail.publishTime == answerDetail.updateTime) { mBinding.timeTv.text = String.format("发布于 %s", NewsUtils.getFormattedTime(answerDetail.publishTime)) } else { - mBinding.timeTv.text = String.format("编辑于 %s", NewsUtils.getFormattedTime(answerDetail.updateTime)) + mBinding.timeTv.text = String.format("修改于 %s", NewsUtils.getFormattedTime(answerDetail.updateTime)) } if (mIsShowCommentManager) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/draft/AnswerDraftAdapter.java b/app/src/main/java/com/gh/gamecenter/qa/answer/draft/AnswerDraftAdapter.java index b6c3b7570c..5bae03f4df 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/draft/AnswerDraftAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/draft/AnswerDraftAdapter.java @@ -132,7 +132,7 @@ class AnswerDraftAdapter extends ListAdapter { DialogUtils.showAlertDialog(mContext, "警告", "确定要删除回答草稿吗?删除之后不可恢复", "确定", "取消", () -> deleteAnswerDraft(answerEntity), null); }); draftViewHolder.itemView.setOnClickListener(v -> { - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(mContext, () -> { + PermissionHelper.checkStoragePermissionBeforeAction(mContext, () -> { if (mContext instanceof AnswerDraftActivity) { // 不需要回传任何数据 ((AnswerDraftActivity) mContext).setResult(Activity.RESULT_OK); diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/edit/AnswerEditActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/edit/AnswerEditActivity.kt index 3249745143..5603469aa5 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/edit/AnswerEditActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/edit/AnswerEditActivity.kt @@ -290,6 +290,7 @@ class AnswerEditActivity : BaseRichEditorActivity(), KeyboardHeightObserver { private fun initQuestionContent() { val question = mViewModel.question + question.title = HtmlUtils.filterHtmlLabel(question.title) val video = if (!question.videos.isNullOrEmpty()) question.videos[0] else null val videoSize = if (video != null) 1 else 0 diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/MyArticleFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/article/MyArticleFragment.kt index 88731092f5..9605139395 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/MyArticleFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/MyArticleFragment.kt @@ -5,9 +5,8 @@ import android.content.Intent import android.os.Bundle import android.view.MenuItem import androidx.lifecycle.ViewModelProviders -import androidx.recyclerview.widget.RecyclerView import com.gh.common.util.EntranceUtils -import com.gh.common.util.checkReadPhoneStateAndStoragePermissionBeforeAction +import com.gh.common.util.checkStoragePermissionBeforeAction import com.gh.common.util.ifLogin import com.gh.gamecenter.R import com.gh.gamecenter.baselist.ListFragment @@ -70,7 +69,7 @@ class MyArticleFragment : ListFragment(R.id.container) val entities = ArrayList() if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId) { - entities.add(MenuItemEntity("编辑", R.drawable.menu_more_edit)) + entities.add(MenuItemEntity("修改", R.drawable.menu_more_edit)) } if (mViewModel.detailEntity?.user?.id != UserManager.getInstance().userId) { entities.add(MenuItemEntity("投诉", R.drawable.ic_menu_gamedetail_feedback)) @@ -382,7 +382,7 @@ class ArticleDetailFragment : BaseArticleDetailCommentFragment { + "修改" -> { startActivityForResult(ArticleEditActivity.getPatchIntent(requireContext(), mViewModel.detailEntity!!), ArticleDetailActivity.ARTICLE_PATCH_REQUEST) } "投诉" -> { diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/BaseArticleDetailCommentAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/BaseArticleDetailCommentAdapter.kt index 60f64b5ce1..fc7f406303 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/BaseArticleDetailCommentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/BaseArticleDetailCommentAdapter.kt @@ -3,6 +3,7 @@ package com.gh.gamecenter.qa.article.detail import android.annotation.SuppressLint import android.content.Context import android.text.SpannableStringBuilder +import android.view.Gravity import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil @@ -59,6 +60,7 @@ abstract class BaseArticleDetailCommentAdapter(context: Context, && oldItem?.commentNormal?.reply == newItem?.commentNormal?.reply && oldItem?.commentNormal?.me?.isCommentVoted == newItem?.commentNormal?.me?.isCommentVoted && oldItem?.commentNormal?.floor == newItem?.commentNormal?.floor + && oldItem?.commentNormal?.isTop == newItem?.commentNormal?.isTop } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { @@ -317,9 +319,9 @@ abstract class BaseArticleDetailCommentAdapter(context: Context, val finalName = "$name " val colon = " :" - val nameSpan = SpanBuilder(finalName).bold(0, finalName.length).build() + val nameSpan = SpanBuilder(finalName).color(0, finalName.length, R.color.theme_font).build() val authorSpan = if (finalAuthor.isNotEmpty()) SpanBuilder(finalAuthor).image(0, finalAuthor.length, R.drawable.ic_hint_author).build() else "" - val colonSpan = SpanBuilder(colon).bold(0, colon.length).build() + val colonSpan = SpanBuilder(colon).color(0, colon.length, R.color.theme_font).build() return SpannableStringBuilder().append(nameSpan).append(authorSpan).append(colonSpan).append(content) } @@ -382,14 +384,36 @@ abstract class BaseArticleDetailCommentAdapter(context: Context, false, viewModel.articleId, viewModel.communityId, - true, + isShowTop = path == PATH_ARTICLE_DETAIL, + ignoreModerator = true, listener = object : OnCommentOptionClickListener { override fun onCommentOptionClick(entity: CommentEntity, option: String) { - DialogUtils.showNewAlertDialog(binding.moreIv.context, "提示", "删除评论后,评论下所有的回复都将被删除", "取消", "删除", null, { - viewModel.hideCommunityArticleComment(comment.id ?: "") { - deleteCallBack?.invoke(comment) + when (option) { + "删除评论" -> { + DialogUtils.showNewAlertDialog(binding.moreIv.context, "提示", "删除评论后,评论下所有的回复都将被删除", "取消", "删除", null, { + viewModel.hideCommunityArticleComment(comment.id + ?: "") { + deleteCallBack?.invoke(comment) + } + }) } - }) + "置顶" -> { + DialogUtils.showNewAlertDialog(binding.root.context, "提示", "是否将此条评论置顶?", "取消", "确认", null, Gravity.CENTER, {}, { + commentTop(binding.root.context, viewModel, comment, false) + }) + } + "取消置顶" -> { + DialogUtils.showNewAlertDialog(binding.root.context, "提示", "是否将此条评论取消置顶?", "取消", "确认", null, Gravity.CENTER, {}, { + viewModel.updateCommentTop(comment.id + ?: "", top = false, isAgain = false) { isSuccess, errorCode -> + if (isSuccess) { + viewModel.load(LoadType.REFRESH) + } + } + }) + } + } + } }) @@ -401,6 +425,21 @@ abstract class BaseArticleDetailCommentAdapter(context: Context, } } } + + private fun commentTop(context: Context, viewModel: BaseArticleDetailCommentViewModel, comment: CommentEntity, isAgain: Boolean) { + viewModel.updateCommentTop(comment.id + ?: "", top = true, isAgain = isAgain) { isSuccess, errorCode -> + if (isSuccess) { + viewModel.load(LoadType.REFRESH) + } else { + if (errorCode == 403095) { + DialogUtils.showNewAlertDialog(context, "提示", "当前已有置顶评论,\n是否将此条评论覆盖展示?", "取消", "确认", null, Gravity.CENTER, {}, { + commentTop(context, viewModel, comment, true) + }) + } + } + } + } } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/BaseArticleDetailCommentViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/BaseArticleDetailCommentViewModel.kt index 5635be3e49..17f3dc079e 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/BaseArticleDetailCommentViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/BaseArticleDetailCommentViewModel.kt @@ -6,6 +6,7 @@ import com.gh.common.syncpage.SyncDataEntity import com.gh.common.syncpage.SyncFieldConstants import com.gh.common.syncpage.SyncPageRepository import com.gh.common.util.CommentDraftContainer +import com.gh.common.util.ErrorHelper import com.gh.common.util.PostCommentUtils import com.gh.common.util.ToastUtils import com.gh.gamecenter.baselist.ListViewModel @@ -214,7 +215,41 @@ abstract class BaseArticleDetailCommentViewModel(application: Application, var a }) } - open fun hideCommunityArticleCommentSuccess(){} + fun updateCommentTop(commentId: String, top: Boolean = false, isAgain: Boolean = false, callback: (isSuccess: Boolean, errorCode: Int) -> Unit) { + val observable = if (top) { + val map = hashMapOf() + if (isAgain) { + map["again"] = isAgain + } + RetrofitManager.getInstance(getApplication()).api.commentTop(communityId, articleId, commentId, map) + } else { + RetrofitManager.getInstance(getApplication()).api.commentUnTop(communityId, articleId, commentId) + } + observable.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + callback.invoke(true, 0) + } + + override fun onFailure(e: HttpException?) { + super.onFailure(e) + e?.let { + ErrorHelper.handleErrorWithCustomizedHandler(getApplication(), e.response()?.errorBody()?.string(), false) { + if (it == 403095) { + callback.invoke(false, it) + true + } else false + } + } + } + }) + + } + + + open fun hideCommunityArticleCommentSuccess() {} enum class LoadResult { SUCCESS, diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/comment/ArticleDetailCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/comment/ArticleDetailCommentFragment.kt index 545534fde0..d64e4456c8 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/comment/ArticleDetailCommentFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/comment/ArticleDetailCommentFragment.kt @@ -118,15 +118,23 @@ class ArticleDetailCommentFragment : BaseArticleDetailCommentFragment { + DialogUtils.showNewAlertDialog(requireContext(), "提示", "删除评论后,评论下所有的回复都将被删除", "取消", "删除", null, { + mViewModel.hideCommunityArticleComment(entity.id ?: "") { + EventBus.getDefault().post(EBDeleteCommentDetail(entity.id)) + requireActivity().finish() + } + }) } - }) + else -> { + //do nothing + } + } } }) diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/draft/ArticleDraftFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/article/draft/ArticleDraftFragment.kt index e5a17bd1ba..6245086e2e 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/draft/ArticleDraftFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/draft/ArticleDraftFragment.kt @@ -6,7 +6,7 @@ import android.os.Bundle import androidx.lifecycle.ViewModelProviders import com.gh.common.util.EntranceUtils import com.gh.common.util.UrlFilterUtils -import com.gh.common.util.checkReadPhoneStateAndStoragePermissionBeforeAction +import com.gh.common.util.checkStoragePermissionBeforeAction import com.gh.gamecenter.R import com.gh.gamecenter.baselist.ListFragment import com.gh.gamecenter.baselist.LoadType @@ -40,7 +40,7 @@ class ArticleDraftFragment : ListFragment() { mCancelBtn.setOnClickListener { val fragment = parentFragment - (fragment as? BaseDialogWrapperFragment)?.dismiss() + (fragment as? BaseDialogWrapperFragment)?.dismissAllowingStateLoss() } mPostBtn.setOnClickListener { mViewModel?.postArticle() diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt index 18d4781a3a..5a3cf695ed 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt @@ -167,8 +167,9 @@ class NewCommentAdapter(context: Context, mIsShowingConversation, mViewModel.articleId, mViewModel.communityId, - false, - mCommentOptionClickListener) + isShowTop = false, + ignoreModerator = false, + listener = mCommentOptionClickListener) } CommentType.VIDEO, diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt index 01d6542645..5b2f1157fc 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt @@ -29,6 +29,7 @@ import com.gh.gamecenter.adapter.OnCommentCallBackListener import com.gh.gamecenter.baselist.ListAdapter import com.gh.gamecenter.baselist.ListFragment import com.gh.gamecenter.entity.CommentEntity +import com.gh.gamecenter.eventbus.EBCommentSuccess import com.gh.gamecenter.eventbus.EBDeleteComment import com.gh.gamecenter.eventbus.EBReuse import com.gh.gamecenter.qa.answer.detail.AnswerDetailFragment @@ -101,7 +102,7 @@ open class NewCommentFragment : ListFragment mArticleId = getString(ARTICLE_ID, "") mVideoId = getString(VIDEO_ID, "") mCommentCount = getInt(COMMENT_COUNT, 0) - mCommentType = getSerializable(COMMENT_TYPE) as CommentType + mCommentType = getSerializable(COMMENT_TYPE) as? CommentType ?: CommentType.ANSWER mCommunityId = getString(COMMUNITY_ID, "") mShowInputOnly = getBoolean(SHOW_INPUT_ONLY, false) mCommentEntity = getParcelable(COMMENT_ENTITY) @@ -136,15 +137,21 @@ open class NewCommentFragment : ListFragment } commentEt.postDelayed({ setSoftInput(false) }, 100) - if (mCommentType == CommentType.COMMUNITY_ARTICLE) { - SyncPageRepository.postSyncData(SyncDataEntity(mArticleId, - SyncFieldConstants.ARTICLE_COMMENT_COUNT, - mCommentCount, - checkFieldEntity = true)) - } else if (mCommentType == CommentType.ANSWER) { - SyncPageRepository.postSyncData(SyncDataEntity(mAnswerId, - SyncFieldConstants.ANSWER_COMMENT_COUNT, - mCommentCount)) + when (mCommentType) { + CommentType.COMMUNITY_ARTICLE -> { + SyncPageRepository.postSyncData(SyncDataEntity(mArticleId, + SyncFieldConstants.ARTICLE_COMMENT_COUNT, + mCommentCount, + checkFieldEntity = true)) + } + CommentType.ANSWER -> { + SyncPageRepository.postSyncData(SyncDataEntity(mAnswerId, + SyncFieldConstants.ANSWER_COMMENT_COUNT, + mCommentCount)) + } + CommentType.VIDEO -> { + EventBus.getDefault().post(EBCommentSuccess()) + } } if (mShowInputOnly) { @@ -342,10 +349,8 @@ open class NewCommentFragment : ListFragment when (view.id) { R.id.answer_comment_send_btn -> if (!ClickUtils.isFastDoubleClick(R.id.answer_comment_send_btn, 5000)) { ifLogin(getLoginEntrance()) { - checkReadPhoneStatePermissionBeforeAction { - showRegulationTestDialogIfNeeded { - postComment() - } + showRegulationTestDialogIfNeeded { + postComment() } } } else { diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt index cbca7b079b..6ab5d191ce 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt @@ -11,6 +11,7 @@ import com.gh.common.syncpage.SyncFieldConstants import com.gh.common.syncpage.SyncPageRepository import com.gh.common.util.CommentDraftContainer import com.gh.common.util.createRequestBody +import com.gh.common.util.tryCatchInRelease import com.gh.gamecenter.baselist.ListViewModel import com.gh.gamecenter.entity.CommentDraft import com.gh.gamecenter.entity.CommentEntity @@ -170,7 +171,7 @@ open class NewCommentViewModel(application: Application, if (draftContent.isNotEmpty()) { val draft = CommentDraft(id = id, draft = draftContent) if (it.updateDraft(draft) <= 0) { - it.addDraft(draft) + tryCatchInRelease { it.addDraft(draft) } } } else { it.deleteDraftById(id) diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/VideoActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/VideoActivity.kt index 4951415637..9468d04713 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/editor/VideoActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/editor/VideoActivity.kt @@ -93,7 +93,7 @@ class VideoActivity : ListActivity { holder.concern.setTextColor(ContextCompat.getColor(mContext, R.color.text_666666)) - DrawableView.setTextDrawable(holder.concern, R.drawable.ic_edit_question, "编辑问题") + DrawableView.setTextDrawable(holder.concern, R.drawable.ic_edit_question, "修改问题") } mQuestionEntity!!.me.isQuestionFollowed -> { holder.concern.setTextColor(ContextCompat.getColor(mContext, R.color.text_666666)) diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt index ab4dc13fdf..a2579690c7 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt @@ -349,7 +349,7 @@ class QuestionsDetailFragment : } R.id.reuse_nodata_skip -> ifLogin("问题详情-[我来回答]") { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { startAnswerEditActivity() } } @@ -375,7 +375,7 @@ class QuestionsDetailFragment : } mFabContainer.setOnClickListener { - checkReadPhoneStateAndStoragePermissionBeforeAction { + checkStoragePermissionBeforeAction { ifLogin("问题详情-[我来回答]") { showRegulationTestDialogIfNeeded { if (mQuestionsDetailEntity != null && !TextUtils.isEmpty(mQuestionsDetailEntity?.me?.myAnswerId)) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditActivity.kt index b89b1e72d2..68b155a1b5 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditActivity.kt @@ -137,7 +137,7 @@ class QuestionEditActivity : ToolBarActivity() { // Navigation when { mViewModel.isModeratorPatch -> setNavigationTitle("修改问题") - mViewModel.questionEntity != null -> setNavigationTitle("编辑问题") + mViewModel.questionEntity != null -> setNavigationTitle("修改问题") else -> setNavigationTitle("提问") } @@ -377,7 +377,7 @@ class QuestionEditActivity : ToolBarActivity() { } DialogUtils.showCancelAlertDialog(this, "提示" - , if (mViewModel.questionEntity == null) "确定放弃提问吗?" else "确定放弃编辑吗?" + , if (mViewModel.questionEntity == null) "确定放弃提问吗?" else "确定放弃修改吗?" , "再想想", " 放弃", null) { finish() } return true } else if (mViewModel.questionEntity == null && !mViewModel.isFromSearch) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/TagsSelectFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/TagsSelectFragment.kt index 72a6efa315..8aa043fdc1 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/TagsSelectFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/TagsSelectFragment.kt @@ -92,7 +92,7 @@ class TagsSelectFragment : BaseFragment() { } mModeratorPatchTagsCallback?.onPatchTagsSuccess() val fragment = parentFragment - (fragment as? BaseDialogWrapperFragment)?.dismiss() + (fragment as? BaseDialogWrapperFragment)?.dismissAllowingStateLoss() AppExecutor.uiExecutor.executeWithDelay(Runnable { NotificationHelper.showNotificationHintDialog(NotificationUgc.QUESTION) }, 1000) @@ -107,7 +107,7 @@ class TagsSelectFragment : BaseFragment() { "确定", null, DialogUtils.ConfirmListener { mModeratorPatchTagsCallback?.onPermissionError() val fragment = parentFragment - (fragment as? BaseDialogWrapperFragment)?.dismiss() + (fragment as? BaseDialogWrapperFragment)?.dismissAllowingStateLoss() }, null) return@Observer } @@ -198,7 +198,7 @@ class TagsSelectFragment : BaseFragment() { mCancelBtn.setOnClickListener { val fragment = parentFragment - (fragment as? BaseDialogWrapperFragment)?.dismiss() + (fragment as? BaseDialogWrapperFragment)?.dismissAllowingStateLoss() if (mViewModel?.postLiveData?.value != null) { mViewModel?.postLiveData?.postValue(null) diff --git a/app/src/main/java/com/gh/gamecenter/qa/recommends/AskQuestionsRecommendsViewModel.java b/app/src/main/java/com/gh/gamecenter/qa/recommends/AskQuestionsRecommendsViewModel.java index 78415325ad..2bcff3c13c 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/recommends/AskQuestionsRecommendsViewModel.java +++ b/app/src/main/java/com/gh/gamecenter/qa/recommends/AskQuestionsRecommendsViewModel.java @@ -1,14 +1,16 @@ package com.gh.gamecenter.qa.recommends; import android.app.Application; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteException; +import android.preference.PreferenceManager; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.lifecycle.LiveData; import androidx.lifecycle.MediatorLiveData; import androidx.lifecycle.MutableLiveData; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.text.TextUtils; import com.gh.common.util.UrlFilterUtils; import com.gh.gamecenter.R; @@ -379,7 +381,11 @@ public class AskQuestionsRecommendsViewModel extends BaseListViewModel { - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(this, () -> { + PermissionHelper.checkStoragePermissionBeforeAction(this, () -> { startActivityForResult(QuestionEditActivity.Companion.getIntent(this, mSearchKey), QUESTION_REQUEST_CODE); }); }); diff --git a/app/src/main/java/com/gh/gamecenter/qa/select/SelectGameDialogAdapter.java b/app/src/main/java/com/gh/gamecenter/qa/select/SelectGameDialogAdapter.java index 5bafb8b1a5..8433b86a0d 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/select/SelectGameDialogAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/qa/select/SelectGameDialogAdapter.java @@ -14,6 +14,7 @@ import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; import com.gh.common.util.BitmapUtils; +import com.gh.common.util.PackageUtils; import com.gh.common.util.UrlFilterUtils; import com.gh.gamecenter.R; import com.gh.gamecenter.entity.GameInstall; @@ -101,7 +102,7 @@ public class SelectGameDialogAdapter extends BaseRecyclerAdapter { PackageManager pm = mContext.getPackageManager(); - List installedPackages = pm.getInstalledPackages(0); + List installedPackages = PackageUtils.getInstalledPackages(mContext, 0); for (PackageInfo installedPackage : installedPackages) { diff --git a/app/src/main/java/com/gh/gamecenter/receiver/InstallAndUninstallReceiver.java b/app/src/main/java/com/gh/gamecenter/receiver/InstallAndUninstallReceiver.java index 336c1462d8..1682ff06fd 100644 --- a/app/src/main/java/com/gh/gamecenter/receiver/InstallAndUninstallReceiver.java +++ b/app/src/main/java/com/gh/gamecenter/receiver/InstallAndUninstallReceiver.java @@ -9,6 +9,7 @@ import com.gh.common.util.ExtensionsKt; import com.gh.common.util.InstallUtils; import com.gh.common.util.PackageHelper; import com.gh.common.util.PackageUtils; +import com.gh.download.PackageObserver; import com.gh.gamecenter.eventbus.EBPackage; import com.lightgame.utils.Utils; @@ -35,7 +36,9 @@ public class InstallAndUninstallReceiver extends BroadcastReceiver { PackageHelper.refreshLocalPackageList(); String versionName = PackageUtils.getVersionByPackage(packageName); - EventBus.getDefault().post(new EBPackage("安装", packageName, versionName)); + EBPackage installEb = new EBPackage("安装", packageName, versionName); + EventBus.getDefault().post(installEb); + PackageObserver.onPackageChanged(installEb); } // 接收卸载广播 @@ -45,7 +48,10 @@ public class InstallAndUninstallReceiver extends BroadcastReceiver { Utils.log("卸载了:" + packageName + "包名的程序"); InstallUtils.getInstance(context).removeUninstall(packageName); PackageHelper.refreshLocalPackageList(); - EventBus.getDefault().post(new EBPackage("卸载", packageName, "")); + + EBPackage uninstallEb = new EBPackage("卸载", packageName, ""); + EventBus.getDefault().post(uninstallEb); + PackageObserver.onPackageChanged(uninstallEb); } // 接收替换广播 @@ -57,7 +63,10 @@ public class InstallAndUninstallReceiver extends BroadcastReceiver { DataUtils.onEvent(context, "软件更新", "更新完成"); } String versionName = PackageUtils.getVersionByPackage(packageName); + + EBPackage updateEb = new EBPackage("替换", packageName, versionName); EventBus.getDefault().post(new EBPackage("替换", packageName, versionName)); + PackageObserver.onPackageChanged(updateEb); } }); } diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/OkHttpCacheInterceptor.java b/app/src/main/java/com/gh/gamecenter/retrofit/OkHttpCacheInterceptor.java index 46d2311c85..3e43a1206d 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/OkHttpCacheInterceptor.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/OkHttpCacheInterceptor.java @@ -96,7 +96,7 @@ class OkHttpCacheInterceptor implements Interceptor { // } request = request.newBuilder() - .addHeader("IMEI", MetaUtil.getIMEI()) + .addHeader("JNFJ", MetaUtil.getBase64EncodedIMEI()) .addHeader("CHANNEL", HaloApp.getInstance().getChannel()) .addHeader("VERSION", PackageUtils.getVersionName()) .addHeader("OAID", HaloApp.getInstance().getOAID()) diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index 385d6d34b2..63b9ad57e9 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -11,6 +11,7 @@ import com.gh.gamecenter.entity.AuthDialogEntity; import com.gh.gamecenter.entity.AvatarBorderEntity; import com.gh.gamecenter.entity.BackgroundImageEntity; import com.gh.gamecenter.entity.BadgeEntity; +import com.gh.gamecenter.entity.CatalogEntity; import com.gh.gamecenter.entity.CategoryEntity; import com.gh.gamecenter.entity.CommentEntity; import com.gh.gamecenter.entity.CommentnumEntity; @@ -60,6 +61,7 @@ import com.gh.gamecenter.entity.SettingsEntity; import com.gh.gamecenter.entity.SignEntity; import com.gh.gamecenter.entity.SimpleGameEntity; import com.gh.gamecenter.entity.SimulatorEntity; +import com.gh.gamecenter.entity.SpecialCatalogEntity; import com.gh.gamecenter.entity.SubjectEntity; import com.gh.gamecenter.entity.SubjectRecommendEntity; import com.gh.gamecenter.entity.SubjectRefreshEntity; @@ -104,8 +106,10 @@ import com.gh.gamecenter.qa.entity.SuggestedFollowEntity; import com.google.gson.JsonObject; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import io.reactivex.Observable; import io.reactivex.Single; @@ -124,6 +128,7 @@ import retrofit2.http.PUT; import retrofit2.http.Part; import retrofit2.http.Path; import retrofit2.http.Query; +import retrofit2.http.QueryMap; import retrofit2.http.Url; /** @@ -301,7 +306,7 @@ public interface ApiService { * 获取专题数据 */ @GET("columns/{column_id}/games") - Observable> getColumn(@Path("column_id") String column_id, @Query("sort") String sort, @Query("filter") String order, @Query("page") int page); + Single> getColumn(@Path("column_id") String column_id, @Query("sort") String sort, @Query("filter") String order, @Query("page") int page); /** * 获取专题数据标题 @@ -2720,4 +2725,64 @@ public interface ApiService { */ @GET("devices/{device_id}/download_simulator_games") Single> getSimulatorGames(@Path("device_id") String deviceId, @Query("page") int page, @Query("filter") String filter); + + /** + * 搜索用户 + */ + @GET("./users:search") + Observable> searchUsers(@Query("keyword") String keyword, @Query("page") int page); + + /** + * 置顶评论 + */ + @POST("communities/{community_id}/articles/{article_id}/comments/{comment_id}:set-top") + Observable commentTop(@Path("community_id") String communityId, @Path("article_id") String articleId, @Path("comment_id") String commentId, @QueryMap Map params); + + /** + * 取消置顶评论 + */ + @POST("communities/{community_id}/articles/{article_id}/comments/{comment_id}:unset-top") + Observable commentUnTop(@Path("community_id") String communityId, @Path("article_id") String articleId, @Path("comment_id") String commentId); + + /** + * 获取推荐的论坛 + */ + @POST("users/{user_id}/recommends/bbses") + Observable> getRecommendForum(@Path("user_id") String userId, @Body RequestBody body); + + /** + * 获取推荐的论坛(未登录) + */ + @POST("recommends/bbses") + Observable> getRecommendForumNotLoggedIn(@Body RequestBody body); + + /** + * 论坛首页搜索 + */ + @GET("./bbses:search") + Observable> searchForumContent(@QueryMap HashMap map, @Query("page") int page); + + /** + * 应用跳转 + */ + @GET("packages/{package}/redirect") + Single redirectGameDetail(@Path("package") String packageName); + + /** + * 获取一级分类数据 + */ + @GET("catalogs/{catalog_id}") + Single getCatalogs(@Path("catalog_id") String catalogId); + + /** + * 获取一级分类数据 及其 二级分类数据 + */ + @GET("catalogs/{catalog_id}/{primary_catalog_id}") + Single getSubCatalogs(@Path("catalog_id") String catalogId, @Path("primary_catalog_id") String primaryCatalogId); + + /** + * 获取精选分类 + */ + @GET("catalogs/{catalog_id}/special") + Single> getSpecialCatalogs(@Path("catalog_id") String catalogId, @Query("page") int page); } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchDefaultFragment.kt b/app/src/main/java/com/gh/gamecenter/search/SearchDefaultFragment.kt index cff3003518..7889cda099 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchDefaultFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchDefaultFragment.kt @@ -37,7 +37,7 @@ open class SearchDefaultFragment : BaseFragment() { // FlexboxLayout:maxLine 不符合需求 暂且用这种方法实现(历史:最多两行,标签:一行) private val mTagFlexMaxHeight = DisplayUtils.dip2px(44F) - protected val mHistoryFlexMaxHeight = DisplayUtils.dip2px(126F) + protected val mHistoryFlexMaxHeight = DisplayUtils.dip2px(84F) override fun getLayoutId(): Int { return R.layout.fragment_search_default @@ -125,21 +125,22 @@ open class SearchDefaultFragment : BaseFragment() { val flexCell = TextView(context) flexView.addView(flexCell) - val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 25F.dip2px()) + val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) params.setMargins(0, 0, 16F.dip2px(), 16F.dip2px()) flexCell.layoutParams = params flexCell.setSingleLine() flexCell.ellipsize = TextUtils.TruncateAt.END - flexCell.textSize = 13f + flexCell.textSize = 12F flexCell.gravity = Gravity.CENTER flexCell.text = contentList[index] - flexCell.setTextColor(Color.WHITE) - flexCell.setPadding(10F.dip2px(), 0, 10F.dip2px(), 0) + flexCell.maxEms = 6 + flexCell.setTextColor(R.color.text_666666.toColor()) + if (!isHistoryFlex) flexCell.setPadding(8F.dip2px(), 6F.dip2px(), 8F.dip2px(), 6F.dip2px()) flexCell.background = if (isHistoryFlex) { - DrawableView.getOvalDrawable(R.color.text_d5d5d5) + null } else { - DrawableView.getOvalDrawable(R.color.theme) + DrawableView.getOvalDrawable(R.color.text_F5F5F5) } flexCell.setOnClickListener { clickListener.invoke(index) 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 ff35b8c683..705e3dba10 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt @@ -14,18 +14,18 @@ import com.gh.common.exposure.ExposureType import com.gh.common.exposure.IExposable import com.gh.common.filter.RegionSettingHelper import com.gh.common.util.* +import com.gh.common.view.DrawableView import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.SearchType import com.gh.gamecenter.adapter.viewholder.GameViewHolder import com.gh.gamecenter.adapter.viewholder.SearchHistoryViewHolder import com.gh.gamecenter.baselist.ListAdapter -import com.gh.gamecenter.databinding.GameItemBinding +import com.gh.gamecenter.databinding.SearchGameIndexItemBinding import com.gh.gamecenter.db.SearchHistoryDao import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.eventbus.EBDownloadStatus import com.gh.gamecenter.eventbus.EBSearch -import com.gh.gamecenter.game.GameItemViewHolder import com.lightgame.download.DownloadEntity import com.lightgame.utils.Util_System_Keyboard import org.greenrobot.eventbus.EventBus @@ -66,8 +66,8 @@ class SearchGameIndexAdapter(context: Context, override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == ItemViewType.GAME_NORMAL) { val itemView = LayoutInflater.from(viewGroup.context) - .inflate(R.layout.game_item, viewGroup, false) - GameItemViewHolder(GameItemBinding.bind(itemView)) + .inflate(R.layout.search_game_index_item, viewGroup, false) + SearchGameIndexItemViewHolder(SearchGameIndexItemBinding.bind(itemView)) } else { val itemView = LayoutInflater.from(viewGroup.context) .inflate(R.layout.fm_search_history_item, viewGroup, false) @@ -87,19 +87,11 @@ class SearchGameIndexAdapter(context: Context, ExposureType.EXPOSURE) exposureEventArray!!.put(position, exposureEvent) - if (holder is GameItemViewHolder) { - if (position == 0) { - holder.itemView.setPadding( - DisplayUtils.dip2px(16f), DisplayUtils.dip2px(20f), - DisplayUtils.dip2px(20f), DisplayUtils.dip2px(8f)) - } else { - holder.itemView.setPadding( - DisplayUtils.dip2px(16f), DisplayUtils.dip2px(8f), - DisplayUtils.dip2px(20f), DisplayUtils.dip2px(8f)) - } - + if (holder is SearchGameIndexItemViewHolder) { val binding = holder.binding - binding.game = gameEntity + binding.gameItemIncluded.game = gameEntity + binding.divider.goneIf(position == 0) + binding.gameItemIncluded.root.setPadding(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 16F.dip2px()) holder.initServerType(gameEntity) binding.executePendingBindings() @@ -124,36 +116,37 @@ class SearchGameIndexAdapter(context: Context, LogUtils.uploadSearchClick("search_click", "搜索页", key, SearchType.fromString(type).toChinese(), gameEntity.id, gameEntity.name) } - DownloadItemUtils.setOnClickListenerWithInvokeCallbackForAllState( + DownloadItemUtils.setOnClickListener( mContext, - binding.downloadBtn, + binding.gameItemIncluded.downloadBtn, gameEntity, holder.adapterPosition, this, StringUtils.buildString(entrance, "+(搜索-列表[", key, "=", type, "=", (holder.getAdapterPosition() + 1).toString(), "])"), "搜索-列表:" + gameEntity.name!!, - exposureEvent, object : EmptyCallback { - override fun onCallback() { - Util_System_Keyboard.hideSoftKeyboardByIBinder(mContext, binding.downloadBtn.windowToken) + exposureEvent, + null, + object : EmptyCallback { + override fun onCallback() { + Util_System_Keyboard.hideSoftKeyboardByIBinder(mContext, binding.gameItemIncluded.downloadBtn.windowToken) - if (searchMap[gameEntity.id] == null) { - EventBus.getDefault().post(EBSearch("search", gameEntity.id, gameEntity.name)) - searchMap[gameEntity.id] = gameEntity.name - } + if (searchMap[gameEntity.id] == null) { + EventBus.getDefault().post(EBSearch("search", gameEntity.id, gameEntity.name)) + searchMap[gameEntity.id] = gameEntity.name + } - if (SearchType.fromString(type) == SearchType.AUTO) { + if (SearchType.fromString(type) == SearchType.AUTO) { // MtaHelper.onEvent("游戏搜索", "自动搜索", key) - } + } - LogUtils.uploadSearchClick("search_click", "搜索页", key, SearchType.fromString(type).toChinese(), gameEntity.id, gameEntity.name) - } - } + LogUtils.uploadSearchClick("search_click", "搜索页", key, SearchType.fromString(type).toChinese(), gameEntity.id, gameEntity.name) + } + } ) - DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(binding), true) + DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(binding.gameItemIncluded), true) } else if (holder is SearchHistoryViewHolder) { holder.searchHistoryName.text = gameEntity.name - holder.searchHistoryLine.visibility = View.GONE holder.itemView.setOnClickListener { if (searchMap[gameEntity.id] == null) { EventBus.getDefault().post(EBSearch("search", gameEntity.id, gameEntity.name)) @@ -215,4 +208,25 @@ class SearchGameIndexAdapter(context: Context, } } } + + class SearchGameIndexItemViewHolder(var binding: SearchGameIndexItemBinding) : RecyclerView.ViewHolder(binding.root) { + fun initServerType(gameEntity: GameEntity) { + val serverLabel = gameEntity.serverLabel + when { + gameEntity.test != null -> { + binding.gameItemIncluded.gameKaifuType.visibility = View.GONE + binding.gameItemIncluded.gameKaifuType.text = "" + } + serverLabel != null -> { + binding.gameItemIncluded.gameKaifuType.visibility = View.VISIBLE + binding.gameItemIncluded.gameKaifuType.text = serverLabel.value + binding.gameItemIncluded.gameKaifuType.background = DrawableView.getServerDrawable(serverLabel.color) + } + else -> binding.gameItemIncluded.gameKaifuType.visibility = View.GONE + } + + // 由于RecyclerView的复用机制 需要每次测量gameName的宽 + binding.gameItemIncluded.gameName.requestLayout() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexFragment.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexFragment.kt index ce89963909..df4731a937 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexFragment.kt @@ -1,15 +1,12 @@ package com.gh.gamecenter.search -import android.graphics.Rect import android.os.Bundle import android.text.SpannableString import android.text.Spanned import android.text.TextPaint import android.text.method.LinkMovementMethod import android.text.style.ClickableSpan -import android.view.Gravity import android.view.View -import android.view.ViewTreeObserver import android.widget.LinearLayout import android.widget.TextView import androidx.core.content.ContextCompat @@ -25,9 +22,11 @@ import com.gh.common.xapk.XapkInstaller import com.gh.common.xapk.XapkUnzipStatus import com.gh.download.DownloadManager import com.gh.gamecenter.R +import com.gh.gamecenter.SearchActivity import com.gh.gamecenter.SearchType import com.gh.gamecenter.SuggestionActivity import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.baselist.LoadType import com.gh.gamecenter.baselist.NormalListViewModel import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.entity.SettingsEntity @@ -56,8 +55,6 @@ class SearchGameIndexFragment : ListFragment 0) { - val activity = activity - if (activity != null) { - mSearchNoData.gravity = Gravity.CENTER_HORIZONTAL - mSearchNoData.setPadding(0, DisplayUtils.dip2px(activity, 10f), 0, 0) - } - } else { - mSearchNoData.gravity = Gravity.CENTER - } - } - decorView?.viewTreeObserver?.addOnGlobalLayoutListener(mOnGlobalLayoutListener) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -124,11 +109,6 @@ class SearchGameIndexFragment : ListFragment bindGameItem(holder) + is GameItemViewHolder -> { + val padTop= if (position == 0) 16F.dip2px() else 12F.dip2px() + holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 12F.dip2px()) + bindGameItem(holder) + } is FooterViewHolder -> holder.initFooterViewHolder(listViewModel, mIsLoading, mIsNetworkError, mIsOver) is SearchGameFooterViewHolder -> bindFooterItem(holder) } @@ -144,7 +148,7 @@ class SearchGameResultAdapter(context: Context, } } - DownloadItemUtils.setOnClickListenerWithInvokeCallbackForAllState( + DownloadItemUtils.setOnClickListener( mContext, binding.downloadBtn, gameEntity, @@ -153,6 +157,7 @@ class SearchGameResultAdapter(context: Context, StringUtils.buildString(entrance, "+(搜索-列表[", key, "=", type, "=", (holder.adapterPosition + 1).toString(), "])"), "搜索-列表:" + gameEntity.name!!, exposureEvent, + null, object : EmptyCallback { override fun onCallback() { Util_System_Keyboard.hideSoftKeyboardByIBinder(mContext, binding.downloadBtn.windowToken) diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultFragment.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultFragment.kt index aac11939f4..fcf4f0f516 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultFragment.kt @@ -1,15 +1,12 @@ package com.gh.gamecenter.search -import android.graphics.Rect import android.os.Bundle import android.text.SpannableString import android.text.Spanned import android.text.TextPaint import android.text.method.LinkMovementMethod import android.text.style.ClickableSpan -import android.view.Gravity import android.view.View -import android.view.ViewTreeObserver import android.view.animation.Animation import android.view.animation.TranslateAnimation import android.widget.ImageView @@ -28,9 +25,11 @@ import com.gh.common.xapk.XapkInstaller import com.gh.common.xapk.XapkUnzipStatus import com.gh.download.DownloadManager import com.gh.gamecenter.R +import com.gh.gamecenter.SearchActivity import com.gh.gamecenter.SearchType import com.gh.gamecenter.SuggestionActivity import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.baselist.LoadType import com.gh.gamecenter.baselist.NormalListViewModel import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.eventbus.EBDownloadStatus @@ -73,8 +72,6 @@ class SearchGameResultFragment : ListFragment 0) { - if (activity != null) { - mSearchNoData.gravity = Gravity.CENTER_HORIZONTAL - mSearchNoData.setPadding(0, DisplayUtils.dip2px(activity, 10f), 0, 0) - } - } else { - mSearchNoData.gravity = Gravity.CENTER - } - } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -226,6 +215,13 @@ class SearchGameResultFragment : ListFragment 2) userName = "${userName[0]}**${userName[userName.length - 1]}" + mCurrentName.text = userName mCurrentDesc.text = "注册方式:${getRegisterType(registerType)}" - mCurrentName.text = name ImageUtils.display(mCurrentIcon, icon) } diff --git a/app/src/main/java/com/gh/gamecenter/security/SecurityFragment.kt b/app/src/main/java/com/gh/gamecenter/security/SecurityFragment.kt index 0a5d03e075..4b3aad6348 100644 --- a/app/src/main/java/com/gh/gamecenter/security/SecurityFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/security/SecurityFragment.kt @@ -21,6 +21,7 @@ class SecurityFragment : NormalFragment() { private val mSecurityRegisterWay by bindView(R.id.security_register_way) private val mSecurityBindPhone by bindView(R.id.security_bind_phone) + private val mSecuritySafeCenterDivider by bindView(R.id.safe_center_divider) private val mSecuritySafeCenterContainer by bindView(R.id.safe_center_container) private val mSecurityRegisterWayContainer by bindView(R.id.security_register_way_container) @@ -42,6 +43,7 @@ class SecurityFragment : NormalFragment() { } else { mSecurityRegisterWayContainer.visibility = View.GONE mSecurityBindPhoneContainer.visibility = View.GONE + mSecuritySafeCenterDivider.visibility = View.GONE mSecuritySafeCenterTv.text = "注销帐号" mSecuritySafeCenterContainer.setOnClickListener { if ("internal" == BuildConfig.FLAVOR) { diff --git a/app/src/main/java/com/gh/gamecenter/subject/SubjectListViewModel.kt b/app/src/main/java/com/gh/gamecenter/subject/SubjectListViewModel.kt index 24ed674125..77c65c6b18 100644 --- a/app/src/main/java/com/gh/gamecenter/subject/SubjectListViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/subject/SubjectListViewModel.kt @@ -12,6 +12,7 @@ import com.gh.gamecenter.entity.SubjectSettingEntity import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager import io.reactivex.Observable +import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import retrofit2.HttpException @@ -23,7 +24,9 @@ class SubjectListViewModel(application: Application, var selectedLabelList = arrayListOf() var selectedFilterSize = SubjectSettingEntity.Size(text = "全部大小") - override fun provideDataObservable(page: Int): Observable> { + override fun provideDataObservable(page: Int): Observable>? = null + + override fun provideDataSingle(page: Int): Single> { return RetrofitManager.getInstance(getApplication()).sensitiveApi.getColumn( subjectData.subjectId, subjectData.sort, diff --git a/app/src/main/java/com/gh/gamecenter/suggest/SuggestSelectGameAdapter.java b/app/src/main/java/com/gh/gamecenter/suggest/SuggestSelectGameAdapter.java index 1d5d57c863..12132d603d 100644 --- a/app/src/main/java/com/gh/gamecenter/suggest/SuggestSelectGameAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/suggest/SuggestSelectGameAdapter.java @@ -11,6 +11,7 @@ import android.widget.ProgressBar; import com.gh.base.OnRequestCallBackListener; import com.gh.base.fragment.BaseFragment; import com.gh.common.util.BitmapUtils; +import com.gh.common.util.PackageUtils; import com.gh.gamecenter.R; import com.gh.gamecenter.SuggestionActivity; import com.gh.gamecenter.entity.InstallGameEntity; @@ -60,7 +61,7 @@ public class SuggestSelectGameAdapter extends BaseRecyclerAdapter { PackageManager pm = mContext.getPackageManager(); - List installedPackages = pm.getInstalledPackages(0); + List installedPackages = PackageUtils.getInstalledPackages(mContext, 0); for (PackageInfo installedPackage : installedPackages) { if ((installedPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { diff --git a/app/src/main/java/com/gh/gamecenter/tag/TagsHorizontalAdapter.kt b/app/src/main/java/com/gh/gamecenter/tag/TagsHorizontalAdapter.kt index 0c5d7da21f..c68ae9a698 100644 --- a/app/src/main/java/com/gh/gamecenter/tag/TagsHorizontalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/tag/TagsHorizontalAdapter.kt @@ -2,14 +2,12 @@ package com.gh.gamecenter.tag import android.content.Context import android.graphics.Color -import android.graphics.drawable.GradientDrawable import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.core.content.ContextCompat import butterknife.BindView import com.gh.base.BaseRecyclerViewHolder -import com.gh.common.util.DisplayUtils import com.gh.gamecenter.R import com.gh.gamecenter.entity.TagEntity import com.lightgame.adapter.BaseRecyclerAdapter @@ -26,21 +24,16 @@ class TagsHorizontalAdapter(context: Context, override fun onBindViewHolder(holder: TagsViewHolder, position: Int) { val tagEntity = mTagList[position] - val gradientDrawable = GradientDrawable() - gradientDrawable.shape = GradientDrawable.RECTANGLE if (mViewModel.selectedTag.name == tagEntity.name) { - gradientDrawable.setColor(ContextCompat.getColor(mContext, R.color.theme)) - gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat() + holder.tagTv.background = ContextCompat.getDrawable(mContext, R.drawable.bg_tag_text) holder.tagTv.setTextColor(Color.WHITE) } else { - gradientDrawable.setColor(Color.WHITE) - gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat() - holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_3a3a3a)) + holder.tagTv.background = null + holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_757575)) } holder.tagTv.text = tagEntity.name - holder.tagTv.background = gradientDrawable holder.tagTv.setOnClickListener { mViewModel.changeSelectedTag(tagEntity) notifyDataSetChanged() diff --git a/app/src/main/java/com/gh/gamecenter/tag/TagsListAdapter.kt b/app/src/main/java/com/gh/gamecenter/tag/TagsListAdapter.kt index 5aa69e1f41..83d913e38d 100644 --- a/app/src/main/java/com/gh/gamecenter/tag/TagsListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/tag/TagsListAdapter.kt @@ -9,6 +9,7 @@ import com.gh.common.exposure.ExposureSource import com.gh.common.exposure.IExposable import com.gh.common.util.DownloadItemUtils import com.gh.common.util.StringUtils +import com.gh.common.util.dip2px import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder @@ -82,6 +83,9 @@ class TagsListAdapter(context: Context, holder.initServerType(gameEntity) holder.binding.executePendingBindings() + val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px() + holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px()) + gameEntity.sequence = position + 1 val exposureSource = ExposureSource("标签详情", "${mViewModel.selectedTag.name} + ${mViewModel.getSortTypeInChinese()}") diff --git a/app/src/main/java/com/gh/gamecenter/tag/TagsListFragment.kt b/app/src/main/java/com/gh/gamecenter/tag/TagsListFragment.kt index 522d781cfd..899aa3bd5b 100644 --- a/app/src/main/java/com/gh/gamecenter/tag/TagsListFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/tag/TagsListFragment.kt @@ -121,6 +121,8 @@ class TagsListFragment : ListFragment() { DownloadManager.getInstance(context).removeObserver(mDataWatcher) } + override fun getItemDecoration() = null + override fun getLayoutId(): Int { return R.layout.fragment_tags } diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/VideoAdapter.kt b/app/src/main/java/com/gh/gamecenter/video/detail/VideoAdapter.kt index dddb0e3fd3..112cfc8f7a 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/VideoAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/VideoAdapter.kt @@ -9,6 +9,7 @@ import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.gh.base.BaseActivity import com.gh.common.constant.Config import com.gh.common.constant.Constants @@ -39,7 +40,7 @@ import com.squareup.picasso.Picasso import kotlinx.android.synthetic.main.layout_video_detail_surface.view.* import java.util.* -class VideoAdapter(val mContext: Context, val mRecyclerView: RecyclerView, val mViewModel: VideoDetailContainerViewModel) +class VideoAdapter(val mContext: Context, val mRecyclerView: RecyclerView, val refreshLayout: SwipeRefreshLayout, val mViewModel: VideoDetailContainerViewModel) : RecyclerView.Adapter(), IExposable { var videoList = arrayListOf() var isVisible = false//fragment是否可见 @@ -86,6 +87,7 @@ class VideoAdapter(val mContext: Context, val mRecyclerView: RecyclerView, val m videoView.updateThumb(videoList[position].getThumb()) videoView.updateMuteStatus() videoView.fullscreenButton.setOnClickListener { + if (refreshLayout.isRefreshing) return@setOnClickListener if (mOrientationUtils.isLand == 0) { videoView.recordMta("进入全屏") MtaHelper.onEvent("视频详情", "进入全屏", "${videoList[position].title}(${videoList[position].id})") @@ -93,14 +95,14 @@ class VideoAdapter(val mContext: Context, val mRecyclerView: RecyclerView, val m } videoView.hideAllButton(true) mOrientationUtils.resolveByClick() - val fullVideoPlayer = videoView.startWindowFullscreen(mContext, true, true) as DetailPlayerView - fullVideoPlayer.observeVolume(mContext as AppCompatActivity) - fullVideoPlayer.setViewModel(mViewModel) - fullVideoPlayer.hideAllButton(true) - fullVideoPlayer.updateViewDetail(videoList[position]) - fullVideoPlayer.updateMuteStatus() + val fullVideoPlayer = videoView.startWindowFullscreen(mContext, true, true) as? DetailPlayerView + fullVideoPlayer?.observeVolume(mContext as AppCompatActivity) + fullVideoPlayer?.setViewModel(mViewModel) + fullVideoPlayer?.hideAllButton(true) + fullVideoPlayer?.updateViewDetail(videoList[position]) + fullVideoPlayer?.updateMuteStatus() //金进入全屏后直接播放 - if (fullVideoPlayer.currentState == GSYVideoView.CURRENT_STATE_PAUSE) { + if (fullVideoPlayer?.currentState == GSYVideoView.CURRENT_STATE_PAUSE) { fullVideoPlayer.setCurrentPosition(videoView.getCurrentPosition()) fullVideoPlayer.onVideoResume() } diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt index 99d6a6f423..02f3abd295 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt @@ -107,6 +107,7 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { override fun onFragmentFirstVisible() { super.onFragmentFirstVisible() + mViewModel.setRecyclerView(recyclerview) initListener() if (!mIsHomeVideo) { toolbar.setNavigationIcon(R.drawable.ic_toolbar_back_white) @@ -119,7 +120,7 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mViewModel.videoList.observeNonNull(this) { hideNetworkErrorView() if (!::mAdapter.isInitialized) { - mAdapter = VideoAdapter(requireContext(), recyclerview, mViewModel) + mAdapter = VideoAdapter(requireContext(), recyclerview, refresh, mViewModel) mExposureListener = ExposureListener(this, mAdapter) recyclerview.addOnScrollListener(mExposureListener!!) recyclerview.adapter = mAdapter @@ -187,6 +188,11 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mViewModel.followVideoInfo.observeNonNull(this) { updateAllFollowDatas(it.user.id ?: "", it.me.isFollower) } + mViewModel.refreshFinish.observeNonNull(this) { + if (it) { + refresh.isRefreshing = false + } + } mViewModel.getVideoDetailList(mInitialVideoId, mLocation, isLoadNext = true) } @@ -227,6 +233,7 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mIsFirstIn = true mViewModel.getVideoDetailList(mViewModel.currentDisplayingVideo?.id ?: "", mLocation, isLoadNext = false) + findVisibleVideoViewByPosition()?.uploadVideoStreamingPlaying("视频流刷新") } mViewPagerLayoutManager.setOnViewPagerListener(object : OnPagerListener { @@ -672,6 +679,12 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { } } + //评论成功 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(commentSuccess: EBCommentSuccess) { + findVisibleVideoViewByPosition()?.uploadVideoStreamingPlaying("提交评论") + } + //下载被删除事件 @Subscribe(threadMode = ThreadMode.MAIN) fun onEventMainThread(status: EBDownloadStatus) { diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt index bba19571f2..16ef0ad21b 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt @@ -4,11 +4,14 @@ import android.annotation.SuppressLint import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData +import androidx.recyclerview.widget.RecyclerView import com.gh.common.exposure.meta.MetaUtil import com.gh.common.history.HistoryDatabase import com.gh.common.runOnIoThread import com.gh.common.util.UrlFilterUtils import com.gh.common.util.createRequestBodyAny +import com.gh.common.util.tryCatchInRelease +import com.gh.common.util.tryWithDefaultCatch import com.gh.download.DownloadManager import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.entity.MyVideoEntity @@ -23,6 +26,7 @@ import com.lightgame.utils.Utils import io.reactivex.Single import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody +import java.lang.ref.WeakReference import java.util.* import kotlin.random.Random @@ -36,6 +40,7 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel var path = "" var entranceDetail = "" // 视频流入口链接, WEB($页面Url$) + var refreshFinish = MutableLiveData() var noDataError = MutableLiveData() var networkError = MutableLiveData() var videoList = MutableLiveData>() @@ -51,15 +56,20 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel var paginationType = "page"//活动分页方式 page(默认) filter var fieldId = ""//专区视频板块id var sectionName = ""//专区视频专题名 + var positionAndPackageMap = HashMap() // key: packageName + position, value: position + var isPauseVideo = true private var page = 1 private var cacheVideoIds: MutableList? = null private var cacheId = "" - var positionAndPackageMap = HashMap() // key: packageName + position, value: position - var isPauseVideo = true + private var mRecyclerViewRef: WeakReference? = null // 是否为第一次加载(即没有进行加载更多) private var mIsFirstLoad = true + fun setRecyclerView(recyclerView: RecyclerView) { + mRecyclerViewRef = WeakReference(recyclerView) + } + fun collect() { collectVideo(currentDisplayingVideo) } @@ -168,10 +178,21 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel } page++ //下拉刷新清除列表数据 - if (!isLoadNext) { +// if (!isLoadNext) { +// videoList.value?.clear() +// } +// mergeVideoList(data, isLoadNext) + if (isLoadNext) { + mergeVideoList(data, isLoadNext) + } else if (!isLoadNext && mRecyclerViewRef?.get()?.computeVerticalScrollOffset() == 0) { + //下拉刷新并且列表没有滚动清除列表数据,数据发生变化 videoList.value?.clear() + mergeVideoList(data, isLoadNext) + } else { + //下拉刷新并且列表滚动中关闭下拉刷新动画,数据不变 + refreshFinish.postValue(true) } - mergeVideoList(data, isLoadNext) + mIsFirstLoad = false } @@ -218,10 +239,20 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel } if (mIsFirstLoad || !(data.size == 1 && data[0].id == videoId)) { //下拉刷新清除列表数据 - if (!isLoadNext) { +// if (!isLoadNext) { +// videoList.value?.clear() +// } +// mergeVideoList(data, isLoadNext) + if (isLoadNext) { + mergeVideoList(data, isLoadNext) + } else if (!isLoadNext && mRecyclerViewRef?.get()?.computeVerticalScrollOffset() == 0) { + //下拉刷新并且列表没有滚动清除列表数据,数据发生变化 videoList.value?.clear() + mergeVideoList(data, isLoadNext) + } else { + //下拉刷新并且列表滚动中关闭下拉刷新动画,数据不变 + refreshFinish.postValue(true) } - mergeVideoList(data, isLoadNext) } mIsFirstLoad = false @@ -419,10 +450,8 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel commentCount = videoEntity.commentCount videoStreamRecord = if (location == Location.VIDEO_CHOICENESS.value || location == Location.VIDEO_HOT.value) 1 else 0 } - runOnIoThread { - HistoryDatabase.instance.videoHistoryDao().addVideo(videoHistory) - } + runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().addVideo(videoHistory) } } } fun shareVideoStatistics(videoEntity: VideoEntity?) { diff --git a/app/src/main/java/com/gh/gamecenter/video/upload/UploadManager.kt b/app/src/main/java/com/gh/gamecenter/video/upload/UploadManager.kt index 2368c0861a..544eeafb3c 100644 --- a/app/src/main/java/com/gh/gamecenter/video/upload/UploadManager.kt +++ b/app/src/main/java/com/gh/gamecenter/video/upload/UploadManager.kt @@ -3,15 +3,14 @@ package com.gh.gamecenter.video.upload import android.annotation.SuppressLint import com.alibaba.sdk.android.oss.common.OSSLog import com.gh.common.util.MD5Utils +import com.gh.common.util.tryCatchInRelease import com.gh.gamecenter.BuildConfig - import com.gh.gamecenter.entity.OssEntity import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.RetrofitManager import com.gh.gamecenter.room.AppDatabase import com.halo.assistant.HaloApp import io.reactivex.android.schedulers.AndroidSchedulers - import io.reactivex.schedulers.Schedulers import java.io.File import java.util.* @@ -36,7 +35,7 @@ object UploadManager : OnUploadListener { val entity = mUploadDao.getUploadByFilePath(uploadFilePath) if (entity != null) { entity.success = true - mUploadDao.addUpload(entity) + tryCatchInRelease { mUploadDao.addUpload(entity) } } mUploadListenerMap[uploadFilePath]?.onUploadSuccess(uploadFilePath, url) mUploadListenerMap.remove(uploadFilePath) @@ -76,7 +75,7 @@ object UploadManager : OnUploadListener { data.domain = uploadEntity.domain data.key = uploadEntity.key } else { - mUploadDao.addUpload(UploadEntity(uploadFilePath, fileMD5, data.domain, data.key, false)) + tryCatchInRelease { mUploadDao.addUpload(UploadEntity(uploadFilePath, fileMD5, data.domain, data.key, false)) } } val uploadThread = UploadThread(data, this@UploadManager) diff --git a/app/src/main/java/com/gh/gamecenter/video/upload/view/UploadVideoActivity.kt b/app/src/main/java/com/gh/gamecenter/video/upload/view/UploadVideoActivity.kt index a959c25156..f5d2e02103 100644 --- a/app/src/main/java/com/gh/gamecenter/video/upload/view/UploadVideoActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/video/upload/view/UploadVideoActivity.kt @@ -111,7 +111,7 @@ class UploadVideoActivity : ToolBarActivity() { val imagePath = data.getStringExtra(CropImageActivity.RESULT_CLIP_PATH) mUpdatedPosterPath = imagePath mBinding.videoPoster.setImageURI("file://$imagePath") - + LogUtils.logVideoStreamingUpload("更换封面", mPath, mEntranceLink, "") checkPostButtonStatus() } } else if (requestCode == REQUEST_CODE_CHOOSE_LABEL && resultCode == Activity.RESULT_OK) { @@ -158,6 +158,7 @@ class UploadVideoActivity : ToolBarActivity() { mBinding.postButton.setOnClickListener { verifyData(false) LogUtils.logVideoStreamingUpload("点击提交", mPath, mEntranceLink, "") + LogUtils.logVideoStreamingUpload("提交视频", mPath, mEntranceLink, "") } mBinding.videoPosterPatchHint.setOnClickListener { startMediaStore() @@ -173,6 +174,7 @@ class UploadVideoActivity : ToolBarActivity() { startActivityForResult(VideoLabelActivity.getIntent(this, mActivityLabelEntity?.id ?: ""), REQUEST_CODE_CHOOSE_LABEL) + LogUtils.logVideoStreamingUpload("查看活动标签", mPath, mEntranceLink, "") } mBinding.deleteActivity.setOnClickListener { mActivityLabelEntity = null @@ -206,8 +208,10 @@ class UploadVideoActivity : ToolBarActivity() { if (mViewModel.videoPatch != null) { setNavigationTitle("视频编辑") + LogUtils.logVideoStreamingUpload("进入视频编辑页", mPath, mEntranceLink, "") } else { setNavigationTitle("视频上传") + LogUtils.logVideoStreamingUpload("进入视频上传页", mPath, mEntranceLink, "") } if (mViewModel.gameEntity != null) { @@ -740,6 +744,7 @@ class UploadVideoActivity : ToolBarActivity() { runOnUiThread { handleUploadSuccess(url) MtaHelper.onEvent("上传视频", "上传视频", "上传成功") + LogUtils.logVideoStreamingUpload("视频上传完毕", mPath, mEntranceLink, "") } } diff --git a/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoDraftAdapter.kt b/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoDraftAdapter.kt index 104269163d..760b1bc9e3 100644 --- a/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoDraftAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoDraftAdapter.kt @@ -63,10 +63,11 @@ class VideoDraftAdapter(context: Context, holder.binding.videoStatus.text = "继续上传" holder.binding.videoTitle.text = if (draftEntity.title.isEmpty()) "标题为空" else draftEntity.title holder.itemView.setOnClickListener { - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(mContext, + PermissionHelper.checkStoragePermissionBeforeAction(mContext, object : EmptyCallback { override fun onCallback() { MtaHelper.onEvent("上传视频", "视频投稿-草稿箱", "继续上传") + LogUtils.logVideoStreamingUpload("点击继续上传按钮", mPath, "", "") val intent = UploadVideoActivity.getIntent(mContext, draftEntity, mEntrance, mPath) (mContext as Activity).startActivityForResult(intent, VideoManagerActivity.REQUEST_CODE_DRAFT) } @@ -102,6 +103,7 @@ class VideoDraftAdapter(context: Context, "确定删除", "暂时不了", DialogUtils.ConfirmListener { mViewModel.deleteDraft(entity.id) + LogUtils.logVideoStreamingUpload("点击删除按钮", mPath, "", "") }, null) popupWindow.dismiss() } diff --git a/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoManagerActivity.kt b/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoManagerActivity.kt index d9bddc5586..f79e8e0f01 100644 --- a/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoManagerActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoManagerActivity.kt @@ -59,14 +59,16 @@ class VideoManagerActivity : BaseActivity_TabLayout() { if (mVideoLink != null) { onMenuItemClick(menuItem) } + LogUtils.logVideoStreamingUpload("进入视频投稿页", "视频投稿", "", "") } override fun onMenuItemClick(item: MenuItem): Boolean { if (item.itemId == R.id.menu_text) { - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(this, + PermissionHelper.checkStoragePermissionBeforeAction(this, object : EmptyCallback { override fun onCallback() { MtaHelper.onEvent("我的光环_新", "视频投稿", "上传视频") + LogUtils.logVideoStreamingUpload("点击上传视频按钮", "视频投稿", "", "") Matisse.from(this@VideoManagerActivity) .choose(MimeType.ofVideo()) .countable(true) @@ -89,6 +91,7 @@ class VideoManagerActivity : BaseActivity_TabLayout() { override fun onPageSelected(position: Int) { super.onPageSelected(position) MtaHelper.onEvent("我的光环_新", "视频投稿", "${mTabTitleList[position]}Tab") + LogUtils.logVideoStreamingUpload("点击${mTabTitleList[position]}tab", "视频投稿", "", "") } override fun initFragmentList(fragments: MutableList) { diff --git a/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoVerifyAdapter.kt b/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoVerifyAdapter.kt index 3e1926abbc..4fa28c5c82 100644 --- a/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoVerifyAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/video/videomanager/VideoVerifyAdapter.kt @@ -129,13 +129,14 @@ class VideoVerifyAdapter(context: Context, delete.setTextColor(R.color.text_cccccc.toColor()) } edit.setOnClickListener { - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(mContext, + PermissionHelper.checkStoragePermissionBeforeAction(mContext, object : EmptyCallback { override fun onCallback() { val intent = UploadVideoActivity.getIntent(mContext, entity, mEntrance, "视频投稿-已投稿") if (mContext is Activity) { (mContext as Activity).startActivityForResult(intent, VideoManagerActivity.REQUEST_CODE_VIDEO) } + LogUtils.logVideoStreamingUpload("点击编辑按钮", "视频投稿-已投稿", "", "") } }) popupWindow.dismiss() @@ -149,7 +150,10 @@ class VideoVerifyAdapter(context: Context, , "视频删除后不可恢复,确定删除吗?" , "确定删除" , "暂不删除" - , DialogUtils.ConfirmListener { mViewModel.deleteVideo(entity.id) }, null) + , DialogUtils.ConfirmListener { + mViewModel.deleteVideo(entity.id) + LogUtils.logVideoStreamingUpload("点击删除按钮", "视频投稿-已投稿", "", entity.id) + }, null) } popupWindow.dismiss() } diff --git a/app/src/main/java/com/halo/assistant/HaloApp.java b/app/src/main/java/com/halo/assistant/HaloApp.java index 3f534ddb27..21fe87629c 100644 --- a/app/src/main/java/com/halo/assistant/HaloApp.java +++ b/app/src/main/java/com/halo/assistant/HaloApp.java @@ -8,6 +8,7 @@ import android.net.ConnectivityManager; import android.net.Uri; import android.preference.PreferenceManager; import android.text.TextUtils; + import androidx.collection.ArrayMap; import androidx.lifecycle.ProcessLifecycleOwner; @@ -31,6 +32,7 @@ import com.gh.common.videolog.VideoRecordUtils; import com.gh.gamecenter.BuildConfig; import com.gh.gamecenter.Injection; import com.gh.gamecenter.entity.SubjectRecommendEntity; +import com.gh.gamecenter.packagehelper.PackageRepository; import com.gh.gamecenter.receiver.ActivitySkipReceiver; import com.gh.gamecenter.receiver.DownloadReceiver; import com.gh.gamecenter.receiver.InstallAndUninstallReceiver; @@ -46,31 +48,13 @@ import com.llew.huawei.verifier.LoadedApkHuaWei; import com.shuyu.gsyvideoplayer.cache.CacheFactory; import com.shuyu.gsyvideoplayer.player.PlayerFactory; import com.squareup.picasso.Picasso; + +import java.lang.reflect.Method; + import io.reactivex.plugins.RxJavaPlugins; import tv.danmaku.ijk.media.exo2.Exo2PlayerManager; import tv.danmaku.ijk.media.exo2.ExoPlayerCacheManager; -/** - * 延迟隐私政策相关操作会引起的问题 - *

- * 1. 启动时需要提前获取一大堆数据,有如下(可能出现异常) - * - 主配置项 (含有许多配置项,譬如是否打开下载按钮) - * - 渠道对应表 - * - 标签颜色表? - * - 实名认证弹窗数据 - * - 游戏设备弹窗列表 - * - 游戏详情过滤标签数据 - * - 获取并提交当前设备的已玩过的游戏时间列表 - * - 获取首页可替换游戏列表 - * - 获取数量巨大的一堆光环已收录的游戏的包名 - * - 同步系统时间 - *

- * 2. 隐私弹窗的弹出本身也会调用 MTA 收集用户数据 - *

- * 3. Tinker 也涉及到 bugly 的使用 - *

- * 4. 延迟初始化的友盟推送第一次启动不可用 - */ public class HaloApp extends Application { private static HaloApp mInstance; @@ -81,6 +65,8 @@ public class HaloApp extends Application { private String mUA; private String mOAID = ""; + private boolean mIsPostInitialized = false; // 是否已经延迟初始化过相关组件,避免重复初始化 + public long deviceRamSize = 0; public boolean isBrandNewInstall = false; // 当前用户是否是安装光环后第一次打开 public boolean isRunningForeground = false; // 标记当前 APP 是否处于前台运行中 @@ -163,17 +149,25 @@ public class HaloApp extends Application { if (isUserAcceptPrivacyPolicy(this)) { initPushSdk(); + postInit(); } registerActivityLifecycleCallbacks(new GHActivityLifecycleCallbacksImpl()); } + /** + * 需要延迟初始化的东西,以下代码调用都放置到用户同意了隐私政策之后 + */ public void postInit() { + if (mIsPostInitialized) return; + initDataHelper(); initThirdPartySdk(); FixedRateJobHelper.begin(); + PackageRepository.initData(); + // 刷新内存中的用户信息,避免应用进程重建时因没有用户信息数据而显示为掉登录状态 UserRepository.getInstance(this).getLoginUserInfo(); @@ -195,6 +189,8 @@ public class HaloApp extends Application { } }); } + + mIsPostInitialized = true; } /** @@ -209,10 +205,21 @@ public class HaloApp extends Application { private void initThirdPartySdk() { initPushSdk(); DataUtils.init(this, mChannel); -// GdtHelper.INSTANCE.init(this, mChannel); + initGdt(); // AntiBotHelper.getManager(); } + private void initGdt() { +// GdtHelper.INSTANCE.init(this, mChannel); + try { + Class clazz = Class.forName("com.gh.gamecenter.GdtHelper"); + Method method = clazz.getMethod("init", Application.class, String.class); + method.invoke(null, getApplication(), HaloApp.getInstance().getChannel()); + } catch (Exception e) { + e.printStackTrace(); + } + } + private void initDataHelper() { ExposureManager.init(); LoghubUtils.init(this); diff --git a/app/src/main/java/com/halo/assistant/fragment/AboutFragment.java b/app/src/main/java/com/halo/assistant/fragment/AboutFragment.java index def8c507eb..961c98a3d1 100644 --- a/app/src/main/java/com/halo/assistant/fragment/AboutFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/AboutFragment.java @@ -1,7 +1,5 @@ package com.halo.assistant.fragment; -import android.content.ClipboardManager; -import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Message; @@ -15,6 +13,7 @@ import androidx.core.content.ContextCompat; import com.gh.common.util.DirectUtils; import com.gh.common.util.EntranceUtils; +import com.gh.common.util.ExtensionsKt; import com.gh.common.util.MtaHelper; import com.gh.common.util.PackageUtils; import com.gh.common.util.StringUtils; @@ -110,10 +109,8 @@ public class AboutFragment extends NormalFragment { break; case R.id.about_jump_douyin: MtaHelper.onEvent("我的光环_设置", "关于光环", "抖音"); - ClipboardManager cmb = (ClipboardManager) requireContext().getSystemService(Context.CLIPBOARD_SERVICE); String url = getString(R.string.gh_douyin_url); - cmb.setText(url); - toast(String.format(Locale.CHINA, "已成功复制%s ,打开抖音可直达", url)); + ExtensionsKt.copyTextAndToast(url, String.format(Locale.CHINA, "已成功复制%s ,打开抖音可直达", url)); DirectUtils.directDouyin(requireContext(), "1402577827140941"); break; default: diff --git a/app/src/main/java/com/halo/assistant/fragment/SettingsFragment.java b/app/src/main/java/com/halo/assistant/fragment/SettingsFragment.java index 07cccb69c3..ee6b471fbd 100644 --- a/app/src/main/java/com/halo/assistant/fragment/SettingsFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/SettingsFragment.java @@ -355,9 +355,7 @@ public class SettingsFragment extends NormalFragment { case R.id.setting_rl_security: MtaHelper.onEvent("我的光环_设置", "设置功能", "账号与安全"); CheckLoginUtils.checkLogin(getContext(), "设置-账号与安全-请先登录", () -> { - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(getContext(), () -> { - startActivityForResult(SecurityActivity.getIntent(getContext(), mEntrance, false), INSERT_MOBILE_CODE); - }); + startActivityForResult(SecurityActivity.getIntent(getContext(), mEntrance, false), INSERT_MOBILE_CODE); }); break; @@ -430,7 +428,7 @@ public class SettingsFragment extends NormalFragment { startActivity(new Intent(getContext(), NetworkDiagnosisActivity.class)); break; case R.id.setting_privacy_policy: - SPUtils.setString(Constants.SP_PRIVACY_MD5,SPUtils.getString(Constants.SP_PRIVACY_CURRENT_MD5)); + SPUtils.setString(Constants.SP_PRIVACY_MD5, SPUtils.getString(Constants.SP_PRIVACY_CURRENT_MD5)); mPrivacyRedDotView.setVisibility(checkPrivacyIsSame() ? View.GONE : View.VISIBLE); MtaHelper.onEvent("我的光环_设置", "设置功能", "隐私政策"); startActivity(WebActivity.getPrivacyPolicyIntent(getContext())); @@ -438,7 +436,7 @@ public class SettingsFragment extends NormalFragment { case R.id.setting_game_submission: MtaHelper.onEvent("我的光环_设置", "设置功能", "游戏投稿"); CheckLoginUtils.checkLogin(getContext(), "设置-游戏投稿-请先登录", () -> { - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(getContext(), () -> { + PermissionHelper.checkStoragePermissionBeforeAction(getContext(), () -> { startActivity(GameSubmissionActivity.getIntent(getContext(), mEntrance, "游戏上传")); }); }); diff --git a/app/src/main/java/com/halo/assistant/fragment/WebFragment.java b/app/src/main/java/com/halo/assistant/fragment/WebFragment.java index 42105ff77b..2744f43811 100644 --- a/app/src/main/java/com/halo/assistant/fragment/WebFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/WebFragment.java @@ -16,6 +16,8 @@ import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.annotation.Nullable; + import com.gh.base.BaseActivity; import com.gh.common.AppExecutor; import com.gh.common.DefaultJsApi; @@ -52,7 +54,6 @@ import org.greenrobot.eventbus.ThreadMode; import java.util.HashMap; import java.util.List; -import androidx.annotation.Nullable; import butterknife.BindView; import butterknife.OnClick; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -113,6 +114,7 @@ public class WebFragment extends NormalFragment implements IScrollable { private String mIsCloseButton;//h5游戏是否显示关闭按钮 hide(隐藏)、open(开启) private TimeElapsedHelper mTimeElapsedHelper; + private DefaultJsApi mJsApi; private WebShareEntity mShareEntity; @@ -264,6 +266,7 @@ public class WebFragment extends NormalFragment implements IScrollable { mGameName = args.getString(KEY_GAME_NAME); mIsCloseButton = args.getString(KEY_CLOSE_BUTTON); + mJsApi = new DefaultJsApi(requireContext()); boolean leaveWebpageToHandleTitle = args.getBoolean(KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, false); WebSettings settings = mWebView.getSettings(); @@ -378,7 +381,7 @@ public class WebFragment extends NormalFragment implements IScrollable { mWebView.loadDataWithBaseURL(null, webUrl, "text/html", "utf-8", null); } } - mWebView.addJavascriptObject(new DefaultJsApi(requireContext()), null); + mWebView.addJavascriptObject(mJsApi, null); mWebView.addJavascriptObject(new ShareNativeCallback(), "share"); if (newsId != null) { @@ -436,6 +439,23 @@ public class WebFragment extends NormalFragment implements IScrollable { } else if (mWebView.canGoBack()) { mWebView.goBack(); return true; + } else if (isDisplayingLogoutPage()) { + // 根据网页是否已注销来判断怎么处理返回逻辑 + mWebView.callHandler("onCancelCount", retValue -> { + if (retValue instanceof Boolean) { + if ((Boolean) retValue) { + mJsApi.logoutExitWebViewAndRedirectToLogin(); + } else { + if (mWebView.canGoBack()) { + mWebView.goBack(); + } else { + requireActivity().finish(); + } + } + } + Utils.log(retValue); + }); + return true; } return false; } @@ -470,6 +490,13 @@ public class WebFragment extends NormalFragment implements IScrollable { mWebView.scrollTo(0, 0); } + /** + * 当前页面是否是注销页面 + */ + private boolean isDisplayingLogoutPage() { + return Constants.LOGOUT_ADDRESS_DEV.equals(mWebView.getUrl()) || Constants.LOGOUT_ADDRESS.equals(mWebView.getUrl()); + } + class ShareNativeCallback { @JavascriptInterface public void setNativeShareContent(Object shareJson) { diff --git a/app/src/main/java/com/halo/assistant/fragment/comment/CommentDetailFragment.java b/app/src/main/java/com/halo/assistant/fragment/comment/CommentDetailFragment.java index fa775001b4..0635275f33 100644 --- a/app/src/main/java/com/halo/assistant/fragment/comment/CommentDetailFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/comment/CommentDetailFragment.java @@ -12,6 +12,12 @@ import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.gh.common.util.CheckLoginUtils; import com.gh.common.util.DialogUtils; import com.gh.common.util.DisplayUtils; @@ -19,7 +25,6 @@ import com.gh.common.util.EntranceUtils; import com.gh.common.util.ErrorHelper; import com.gh.common.util.KeyboardHeightObserver; import com.gh.common.util.KeyboardHeightProvider; -import com.gh.common.util.PermissionHelper; import com.gh.common.util.PostCommentUtils; import com.gh.common.util.TextHelper; import com.gh.gamecenter.CommentDetailActivity; @@ -35,11 +40,6 @@ import com.lightgame.utils.Util_System_Keyboard; import org.json.JSONException; import org.json.JSONObject; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; import butterknife.OnClick; import butterknife.OnTouch; @@ -189,55 +189,53 @@ public class CommentDetailFragment extends NormalFragment implements OnCommentCa @OnClick({R.id.answer_comment_send_btn}) public void OnSendCommentListener() { - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(requireContext(), () -> { - final String content = mCommentDetailCommentEt.getText().toString(); + final String content = mCommentDetailCommentEt.getText().toString(); - if (content.length() == 0) { - toast("评论内容不能为空!"); - return; - } + if (content.length() == 0) { + toast("评论内容不能为空!"); + return; + } - mSendingDialog = DialogUtils.showWaitDialog(getContext(), getString(R.string.post_dialog_hint)); + mSendingDialog = DialogUtils.showWaitDialog(getContext(), getString(R.string.post_dialog_hint)); - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("content", content); - } catch (JSONException e) { - e.printStackTrace(); - } - if (mCommentEntity != null && mCommentEntity.getId() == null) { - toast("评论异常 id null"); - mSendingDialog.cancel(); - return; - } + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("content", content); + } catch (JSONException e) { + e.printStackTrace(); + } + if (mCommentEntity != null && mCommentEntity.getId() == null) { + toast("评论异常 id null"); + mSendingDialog.cancel(); + return; + } - PostCommentUtils.addCommentData(getContext(), null, jsonObject, mCommentEntity, - new PostCommentUtils.PostCommentListener() { - @Override - public void postSuccess(JSONObject response) { - mSendingDialog.dismiss(); - toast("发表成功"); - mCommentDetailCommentEt.setText(""); + PostCommentUtils.addCommentData(getContext(), null, jsonObject, mCommentEntity, + new PostCommentUtils.PostCommentListener() { + @Override + public void postSuccess(JSONObject response) { + mSendingDialog.dismiss(); + toast("发表成功"); + mCommentDetailCommentEt.setText(""); - setSoftInput(false); + setSoftInput(false); - } + } - @Override - public void postFailed(Throwable e) { - mSendingDialog.dismiss(); - String errorString = null; - if (e instanceof HttpException) { - try { - errorString = ((HttpException) e).response().errorBody().string(); - } catch (Exception e1) { - e1.printStackTrace(); - } + @Override + public void postFailed(Throwable e) { + mSendingDialog.dismiss(); + String errorString = null; + if (e instanceof HttpException) { + try { + errorString = ((HttpException) e).response().errorBody().string(); + } catch (Exception e1) { + e1.printStackTrace(); } - ErrorHelper.handleError(requireContext(), errorString, false); } - }); - }); + ErrorHelper.handleError(requireContext(), errorString, false); + } + }); } //软键盘控制 diff --git a/app/src/main/java/com/halo/assistant/fragment/user/UserInfoEditFragment.java b/app/src/main/java/com/halo/assistant/fragment/user/UserInfoEditFragment.java index a5da5d6b8f..68ada78286 100644 --- a/app/src/main/java/com/halo/assistant/fragment/user/UserInfoEditFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/user/UserInfoEditFragment.java @@ -15,9 +15,15 @@ import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.ViewModelProviders; + import com.gh.common.util.DialogUtils; +import com.gh.common.util.ExtensionsKt; import com.gh.common.util.MtaHelper; import com.gh.common.util.TextHelper; +import com.gh.common.view.UrlInterceptedLinkMovementMethod; import com.gh.gamecenter.R; import com.gh.gamecenter.entity.IdCardEntity; import com.gh.gamecenter.entity.UserInfoEntity; @@ -33,10 +39,6 @@ import org.json.JSONObject; import java.util.Locale; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.lifecycle.ViewModelProviders; - import butterknife.BindView; import butterknife.OnClick; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -436,7 +438,8 @@ public class UserInfoEditFragment extends NormalFragment { super.onResponse(response); try { String text = response.getString("text"); - mUserInfoInformationTv.setText(text); + mUserInfoInformationTv.setText(ExtensionsKt.fromHtml(text)); + mUserInfoInformationTv.setMovementMethod(new UrlInterceptedLinkMovementMethod()); } catch (JSONException e) { e.printStackTrace(); } diff --git a/app/src/main/res/drawable-hdpi/search_input_delete.png b/app/src/main/res/drawable-hdpi/search_input_delete.png deleted file mode 100644 index 56056e8415..0000000000 Binary files a/app/src/main/res/drawable-hdpi/search_input_delete.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_filter_arrow_down.png b/app/src/main/res/drawable-xhdpi/ic_filter_arrow_down.png deleted file mode 100644 index 3efcaad3eb..0000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_filter_arrow_down.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_filter_arrow_up.png b/app/src/main/res/drawable-xhdpi/ic_filter_arrow_up.png deleted file mode 100644 index f7b2f0d52a..0000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_filter_arrow_up.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/search_history_delete.png b/app/src/main/res/drawable-xhdpi/search_history_delete.png deleted file mode 100644 index b1803b9e40..0000000000 Binary files a/app/src/main/res/drawable-xhdpi/search_history_delete.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/forum_more_guide_rectangle.webp b/app/src/main/res/drawable-xxhdpi/forum_more_guide_rectangle.webp index 96afb48888..adb49da000 100644 Binary files a/app/src/main/res/drawable-xxhdpi/forum_more_guide_rectangle.webp and b/app/src/main/res/drawable-xxhdpi/forum_more_guide_rectangle.webp differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_article_comment_top.png b/app/src/main/res/drawable-xxhdpi/ic_article_comment_top.png new file mode 100644 index 0000000000..a027151e7b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_article_comment_top.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_article_tag_arrow_right.png b/app/src/main/res/drawable-xxhdpi/ic_article_tag_arrow_right.png new file mode 100644 index 0000000000..4fb8c424e0 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_article_tag_arrow_right.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_catalog_selected.png b/app/src/main/res/drawable-xxhdpi/ic_catalog_selected.png new file mode 100755 index 0000000000..39ee749f72 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_catalog_selected.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_down.png b/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_down.png new file mode 100755 index 0000000000..cd1d3b5f3b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_down.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_up.png b/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_up.png new file mode 100755 index 0000000000..c8abc870f0 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_filter_arrow_up.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_forum_detail_search.png b/app/src/main/res/drawable-xxhdpi/ic_forum_detail_search.png new file mode 100644 index 0000000000..c5e7736ffc Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_forum_detail_search.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_forum_detail_search_light.png b/app/src/main/res/drawable-xxhdpi/ic_forum_detail_search_light.png new file mode 100644 index 0000000000..2357f25c9b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_forum_detail_search_light.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_forum_recommend.png b/app/src/main/res/drawable-xxhdpi/ic_forum_recommend.png new file mode 100644 index 0000000000..eb9026fc0f Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_forum_recommend.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_hint_author.png b/app/src/main/res/drawable-xxhdpi/ic_hint_author.png index a186799ba1..399046ded9 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_hint_author.png and b/app/src/main/res/drawable-xxhdpi/ic_hint_author.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_recommend.png b/app/src/main/res/drawable-xxhdpi/ic_recommend.png new file mode 100755 index 0000000000..17285800a7 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_recommend.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_forum_more.png b/app/src/main/res/drawable-xxhdpi/icon_forum_more.png old mode 100755 new mode 100644 index 7e9a972cf5..8651eb572e Binary files a/app/src/main/res/drawable-xxhdpi/icon_forum_more.png and b/app/src/main/res/drawable-xxhdpi/icon_forum_more.png differ diff --git a/app/src/main/res/drawable-xxhdpi/search_history_delete.png b/app/src/main/res/drawable-xxhdpi/search_history_delete.png new file mode 100755 index 0000000000..420fcc7e15 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/search_history_delete.png differ diff --git a/app/src/main/res/drawable-xxhdpi/search_input_delete.png b/app/src/main/res/drawable-xxhdpi/search_input_delete.png new file mode 100755 index 0000000000..b7099ef07f Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/search_input_delete.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_catalog_selected.png b/app/src/main/res/drawable-xxxhdpi/ic_catalog_selected.png new file mode 100755 index 0000000000..ab1b4a3d4e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_catalog_selected.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_down.png b/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_down.png new file mode 100755 index 0000000000..8e70509fa2 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_down.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_up.png b/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_up.png new file mode 100755 index 0000000000..39fcfcbaf4 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_filter_arrow_up.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_hint_author.png b/app/src/main/res/drawable-xxxhdpi/ic_hint_author.png index 45f14b0b8a..5f704cb0c4 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_hint_author.png and b/app/src/main/res/drawable-xxxhdpi/ic_hint_author.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend.png b/app/src/main/res/drawable-xxxhdpi/ic_recommend.png new file mode 100755 index 0000000000..9c81073cd4 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_recommend.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/search_history_delete.png b/app/src/main/res/drawable-xxxhdpi/search_history_delete.png new file mode 100755 index 0000000000..313a4ee350 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/search_history_delete.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/search_input_delete.png b/app/src/main/res/drawable-xxxhdpi/search_input_delete.png new file mode 100755 index 0000000000..94c240e505 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/search_input_delete.png differ diff --git a/app/src/main/res/drawable/actionbar_search_bg.xml b/app/src/main/res/drawable/actionbar_search_bg.xml index 22f407e085..737aab1104 100644 --- a/app/src/main/res/drawable/actionbar_search_bg.xml +++ b/app/src/main/res/drawable/actionbar_search_bg.xml @@ -1,9 +1,9 @@ - + - + - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_circle_permission_detail.xml b/app/src/main/res/drawable/bg_circle_permission_detail.xml new file mode 100644 index 0000000000..283a432384 --- /dev/null +++ b/app/src/main/res/drawable/bg_circle_permission_detail.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shape_f5_radius_5.xml b/app/src/main/res/drawable/bg_shape_f5_radius_5.xml new file mode 100644 index 0000000000..d7d69eef8e --- /dev/null +++ b/app/src/main/res/drawable/bg_shape_f5_radius_5.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_sub_catalog_item.xml b/app/src/main/res/drawable/bg_sub_catalog_item.xml new file mode 100644 index 0000000000..6710f5e133 --- /dev/null +++ b/app/src/main/res/drawable/bg_sub_catalog_item.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_tag_text.xml b/app/src/main/res/drawable/bg_tag_text.xml new file mode 100644 index 0000000000..078c47dd4e --- /dev/null +++ b/app/src/main/res/drawable/bg_tag_text.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/package_check_complete_bg.xml b/app/src/main/res/drawable/package_check_complete_bg.xml new file mode 100644 index 0000000000..47afa8527b --- /dev/null +++ b/app/src/main/res/drawable/package_check_complete_bg.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/text_blue_or_white_style.xml b/app/src/main/res/drawable/text_blue_or_white_style.xml index 645b7dfbf4..a9eb9a44f1 100644 --- a/app/src/main/res/drawable/text_blue_or_white_style.xml +++ b/app/src/main/res/drawable/text_blue_or_white_style.xml @@ -1,8 +1,8 @@ - - + + diff --git a/app/src/main/res/drawable/webview_scrollbar_thumb_vertical.xml b/app/src/main/res/drawable/webview_scrollbar_thumb_vertical.xml index 697ecc46e6..3d61648f67 100644 --- a/app/src/main/res/drawable/webview_scrollbar_thumb_vertical.xml +++ b/app/src/main/res/drawable/webview_scrollbar_thumb_vertical.xml @@ -1,7 +1,7 @@ - + - + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_header_item.xml b/app/src/main/res/layout/catalog_header_item.xml new file mode 100644 index 0000000000..d55cba8b49 --- /dev/null +++ b/app/src/main/res/layout/catalog_header_item.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_image_item.xml b/app/src/main/res/layout/catalog_image_item.xml new file mode 100644 index 0000000000..30475929ce --- /dev/null +++ b/app/src/main/res/layout/catalog_image_item.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_item.xml b/app/src/main/res/layout/catalog_item.xml new file mode 100644 index 0000000000..3940cfc7d0 --- /dev/null +++ b/app/src/main/res/layout/catalog_item.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_subject_collection_item.xml b/app/src/main/res/layout/catalog_subject_collection_item.xml new file mode 100644 index 0000000000..2cfeff5c6e --- /dev/null +++ b/app/src/main/res/layout/catalog_subject_collection_item.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/app/src/main/res/layout/catalog_subject_collection_list_item.xml b/app/src/main/res/layout/catalog_subject_collection_list_item.xml new file mode 100644 index 0000000000..5d1e42dee8 --- /dev/null +++ b/app/src/main/res/layout/catalog_subject_collection_list_item.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_subject_game_item.xml b/app/src/main/res/layout/catalog_subject_game_item.xml new file mode 100644 index 0000000000..f40e40942e --- /dev/null +++ b/app/src/main/res/layout/catalog_subject_game_item.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalog_subject_item.xml b/app/src/main/res/layout/catalog_subject_item.xml new file mode 100644 index 0000000000..009bbac5a7 --- /dev/null +++ b/app/src/main/res/layout/catalog_subject_item.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/community_answer_item.xml b/app/src/main/res/layout/community_answer_item.xml index 83cd04ae27..fe2e3e3302 100644 --- a/app/src/main/res/layout/community_answer_item.xml +++ b/app/src/main/res/layout/community_answer_item.xml @@ -21,7 +21,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" - android:paddingLeft="14dp" + android:paddingLeft="12dp" android:paddingRight="20dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" @@ -50,7 +50,7 @@ android:id="@+id/user_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="14dp" + android:layout_marginTop="12dp" app:avatar_width="32dp" app:badge_width="12dp" app:border_color="@color/transparent" @@ -71,20 +71,21 @@ android:textColor="@color/text_333333" android:textSize="14sp" app:layout_constrainedWidth="true" - app:layout_constraintBottom_toTopOf="@id/time" + app:layout_constraintBottom_toTopOf="@id/timeContainer" app:layout_constraintHorizontal_bias="0" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintLeft_toRightOf="@id/user_icon" app:layout_constraintRight_toLeftOf="@+id/user_badge_icon" app:layout_constraintTop_toTopOf="@id/user_icon" + app:layout_constraintVertical_chainStyle="packed" tools:text="我的名字很长我的名字很长我的名字很长" /> - + app:layout_constraintTop_toBottomOf="@id/user_name"> + + + + + diff --git a/app/src/main/res/layout/dialog_install_permission.xml b/app/src/main/res/layout/dialog_install_permission.xml index 5b29ec0562..4ff6b2fc2a 100644 --- a/app/src/main/res/layout/dialog_install_permission.xml +++ b/app/src/main/res/layout/dialog_install_permission.xml @@ -87,7 +87,8 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/activateTv" /> + app:layout_constraintTop_toBottomOf="@+id/activateTv" + tools:visibility="visible"/> @@ -12,16 +13,19 @@ + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="标题" /> + app:layout_constraintTop_toBottomOf="@id/title" + tools:text="内容内容内容内容内容内容"/> - + app:cardBackgroundColor="@color/white" + app:cardCornerRadius="8dp" + app:cardElevation="0dp"> - + android:layout_height="wrap_content"> - + - + - + - - - + android:layout_marginLeft="16dp" + android:layout_marginTop="28dp" + android:layout_marginRight="16dp" + android:includeFontPadding="false" + android:lineSpacingExtra="8dp" + android:textColor="@color/text_333333" + android:textSize="13sp" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@id/title" + app:layout_goneMarginTop="16dp" + tools:text="为提供完整的" /> - + - + android:orientation="vertical"> - - + - + - + + - + - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_privacy_protocol.xml b/app/src/main/res/layout/dialog_privacy_protocol.xml index 36aa49c4fe..b6477993b1 100644 --- a/app/src/main/res/layout/dialog_privacy_protocol.xml +++ b/app/src/main/res/layout/dialog_privacy_protocol.xml @@ -12,81 +12,74 @@ android:layout_height="wrap_content" android:gravity="center"> - - - - - - - + app:layout_constraintTop_toTopOf="parent" /> + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:layout_marginBottom="16dp" + app:layout_constraintBottom_toTopOf="@id/descTv" + app:layout_constraintTop_toBottomOf="@id/privacyTitleTv"> - - - - + android:includeFontPadding="false" + android:lineSpacingExtra="8dp" + android:paddingRight="6dp" + android:scrollbarStyle="outsideOverlay" + android:scrollbarThumbVertical="@drawable/webview_scrollbar_thumb_vertical" + android:scrollbars="vertical" + android:text="@string/dialog_privacy_policy_content" + android:textColor="@color/text_333333" + android:textSize="14sp" /> + + + app:layout_constraintTop_toBottomOf="@+id/descTv" /> - + + android:id="@+id/search_history_line" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:background="@color/text_F5F5F5" /> - - + android:id="@+id/search_history_name" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:ellipsize="end" + android:gravity="center_vertical" + android:padding="16dp" + android:singleLine="true" + android:textColor="@color/bg_303030" + android:textSize="14sp" /> + diff --git a/app/src/main/res/layout/forum_search_content_list.xml b/app/src/main/res/layout/forum_search_content_list.xml new file mode 100644 index 0000000000..eec4c08023 --- /dev/null +++ b/app/src/main/res/layout/forum_search_content_list.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_catalog.xml b/app/src/main/res/layout/fragment_catalog.xml new file mode 100644 index 0000000000..ff3db77722 --- /dev/null +++ b/app/src/main/res/layout/fragment_catalog.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_catalog_list.xml b/app/src/main/res/layout/fragment_catalog_list.xml new file mode 100644 index 0000000000..3611e77cc9 --- /dev/null +++ b/app/src/main/res/layout/fragment_catalog_list.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_forum_detail.xml b/app/src/main/res/layout/fragment_forum_detail.xml index 0852ca2019..4ebcabb9b5 100644 --- a/app/src/main/res/layout/fragment_forum_detail.xml +++ b/app/src/main/res/layout/fragment_forum_detail.xml @@ -241,15 +241,25 @@ + + diff --git a/app/src/main/res/layout/fragment_forum_home.xml b/app/src/main/res/layout/fragment_forum_home.xml index 2efbfbc772..ef020231f6 100644 --- a/app/src/main/res/layout/fragment_forum_home.xml +++ b/app/src/main/res/layout/fragment_forum_home.xml @@ -1,9 +1,9 @@ + android:layout_height="match_parent"> - - - - + + + + + + + + + + + + android:layout_marginTop="20dp" + android:layout_marginRight="20dp" + android:orientation="horizontal"> + + + android:src="@drawable/ic_right_arrow" /> + + android:layout_marginTop="12dp" /> + android:paddingRight="10dp"> + + android:layout_marginLeft="4dp" + android:src="@drawable/forum_more_guide_rectangle" /> + + android:src="@drawable/forum_more_guide" /> diff --git a/app/src/main/res/layout/fragment_game.xml b/app/src/main/res/layout/fragment_game.xml index 2828e52d54..6b2477092c 100644 --- a/app/src/main/res/layout/fragment_game.xml +++ b/app/src/main/res/layout/fragment_game.xml @@ -35,7 +35,7 @@ + visibleGone="@{loadStatus == LoadStatus.INIT_FAILED? true: false}" /> + android:layout_centerInParent="true" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_search_default.xml b/app/src/main/res/layout/fragment_search_default.xml index 5f97472ea5..f79380e696 100644 --- a/app/src/main/res/layout/fragment_search_default.xml +++ b/app/src/main/res/layout/fragment_search_default.xml @@ -25,16 +25,12 @@ visibleGone="@{isExistHistory}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:background="@android:color/white" android:includeFontPadding="false" - android:paddingLeft="20dp" - android:paddingTop="16dp" - android:paddingRight="20dp" - android:paddingBottom="16dp" + android:padding="16dp" android:text="@string/search_history" - android:textColor="@color/black" - android:textSize="15sp" + android:textColor="@color/text_0E0E0E" + android:textSize="14sp" android:textStyle="bold" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -44,11 +40,12 @@ visibleGone="@{isExistHistory}" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginRight="20dp" + android:layout_marginRight="16dp" android:drawableLeft="@drawable/search_history_delete" - android:drawablePadding="8dp" - android:text="@string/search_history_clean" + android:drawablePadding="4dp" + android:textColor="@color/text_999999" android:textSize="12sp" + android:text="@string/search_history_clean" app:layout_constraintBottom_toBottomOf="@id/history_title" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="@id/history_title" /> @@ -65,8 +62,7 @@ visibleGone="@{isExistHistory}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="20dp" - android:paddingBottom="5dp" + android:paddingLeft="16dp" app:flexWrap="wrap" /> @@ -75,16 +71,12 @@ visibleGone="@{isExistHotTag}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:background="@android:color/white" android:includeFontPadding="false" - android:paddingLeft="20dp" - android:paddingTop="16dp" - android:paddingRight="20dp" - android:paddingBottom="16dp" + android:padding="16dp" android:text="@string/search_hot_tag" - android:textColor="@color/black" - android:textSize="15sp" + android:textColor="@color/text_0E0E0E" + android:textSize="14sp" android:textStyle="bold" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/history_flex_container" /> @@ -101,8 +93,7 @@ visibleGone="@{isExistHotTag}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="20dp" - android:paddingBottom="7dp" + android:paddingLeft="16dp" app:flexWrap="wrap" /> @@ -111,16 +102,12 @@ visibleGone="@{isExistHotSearch}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:background="@android:color/white" android:includeFontPadding="false" - android:paddingLeft="20dp" - android:paddingTop="16dp" - android:paddingRight="20dp" - android:paddingBottom="11dp" + android:padding="16dp" android:text="@string/search_hot" - android:textColor="@color/black" - android:textSize="15sp" + android:textColor="@color/text_0E0E0E" + android:textSize="14sp" android:textStyle="bold" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/hot_tag_flex_container" /> diff --git a/app/src/main/res/layout/fragment_search_result.xml b/app/src/main/res/layout/fragment_search_result.xml index 5f6b088406..47c0945424 100644 --- a/app/src/main/res/layout/fragment_search_result.xml +++ b/app/src/main/res/layout/fragment_search_result.xml @@ -46,21 +46,23 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" - android:gravity="center" + android:gravity="center_horizontal" android:orientation="vertical" + android:background="@color/white" android:visibility="gone" tools:visibility="visible"> + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_tags.xml b/app/src/main/res/layout/fragment_tags.xml index fec4630e35..b518d6c427 100644 --- a/app/src/main/res/layout/fragment_tags.xml +++ b/app/src/main/res/layout/fragment_tags.xml @@ -8,11 +8,10 @@ android:id="@+id/tags_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:background="@color/all_white" android:clipToPadding="false" android:paddingLeft="20dp" - android:paddingTop="16dp" + android:paddingTop="8dp" android:paddingRight="12dp" android:paddingBottom="8dp" /> @@ -32,11 +31,18 @@ android:layout_height="wrap_content" android:visibility="gone" /> + + + android:layout_below="@id/divider"> diff --git a/app/src/main/res/layout/game_horizontal_item.xml b/app/src/main/res/layout/game_horizontal_item.xml index 6b4adef663..0c869f2654 100644 --- a/app/src/main/res/layout/game_horizontal_item.xml +++ b/app/src/main/res/layout/game_horizontal_item.xml @@ -45,10 +45,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" - android:drawableLeft="@drawable/game_horizontal_rating" + android:drawableLeft="@{game.commentCount > 3?@drawable/game_horizontal_rating: null}" android:drawablePadding="4dp" android:includeFontPadding="false" - android:text="@{game.commentCount > 3?game.star +``: `评分过少`}" + android:text="@{game.commentCount > 3?(game.star == 10.0? `10` : game.star + ``): ``}" android:textColor="@color/theme" android:textSize="12sp" android:textStyle="bold" diff --git a/app/src/main/res/layout/game_item.xml b/app/src/main/res/layout/game_item.xml index de87516be1..098f6eea86 100644 --- a/app/src/main/res/layout/game_item.xml +++ b/app/src/main/res/layout/game_item.xml @@ -8,6 +8,8 @@ + + @@ -148,11 +150,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" - android:drawableLeft="@drawable/game_horizontal_rating" + android:drawableLeft="@{game.commentCount > 3?@drawable/game_horizontal_rating: null}" android:drawablePadding="4dp" android:includeFontPadding="false" - android:paddingRight="8dp" - android:text="@{game.commentCount > 3?game.star + ``: `评分过少`}" + android:paddingRight="@{game.commentCount > 3?DisplayUtils.dip2px(8F): 0}" + android:text="@{game.commentCount > 3?(game.star == 10.0? `10` : game.star + ``): ``}" android:textColor="@{Color.parseColor(game.commentCount > 3?`#1383EB`:`#2496FF`)}" android:textStyle="bold" android:visibility="gone" /> diff --git a/app/src/main/res/layout/game_permission_dialog.xml b/app/src/main/res/layout/game_permission_dialog.xml new file mode 100644 index 0000000000..a3840eb481 --- /dev/null +++ b/app/src/main/res/layout/game_permission_dialog.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/game_permission_item.xml b/app/src/main/res/layout/game_permission_item.xml new file mode 100644 index 0000000000..6f657d4cd4 --- /dev/null +++ b/app/src/main/res/layout/game_permission_item.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_article_detail_comment.xml b/app/src/main/res/layout/item_article_detail_comment.xml index 8168da78b3..1a24c64aef 100644 --- a/app/src/main/res/layout/item_article_detail_comment.xml +++ b/app/src/main/res/layout/item_article_detail_comment.xml @@ -15,16 +15,16 @@ + android:background="@color/white"> @@ -64,17 +64,14 @@ + + @@ -213,11 +222,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="6dp" - android:drawableRight="@drawable/ic_right_arrow_blue" + android:drawableRight="@drawable/ic_right_arrow_darker" android:drawablePadding="4dp" android:includeFontPadding="false" android:text="查看更多回复" - android:textColor="@color/theme_font" + android:textColor="@color/text_999999" android:textSize="12sp" /> diff --git a/app/src/main/res/layout/item_filter_size.xml b/app/src/main/res/layout/item_filter_size.xml index a65ea1370e..3cccf55aaa 100644 --- a/app/src/main/res/layout/item_filter_size.xml +++ b/app/src/main/res/layout/item_filter_size.xml @@ -1,7 +1,7 @@ @@ -10,7 +10,7 @@ android:layout_width="wrap_content" android:layout_height="24dp" android:layout_centerInParent="true" - android:background="@drawable/textview_blue_style" + android:background="@drawable/bg_tag_text" android:gravity="center" android:lines="1" android:paddingLeft="8dp" @@ -19,4 +19,14 @@ android:textColor="@color/all_white" android:textSize="12sp" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_forum_follow.xml b/app/src/main/res/layout/item_forum_follow.xml index 2e3cdfa957..fc051be0d1 100644 --- a/app/src/main/res/layout/item_forum_follow.xml +++ b/app/src/main/res/layout/item_forum_follow.xml @@ -15,10 +15,22 @@ android:id="@+id/forumIcon" android:layout_width="48dp" android:layout_height="48dp" + android:layout_marginTop="4dp" + android:layout_marginRight="4dp" + app:gameIconOverlayColor="@color/white" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_config_filter.xml b/app/src/main/res/layout/layout_config_filter.xml index ab6525f8e5..3bf1108a30 100644 --- a/app/src/main/res/layout/layout_config_filter.xml +++ b/app/src/main/res/layout/layout_config_filter.xml @@ -4,18 +4,17 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/config_controller" android:layout_width="match_parent" - android:layout_height="48dp" + android:layout_height="40dp" android:background="@color/all_white" android:paddingLeft="16dp" - android:paddingRight="16dp" - android:paddingBottom="8dp"> + android:paddingRight="16dp"> diff --git a/app/src/main/res/layout/layout_video_detail_base.xml b/app/src/main/res/layout/layout_video_detail_base.xml index c73db07c41..496f0d9420 100644 --- a/app/src/main/res/layout/layout_video_detail_base.xml +++ b/app/src/main/res/layout/layout_video_detail_base.xml @@ -97,8 +97,6 @@ android:layout_width="match_parent" android:layout_height="48dp" android:layout_alignParentTop="true" - android:layout_toEndOf="@+id/back_tiny" - android:layout_toRightOf="@+id/back_tiny" android:gravity="center_vertical"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/personal_home_item.xml b/app/src/main/res/layout/personal_home_item.xml index fda82f16d2..abbba2e73f 100644 --- a/app/src/main/res/layout/personal_home_item.xml +++ b/app/src/main/res/layout/personal_home_item.xml @@ -51,7 +51,6 @@ app:layout_constraintHorizontal_bias="0" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintLeft_toRightOf="@id/user_icon" - app:layout_constraintRight_toLeftOf="@+id/sdv_user_badge" app:layout_constraintTop_toTopOf="@id/user_icon" tools:text="我的昵称很长很长有十二字" /> diff --git a/app/src/main/res/layout/piece_community_vote_and_comment.xml b/app/src/main/res/layout/piece_community_vote_and_comment.xml index 275545fc92..cad102fa39 100644 --- a/app/src/main/res/layout/piece_community_vote_and_comment.xml +++ b/app/src/main/res/layout/piece_community_vote_and_comment.xml @@ -1,76 +1,79 @@ - + - + - + + + + + + + app:layout_constraintBottom_toBottomOf="@id/comment_count_container" + app:layout_constraintLeft_toRightOf="@id/comment_count_container" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="@id/comment_count_container"> - + - + - + - + + + android:paddingTop="20dp" + android:paddingBottom="20dp" + android:textColor="@color/text_999999" + android:textSize="12sp" + tools:text="11" /> - - - - - - - - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/layout/privacy_item.xml b/app/src/main/res/layout/privacy_item.xml index 08f055e880..da6927ce19 100644 --- a/app/src/main/res/layout/privacy_item.xml +++ b/app/src/main/res/layout/privacy_item.xml @@ -50,6 +50,7 @@ android:text="@{data.intro}" android:textColor="@color/text_333333" android:textSize="13sp" + android:lineSpacingExtra="6dp" app:layout_constraintLeft_toRightOf="@id/icon" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/name" /> diff --git a/app/src/main/res/layout/questionsdedit_tag_item.xml b/app/src/main/res/layout/questionsdedit_tag_item.xml index 83d88b17b4..3a4dc90c97 100644 --- a/app/src/main/res/layout/questionsdedit_tag_item.xml +++ b/app/src/main/res/layout/questionsdedit_tag_item.xml @@ -1,12 +1,10 @@ \ No newline at end of file diff --git a/app/src/main/res/layout/reuse_loading.xml b/app/src/main/res/layout/reuse_loading.xml index f75775d4c3..572d37cf12 100644 --- a/app/src/main/res/layout/reuse_loading.xml +++ b/app/src/main/res/layout/reuse_loading.xml @@ -1,16 +1,19 @@ - + - + - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/reuse_no_connection.xml b/app/src/main/res/layout/reuse_no_connection.xml index 9e8d2d645a..2b35613b7f 100644 --- a/app/src/main/res/layout/reuse_no_connection.xml +++ b/app/src/main/res/layout/reuse_no_connection.xml @@ -1,34 +1,37 @@ - + - + - + - + - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/reuse_nodata_skip.xml b/app/src/main/res/layout/reuse_nodata_skip.xml index b0543b9fba..50384cb928 100644 --- a/app/src/main/res/layout/reuse_nodata_skip.xml +++ b/app/src/main/res/layout/reuse_nodata_skip.xml @@ -1,29 +1,32 @@ - + - + - + - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/reuse_none_data.xml b/app/src/main/res/layout/reuse_none_data.xml index bedd9ed7c8..6331646c2e 100644 --- a/app/src/main/res/layout/reuse_none_data.xml +++ b/app/src/main/res/layout/reuse_none_data.xml @@ -1,27 +1,30 @@ - + - + - + - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/reuse_toolbar.xml b/app/src/main/res/layout/reuse_toolbar.xml index 87d3f70b32..4a8d8d064a 100644 --- a/app/src/main/res/layout/reuse_toolbar.xml +++ b/app/src/main/res/layout/reuse_toolbar.xml @@ -1,26 +1,29 @@ - + - + android:layout_height="@dimen/appbar_height"> - + - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/search_default_hot_item.xml b/app/src/main/res/layout/search_default_hot_item.xml index 87a4f7cc79..44db71c1ba 100644 --- a/app/src/main/res/layout/search_default_hot_item.xml +++ b/app/src/main/res/layout/search_default_hot_item.xml @@ -14,34 +14,36 @@ + android:paddingLeft="16dp" + android:paddingBottom="16dp"> - + + android:id="@+id/hint_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:text="@string/search_bottom_hint" + android:textColor="@color/c7c7c7" + android:textSize="15sp" /> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="15dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:gravity="center"> + android:id="@+id/skip_game" + android:layout_width="0dp" + android:layout_height="40dp" + android:layout_weight="1" + android:layout_marginRight="16dp" + android:background="@drawable/bg_tag_text" + android:gravity="center" + android:text="求游戏" + android:textColor="@android:color/white" + android:textSize="14sp" /> - + android:id="@+id/skip_function" + android:layout_width="0dp" + android:layout_height="40dp" + android:layout_weight="1" + android:background="@drawable/bg_tag_text" + android:gravity="center" + android:text="求功能" + android:textColor="@android:color/white" + android:textSize="14sp" /> diff --git a/app/src/main/res/layout/search_game_index_item.xml b/app/src/main/res/layout/search_game_index_item.xml new file mode 100644 index 0000000000..4339677327 --- /dev/null +++ b/app/src/main/res/layout/search_game_index_item.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/sub_catalog_item.xml b/app/src/main/res/layout/sub_catalog_item.xml new file mode 100644 index 0000000000..78bd425f1b --- /dev/null +++ b/app/src/main/res/layout/sub_catalog_item.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/toolbar_search.xml b/app/src/main/res/layout/toolbar_search.xml index 05a49a9d6d..e49ae0b538 100644 --- a/app/src/main/res/layout/toolbar_search.xml +++ b/app/src/main/res/layout/toolbar_search.xml @@ -2,14 +2,14 @@ + android:layout_width="44dp" + android:layout_height="match_parent"> + + \ No newline at end of file diff --git a/app/src/main/res/layout/user_search_list_item.xml b/app/src/main/res/layout/user_search_list_item.xml new file mode 100644 index 0000000000..9636b5c4de --- /dev/null +++ b/app/src/main/res/layout/user_search_list_item.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/raw/keep.xml b/app/src/main/res/raw/keep.xml deleted file mode 100644 index 73ce6fd2af..0000000000 --- a/app/src/main/res/raw/keep.xml +++ /dev/null @@ -1,3 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index c299214efb..349bede2a4 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -109,6 +109,7 @@ + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 9e731edf75..c679433078 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -211,6 +211,11 @@ #FFA142 #06CCF4 #F8A142 + #f9f9f9 + #FF4147 + #a9a9a9 + #757575 + #0E0E0E #99666666 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 759dabcd36..cdd7bd3aee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -341,6 +341,7 @@ 关注 关注成功 取消关注 + 已取消关注 关注失败 取消关注失败 @@ -553,7 +554,7 @@ 我的问答 我的草稿 我的积分 - 我的问答 + 我的论坛 已关注 回答为什么折叠? 继续撰写 @@ -780,6 +781,7 @@ 将已安装游戏标记为玩过的游戏 https://v.douyin.com/C9UHr6/ 你有%1$d]]>款预约的游戏上线啦 + 欢迎您使用光环助手!\n在您使用光环助手之前,请您认真阅读《用户协议》和《隐私政策》的全部内容,以了解用户权利义务和个人信息处理规则。主要内容向您说明如下:\n1.为了正常地提供优质的产品服务,基于您的授权我们会获取必要的个人信息,您有权拒绝或取消授权\n2.我们会采取合理的安全措施保护您的个人信息,防止数据被不当使用或未经授权的情况下被访问、公开披露、使用、修改、损坏、丢失或泄漏。\n3.未经您同意,我们不会从第三方处获取、共享或向其提供您的信息\n4.您可以查询、更正、删除您的个人信息,我们也提供账户注销的渠道 此游戏下载资源由第三方提供。若该资源侵犯了您的合法权益或违反了当地法规,请点击页面右上角-版权申诉,按指引发起申诉,我们会尽快联系您并解决。 该游戏暂时仅提供试玩版本。试玩版资源来自第三方网站,可能存在bug或兼容性问题。敬请留意后续相关消息。 该游戏暂时仅提供试玩版本。试玩版可能存在bug或兼容性问题。敬请留意后续相关消息。 diff --git a/app/src/tea/java/com/gh/gamecenter/TeaHelper.kt b/app/src/tea/java/com/gh/gamecenter/TeaHelper.kt new file mode 100644 index 0000000000..35df3388f2 --- /dev/null +++ b/app/src/tea/java/com/gh/gamecenter/TeaHelper.kt @@ -0,0 +1,35 @@ +package com.gh.gamecenter + +import android.content.Context +import android.util.Log +import com.bytedance.applog.AppLog +import com.bytedance.applog.GameReportHelper +import com.bytedance.applog.InitConfig +import com.bytedance.applog.util.UriConfig +import com.gh.common.exposure.meta.MetaUtil +import com.gh.common.util.ToastUtils +import com.halo.assistant.HaloApp +import com.lightgame.utils.Utils + +object TeaHelper { + @JvmStatic + fun init(context: Context, channel: String) { + val config = InitConfig("163824", channel) + config.setUriConfig(UriConfig.DEFAULT) + config.appName = "guanghuan1" + config.setEnablePlay(true) + AppLog.setEnableLog(false) + AppLog.init(context, config) + + AppLog.setOaidObserver { + HaloApp.getInstance().oaid = it.id + Utils.log("oaid is $it.id") + MetaUtil.refreshMeta() + } + + // gameReportHelper ?! + GameReportHelper.onEventRegister("wechat", true) + GameReportHelper.onEventPurchase("gift", "flower", "008", 1, "wechat", "¥", true, 1) + Utils.log("init TeaHelper") + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 584565b4fd..732c953513 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ apply from: 'dependencies.gradle' buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.3.72' repositories { google() @@ -16,7 +16,7 @@ buildscript { } dependencies { - classpath "com.android.tools.build:gradle:3.4.1" + classpath "com.android.tools.build:gradle:4.1.0" // for tinker // classpath 'com.tencent.tinker:tinker-patch-gradle-plugin:1.8.1' diff --git a/dependencies.gradle b/dependencies.gradle index c0262a31e4..c42493a39d 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,8 +7,8 @@ ext { targetSdkVersion = 26 // application info (每个大版本之间的 versionCode 增加 20) - versionCode = 230 - versionName = "4.4.0" + versionCode = 250 + versionName = "4.5.0" applicationId = "com.gh.gamecenter" // AndroidX @@ -106,4 +106,6 @@ ext { chart = "3.1.0" zip4j = "2.6.1" whatTheStack = "0.1.0_rt" + + sentry = "2.3.2" // 不要更新到 3.X,3.X 需要后台版本支持 } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 1ce0bf5e6c..b64e109a90 100644 --- a/gradle.properties +++ b/gradle.properties @@ -46,10 +46,10 @@ DOUYIN_CLIENTKEY=aw66h51ftb71dkhi DOUYIN_CLIENTSECRET=155dee6c1de9ae31bffcbf32475dc161 # hosts -DEV_API_HOST=https\://dev.api.ghzs.com/v4d4d0/ +DEV_API_HOST=https\://dev.api.ghzs.com/v4d5d0/ -API_HOST=https\://and-api.ghzs.com/v4d4d0/ -SENSITIVE_API_HOST=https\://and-core-api.ghzs.com/v4d4d0/ +API_HOST=https\://and-api.ghzs.com/v4d5d0/ +SENSITIVE_API_HOST=https\://and-core-api.ghzs.com/v4d5d0/ # 请不要手动改动下面的值,除非你明确需要以某个apk作为基准包,需要打包请以scripts/tinker*.sh为准 TINKER_ENABLE= diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 442d8ae9fa..45d9f6e8ae 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip diff --git a/libraries/LGLibrary b/libraries/LGLibrary index 89a66d91c3..c16fa1f534 160000 --- a/libraries/LGLibrary +++ b/libraries/LGLibrary @@ -1 +1 @@ -Subproject commit 89a66d91c3092e6b09373339ad7f50523c1b5ef1 +Subproject commit c16fa1f5345fd58d53fbebc18a23884a16d0c65e diff --git a/libraries/MTA/libs/mid-core-sdk-4.3.0.jar b/libraries/MTA/libs/mid-core-sdk-4.3.0.jar new file mode 100644 index 0000000000..498eb975b5 Binary files /dev/null and b/libraries/MTA/libs/mid-core-sdk-4.3.0.jar differ diff --git a/libraries/MTA/libs/mid-sdk-4.06.jar b/libraries/MTA/libs/mid-sdk-4.06.jar deleted file mode 100644 index 9db98e295b..0000000000 Binary files a/libraries/MTA/libs/mid-sdk-4.06.jar and /dev/null differ diff --git a/libraries/MTA/libs/mta-android-sdk-3.4.7.jar b/libraries/MTA/libs/mta-android-sdk-3.4.7.jar deleted file mode 100644 index 6f7b1dced8..0000000000 Binary files a/libraries/MTA/libs/mta-android-sdk-3.4.7.jar and /dev/null differ diff --git a/libraries/MTA/libs/mta-android-sdk-3.7.1.jar b/libraries/MTA/libs/mta-android-sdk-3.7.1.jar new file mode 100644 index 0000000000..d632b7ecc1 Binary files /dev/null and b/libraries/MTA/libs/mta-android-sdk-3.7.1.jar differ diff --git a/settings.gradle b/settings.gradle index 1b339eb9e9..25b9bf0710 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,7 @@ include ':app' //include ':libraries:im' include ':libraries:LGLibrary' -//include ':libraries:MTA' +include ':libraries:MTA' include ':libraries:QQShare' //include ':libraries:TalkingData' //include ':libraries:UmengPush'