Compare commits
25 Commits
v4.9.1-331
...
v4.9.6-336
| Author | SHA1 | Date | |
|---|---|---|---|
| 557f22b23b | |||
| f40a192e82 | |||
| 84f3556275 | |||
| a0b8caa60a | |||
| 28fb45f0b8 | |||
| ea5627b3da | |||
| 039203408a | |||
| 60b325812e | |||
| 06a43f617b | |||
| 85d3412fd8 | |||
| 71b8cbbef3 | |||
| dfc0183a14 | |||
| 156e52f619 | |||
| 252cb3825b | |||
| 075a7e4e77 | |||
| 0c95f911d1 | |||
| f35baf0e5b | |||
| 49b74c9a37 | |||
| c4240440d1 | |||
| e0205ec060 | |||
| 895024aa09 | |||
| 2140c9eb40 | |||
| a0331f0437 | |||
| 63798c94cf | |||
| 6c2ff6a94f |
93
README.md
93
README.md
@ -1,69 +1,68 @@
|
||||
# 光环助手Android客户端
|
||||
|
||||
### APK打包配置
|
||||
### 概述
|
||||
|
||||
* 使用[ApkChannelPackage](https://github.com/ltlovezh/ApkChannelPackage)的方案
|
||||
* 打包命令,视情况使用:
|
||||
光环助手Android客户端目前使用 Kotlin 作为主要开发语言,以 MVVM 作为参考架构模式进行开发
|
||||
|
||||
> 打包Tinker基准包:`./scripts/tinker_release_base.sh`
|
||||
### 约束
|
||||
|
||||
> 以Tinker基准包打渠道包:`./scripts/tinker_release_channel.sh`
|
||||
为编写易读易维护且较健壮的代码,可参考以下约束
|
||||
|
||||
> 以Tinker基准包打补丁包:`./scripts/tinker_release_patch.sh`
|
||||
1. 尽量将逻辑代码放置于 ViewModel 中,View 中只执行 UI 操作
|
||||
2. 尽量使 View 在被销毁之后仍能恢复状态,处理方式可参考 [保存界面状态](https://developer.android.com/topic/libraries/architecture/saving-states)
|
||||
3. 尽量参考原有文件结构及命名规范,即以 大模块 - 小模块 的形式生成包关系
|
||||
4. 遵循最小改动原则,在提交代码前务必先检查变动的代码,尽量以可控的变动规模来构成一个 commit ,以便日后追踪问题
|
||||
5. 代码规范可参考 [AOSP Java 风格](https://source.android.com/setup/contribute/code-style)
|
||||
6. 尽量使用 Kotlin 来写新文件
|
||||
7. RecyclerView 的 ViewHolder 尽量使用 DataBinding 来减少代码以及提高可读性
|
||||
8. Commit 前请确保不带入非项目必须文件,可手动修改 [.gitignore](https://stackoverflow.com/questions/8527597/how-do-i-ignore-files-in-a-directory-in-git) 文件忽略
|
||||
9. 新页面请勿使用 ButterKnife 来进行 View 获取和绑定,请使用 ViewBinding
|
||||
10. No AsyncTask!
|
||||
|
||||
### 混淆配置
|
||||
### 公用部分
|
||||
|
||||
* 配置文件:Android默认配置+proguard-rules.txt等
|
||||
* 参考libraries下每个项目独立的配置文件`proguard-project.txt`
|
||||
本项目使用 LiveData 实现了一个简单通用的基础列表分页功能,具体可见 `ListFragment`, `ListViewModel` 等类,理想情况下只需少量代码即可新建一个简单分页列表
|
||||
|
||||
### apk大小优化
|
||||
### 首次拉取项目代码
|
||||
|
||||
* 限制resConfig资源集
|
||||
* 开启ShrinkResources
|
||||
* 开启混淆,使用minifyEnabled(仅在release开启)
|
||||
* pngquant对png压缩、png/jpg->webp(未尝试)
|
||||
`git clone -b dev git@git.ghzs.com:halo/android/assistant-android.git --recursive`
|
||||
|
||||
### git 版本管理
|
||||
|
||||
本项目使用简化版的 git flow 来管理分支,细节请看 [光环安卓简单 git 规范](https://git.ghzs.com/halo/android/assistant-android/-/wikis/%E5%85%89%E7%8E%AF%E5%AE%89%E5%8D%93%E7%AE%80%E5%8D%95-git-%E8%A7%84%E8%8C%83)
|
||||
|
||||
### API 环境配置
|
||||
|
||||
本项目使用 Build Variants 来切换 API 环境
|
||||
|
||||
* internal 为测试环境
|
||||
* publish 为正式环境
|
||||
|
||||
### 图片资源配置
|
||||
|
||||
* 新增图片资源时,默认只添加最高规格的 xxxhdpi 文件
|
||||
* 新增图片资源时,需要将其转换为 .webp 格式 (包括含透明图层的图片,默认质量为90%) (转换后体积变大的文件除外)
|
||||
|
||||
### 第三方appkey等配置
|
||||
|
||||
* 修改`gradle.properties`文件将各种key填入其中,实现统一管理
|
||||
* 通过gradle文件内的resValue/buildConfigField/manifestPlaceHolder方式实现编译期间修改,具体情况请参考``./build.gradle``和``./app/build.gradle``配置
|
||||
|
||||
### 拉取代码步骤
|
||||
### 混淆配置
|
||||
|
||||
1. 拉取主项目代码: `git clone -b dev git@gitlab.ghzhushou.com:halo/assistant-android.git`
|
||||
2. 初始化公用类库: `bash ./scripts/submodules_init.sh`
|
||||
* 本项目使用了微信的 [AndResGuard](https://github.com/shwenzhang/AndResGuard) 作为资源混淆压缩方案,新增需要使用 `getIdentifier` 获取的资源文件时需要添加至白名单
|
||||
* 本项目默认使用 R8 作为混淆工具,往 proguard-rules.txt 添加 proguard 新配置项时请检查可用性(如语法等)
|
||||
|
||||
### submodule管理方式(只拉取master)
|
||||
### APK打包配置
|
||||
|
||||
* 提交代码,需要cd到submodule文件夹去做修改
|
||||
* 更新远端代码,`bash ./scripts/submodules_update.sh`
|
||||
* 本项目使用了 [VasDolly](https://github.com/Tencent/VasDolly) 作为渠道包实现方案
|
||||
* 打包命令,具体参数请见相应文件:
|
||||
|
||||
> 打内部测试包:`./scripts/test_build.sh`
|
||||
> 打正式发布包:`./scripts/build_with_simple_backup.sh`
|
||||
|
||||
### TODO
|
||||
|
||||
* GSON 序列化用统一的一个, GsonUtil fromJson
|
||||
* CleanApkAdapter 转化字符串size工具函数 比如SpeedUtils
|
||||
* getString 解决 字符串hardcode问题
|
||||
* ~~Adapter 里面clicklistener 用接口传参将点击操作委托给controller~~
|
||||
* ~~Adapter ViewHolder的功能,部分重写到ViewHolder类本身~~
|
||||
|
||||
* ~~activity 统一入口未完成(外部入口相关),去除多余activity使用,统一toolbar~~
|
||||
* ~~release / debug compile不同的类库,不需要再做什么开关~~
|
||||
|
||||
* ~~Toolbar分离,有图形按钮/没有图形按钮~~
|
||||
|
||||
### TODO Since 3.1
|
||||
|
||||
- 解决 Utils 工具类引发的内存泄漏问题
|
||||
- 把原有 EventBus 的消息 Type 统一到一个文件内
|
||||
- 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
|
||||
- ~~将 ListViewModel 所对应的 ListRepository 合并到 ListViewModel 中~~
|
||||
- 依照光环助手界面功能以大模块 - 小模块的方式去修改包结构,包内文件建议以包名摘要作为前缀
|
||||
- ~~使用 RxJava 的 Debounce 和 Map 操作优化搜索触发机制 参考资料:[1](https://proandroiddev.com/building-an-autocompleting-edittext-using-rxjava-f69c5c3f5a40),[2](https://medium.com/@kurtisnusbaum/rxandroid-basics-part-2-6e877af352)~~
|
||||
|
||||
- ~~把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题~~
|
||||
|
||||
- ~~rxjava2 如果接口返回为空 会发生异常:java.lang.NullPointerException: Null is not a valid element (答案编辑) 解决方法->com.gh.gamecenter.retrofit.Response~~
|
||||
- constraintLayout 1.1.2 导致布局出现异常(问题编辑标签选择弹窗)
|
||||
|
||||
- 搞清楚 GameManager 的用途,看能不能去掉
|
||||
- 重构一下 MainActivity
|
||||
* 把原有 EventBus 的消息 Type 统一到一个文件内
|
||||
* 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
|
||||
* 重构 MainActivity
|
||||
@ -461,6 +461,11 @@ andResGuard {
|
||||
"R.drawable.ic_search_no_18",
|
||||
"R.drawable.ic_search_no_19",
|
||||
"R.drawable.ic_search_no_20",
|
||||
"R.drawable.ic_recommend_activity",
|
||||
"R.drawable.ic_recommend_discount",
|
||||
"R.drawable.ic_recommend_function",
|
||||
"R.drawable.ic_recommend_gift",
|
||||
"R.drawable.ic_recommend_role",
|
||||
"R.drawable.login_btn_bg",
|
||||
"R.drawable.ic_quick_login_check",
|
||||
"R.drawable.ic_quick_login_uncheck",
|
||||
|
||||
@ -158,9 +158,11 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
}
|
||||
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, "");
|
||||
if (downloadEntity != null) {
|
||||
PackageInstaller.install(this, downloadEntity, false);
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -62,6 +62,7 @@ public class Config {
|
||||
public static final String PATCHES = "patches";
|
||||
|
||||
public static final String DEFAULT_CHANNEL = "GH_TEST2";
|
||||
public static final String DEFAULT_CHANNEL_FOR_RELEASE = "GH_206"; // 正式包的缺省渠道,避免因渠道丢失而回落到测试渠道
|
||||
|
||||
private static String SETTINGS_KEY = "settingsKey";
|
||||
|
||||
@ -301,7 +302,7 @@ public class Config {
|
||||
});
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
|
||||
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel)
|
||||
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BiResponse<NewSettingsEntity>() {
|
||||
|
||||
@ -42,6 +42,7 @@ import org.greenrobot.eventbus.ThreadMode
|
||||
/**
|
||||
* 包名检测弹窗
|
||||
*/
|
||||
// TODO 将 gameEntity 放到 argument 里再取出,避免重建时为空
|
||||
class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private lateinit var binding: FragmentPackageCheckBinding
|
||||
@ -73,7 +74,9 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
EventBus.getDefault().register(this)
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "出现弹窗", gameEntity, "", "", "", "")
|
||||
gameEntity?.let {
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "出现弹窗", it, "", "", "", "")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
|
||||
32
app/src/main/java/com/gh/common/json/JsonBuilder.kt
Normal file
32
app/src/main/java/com/gh/common/json/JsonBuilder.kt
Normal file
@ -0,0 +1,32 @@
|
||||
package com.gh.common.json
|
||||
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
|
||||
//Source: https://stackoverflow.com/questions/41861449/kotlin-dsl-for-creating-json-objects-without-creating-garbage
|
||||
|
||||
fun json(build: JsonObjectBuilder.() -> Unit): JSONObject {
|
||||
return JsonObjectBuilder().json(build)
|
||||
}
|
||||
|
||||
class JsonObjectBuilder {
|
||||
private val deque: Deque<JSONObject> = ArrayDeque()
|
||||
|
||||
fun json(build: JsonObjectBuilder.() -> Unit): JSONObject {
|
||||
deque.push(JSONObject())
|
||||
this.build()
|
||||
return deque.pop()
|
||||
}
|
||||
|
||||
infix fun <T> String.to(value: T) {
|
||||
// wrap value into json block if it is a lambda
|
||||
val wrapped = when (value) {
|
||||
is Function0<*> -> json { value.invoke() }
|
||||
is Array<*> -> JSONArray().apply { value.forEach { put(it) } }
|
||||
else -> value
|
||||
}
|
||||
|
||||
deque.peek().put(this, wrapped)
|
||||
}
|
||||
}
|
||||
@ -138,7 +138,7 @@ public class DownloadItemUtils {
|
||||
holder.gameDownloadBtn.setText("已预约");
|
||||
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(holder.gameDes.getContext(), R.color.aaaaaa));
|
||||
holder.gameDownloadBtn.setBackgroundResource(R.drawable.button_round_f5f5f5);
|
||||
updateItemViewStatus(holder, false, null);
|
||||
updateItemViewStatus(holder, false, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ public class DownloadItemUtils {
|
||||
|
||||
// 显示预约
|
||||
if (gameEntity.isReservable()) {
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
updateItemViewStatus(holder, false, briefStyle, gameEntity.getColumnRecommend());
|
||||
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
|
||||
holder.gameDownloadBtn.setText("预约");
|
||||
holder.gameDownloadBtn.setTextColor(Color.WHITE);
|
||||
@ -189,7 +189,7 @@ public class DownloadItemUtils {
|
||||
LinkEntity h5LinkEntity = gameEntity.getH5Link();
|
||||
String offStatus = gameEntity.getDownloadOffStatus();
|
||||
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
updateItemViewStatus(holder, false, briefStyle, gameEntity.getColumnRecommend());
|
||||
|
||||
if (h5LinkEntity != null) {
|
||||
if ("play".equals(h5LinkEntity.getType())) {
|
||||
@ -252,7 +252,7 @@ public class DownloadItemUtils {
|
||||
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn, pluginLocation);
|
||||
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
updateItemViewStatus(holder, false, briefStyle, gameEntity.getColumnRecommend());
|
||||
}
|
||||
|
||||
// 更新插件的条目,有多个apk包
|
||||
@ -276,14 +276,14 @@ public class DownloadItemUtils {
|
||||
return;
|
||||
}
|
||||
}
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
updateItemViewStatus(holder, false, briefStyle, gameEntity.getColumnRecommend());
|
||||
}
|
||||
|
||||
// 更改进度条和提示文本的状态
|
||||
public static void changeStatus(Context context, GameViewHolder holder, DownloadEntity downloadEntity,
|
||||
boolean isShowPlatform, boolean isNormal) {
|
||||
|
||||
updateItemViewStatus(holder, true, null);
|
||||
updateItemViewStatus(holder, true, null, null);
|
||||
holder.gameProgressbar.setProgressDrawable(context.getResources().getDrawable(R.drawable.progressbar_bg_style));
|
||||
|
||||
String platform = PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform());
|
||||
@ -377,22 +377,53 @@ public class DownloadItemUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateItemViewStatus(GameViewHolder holder, boolean hasDownload, @Nullable String briefStyle) {
|
||||
private static void updateItemViewStatus(GameViewHolder holder,
|
||||
boolean hasDownload,
|
||||
@Nullable String briefStyle,
|
||||
@Nullable LinkEntity recommendStyle) {
|
||||
if (hasDownload) {
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
|
||||
holder.gameDes.setVisibility(View.GONE);
|
||||
holder.gameProgressbar.setVisibility(View.VISIBLE);
|
||||
holder.gameInfo.setVisibility(View.VISIBLE);
|
||||
holder.recommendContainer.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.gameProgressbar.setVisibility(View.GONE);
|
||||
holder.gameInfo.setVisibility(View.GONE);
|
||||
|
||||
// 推荐优先,有推荐内容时不执行下面的 star 和 brief 代码块
|
||||
if (briefStyle != null
|
||||
&& recommendStyle != null
|
||||
&& briefStyle.contains("recommend")) {
|
||||
holder.recommendContainer.setVisibility(View.VISIBLE);
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
|
||||
holder.gameDes.setVisibility(View.GONE);
|
||||
|
||||
holder.recommendTv.setText(recommendStyle.getText());
|
||||
if ("none".equals(recommendStyle.getType())) {
|
||||
holder.recommendIv.setVisibility(View.GONE);
|
||||
} else {
|
||||
Context context = holder.recommendContainer.getContext();
|
||||
int drawableId = context.getResources().getIdentifier(
|
||||
"ic_recommend_" + recommendStyle.getType(),
|
||||
"drawable",
|
||||
context.getPackageName());
|
||||
holder.recommendIv.setVisibility(View.VISIBLE);
|
||||
holder.recommendIv.setImageResource(drawableId);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
holder.recommendContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (briefStyle != null && briefStyle.contains("star")) {
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(briefStyle) || briefStyle.contains("brief")) {
|
||||
// 缺省情况下回落到游戏简介
|
||||
if (TextUtils.isEmpty(briefStyle) || briefStyle.contains("brief") || briefStyle.contains("recommend")) {
|
||||
holder.gameDes.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.gameDes.setVisibility(View.GONE);
|
||||
|
||||
@ -489,8 +489,8 @@ fun Float.sp2px(): Int {
|
||||
return (this * scale + 0.5f).toInt()
|
||||
}
|
||||
|
||||
fun Float.roundTo(n : Int) : Float {
|
||||
return "%.${n}f".format(this).toFloat()
|
||||
fun Float.roundTo(n: Int): Float {
|
||||
return "%.${n}f".format(Locale.CHINA, this).toFloat()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -24,17 +24,24 @@ object HomePluggableHelper {
|
||||
val apkList = gameEntity.getApk()
|
||||
if (apkList.isNotEmpty()) {
|
||||
val apk = apkList.first()
|
||||
val filterData = mHomePluggableFilterDao.getDataByPkgName(apk.packageName)
|
||||
if (filterData?.active == true) {
|
||||
val filterTag = filterData.tag
|
||||
return filterTag != "never" && apk.version != filterTag
|
||||
tryCatchInRelease {
|
||||
val filterData = mHomePluggableFilterDao.getDataByPkgName(apk.packageName)
|
||||
if (filterData?.active == true) {
|
||||
val filterTag = filterData.tag
|
||||
return filterTag != "never" && apk.version != filterTag
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getPermanentInactivePluggablePackage() = mHomePluggableFilterDao.getDataByTag("never")
|
||||
fun getPermanentInactivePluggablePackage(): List<HomePluggableFilterEntity>? {
|
||||
tryCatchInRelease {
|
||||
return mHomePluggableFilterDao.getDataByTag("never")
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun activationFilterData() {
|
||||
|
||||
@ -484,4 +484,22 @@ object ImageUtils {
|
||||
fun getVideoSnapshot(videoUrl: String, progress: Long): String {
|
||||
return "$videoUrl?x-oss-process=video/snapshot,t_$progress,f_jpg,w_0,h_0"
|
||||
}
|
||||
|
||||
/**
|
||||
* 虽然在 Application 里有使用子线程初始化但有可能出现初始化超时(卡住?)的情况,
|
||||
* 这里反射获取 sDraweecontrollerbuildersupplier 根据是否有值确定是否被初始化了
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isFrescoInitialized(): Boolean {
|
||||
val clazz = SimpleDraweeView::class.java
|
||||
return try {
|
||||
val field =
|
||||
clazz.getDeclaredField("sDraweecontrollerbuildersupplier")
|
||||
field.isAccessible = true
|
||||
val obj = field[SimpleDraweeView::class.java]
|
||||
obj != null
|
||||
} catch (ignore: java.lang.Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -956,6 +956,8 @@ public class LogUtils {
|
||||
}
|
||||
|
||||
public static void uploadPackageCheck(String event, String action, GameEntity gameEntity, String linkTitle, String linkDesc, String downloadGameId, String downloadGameName) {
|
||||
if (gameEntity == null) return;
|
||||
|
||||
PackageDialogEntity packageDialog = gameEntity.getPackageDialog();
|
||||
if (packageDialog == null) return;
|
||||
JSONObject object = new JSONObject();
|
||||
|
||||
33
app/src/main/java/com/gh/common/util/NewLogUtils.kt
Normal file
33
app/src/main/java/com/gh/common/util/NewLogUtils.kt
Normal file
@ -0,0 +1,33 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.gh.common.json.json
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.gamecenter.entity.LinkEntity
|
||||
import com.lightgame.utils.Utils
|
||||
import org.json.JSONObject
|
||||
|
||||
object NewLogUtils {
|
||||
|
||||
// 专题右上角的点击事件
|
||||
fun logSubjectTopTabClick(buttonName: String?, subjectName: String?, linkEntity: LinkEntity?) {
|
||||
val json = json {
|
||||
"event" to "column_list_click_button"
|
||||
"button_type" to buttonName
|
||||
"column_name" to subjectName
|
||||
"meta" to LogUtils.getMetaObject()
|
||||
if (linkEntity != null) {
|
||||
"link_type" to linkEntity.type
|
||||
"link_title" to linkEntity.text
|
||||
}
|
||||
"timestamp" to System.currentTimeMillis() / 1000
|
||||
}
|
||||
|
||||
log(json, "event", false)
|
||||
}
|
||||
|
||||
private fun log(jsonObject: JSONObject, logStore: String, uploadImmediately: Boolean) {
|
||||
Utils.log("NewLogUtils", jsonObject.toString(4))
|
||||
LoghubUtils.log(jsonObject, logStore, uploadImmediately)
|
||||
}
|
||||
|
||||
}
|
||||
@ -274,7 +274,9 @@ object QuickLoginHelper {
|
||||
|
||||
private fun startCodeLoginPage(context: Context, entrance: String, isFinishAuth: Boolean, isFromPermission: Boolean) {
|
||||
if (mPreDialog != null && mPreDialog!!.isShowing) {
|
||||
mPreDialog?.dismiss()
|
||||
tryWithDefaultCatch {
|
||||
mPreDialog?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
if (isFinishAuth) {
|
||||
|
||||
@ -121,9 +121,14 @@ object XapkInstaller : IXapkUnzipListener {
|
||||
DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
|
||||
SentryHelper.onEvent("XAPK_UNZIP_ERROR",
|
||||
// 仅官网渠道上报 XAPK 异常信息
|
||||
if (HaloApp.getInstance().channel == "GH_206") {
|
||||
SentryHelper.onEvent(
|
||||
"XAPK_UNZIP_ERROR",
|
||||
"gameName", downloadEntity.name,
|
||||
"errorDigest", exception.localizedMessage)
|
||||
"errorDigest", exception.localizedMessage
|
||||
)
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("unzip", "onFailure->$exception")
|
||||
|
||||
@ -196,7 +196,9 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
setNavigationTitle(mName);
|
||||
mLibaoEntity = (LibaoEntity) HaloApp.get(LibaoEntity.TAG, false);
|
||||
isClickReceiveBtnIn = getIntent().getBooleanExtra(EntranceUtils.KEY_IS_CLICK_RECEIVE_BTN, false);
|
||||
mLibaoEntity.setClickReceiveBtnIn(isClickReceiveBtnIn);
|
||||
if (mLibaoEntity != null) {
|
||||
mLibaoEntity.setClickReceiveBtnIn(isClickReceiveBtnIn);
|
||||
}
|
||||
|
||||
mIsScroll = true;
|
||||
|
||||
|
||||
@ -24,7 +24,6 @@ import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.base.AppUncaughtHandler;
|
||||
import com.gh.base.BaseActivity;
|
||||
import com.gh.base.fragment.BaseFragment_ViewPager;
|
||||
@ -52,6 +51,7 @@ import com.gh.common.util.ErrorHelper;
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.common.util.GsonUtils;
|
||||
import com.gh.common.util.HomePluggableHelper;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
import com.gh.common.util.LogUtils;
|
||||
import com.gh.common.util.LunchType;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
@ -176,8 +176,12 @@ public class MainActivity extends BaseActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
setStatusBarColor(Color.TRANSPARENT);
|
||||
|
||||
if (!isFrescoInitialized()) {
|
||||
BigImageViewer.initialize(FrescoImageLoader.with(this));
|
||||
if (!ImageUtils.isFrescoInitialized()) {
|
||||
try {
|
||||
BigImageViewer.initialize(FrescoImageLoader.with(this));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Fragment fragmentFromFM = getSupportFragmentManager().findFragmentById(R.id.layout_activity_content);
|
||||
@ -966,19 +970,4 @@ public class MainActivity extends BaseActivity {
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 虽然在 Application 里有使用子线程初始化但有可能出现初始化超时(卡住?)的情况,
|
||||
* 这里反射获取 sDraweecontrollerbuildersupplier 根据是否有值确定是否被初始化了
|
||||
*/
|
||||
public boolean isFrescoInitialized() {
|
||||
Class<SimpleDraweeView> clazz = SimpleDraweeView.class;
|
||||
try {
|
||||
Field field = clazz.getDeclaredField("sDraweecontrollerbuildersupplier");
|
||||
field.setAccessible(true);
|
||||
Object object = field.get(SimpleDraweeView.class);
|
||||
return object != null;
|
||||
} catch (Exception ignore) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -550,6 +550,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
@Override
|
||||
public <T> void onListClick(View view, int position, T data) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
|
||||
startActivityForResult(intent, MEDIA_STORE_CREDENTIALS_REQUEST);
|
||||
}
|
||||
}, null);
|
||||
@ -567,6 +568,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
@Override
|
||||
public <T> void onListClick(View view, int position, T data) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
|
||||
startActivityForResult(intent, MEDIA_STORE_SCREENSHOT_REQUEST);
|
||||
}
|
||||
}, null);
|
||||
@ -1381,6 +1383,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
List<String> picList = (List<String>) data;
|
||||
if (position == mAdapter.getItemCount() - 1 && picList.size() < 5) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
|
||||
startActivityForResult(intent, MEDIA_STORE_REQUEST);
|
||||
}
|
||||
}, null);
|
||||
@ -1389,6 +1392,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
List<String> picList = (List<String>) data;
|
||||
if (position == mAdapter.getItemCount() - 1 && picList.size() < 5) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
|
||||
startActivityForResult(intent, MEDIA_STORE_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,8 @@ import com.gh.common.util.dip2px
|
||||
import com.gh.gamecenter.databinding.GameHeadItemBinding
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
|
||||
class GameHeadViewHolder(var binding: GameHeadItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
|
||||
class GameHeadViewHolder(var binding: GameHeadItemBinding) :
|
||||
BaseRecyclerViewHolder<Any>(binding.root) {
|
||||
|
||||
fun bindHead(subject: SubjectEntity) {
|
||||
val headContainerLp = binding.headContainer.layoutParams
|
||||
@ -24,10 +25,19 @@ class GameHeadViewHolder(var binding: GameHeadItemBinding) : BaseRecyclerViewHol
|
||||
|
||||
binding.subject = subject
|
||||
binding.headPb.visibility = View.GONE
|
||||
val text = if ("change" == subject.home) "换一批" else "全部 >"
|
||||
val text = if ("change" == subject.home) {
|
||||
"换一批"
|
||||
} else {
|
||||
when (subject.home) {
|
||||
"more" -> "更多 >"
|
||||
"hide" -> ""
|
||||
else -> "全部 >"
|
||||
}
|
||||
}
|
||||
binding.headMore.text = text
|
||||
|
||||
if (subject.indexRightTop != null && subject.indexRightTop != "none") {
|
||||
// 开测表用到的
|
||||
binding.headMore.visibility = View.VISIBLE
|
||||
if (subject.indexRightTop == "all") {
|
||||
binding.headMore.text = "全部 >"
|
||||
@ -40,6 +50,8 @@ class GameHeadViewHolder(var binding: GameHeadItemBinding) : BaseRecyclerViewHol
|
||||
&& subject.type != "column_collection"
|
||||
&& subject.type != "gallery_slide") {
|
||||
binding.headMore.visibility = View.GONE
|
||||
} else if (subject.home == "hide"){
|
||||
binding.headMore.visibility = View.GONE
|
||||
} else {
|
||||
binding.headMore.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.gamecenter.adapter.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
@ -24,6 +25,9 @@ public class GameViewHolder extends BaseRecyclerViewHolder {
|
||||
public LinearLayout gameLabelList;
|
||||
public LinearLayout gameInfo;
|
||||
public ProgressBar gameProgressbar;
|
||||
public View recommendContainer;
|
||||
public TextView recommendTv;
|
||||
public ImageView recommendIv;
|
||||
public TextView gameDownloadSpeed;
|
||||
public TextView gameDownloadPercentage;
|
||||
public TextView gameServerType;
|
||||
@ -44,6 +48,9 @@ public class GameViewHolder extends BaseRecyclerViewHolder {
|
||||
gameDes = binding.gameDes;
|
||||
gameDownloadSpeed = binding.downloadSpeed;
|
||||
gameRating = binding.gameRating;
|
||||
recommendContainer = binding.recommendContainer;
|
||||
recommendTv = binding.recommendTv;
|
||||
recommendIv = binding.recommendIv;
|
||||
}
|
||||
|
||||
public void initServerType(GameEntity gameEntity) {
|
||||
|
||||
@ -238,6 +238,8 @@ data class GameEntity(
|
||||
val packageDialog: PackageDialogEntity? = null,
|
||||
@SerializedName("top_video")
|
||||
val topVideo: SimpleVideoEntity? = null,
|
||||
@SerializedName("column_recommend")
|
||||
val columnRecommend: LinkEntity? = null,
|
||||
|
||||
// 本地字段,使用镜像信息
|
||||
var useMirrorInfo: Boolean = false,
|
||||
@ -573,6 +575,10 @@ data class GameEntity(
|
||||
return entity
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG: String = "GameEntity"
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class Dialog(var title: String = "",
|
||||
var content: String = "",
|
||||
@ -634,10 +640,6 @@ data class GameEntity(
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG: String = "GameEntity"
|
||||
}
|
||||
|
||||
// 游戏位置, 根据游戏位置只显示某个单独的APK
|
||||
enum class GameLocation {
|
||||
INDEX,
|
||||
|
||||
@ -10,37 +10,41 @@ import kotlinx.android.parcel.Parcelize
|
||||
* Created by LGT on 2016/7/1.
|
||||
*/
|
||||
@Parcelize
|
||||
data class SubjectEntity(@SerializedName("_id")
|
||||
var id: String? = null,
|
||||
var name: String? = null,
|
||||
var more: Int? = null,
|
||||
@SerializedName("order")
|
||||
var isOrder: Boolean = false,
|
||||
var home: String? = null,
|
||||
var tag: String? = null,
|
||||
var sort: Int = 0,
|
||||
var data: MutableList<GameEntity>? = null,
|
||||
var type: String? = null,
|
||||
var des: String? = null,
|
||||
@SerializedName("relation_column_id")
|
||||
var relatedColumnId: String? = null,
|
||||
var style: String? = "", // 值为 "top" 时表示此专题(合集)为排行榜 https://gitlab.ghzs.com/pm/halo-app-issues/issues/699
|
||||
val list: Int = 0,
|
||||
data class SubjectEntity(
|
||||
@SerializedName("_id")
|
||||
var id: String? = null,
|
||||
var name: String? = null,
|
||||
var more: Int? = null,
|
||||
@SerializedName("order")
|
||||
var isOrder: Boolean = false,
|
||||
var home: String? = null,
|
||||
var tag: String? = null,
|
||||
var sort: Int = 0,
|
||||
var data: MutableList<GameEntity>? = null,
|
||||
var type: String? = null,
|
||||
var des: String? = null,
|
||||
@SerializedName("relation_column_id")
|
||||
var relatedColumnId: String? = null,
|
||||
var style: String? = "", // 值为 "top" 时表示此专题(合集)为排行榜 https://gitlab.ghzs.com/pm/halo-app-issues/issues/699
|
||||
val list: Int = 0,
|
||||
|
||||
@SerializedName("show_name")
|
||||
var showName: Boolean = true, // 是否显示“专题名字”,true、false
|
||||
@SerializedName("show_suffix")
|
||||
var showSuffix: Boolean = true, // 是否显示”游戏后缀“,true、false
|
||||
@SerializedName("type_style")
|
||||
var typeStyle: String = "", // 横屏样式,不显示(default)、评分(star)、备注(remark)
|
||||
@SerializedName("brief_style")
|
||||
var briefStyle: String = "", // 简介样式,大小+简介(size&brief)、评分+简介(star&brief)、评分(star)
|
||||
@SerializedName("show_name")
|
||||
var showName: Boolean = true, // 是否显示“专题名字”,true、false
|
||||
@SerializedName("show_suffix")
|
||||
var showSuffix: Boolean = true, // 是否显示”游戏后缀“,true、false
|
||||
@SerializedName("type_style")
|
||||
var typeStyle: String = "", // 横屏样式,不显示(default)、评分(star)、备注(remark)
|
||||
@SerializedName("brief_style")
|
||||
var briefStyle: String = "", // 简介样式,大小+简介(size&brief)、评分+简介(star&brief)、评分(star)、推荐优先(recommend)
|
||||
@SerializedName("more_link")
|
||||
var moreLink: LinkEntity? = null,
|
||||
|
||||
@SerializedName("index_right_top")
|
||||
var indexRightTop: String? = null,
|
||||
@SerializedName("index_right_top_link")
|
||||
var indexRightTopLink: LinkEntity? = null,
|
||||
var remark: String? = null // 开测表备注
|
||||
// 开测表部分字段
|
||||
@SerializedName("index_right_top")
|
||||
var indexRightTop: String? = null,
|
||||
@SerializedName("index_right_top_link")
|
||||
var indexRightTopLink: LinkEntity? = null,
|
||||
var remark: String? = null // 开测表备注
|
||||
) : Parcelable {
|
||||
|
||||
fun getFilterName(): String {
|
||||
|
||||
@ -61,6 +61,13 @@ public class SearchToolWrapperFragment extends LazyFragment {
|
||||
.replace(R.id.wrapper_toolbar, mSearchToolbarFragment)
|
||||
.replace(R.id.wrapper_main_content, Objects.requireNonNull(mContentFragment)).commitAllowingStateLoss();
|
||||
|
||||
// 补上底部 tab 的高度
|
||||
inflatedView.findViewById(R.id.wrapperLl).setPadding(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(int) requireContext().getResources().getDimension(R.dimen.main_bottom_tab_height));
|
||||
|
||||
mCachedView.post(() -> mSearchToolbarFragment.updateSearchToolbarColor(Color.WHITE));
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -578,11 +579,15 @@ class GameFragmentAdapter(context: Context,
|
||||
val column = mItemDataList[position].columnHead
|
||||
holder.bindHead(column!!)
|
||||
|
||||
holder.binding.headMore.setOnClickListener {
|
||||
holder.binding.headMore.setOnClickListener { it as TextView
|
||||
if ("change" == column.home) {
|
||||
MtaHelper.onEvent("游戏专题", "换一批", column.name)
|
||||
holder.binding.headPb.visibility = View.VISIBLE
|
||||
mViewModel.changeSubjectGame(column.id!!)
|
||||
} else if ("more" == column.home) {
|
||||
column.moreLink?.let { link ->
|
||||
DirectUtils.directToLinkPage(it.context, link, "(板块)", "(游戏-专题:" + column.name + "-全部)")
|
||||
}
|
||||
} else {
|
||||
if (column.type == "column_collection") {
|
||||
MtaHelper.onEvent("游戏专题合集", "全部", column.name)
|
||||
@ -605,6 +610,7 @@ class GameFragmentAdapter(context: Context,
|
||||
MtaHelper.onEvent("游戏专题", "全部", column.name)
|
||||
}
|
||||
}
|
||||
NewLogUtils.logSubjectTopTabClick(it.text.toString(), column.name, column.moreLink)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import com.gh.base.BaseRecyclerViewHolder
|
||||
import com.gh.common.iinterface.IOffsetable
|
||||
import com.gh.common.util.TimeUtils
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.tryCatchInRelease
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.GameHorizontalListBinding
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
@ -51,7 +52,10 @@ class GameHorizontalSlideListViewHolder(val binding: GameHorizontalListBinding)
|
||||
binding.horizontalRv.scrollToPosition(0)
|
||||
}
|
||||
} else {
|
||||
binding.horizontalRv.scrollBy(offset, offset)
|
||||
// 可能会因为上下复用数据变化而出现 IndexOutOfBoundsException 异常,毕竟有局部更新功能...
|
||||
tryCatchInRelease {
|
||||
binding.horizontalRv.scrollBy(offset, offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
package com.gh.gamecenter.gamedetail.desc
|
||||
|
||||
import android.content.Context
|
||||
import android.view.*
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View.MeasureSpec
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.TimeUtils
|
||||
import com.gh.common.util.safelyGetInRelease
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailLatestServiceBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailMoreBinding
|
||||
@ -79,7 +83,10 @@ class GameLatestServiceAdapter(val context: Context, val datas: ArrayList<Server
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is GameLatestServiceViewHolder) {
|
||||
val entity = if (mIsExpand) mExpandEntities[position] else mShrinkEntities[position]
|
||||
// TODO 这里会数组越界,需要检查原因
|
||||
val entity = (if (mIsExpand) mExpandEntities.safelyGetInRelease(position) else mShrinkEntities.safelyGetInRelease(position))
|
||||
?: return
|
||||
|
||||
holder.binding.timeTv.text = TimeUtils.getFormatDate(entity.getTime())
|
||||
holder.binding.serviceNameTv.text = "${entity.getNote()} ${entity.remark}"
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import android.graphics.Color
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
@ -503,7 +504,7 @@ class LegacyHomeFragmentAdapterAssistant(private var mContext: Context,
|
||||
val column = item.columnHead
|
||||
holder.bindHead(column!!)
|
||||
|
||||
holder.binding.headMore.setOnClickListener {
|
||||
holder.binding.headMore.setOnClickListener { it as TextView
|
||||
if ("change" == column.home) {
|
||||
MtaHelper.onEvent("游戏专题", "新首页专题点击", "内容" + item.blockPosition + "_换一批")
|
||||
holder.binding.headPb.visibility = View.VISIBLE
|
||||
@ -512,6 +513,10 @@ class LegacyHomeFragmentAdapterAssistant(private var mContext: Context,
|
||||
if (mAdapter is HomeFragmentAdapter) {
|
||||
(mAdapter as HomeFragmentAdapter).viewModel.changeSubjectGame(column.id!!)
|
||||
}
|
||||
} else if ("more" == column.home) {
|
||||
column.moreLink?.let { link ->
|
||||
DirectUtils.directToLinkPage(it.context, link, "(首页)", "(游戏-专题:" + column.name + "-全部)")
|
||||
}
|
||||
} else {
|
||||
if (column.type == "column_collection") {
|
||||
MtaHelper.onEvent("游戏专题合集", "新首页合辑点击", "内容" + item.blockPosition + "_全部")
|
||||
@ -538,6 +543,7 @@ class LegacyHomeFragmentAdapterAssistant(private var mContext: Context,
|
||||
MtaHelper.onEvent("游戏专题", "新首页专题点击", "内容" + item.blockPosition + "_全部")
|
||||
}
|
||||
}
|
||||
NewLogUtils.logSubjectTopTabClick(it.text.toString(), column.name, column.moreLink)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1030,7 +1030,12 @@ public interface ApiService {
|
||||
* 获取新的配置信息,因为旧的已经太大了避免冲突
|
||||
*/
|
||||
@GET("new_settings")
|
||||
Single<NewSettingsEntity> getNewSettings(@Query("manufacture") String manufacture, @Query("model") String model, @Query("channel") String channel);
|
||||
Single<NewSettingsEntity> getNewSettings(
|
||||
@Query("manufacture") String manufacture,
|
||||
@Query("model") String model,
|
||||
@Query("channel") String channel,
|
||||
@Query("systemVersion") int systemVersion,
|
||||
@Query("ghVersion") String ghVersion);
|
||||
|
||||
/**
|
||||
* 给一个回答新增评论
|
||||
|
||||
@ -125,7 +125,9 @@ class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewModel>()
|
||||
|
||||
// 与外部Appbar交互
|
||||
override fun onTitleClick() {
|
||||
if (mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0 || provideListAdapter().itemCount == 0) {
|
||||
if (mLayoutManager == null
|
||||
|| mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0
|
||||
|| provideListAdapter().itemCount == 0) {
|
||||
// do nothing
|
||||
} else {
|
||||
mLayoutManager.scrollToPosition(0)
|
||||
|
||||
@ -16,7 +16,6 @@ import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.OrientationHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.base.fragment.BaseLazyFragment
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.ExposureListener
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.videolog.VideoRecordUtils
|
||||
@ -558,10 +557,14 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener {
|
||||
}
|
||||
|
||||
fun findVisibleVideoViewByPosition(): DetailPlayerView? {
|
||||
val pos = findVisibleItemPosition()
|
||||
val holder = mBinding.recyclerview?.findViewHolderForAdapterPosition(pos)
|
||||
|
||||
return holder?.itemView as? DetailPlayerView
|
||||
// 页面被销毁重建时,旧 fragment 可能会收到 onActivityResult 的 callback ,这时 mBinding 为未初始化状态
|
||||
return if (::mBinding.isInitialized) {
|
||||
val pos = findVisibleItemPosition()
|
||||
val holder = mBinding.recyclerview?.findViewHolderForAdapterPosition(pos)
|
||||
holder?.itemView as? DetailPlayerView
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun findVisibleItemPosition(): Int {
|
||||
|
||||
@ -27,6 +27,7 @@ import com.gh.common.util.DeviceUtils;
|
||||
import com.gh.common.util.DownloadNotificationHelper;
|
||||
import com.gh.common.util.DownloadObserver;
|
||||
import com.gh.common.util.HomeBottomBarHelper;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
import com.gh.common.util.PackageHelper;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.SPUtils;
|
||||
@ -104,7 +105,12 @@ public class HaloApp extends MultiDexApplication {
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
return mChannel;
|
||||
// 存在 IO 初始化线程阻塞(万物皆可阻塞)导致 mChannel 为空的情况,这里特殊处理下
|
||||
if (TextUtils.isEmpty(mChannel)) {
|
||||
return "";
|
||||
} else {
|
||||
return mChannel;
|
||||
}
|
||||
}
|
||||
|
||||
public void setOAID(String oaid) {
|
||||
@ -141,14 +147,24 @@ public class HaloApp extends MultiDexApplication {
|
||||
initDataHelper();
|
||||
Tracker.init(this);
|
||||
|
||||
//初始化Fresco(BigImageViewer 已包含Fresco)
|
||||
BigImageViewer.initialize(FrescoImageLoader.with(this));
|
||||
// 初始化 Fresco(BigImageViewer 已包含Fresco)
|
||||
if (!ImageUtils.isFrescoInitialized()) {
|
||||
try {
|
||||
BigImageViewer.initialize(FrescoImageLoader.with(this));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
deviceRamSize = DeviceUtils.getTotalRamSizeOfDevice(this);
|
||||
|
||||
mChannel = ChannelReaderUtil.getChannel(this);
|
||||
if (mChannel == null || TextUtils.isEmpty(mChannel.trim())) {
|
||||
mChannel = Config.DEFAULT_CHANNEL;
|
||||
if (BuildConfig.BUILD_TIME != 0L || BuildConfig.DEBUG) {
|
||||
mChannel = Config.DEFAULT_CHANNEL;
|
||||
} else {
|
||||
mChannel = Config.DEFAULT_CHANNEL_FOR_RELEASE;
|
||||
}
|
||||
}
|
||||
// 异步初始化 SP
|
||||
SPUtils.getString("");
|
||||
|
||||
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_activity.webp
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_activity.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 672 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_discount.webp
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_discount.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 686 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_function.webp
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_function.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 766 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_gift.webp
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_gift.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 538 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_role.webp
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_recommend_role.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 764 B |
6
app/src/main/res/drawable/bg_game_item_recommend.xml
Normal file
6
app/src/main/res/drawable/bg_game_item_recommend.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="4dp"/>
|
||||
<solid android:color="#FFFFF4F0" />
|
||||
</shape>
|
||||
@ -71,7 +71,7 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<com.gh.common.view.Gh_ViewPager
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:fresco="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
@ -72,8 +73,8 @@
|
||||
imageUrl="@{game.getRawIconInAdvanced()}"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
fresco:roundedCornerRadius="10dp"
|
||||
fresco:viewAspectRatio="1" />
|
||||
app:roundedCornerRadius="10dp"
|
||||
app:viewAspectRatio="1" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/gameIconDecoratorIv"
|
||||
@ -81,7 +82,7 @@
|
||||
imageUrl="@{game.iconSubscript}"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
fresco:viewAspectRatio="1" />
|
||||
app:viewAspectRatio="1" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
@ -111,7 +112,8 @@
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/text_333333"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"
|
||||
tools:text="地海争霸:巫妖王再怒" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recent_played_tag"
|
||||
@ -172,7 +174,8 @@
|
||||
android:singleLine="true"
|
||||
android:text="@{(game.apk.size > 0 && !hideSize && (TextUtils.isEmpty(briefStyle)||briefStyle.contains(`size`))) ? game.getApk().get(0).getSize() + ` ` + game.brief : game.brief }"
|
||||
android:textColor="@color/text_999999"
|
||||
android:textSize="10sp" />
|
||||
android:textSize="10sp"
|
||||
tools:text="巫妖王再怒霜之哀殤又飢渴" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/game_info"
|
||||
@ -220,6 +223,43 @@
|
||||
android:progressDrawable="@drawable/progressbar_bg_style"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/recommendContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:background="@drawable/bg_game_item_recommend"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/recommendIv"
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="12dp"
|
||||
android:src="@drawable/ic_recommend_activity"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recommendTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="2dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/text_FF7C1F"
|
||||
android:textSize="10sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/recommendIv"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginStart="4dp"
|
||||
tools:text="最新活动火爆来袭" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<com.gh.common.view.GameTagContainerView
|
||||
|
||||
@ -184,6 +184,7 @@
|
||||
<color name="text_F10000">#F10000</color>
|
||||
<color name="text_EA3333">#EA3333</color>
|
||||
<color name="text_FF700F">#FF700F</color>
|
||||
<color name="text_FF7C1F">#FF7C1F</color>
|
||||
<color name="text_181927">#181927</color>
|
||||
<color name="text_e6f3ff">#e6f3ff</color>
|
||||
<color name="text_1383EB">#1383EB</color>
|
||||
|
||||
191
channel.txt
191
channel.txt
@ -1,191 +1,2 @@
|
||||
GH_TEST
|
||||
GH_TEST2
|
||||
GH_REFRESH
|
||||
GH_100
|
||||
GH_101
|
||||
GH_102
|
||||
GH_103
|
||||
GH_104
|
||||
GH_106
|
||||
GH_107
|
||||
GH_108
|
||||
GH_109
|
||||
GH_110
|
||||
GH_111
|
||||
GH_113
|
||||
GH_114
|
||||
GH_115
|
||||
GH_116
|
||||
GH_117
|
||||
GH_118
|
||||
GH_119
|
||||
GH_120
|
||||
GH_121
|
||||
GH_123
|
||||
GH_127
|
||||
GH_200
|
||||
GH_201
|
||||
GH_202
|
||||
GH_203
|
||||
GH_204
|
||||
GH_205
|
||||
GH_206
|
||||
GH_222
|
||||
GH_307
|
||||
GH_333
|
||||
GH_600
|
||||
GH_601
|
||||
GH_602
|
||||
GH_603
|
||||
GH_604
|
||||
GH_605
|
||||
GH_606
|
||||
GH_607
|
||||
GH_608
|
||||
GH_609
|
||||
GH_610
|
||||
GH_611
|
||||
GH_612
|
||||
GH_613
|
||||
GH_614
|
||||
GH_615
|
||||
GH_616
|
||||
GH_617
|
||||
GH_618
|
||||
GH_619
|
||||
GH_620
|
||||
GH_621
|
||||
GH_622
|
||||
GH_623
|
||||
GH_624
|
||||
GH_625
|
||||
GH_626
|
||||
GH_627
|
||||
GH_628
|
||||
GH_629
|
||||
GH_630
|
||||
GH_631
|
||||
GH_632
|
||||
GH_633
|
||||
GH_634
|
||||
GH_635
|
||||
GH_636
|
||||
GH_637
|
||||
GH_638
|
||||
GH_639
|
||||
GH_640
|
||||
GH_641
|
||||
GH_642
|
||||
GH_643
|
||||
GH_644
|
||||
GH_645
|
||||
GH_646
|
||||
GH_647
|
||||
GH_648
|
||||
GH_649
|
||||
GH_650
|
||||
GH_651
|
||||
GH_652
|
||||
GH_653
|
||||
GH_654
|
||||
GH_655
|
||||
GH_656
|
||||
GH_657
|
||||
GH_658
|
||||
GH_659
|
||||
GH_660
|
||||
GH_661
|
||||
GH_662
|
||||
GH_663
|
||||
GH_664
|
||||
GH_665
|
||||
GH_666
|
||||
GH_667
|
||||
GH_667
|
||||
GH_668
|
||||
GH_669
|
||||
GH_670
|
||||
GH_671
|
||||
GH_672
|
||||
GH_673
|
||||
GH_674
|
||||
GH_675
|
||||
GH_676
|
||||
GH_677
|
||||
GH_678
|
||||
GH_679
|
||||
GH_680
|
||||
GH_681
|
||||
GH_682
|
||||
GH_683
|
||||
GH_684
|
||||
GH_685
|
||||
GH_686
|
||||
GH_687
|
||||
GH_688
|
||||
GH_689
|
||||
GH_690
|
||||
GH_691
|
||||
GH_692
|
||||
GH_693
|
||||
GH_694
|
||||
GH_695
|
||||
GH_696
|
||||
GH_697
|
||||
GH_698
|
||||
GH_699
|
||||
GH_700
|
||||
GH_701
|
||||
GH_702
|
||||
GH_703
|
||||
GH_704
|
||||
GH_705
|
||||
GH_706
|
||||
GH_707
|
||||
GH_708
|
||||
GH_709
|
||||
GH_710
|
||||
GH_711
|
||||
GH_712
|
||||
GH_713
|
||||
GH_714
|
||||
GH_715
|
||||
GH_716
|
||||
GH_717
|
||||
GH_718
|
||||
GH_719
|
||||
GH_720
|
||||
GH_721
|
||||
GH_722
|
||||
GH_723
|
||||
GH_724
|
||||
GH_725
|
||||
GH_726
|
||||
GH_727
|
||||
GH_728
|
||||
GH_729
|
||||
GH_730
|
||||
GH_731
|
||||
GH_732
|
||||
GH_733
|
||||
GH_734
|
||||
GH_735
|
||||
GH_736
|
||||
GH_737
|
||||
GH_738
|
||||
GH_739
|
||||
GH_740
|
||||
GH_741
|
||||
GH_742
|
||||
GH_743
|
||||
GH_744
|
||||
GH_745
|
||||
GH_746
|
||||
GH_747
|
||||
GH_748
|
||||
GH_749
|
||||
GH_750
|
||||
GH_777
|
||||
GH_787
|
||||
GH_888
|
||||
GH_999
|
||||
GH_TEST2
|
||||
@ -7,8 +7,8 @@ ext {
|
||||
targetSdkVersion = 26
|
||||
|
||||
// application info (每个大版本之间的 versionCode 增加 20)
|
||||
versionCode = 331
|
||||
versionName = "4.9.1"
|
||||
versionCode = 350
|
||||
versionName = "5.0.0"
|
||||
applicationId = "com.gh.gamecenter"
|
||||
|
||||
// AndroidX
|
||||
@ -73,7 +73,7 @@ ext {
|
||||
// 权限申请库
|
||||
easypermissions = "1.0.0"
|
||||
|
||||
rxPermissions = "0.10.2"
|
||||
rxPermissions = "0.11"
|
||||
|
||||
// httpdns = "1.1.3";
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ QUICK_LOGIN_APPID=300012035775
|
||||
QUICK_LOGIN_APPKEY=002BAABA2C078342DA33BEAB0A4C6A25
|
||||
|
||||
# hosts
|
||||
DEV_API_HOST=https\://dev-and-api.ghzs.com/v4d9d0/
|
||||
DEV_API_HOST=https\://dev-and-api.ghzs.com/v5d0d0/
|
||||
|
||||
API_HOST=https\://and-api.ghzs.com/v4d9d0/
|
||||
SENSITIVE_API_HOST=https\://and-api.ghzs.com/v4d9d0/
|
||||
|
||||
@ -25,10 +25,10 @@ cd ..
|
||||
sed -i "s/TINKER_ENABLE\=\(.*\)/TINKER_ENABLE\=1/g" gradle.properties
|
||||
sed -i 's/buildConfigField "long", "BUILD_TIME", "0"/buildConfigField "long", "BUILD_TIME", '"\"$build_time_without_divider\""'/g' app/build.gradle
|
||||
|
||||
./gradlew aIR
|
||||
./gradlew rIR -I init.gradle
|
||||
mv app/build/outputs/apk/internal/release/app-internal-release.apk app/build/outputs/apk/internal/release/光环助手$version-测试环境-带请求日志-$build_time.apk
|
||||
|
||||
./gradlew aPR
|
||||
./gradlew rPR -I init.gradle
|
||||
mv app/build/outputs/apk/publish/release/app-publish-release.apk app/build/outputs/apk/publish/release/光环助手$version-正式环境-带请求日志-$build_time.apk
|
||||
|
||||
git checkout app/build.gradle
|
||||
|
||||
Reference in New Issue
Block a user