Merge branch 'dev' into dev-5.2.0

# Conflicts:
#	app/build.gradle
This commit is contained in:
leafwai
2021-08-16 18:26:15 +08:00
186 changed files with 4299 additions and 2877 deletions

View File

@ -343,6 +343,8 @@ dependencies {
implementation "com.aliyun.openservices:aliyun-log-android-sdk:${aliyunLog}"
implementation "com.github.princekin-f:EasyFloat:${easyFloat}"
implementation "io.github.florent37:shapeofview:$shapeOfView"
implementation 'io.github.sinaweibosdk:core:11.6.0@aar'
implementation project(':libraries:LGLibrary')

View File

@ -45,6 +45,8 @@ import kotlin.collections.ArrayList
class DefaultJsApi(var context: Context) {
private var mLoginHandler: CompletionHandler<Any>? = null
@JavascriptInterface
fun isGhzs(msg: Any): String {
return "true"
@ -374,6 +376,17 @@ class DefaultJsApi(var context: Context) {
}
}
@JavascriptInterface
fun loginWithCallback(msg: Any, handler: CompletionHandler<Any>) {
mLoginHandler = handler
login(msg)
}
fun onLogin() {
mLoginHandler?.complete(true)
mLoginHandler = null
}
@Keep
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)

View File

@ -303,7 +303,7 @@ object DefaultUrlHandler {
context,
communityEntity,
activityLabelEntity,
BbsType.GAME_BBS.value,
BbsType.OFFICIAL_BBS.value,
false,
entrance,
""
@ -446,10 +446,11 @@ object DefaultUrlHandler {
val name = uri.getQueryParameter("communityName") ?: ""
DirectUtils.directToCommunityColumn(context, CommunityEntity(id, name), columnsId, entrance, "")
}
contains("zone") -> {
contains("zone") && split("/").size > 2 -> {
val gameId = split("/")[2]
DirectUtils.directGameZone(context, gameId, url, entrance)
}
else -> return false
}
}
return true

View File

@ -1,6 +1,5 @@
package com.gh.common.dialog
import android.graphics.Paint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -9,12 +8,17 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentTransaction
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.util.DirectUtils
import com.gh.common.util.SpanBuilder
import com.gh.common.util.dip2px
import com.gh.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogApplyModeratorBinding
class ApplyModeratorDialogFragment : BaseDialogFragment() {
private lateinit var binding: DialogApplyModeratorBinding
private var groupNumber = ""
private var groupKey = ""
private var mCallBack: (() -> Unit)? = null
override fun onCreateView(
@ -28,14 +32,17 @@ class ApplyModeratorDialogFragment : BaseDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.groupTv.text = groupNumber
binding.groupTv.paint.flags = Paint.UNDERLINE_TEXT_FLAG
binding.groupTv.setOnClickListener {
DirectUtils.directToQqGroup(
requireContext(),
binding.groupTv.text.toString()
)
}
val startText = "版主考核群:"
val text = "$startText$groupNumber\n感谢你对论坛建设的支持\n请加入版主考核群并联系群主进行版主资格考核"
binding.desTv.text = SpanBuilder(text)
.click(startText.length, startText.length + groupNumber.length, R.color.theme_font,true) {
DirectUtils.directToQqGroup(
requireContext(),
groupKey
)
}
.build()
binding.desTv.movementMethod = CustomLinkMovementMethod.getInstance()
binding.confirmTv.setOnClickListener {
dismissAllowingStateLoss()
mCallBack?.invoke()
@ -51,11 +58,17 @@ class ApplyModeratorDialogFragment : BaseDialogFragment() {
companion object {
@JvmStatic
fun show(activity: AppCompatActivity, number: String, callBack: (() -> Unit)?) {
fun show(
activity: AppCompatActivity,
number: String,
key: String,
callBack: (() -> Unit)?
) {
var dialogFragment =
activity.supportFragmentManager.findFragmentByTag(ApplyModeratorDialogFragment::class.java.simpleName) as? ApplyModeratorDialogFragment
if (dialogFragment != null) {
dialogFragment.groupNumber = number
dialogFragment.groupKey = key
dialogFragment.mCallBack = callBack
val transaction: FragmentTransaction =
activity.supportFragmentManager.beginTransaction()
@ -64,6 +77,7 @@ class ApplyModeratorDialogFragment : BaseDialogFragment() {
} else {
dialogFragment = ApplyModeratorDialogFragment().apply {
groupNumber = number
groupKey = key
mCallBack = callBack
}
dialogFragment.show(

View File

@ -41,7 +41,7 @@ object LoghubHelper {
// 每次发送前会把日志保存到本地的binlog文件只有发送成功才会删除保证日志上传At Least Once
setPersistent(1)
// 持久化的文件名,需要保证文件所在的文件夹已创建。配置多个客户端时,不应设置相同文件
setPersistentFilePath(HaloApp.getInstance().application.filesDir.absolutePath + "/log.dat")
setPersistentFilePath(HaloApp.getInstance().application.filesDir.absolutePath + "/${logStore}.dat")
// 是否每次AddLog强制刷新高可靠性场景建议打开
setPersistentForceFlush(1)
// 持久化文件滚动个数建议设置成10。

View File

@ -15,6 +15,7 @@ import com.gh.gamecenter.entity.SimulatorGameRecordEntity
import com.gh.gamecenter.manager.UserManager
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.room.AppDatabase
import com.halo.assistant.HaloApp
@ -86,6 +87,8 @@ object SimulatorGameManager {
fun launchSimulatorGame(downloadEntity: DownloadEntity, gameEntity: GameEntity) {
val versionFromInstalledApp = PackageUtils.getVersionByPackage(gameEntity.simulator?.apk?.packageName)
val shouldShowUpdate = Version(gameEntity.simulator?.apk?.version).isHigherThan(versionFromInstalledApp)
updateSimulatorConfigFile(gameId = gameEntity.id)
if (shouldShowUpdate) {
SimulatorDownloadManager.getInstance().showDownloadDialog(AppManager.getInstance().recentActiveActivity, gameEntity.simulator,
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name
@ -305,4 +308,22 @@ object SimulatorGameManager {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(EmptyResponse())
}
private fun updateSimulatorConfigFile(gameId: String) {
RetrofitManager.getInstance(HaloApp.getInstance().application)
.api
.getGameDigest(gameId)
.map(ApkActiveUtils.filterMapper)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<GameEntity>() {
override fun onResponse(game: GameEntity?) {
game?.let {
if (!TextUtils.isEmpty(game.simulatorGameConfig)) {
val configFilePath = getPathByType(game.simulatorType + "/cheat/" + game.getApk().firstOrNull()?.packageName + ".ini")
FileUtils.downloadAndUpdateFile(game.simulatorGameConfig, configFilePath)
}
}
}
})
}
}

View File

@ -120,6 +120,7 @@ object TrackerLogger {
val jsonObject = JSONObject()
val payloadObject = JSONObject()
val signatureHash = PackageUtils.getApkSignatureByPackageName(context, context.packageName)
val sideLoadInfo = PackageUtils.getSideLoadedInfo()
tryCatchInRelease {
payloadObject.put("launch_id", Tracker.launchId)
@ -128,6 +129,13 @@ object TrackerLogger {
payloadObject.put("package_name", context.packageName)
payloadObject.put("app_name", context.getString(R.string.app_name))
sideLoadInfo?.let {
payloadObject.put("is_side_loaded", sideLoadInfo["is_side_loaded"])
sideLoadInfo["installer_store"]?.let {
payloadObject.put("installer_store", it)
}
}
jsonObject.put("event", "app_launch")
jsonObject.put("payload", payloadObject)
jsonObject.put("meta", getMeta())

View File

@ -65,6 +65,7 @@ import com.gh.gamecenter.R;
import com.gh.gamecenter.SuggestionActivity;
import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder;
import com.gh.gamecenter.databinding.DialogBindPhoneBinding;
import com.gh.gamecenter.databinding.DialogEnergySignBinding;
import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding;
import com.gh.gamecenter.databinding.DialogPackageParseErrorBinding;
import com.gh.gamecenter.databinding.DialogQuickLoginPermissionBinding;
@ -1927,7 +1928,7 @@ public class DialogUtils {
return dialog;
}
public static void showEnergyDialog(Context context, String userName, int energy) {
public static void showEnergyDialog(Context context, String userName, long energy) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
@ -2183,6 +2184,38 @@ public class DialogUtils {
dialog.show();
}
public static void showEnergySignDialog(Context context, int sevenDaySerialSign) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
DialogEnergySignBinding binding = DialogEnergySignBinding.inflate(LayoutInflater.from(context));
if (sevenDaySerialSign > 7) sevenDaySerialSign = 7;
for (int i = 1; i <= sevenDaySerialSign; i++) {
int index = (i - 1) * 2;
LinearLayout dayContainer = (LinearLayout) binding.signDaysContainer.getChildAt(index);
ImageView dayIv = (ImageView) dayContainer.getChildAt(1);
dayIv.setImageResource(R.drawable.ic_energy_center_signed);
if (i != 7) {
int rIndex = (i - 1) * 2 + 1;
LinearLayout lineContainer = (LinearLayout) binding.signDaysContainer.getChildAt(rIndex);
View straightLine = lineContainer.getChildAt(0);
View dottedLine = lineContainer.getChildAt(1);
if (i != sevenDaySerialSign) {
straightLine.setVisibility(View.VISIBLE);
} else {
dottedLine.setVisibility(View.VISIBLE);
}
}
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(binding.getRoot());
dialog.show();
}
/**
* @param context may be is application context
* @return activity context

View File

@ -1515,14 +1515,14 @@ object DirectUtils {
* 跳转至活动详情
*/
@JvmStatic
fun directToActivityDetail(context: Context, activityId: String, entrance: String) {
fun directToActivityDetail(context: Context, activityId: String, categoryId: String, entrance: String) {
var url: String = if (isPublishEnv()) {
Constants.ACTIVITY_DETAIL_ADDRESS
} else {
Constants.ACTIVITY_DETAIL_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&id=%s&timestamp=%d", url, activityId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
url = String.format(Locale.CHINA, "%s&id=%s&category_id=%s&timestamp=%d", url, activityId, categoryId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToWebView(context, url, entrance)
}
}

View File

@ -6,6 +6,8 @@ import com.gh.base.BaseActivity
import com.gh.common.constant.Constants
import com.gh.common.exposure.ExposureUtils
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.runOnIoThread
import com.gh.common.runOnUiThread
import com.gh.common.simulator.SimulatorDownloadManager
import com.gh.common.simulator.SimulatorGameManager
import com.gh.common.util.EnergyTaskHelper.postEnergyTask
@ -166,17 +168,21 @@ object DownloadObserver {
Utils.toast(mApplication, R.string.install_failure_hint)
downloadManager.cancel(downloadEntity.url)
} else {
if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) {
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
tryWithDefaultCatch {
PackageInstaller.install(mApplication, downloadEntity, false)
}
} else {
// 弹出卸载提示框
if (downloadEntity.isPlugin) {
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
runOnIoThread {
if (PackageUtils.isInstallable(mApplication, downloadEntity.path)) {
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
tryWithDefaultCatch {
runOnUiThread {
PackageInstaller.install(mApplication, downloadEntity, false)
}
}
} else {
EventBus.getDefault().post(EBShowDialog(BaseActivity.SIGNATURE_CONFLICT, downloadEntity.path))
// 弹出卸载提示框
if (downloadEntity.isPlugin) {
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
} else {
EventBus.getDefault().post(EBShowDialog(BaseActivity.SIGNATURE_CONFLICT, downloadEntity.path))
}
}
}
}

View File

@ -130,27 +130,39 @@ object EnergyTaskHelper {
// 完成弹窗
@JvmStatic
fun showCompletePopup(entity: EnergyTaskCompleteEntity) {
val currentActivity = AppManager.getInstance().recentActiveActivity
currentActivity?.run {
val contentView = View.inflate(this, R.layout.popup_energy_task, null)
contentView.run {
findViewById<TextView>(R.id.taskDesc).text = "恭喜你!完成任务:${entity.name}"
findViewById<TextView>(R.id.taskEnergy).text = "+${entity.energy}光能"
isFocusable = true
isFocusableInTouchMode = true
setOnClickListener {
if (currentActivity::class.java.simpleName != EnergyCenterActivity::class.java.simpleName) {
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
tryWithDefaultCatch {
val currentActivity = AppManager.getInstance().recentActiveActivity
val popWindow = PopupWindow(LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px())
currentActivity?.run {
val contentView = View.inflate(this, R.layout.popup_energy_task, null)
contentView.run {
findViewById<TextView>(R.id.taskDesc).text = "恭喜你!完成任务:${entity.name}"
findViewById<TextView>(R.id.taskEnergy).text = "+${entity.energy}光能"
isFocusable = true
isFocusableInTouchMode = true
setOnClickListener {
if (popWindow != null && popWindow.isShowing) {
popWindow.dismiss()
}
if (currentActivity !is EnergyCenterActivity) {
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
}
}
}
}
val popWindow = PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px())
popWindow.showAtLocation(currentActivity.window.decorView, Gravity.TOP, 0, 0)
countDownTimer(3) { finish, _ ->
if (finish && popWindow != null && popWindow.isShowing) {
popWindow.dismiss()
popWindow.contentView = contentView
currentActivity.window.decorView.post {
popWindow.showAtLocation(currentActivity.window.decorView, Gravity.TOP, 0, 0)
}
contentView.postDelayed({
tryCatchInRelease {
if (popWindow != null && popWindow.isShowing) {
popWindow.dismiss()
}
}
}, 3000)
}
}
}

View File

@ -19,10 +19,12 @@ object ErrorHelper {
* [customizedHandler] 返回 true 为已处理该错误码false 则交由 [handleError] 处理
*/
@JvmStatic
fun handleErrorWithCustomizedHandler(context: Context,
errorString: String?,
showHighPriorityHint: Boolean = false,
customizedHandler: (code: Int) -> Boolean) {
fun handleErrorWithCustomizedHandler(
context: Context,
errorString: String?,
showHighPriorityHint: Boolean = false,
customizedHandler: (code: Int) -> Boolean
) {
val errorEntity = errorString?.toObject<ErrorEntity>()
if (customizedHandler(errorEntity?.code ?: 0)) {
@ -75,8 +77,15 @@ object ErrorHelper {
*403057 游戏评论
*403054 更新社区文章
*403047 回答点赞
*403112 发布视频贴
*403113 修改视频贴
*403114 点赞视频贴
*/
private fun handleError(context: Context, showHighPriorityHint: Boolean = false, errorEntity: ErrorEntity) {
private fun handleError(
context: Context,
showHighPriorityHint: Boolean = false,
errorEntity: ErrorEntity
) {
when (errorEntity.code) {
403050,
403051,
@ -89,7 +98,10 @@ object ErrorHelper {
403054,
403069,
403071,
403047 -> handleErrorWithCommunityBannedDialog(context, errorEntity)
403047,
403112,
403113,
403114 -> handleErrorWithCommunityBannedDialog(context, errorEntity)
403057,
403068 -> handleErrorWithCommentBannedDialog(context, errorEntity)
@ -120,12 +132,15 @@ object ErrorHelper {
403082 -> Utils.toast(context, "作者已关闭评论")
403022 -> Utils.toast(context, "不能回复自己")
403056 -> Utils.toast(context, "发布失败,字数已达上限")
403111 -> Utils.toast(context, "提交失败,评论违规")
403020 -> if (showHighPriorityHint) {
DialogUtils.showAlertDialog(context,
"提醒",
"问过于频繁,请先休息一下哦",
"知道了", null, null, null)
DialogUtils.showAlertDialog(
context,
"",
"提问过于频繁,请先休息一下哦",
"知道了", null, null, null
)
} else {
Utils.toast(context, R.string.comment_failed_toofrequent)
}
@ -148,12 +163,14 @@ object ErrorHelper {
"(非永久)"
}
val dialogContext = DialogUtils.checkDialogContext(context)
DialogUtils.showAlertDialog(dialogContext,
"提示",
"你因违反《光环助手评论规则》,已被禁言$bannedType如有疑问请联系客服QQ${Config.getSettings()?.support?.qq}",
"去看看", "关闭", {
dialogContext.startActivity(WebActivity.getCommentRulesIntent(dialogContext))
}, null)
DialogUtils.showAlertDialog(
dialogContext,
"提示",
"你因违反《光环助手评论规则》,已被禁言$bannedType如有疑问请联系客服QQ${Config.getSettings()?.support?.qq}",
"去看看", "关闭", {
dialogContext.startActivity(WebActivity.getCommentRulesIntent(dialogContext))
}, null
)
}
private fun handleErrorWithCommunityBannedDialog(context: Context, errorEntity: ErrorEntity) {
@ -163,18 +180,21 @@ object ErrorHelper {
"(非永久)"
}
val dialogContext = DialogUtils.checkDialogContext(context)
DialogUtils.showAlertDialog(dialogContext,
"提示",
"你因违反《问答版块规则》,已被禁言$bannedType如有疑问请联系客服QQ1562479331",
"去看看", "关闭", {
dialogContext.startActivity(WebActivity.getCommunityRuleIntent(dialogContext))
}, null)
DialogUtils.showAlertDialog(
dialogContext,
"提示",
"你因违反《问答版块规则》,已被禁言$bannedType如有疑问请联系客服QQ1562479331",
"去看看", "关闭", {
dialogContext.startActivity(WebActivity.getCommunityRuleIntent(dialogContext))
}, null
)
}
@JvmStatic
fun handleLoginError(context: Context, httpException: HttpException?) {
try {
val errorEntity: ErrorEntity? = httpException?.response()?.errorBody()?.string()?.toObject()
val errorEntity: ErrorEntity? =
httpException?.response()?.errorBody()?.string()?.toObject()
when {
errorEntity?.code == 403099 -> {
Utils.toast(context, "当前账号正在注销,禁止登录")

View File

@ -6,6 +6,7 @@ import android.content.ClipboardManager
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
@ -13,11 +14,9 @@ import android.text.*
import android.text.style.ClickableSpan
import android.text.style.ImageSpan
import android.text.style.URLSpan
import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.*
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.PopupWindow
@ -65,21 +64,24 @@ import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import kotlin.math.abs
/**
* 创建以 activity 为观察者上下文的 viewModel
*/
inline fun <reified VM : ViewModel> FragmentActivity.viewModelProvider(
provider: ViewModelProvider.Factory? = null
provider: ViewModelProvider.Factory? = null
) =
ViewModelProviders.of(this, provider).get(VM::class.java)
ViewModelProviders.of(this, provider).get(VM::class.java)
/**
* 创建以 activity 为观察者上下文的 viewModel
* 额外的 key: 用于区分单 activity 多 viewModel 的情况 (如首页tab)
*/
inline fun <reified VM : ViewModel> Fragment.viewModelProviderFromParent(
provider: ViewModelProvider.Factory? = null,
key: String = ""
provider: ViewModelProvider.Factory? = null,
key: String = ""
) = if (key.isEmpty()) {
ViewModelProviders.of(requireActivity(), provider).get(VM::class.java)
} else {
@ -90,28 +92,33 @@ inline fun <reified VM : ViewModel> Fragment.viewModelProviderFromParent(
* 创建以 activity 为观察者上下文的 viewModel
*/
inline fun <reified VM : ViewModel> FragmentActivity.viewModelProviderFromParent(
provider: ViewModelProvider.Factory? = null
provider: ViewModelProvider.Factory? = null
) =
ViewModelProviders.of(this, provider).get(VM::class.java)
ViewModelProviders.of(this, provider).get(VM::class.java)
/**
* 创建以 fragment 为观察者上下文的 viewModel
*/
inline fun <reified VM : ViewModel> Fragment.viewModelProvider(
provider: ViewModelProvider.Factory? = null
provider: ViewModelProvider.Factory? = null
) =
ViewModelProviders.of(this, provider).get(VM::class.java)
ViewModelProviders.of(this, provider).get(VM::class.java)
/**
*
* ViewPager Extensions
*
*/
fun ViewPager.doOnPageSelected(action: (position: Int) -> Unit) = addOnPageChangeListener(onSelected = action)
fun ViewPager.doOnPageSelected(action: (position: Int) -> Unit) =
addOnPageChangeListener(onSelected = action)
fun ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = null) {
val listener = object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
// Do nothing.
}
@ -126,11 +133,17 @@ fun ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = n
addOnPageChangeListener(listener)
}
fun ViewPager.doOnScroll(onStateChanged: ((state: Int) -> Unit)? = null,
onPageScrolled: ((position: Int, positionOffset: Float, positionOffsetPixels: Int) -> Unit)? = null,
onPageSelected: ((position: Int) -> Unit)? = null) {
fun ViewPager.doOnScroll(
onStateChanged: ((state: Int) -> Unit)? = null,
onPageScrolled: ((position: Int, positionOffset: Float, positionOffsetPixels: Int) -> Unit)? = null,
onPageSelected: ((position: Int) -> Unit)? = null
) {
val listener = object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
onPageScrolled?.invoke(position, positionOffset, positionOffsetPixels)
}
@ -150,13 +163,19 @@ fun ViewPager.doOnScroll(onStateChanged: ((state: Int) -> Unit)? = null,
* Fragment related
*/
inline fun <reified T : Fragment> Fragment.fragmentFromActivity() =
parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
?: parentFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
?: parentFragmentManager.fragmentFactory.instantiate(
requireContext().classLoader,
T::class.java.canonicalName
) as T
inline fun <reified T : Fragment> Fragment.fragmentFromParentFragment() =
childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
?: childFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
?: childFragmentManager.fragmentFactory.instantiate(
requireContext().classLoader,
T::class.java.canonicalName
) as T
/**
@ -164,7 +183,12 @@ inline fun <reified T : Fragment> Fragment.fragmentFromParentFragment() =
*/
// 监听滚动距离
fun RecyclerView.doOnScrolledSpecificDistance(distanceX: Int = 0, distanceY: Int = 0, singleTimeEvent: Boolean = false, action: () -> Unit) {
fun RecyclerView.doOnScrolledSpecificDistance(
distanceX: Int = 0,
distanceY: Int = 0,
singleTimeEvent: Boolean = false,
action: () -> Unit
) {
val listener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
@ -186,10 +210,10 @@ fun RecyclerView.doOnScrolledSpecificDistance(distanceX: Int = 0, distanceY: Int
*/
inline fun <reified T : ViewBinding> ViewGroup.toBinding(): T {
return T::class.java.getMethod(
"inflate",
LayoutInflater::class.java,
ViewGroup::class.java,
Boolean::class.java
"inflate",
LayoutInflater::class.java,
ViewGroup::class.java,
Boolean::class.java
).invoke(null, layoutInflater, this, false) as T
}
@ -236,6 +260,43 @@ fun View.setDebouncedClickListener(action: () -> Unit) {
val View.layoutInflater: LayoutInflater
get() = LayoutInflater.from(this.context)
fun View.removeFromParent() {
postDelayed(object : Runnable {
override fun run() {
try {
if (parent == null) {
Utils.log(javaClass.simpleName, "getParent() returning Null")
} else {
try {
(parent as ViewGroup).removeView(this@removeFromParent)
} catch (ex: Exception) {
Utils.log(javaClass.simpleName, "Cannot remove from parent layout")
}
}
} catch (ex: Exception) {
Utils.log(javaClass.simpleName, Log.getStackTraceString(ex))
}
}
}, 100)
}
/**
* 扩大 View 的点击区域
*/
fun View.enlargeTouchArea(enlargedSizeInPx: Int = 4F.dip2px()) {
val parent = parent as View
parent.post {
val rect = Rect()
getHitRect(rect)
rect.top -= enlargedSizeInPx
rect.left -= enlargedSizeInPx
rect.bottom += enlargedSizeInPx
rect.right += enlargedSizeInPx
parent.touchDelegate = TouchDelegate(rect, this)
}
}
fun isPublishEnv(): Boolean {
return BuildConfig.FLAVOR != "internal"
}
@ -288,11 +349,11 @@ fun String.insert(index: Int, string: String): String {
*/
fun String.replaceUnsupportedHtmlTag(): String {
return this.replace("<ul", "<hul")
.replace("</ul>", "</hul>")
.replace("<li", "<hli")
.replace("</li>", "</hli>")
.replace("<ol", "<hol")
.replace("</ol>", "</hol>")
.replace("</ul>", "</hul>")
.replace("<li", "<hli")
.replace("</li>", "</hli>")
.replace("<ol", "<hol")
.replace("</ol>", "</hol>")
}
fun String.containHtmlTag(): Boolean {
@ -307,8 +368,8 @@ fun String.containHtmlTag(): Boolean {
fun Fragment.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
DialogUtils.showRegulationTestDialog(requireContext(),
{ DirectUtils.directToRegulationTestPage(requireContext()) },
{ action.invoke() })
{ DirectUtils.directToRegulationTestPage(requireContext()) },
{ action.invoke() })
} else {
action()
}
@ -317,8 +378,8 @@ fun Fragment.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
fun Context.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
DialogUtils.showRegulationTestDialog(this,
{ DirectUtils.directToRegulationTestPage(this) },
{ action.invoke() })
{ DirectUtils.directToRegulationTestPage(this) },
{ action.invoke() })
} else {
action()
}
@ -417,14 +478,15 @@ fun String.removeInsertedContent(): String {
// 去除视频相关文本
fun String.removeVideoContent(): String {
val videoRegex = "(?s)<div data-id.*?class=\"placeholder-video-container\".*? class=\"video-poster-btn\".*?</div>"
val videoRegex =
"(?s)<div data-id.*?class=\"placeholder-video-container\".*? class=\"video-poster-btn\".*?</div>"
return this.replace(videoRegex.toRegex(), "")
}
// 完全地清除所有 Html 格式
fun String.clearHtmlFormatCompletely(): String {
return Html.fromHtml(this).toString().replace('\n', 32.toChar())
.replace(160.toChar(), 32.toChar()).replace(65532.toChar(), 32.toChar()).trim { it <= ' ' }
.replace(160.toChar(), 32.toChar()).replace(65532.toChar(), 32.toChar()).trim { it <= ' ' }
}
// 如果该字符串长度超过固定长度的话,从头开始截取固定长度并返回
@ -554,19 +616,23 @@ fun PopupWindow.showAutoOrientation(anchorView: View, distanceY: Int = 0, distan
* 权限相关
*/
fun Fragment.checkReadPhoneStateAndStoragePermissionBeforeAction(action: (() -> Unit)) {
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(requireContext(), object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(
requireContext(),
object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
}
fun Fragment.checkReadPhoneStatePermissionBeforeAction(action: (() -> Unit)) {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(requireContext(), object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(
requireContext(),
object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
}
fun Fragment.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
@ -578,11 +644,13 @@ fun Fragment.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
}
fun FragmentActivity.checkReadPhoneStateAndStoragePermissionBeforeAction(action: (() -> Unit)) {
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(this, object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(
this,
object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
}
fun FragmentActivity.checkReadPhoneStatePermissionBeforeAction(action: (() -> Unit)) {
@ -613,20 +681,27 @@ fun <T> List<T>.secondOrNull(): T? {
/**
* TextView related.
*/
fun TextView.setTextWithHighlightedTextWrappedInsideWrapper(text: CharSequence,
wrapper: String = Constants.DEFAULT_TEXT_WRAPPER,
@ColorRes
highlightColorId: Int = R.color.theme_font,
copyClickedText: Boolean = false,
highlightedTextClickListener: (() -> Unit)? = null) {
TextHelper.highlightTextThatIsWrappedInsideWrapper(this, text, wrapper, highlightColorId, object : SimpleCallback<String> {
override fun onCallback(arg: String) {
if (copyClickedText) {
arg.copyTextAndToast("已复制:$arg")
fun TextView.setTextWithHighlightedTextWrappedInsideWrapper(
text: CharSequence,
wrapper: String = Constants.DEFAULT_TEXT_WRAPPER,
@ColorRes
highlightColorId: Int = R.color.theme_font,
copyClickedText: Boolean = false,
highlightedTextClickListener: (() -> Unit)? = null
) {
TextHelper.highlightTextThatIsWrappedInsideWrapper(
this,
text,
wrapper,
highlightColorId,
object : SimpleCallback<String> {
override fun onCallback(arg: String) {
if (copyClickedText) {
arg.copyTextAndToast("已复制:$arg")
}
highlightedTextClickListener?.invoke()
}
highlightedTextClickListener?.invoke()
}
})
})
}
fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before: Int, count: Int) -> Unit) {
@ -667,7 +742,10 @@ fun <T> List<T>.safelyGetInRelease(index: Int): T? {
* @param shrankText 未展开时的文字
* @param expandedText 展开后的文字
*/
fun ExpandTextView.setTextWithInterceptingInternalUrl(shrankText: CharSequence, expandedText: CharSequence) {
fun ExpandTextView.setTextWithInterceptingInternalUrl(
shrankText: CharSequence,
expandedText: CharSequence
) {
var shrankSsb = shrankText.interceptUrlSpanAndRoundImageSpan()
var expandedSsb = expandedText.interceptUrlSpanAndRoundImageSpan()
@ -675,23 +753,42 @@ fun ExpandTextView.setTextWithInterceptingInternalUrl(shrankText: CharSequence,
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
while (shrankSsb.contains("\n\n")) {
val index = shrankSsb.indexOf("\n\n", 0, true)
shrankSsb = SpannableStringBuilder(shrankSsb.subSequence(0, index)).append(shrankSsb.subSequence(index + "\n".length, shrankSsb.length))
shrankSsb = SpannableStringBuilder(
shrankSsb.subSequence(
0,
index
)
).append(shrankSsb.subSequence(index + "\n".length, shrankSsb.length))
}
while (expandedSsb.contains("\n\n")) {
val index = expandedSsb.indexOf("\n\n", 0, true)
expandedSsb = SpannableStringBuilder(expandedSsb.subSequence(0, index)).append(expandedSsb.subSequence(index + "\n".length, expandedSsb.length))
expandedSsb = SpannableStringBuilder(
expandedSsb.subSequence(
0,
index
)
).append(expandedSsb.subSequence(index + "\n".length, expandedSsb.length))
}
}
// 去掉多余的 P 标签换行
if (expandedSsb.endsWith("\n", true)) {
expandedSsb = SpannableStringBuilder((expandedSsb.subSequence(0, expandedSsb.length - "\n".length)))
expandedSsb =
SpannableStringBuilder((expandedSsb.subSequence(0, expandedSsb.length - "\n".length)))
}
movementMethod = CustomLinkMovementMethod.getInstance()
shrankSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, shrankSsb, highlightedTextClickListener = null)
expandedSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, expandedSsb, highlightedTextClickListener = null)
shrankSsb = TextHelper.updateSpannableStringWithHighlightedSpan(
context,
shrankSsb,
highlightedTextClickListener = null
)
expandedSsb = TextHelper.updateSpannableStringWithHighlightedSpan(
context,
expandedSsb,
highlightedTextClickListener = null
)
setShrankTextAndExpandedText(shrankSsb, expandedSsb)
}
@ -699,32 +796,41 @@ fun CharSequence.interceptUrlSpanAndRoundImageSpan(): SpannableStringBuilder {
return SpannableStringBuilder.valueOf(this).apply {
getSpans(0, length, URLSpan::class.java).forEach {
setSpan(
object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(HaloApp.getInstance().application, R.color.theme_font)
ds.isUnderlineText = false
}
object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(
HaloApp.getInstance().application,
R.color.theme_font
)
ds.isUnderlineText = false
}
override fun onClick(widget: View) {
if (!DefaultUrlHandler.interceptUrl(widget.context, it.url, "")) {
widget.context.startActivity(WebActivity.getIntent(widget.context, it.url, true))
}
override fun onClick(widget: View) {
if (!DefaultUrlHandler.interceptUrl(widget.context, it.url, "")) {
widget.context.startActivity(
WebActivity.getIntent(
widget.context,
it.url,
true
)
)
}
},
getSpanStart(it),
getSpanEnd(it),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
}
},
getSpanStart(it),
getSpanEnd(it),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
removeSpan(it)
}
getSpans(0, length, ImageSpan::class.java).forEach {
setSpan(
CenterImageSpan(it.drawable),
getSpanStart(it),
getSpanEnd(it),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
CenterImageSpan(it.drawable),
getSpanStart(it),
getSpanEnd(it),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
removeSpan(it)
}
@ -833,22 +939,22 @@ inline fun testChannelOnly(f: () -> Unit) {
* 倒计时单位s
*/
inline fun countDownTimer(
timeInSeconds: Long,
crossinline block: (finish: Boolean, remainingTime: Long) -> Unit
timeInSeconds: Long,
crossinline block: (finish: Boolean, remainingTime: Long) -> Unit
): Disposable {
var subscribe: Disposable? = null
subscribe = Observable.interval(0, 1000, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (it < timeInSeconds) {
block.invoke(false, timeInSeconds - it)
} else {
block.invoke(true, 0)
if (subscribe != null && !subscribe!!.isDisposed) {
subscribe?.dispose()
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (it < timeInSeconds) {
block.invoke(false, timeInSeconds - it)
} else {
block.invoke(true, 0)
if (subscribe != null && !subscribe!!.isDisposed) {
subscribe?.dispose()
}
}
}
return subscribe
}
@ -857,17 +963,17 @@ inline fun countDownTimer(
* @start 起始时间
*/
inline fun countUpTimer(
start: Long,
period: Long = 1000,
crossinline block: (millisUntilFinished: Long) -> Unit
start: Long,
period: Long = 1000,
crossinline block: (millisUntilFinished: Long) -> Unit
): Disposable {
var startTime = start
return Observable.interval(0, period, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
startTime += period
block.invoke(startTime)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
startTime += period
block.invoke(startTime)
}
}
/**
@ -875,10 +981,10 @@ inline fun countUpTimer(
*/
inline fun rxTimer(interval: Long, crossinline block: (times: Long) -> Unit): Disposable {
return Observable.interval(0, interval, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
block.invoke(it)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
block.invoke(it)
}
}
fun LottieAnimationView.doOnAnimationEnd(action: () -> Unit) {
@ -944,13 +1050,17 @@ fun List<String>?.checkSameFromStringArray(check2: List<String>?): Boolean {
fun EditText.showKeyBoard() {
this.postDelayed({
this.requestFocus()
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
val inputMethodManager =
context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.showSoftInput(this, 0)
}, 300)
}
fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)? = null, onStopTrackingTouch: (() -> Unit)? = null) {
fun SeekBar.doOnSeekBarChangeListener(
progressChange: ((progress: Int) -> Unit)? = null,
onStopTrackingTouch: (() -> Unit)? = null
) {
this.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
progressChange?.invoke(progress)
@ -969,14 +1079,22 @@ fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)?
fun <T> observableToMain(): ObservableTransformer<T, T> {
return ObservableTransformer { upstream ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
}
}
fun <T> singleToMain(): SingleTransformer<T, T> {
return SingleTransformer { upstream ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
}
}
fun clickToastByStatus(status: String, action: () -> Unit) {
when (status) {
"pending" -> ToastUtils.showToast("内容审核中")
"fail" -> ToastUtils.showToast("内容审核不通过")
else -> action.invoke()
}
}

View File

@ -93,6 +93,13 @@ object GameSubstituteRepositoryHelper {
val game = collection.data?.find { game -> isThisGameUnique(game, gameIdList) }
game?.let {
collection.data?.remove(game)
collection.data?.size?.let { remainingSize ->
// 记录被替换游戏的数量10个以上的时候触发
if (remainingSize % 10 == 0) {
SentryHelper.onEvent("game_substitute", "substituted_size", "${50 - remainingSize}")
}
}
// 产品说要记录补充专题的曝光数,所以这个游戏附带了所在专题的名字
game.subjectName = collection.name
return game

View File

@ -312,7 +312,7 @@ object ImageUtils {
if (url == null) return
// 部分自适应宽高图片需要一个 TARGET_WIDTH 来避免加载过小图片
val width = (view?.getTag(TARGET_WIDTH) as? Int) ?: view?.layoutParams?.width
val width = (view?.getTag(TARGET_WIDTH) as? Int) ?: view?.width?.coerceAtLeast(view.layoutParams?.width ?: 0)
val height = view?.layoutParams?.height
var lowResUrl = ""

View File

@ -10,6 +10,8 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.gh.common.constant.Constants
import com.gh.common.dialog.InstallPermissionDialogFragment
import com.gh.common.runOnIoThread
import com.gh.common.runOnUiThread
import com.gh.common.xapk.XapkInstaller
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.BuildConfig
@ -77,20 +79,26 @@ object PackageInstaller {
return
}
if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
runOnIoThread {
if (PackageUtils.isInstallable(context, pkgPath)) {
runOnUiThread {
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
val installIntent = getInstallIntent(context, pkgPath)
context.startActivity(installIntent)
} else {
if (isPluggin) {
DialogHelper.showPluginDialog(context) {
uninstall(context, pkgPath)
val installIntent = getInstallIntent(context, pkgPath)
context.startActivity(installIntent)
}
} else {
// 非插件化的同包名不同签名冲突
DialogHelper.showSignatureConflictDialog(context) {
uninstall(context, pkgPath)
runOnUiThread {
if (isPluggin) {
DialogHelper.showPluginDialog(context) {
uninstall(context, pkgPath)
}
} else {
// 非插件化的同包名不同签名冲突
DialogHelper.showSignatureConflictDialog(context) {
uninstall(context, pkgPath)
}
}
}
}
}

View File

@ -16,8 +16,10 @@ import android.os.PowerManager;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.g00fy2.versioncompare.Version;
import com.gh.common.AppExecutor;
import com.gh.common.xapk.XapkInstaller;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.ApkEntity;
@ -45,7 +47,9 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@ -158,6 +162,42 @@ public class PackageUtils {
return getMetaData(HaloApp.getInstance().getApplication(), packageName, "gh_id");
}
@Nullable
public static Map<String, String> getSideLoadedInfo() {
Context context = HaloApp.getInstance().getApplicationContext();
String packageName = null;
try {
final PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
final PackageManager packageManager = context.getPackageManager();
if (packageInfo != null && packageManager != null) {
packageName = packageInfo.packageName;
// getInstallSourceInfo requires INSTALL_PACKAGES permission which is only given to system
// apps.
final String installerPackageName = packageManager.getInstallerPackageName(packageName);
final Map<String, String> sideLoadedInfo = new HashMap<>();
if (installerPackageName != null) {
sideLoadedInfo.put("is_side_loaded", "false");
// could be amazon, google play etc
sideLoadedInfo.put("installer_store", installerPackageName);
} else {
// if it's installed via adb, system apps or untrusted sources
sideLoadedInfo.put("is_side_loaded", "true");
}
return sideLoadedInfo;
}
} catch (Exception e) {
Utils.log(e.getLocalizedMessage());
}
return null;
}
/*
* 判断是否是插件包
@ -188,9 +228,13 @@ public class PackageUtils {
return null;
}
// TODO 找一个更好的办法来比较签名并且不触发 ANR
// TODO 找一个更高效的方式来比较 V2 签名
public static boolean compareSignatureBetweenInstalledAppWithApk(Context context, String packageName, String apkFilePath) {
try {
AppExecutor.getUiExecutor().execute(() -> {
ToastUtils.toast("安装包校验中约需要3~5秒请稍候");
});
// 据 Sentry 统计,刚上架一个周末的包里对这个方法有 700+ 次调用,然后其中一部分会造成 ANR
Signature sig = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures[0];
@ -243,11 +287,14 @@ public class PackageUtils {
}
/**
* 根据 path 获取 apk 信息确定处理方式
* 根据 path 获取 apk 是否可安装 (全新安装或覆盖安装)
*
* 由于部分不存在 V1 签名的大安装包在调用系统 API 获取签名信息时会非常慢,所以请在工作线程里调用此方法
*
* @return true 为直接唤起系统 PackageInstaller, false 为需要插件化
* @return true 为直接唤起系统 PackageInstaller, false 为需要插件化
*/
public static boolean isCanLaunchSetup(Context context, String path) {
@WorkerThread
public static boolean isInstallable(Context context, String path) {
String packageName = getPackageNameByPath(context, path);
if (TextUtils.isEmpty(packageName)) {

View File

@ -3,6 +3,7 @@ package com.gh.common.util
import android.content.Context
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextPaint
@ -70,6 +71,13 @@ class SpanBuilder(content: CharSequence) {
return this
}
//添加图标
fun image(start: Int, end: Int, drawable: Drawable): SpanBuilder {
val imageSpan = CenterImageSpan(drawable)
spannableString.setSpan(imageSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
return this
}
fun click(start: Int, end: Int, colorRes: Int, isUnderlineText: Boolean = false, onClick: () -> Unit): SpanBuilder {
val clickSpan = object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {

View File

@ -46,7 +46,7 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
val absolutePath = Environment.getExternalStorageDirectory().absolutePath
val xapkFile = File(path)
ZipFile(xapkFile).use { zip ->
val unzipClosure: (zip: ZipFile) -> Unit = { zip ->
for (zipEntry in zip.entries().asSequence()) {
val outputFile = if (zipEntry.name.getExtension() == XapkInstaller.XAPK_DATA_EXTENSION_NAME) {
File(absolutePath + File.separator + zipEntry.name)
@ -91,7 +91,7 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
bytes = input.read(buffer)
if (canceled) {
mUnzipListener.onCancel(mDownloadEntity)
return
return@use
} else {
// 防止多次短时间内多次触发onProgress方法导致阻塞主线程低端机会出现十分明显的卡顿
debounceActionWithInterval(-1, 500) {
@ -104,6 +104,16 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
mUnzipListener.onNext(mDownloadEntity, outputFile.path)
}
}
// Kotlin 1.4.X 在安卓 4.4 以下使用 use 默认关闭 ZipFile 的流时会触发
// java.lang.IncompatibleClassChangeError: interface not implemented 的 Error (Throwable)
// 但实测是不影响解压的,所以这里换用 let 不关闭流,确保不闪退,并且不影响解压结果
// 帮用户解压了,但游戏能不能安装就看天吧 (毕竟支持4.X的游戏也不多了)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ZipFile(File(path)).use { unzipClosure.invoke(it) }
} else {
ZipFile(File(path)).let { unzipClosure.invoke(it) }
}
mUnzipListener.onSuccess(mDownloadEntity)
} catch (e: Exception) {
if (BuildConfig.DEBUG) throw e
@ -208,18 +218,21 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
private fun getUnzipSize(path: String): Long {
var totalSize = 0L
// 这里安卓5.0以下使用use会报错闪退
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ZipFile(File(path)).use {
for (entry in it.entries()) {
totalSize += entry.size
}
}
} else {
for (entry in ZipFile(File(path)).entries()) {
val calculateSizeClosure: (zip: ZipFile) -> Unit = { zip ->
for (entry in zip.entries()) {
totalSize += entry.size
}
}
// Kotlin 1.4.X 在安卓 4.4 以下使用 use 默认ZipFile 的流时会触发
// java.lang.IncompatibleClassChangeError: interface not implemented 的 Error (Throwable)
// 实测是不影响解压,所以这里换用 let 不关闭流,确保不闪退
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ZipFile(File(path)).use { calculateSizeClosure.invoke(it) }
} else {
ZipFile(File(path)).let { calculateSizeClosure.invoke(it) }
}
return totalSize
}
}

View File

@ -257,7 +257,7 @@ public class DownloadManager implements DownloadStatusListener {
// 下载模拟器游戏配置文件,地址是 "模拟器游戏类型根目录/cheat/"
if (!TextUtils.isEmpty(gameEntity.getSimulatorGameConfig())) {
String configFilePath = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/cheat/" + gameEntity.getName() + ".ini";
String configFilePath = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/cheat/" + apkEntity.getPackageName()+ ".ini";
AppExecutor.getIoExecutor().execute(() -> {
FileUtils.downloadFile(gameEntity.getSimulatorGameConfig(), configFilePath);
});

View File

@ -61,6 +61,7 @@ import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.QuickLoginHelper;
import com.gh.common.util.SPUtils;
import com.gh.common.util.SentryHelper;
import com.gh.common.util.ShareUtils;
import com.gh.common.util.ToastUtils;
import com.gh.common.util.UrlFilterUtils;
@ -93,6 +94,7 @@ import com.github.piasy.biv.BigImageViewer;
import com.github.piasy.biv.loader.fresco.FrescoImageLoader;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.halo.assistant.HaloApp;
import com.lightgame.download.DownloadEntity;
@ -456,6 +458,7 @@ public class MainActivity extends BaseActivity {
if (view != null) {
view.setVisibility(View.GONE);
ExtensionsKt.removeFromParent(view);
}
checkDialog();
@ -558,17 +561,27 @@ public class MainActivity extends BaseActivity {
break;
case HOST_LAUNCH_SIMULATOR_GAME:
String json = getIntent().getStringExtra(EntranceUtils.KEY_GAME);
GameEntity gameEntity = GsonUtils.getGson().fromJson(json, new TypeToken<GameEntity>() {
}.getType());
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
if (downloadEntity != null) {
File file = new File(downloadEntity.getPath());
if (!file.exists()) {
ToastUtils.INSTANCE.showToast("文件已被删除,无法启动");
return;
}
try {
GameEntity gameEntity = GsonUtils.getGson().fromJson(json, new TypeToken<GameEntity>() {
}.getType());
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
if (downloadEntity != null) {
File file = new File(downloadEntity.getPath());
if (!file.exists()) {
ToastUtils.INSTANCE.showToast("文件已被删除,无法启动");
return;
}
SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity);
SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity);
}
} catch (JsonSyntaxException exception) {
exception.printStackTrace();
toast("模拟器游戏启动失败,请联系客服反馈相关信息");
SentryHelper.INSTANCE.onEvent(
"SIMULATOR_SHORTCUT_LAUNCH_ERROR",
"raw_json",
json
);
}
break;
case KEY_MARKET_DETAILS:

View File

@ -56,7 +56,7 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mListRv.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
mListRv?.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
mListRv?.layoutParams = (mListRv?.layoutParams as ViewGroup.MarginLayoutParams).apply {
leftMargin = 12F.dip2px()
rightMargin = 12F.dip2px()
@ -81,11 +81,11 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
sizeTv.text = entity.name
if (index == mCurrentIndex) {
sizeTv.setTextColor(R.color.theme_font.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_e6f9fa)
sizeTv.setTextColor(R.color.white.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_00dba4)
} else {
sizeTv.setTextColor(R.color.text_333333.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5)
sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa)
}
root.setOnClickListener {
@ -125,7 +125,7 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
sizeTv.text = "更多 >"
sizeTv.setTextColor(R.color.text_333333.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5)
sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa)
root.setOnClickListener {
IntegralLogHelper.run {
@ -160,12 +160,12 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
}
}
mListRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
mListRv?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (mEntrance == "光能中心" && mListRv.layoutManager?.itemCount ?:0 == 11) {
mListRv.layoutManager?.run {
if (mEntrance == "光能中心" && mListRv?.layoutManager?.itemCount ?:0 == 11) {
mListRv?.layoutManager?.run {
if (childCount > 0 && newState == RecyclerView.SCROLL_STATE_IDLE && mLastVisibleItemPosition >= itemCount - 1) {
mBinding.bottom.visibility = View.VISIBLE
} else {
@ -177,8 +177,8 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (mEntrance == "光能中心" && mListRv.layoutManager?.itemCount ?:0 == 11) {
mListRv.layoutManager?.run {
if (mEntrance == "光能中心" && mListRv?.layoutManager?.itemCount ?:0 == 11) {
mListRv?.layoutManager?.run {
if (mLastPositions == null) {
mLastPositions = IntArray((this as StaggeredGridLayoutManager).spanCount)
}
@ -209,11 +209,11 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
sizeTv.text = entity.name
if (index == mCurrentIndex) {
sizeTv.setTextColor(R.color.theme_font.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_e6f9fa)
sizeTv.setTextColor(R.color.white.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_00dba4)
} else {
sizeTv.setTextColor(R.color.text_333333.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5)
sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa)
}
root.setOnClickListener {
@ -243,7 +243,7 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
sizeTv.text = "更多 >"
sizeTv.setTextColor(R.color.text_333333.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5)
sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa)
root.setOnClickListener {
IntegralLogHelper.run {
@ -276,11 +276,11 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
for (index in 0 until categoryContainer.childCount) {
val sizeTv = categoryContainer.getChildAt(index) as TextView
if (index == mCurrentIndex) {
sizeTv.setTextColor(R.color.theme_font.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_e6f9fa)
sizeTv.setTextColor(R.color.white.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_00dba4)
} else {
sizeTv.setTextColor(R.color.text_333333.toColor())
sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5)
sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa)
}
}
}
@ -325,9 +325,9 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (mEntrance == "光能中心") {
// if (mEntrance == "光能中心") {
mListRefresh?.isNestedScrollingEnabled = false
}
// }
}
override fun onDestroyView() {
@ -345,15 +345,15 @@ class CommodityFragment : ListFragment<CommodityEntity, CommodityViewModel>() {
override fun onLoadEmpty() {
super.onLoadEmpty()
// RecyclerView 被隐藏的话会导致不能 AppBar 不能滑动
mListRv.visibility = View.VISIBLE
mListRv?.visibility = View.VISIBLE
}
override fun onLoadError() {
super.onLoadError()
mListRv.visibility = View.VISIBLE
mListRv?.visibility = View.VISIBLE
}
fun setNestedScrollingEnabled(enable: Boolean) {
mListRv.isNestedScrollingEnabled = enable
mListRv?.isNestedScrollingEnabled = enable
}
}

View File

@ -24,20 +24,11 @@ class EnergyCenterActivity : NormalActivity() {
companion object {
fun getIntent(context: Context?): Intent? {
return getIntent(context, false, 0)
}
fun getIntent(context: Context?, isSign: Boolean): Intent? {
return getIntent(context, isSign, 0)
return getIntent(context, 0)
}
fun getIntent(context: Context?, initTabIndex: Int): Intent? {
return getIntent(context, false, initTabIndex)
}
fun getIntent(context: Context?, isSign: Boolean = false, initTabIndex: Int): Intent? {
val bundle = Bundle()
bundle.putBoolean(EntranceUtils.KEY_IS_SIGN, isSign)
bundle.putInt(EntranceUtils.KEY_TAB_INDEX, if (initTabIndex == 0 || initTabIndex == 1) initTabIndex else 0)
return getTargetIntent(context, EnergyCenterActivity::class.java, EnergyCenterFragment::class.java, bundle)
}

View File

@ -1,22 +1,20 @@
package com.gh.gamecenter.energy
import android.graphics.Typeface
import android.os.Build
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import android.widget.CheckedTextView
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.*
import androidx.fragment.app.Fragment
import butterknife.OnClick
import com.gh.base.adapter.FragmentAdapter
import com.gh.base.fragment.BaseLazyFragment
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentEnergyCenterBinding
import com.gh.gamecenter.databinding.TabItemMainBinding
import com.gh.gamecenter.entity.CommodityCategoryEntity
import com.gh.gamecenter.entity.SignStatusEntity
import com.gh.gamecenter.entity.UserInfoEntity
@ -24,8 +22,8 @@ import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.personalhome.UserHomeViewModel
import com.gh.gamecenter.user.UserViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.tabs.TabLayout
import com.halo.assistant.HaloApp
import kotlin.math.abs
class EnergyCenterFragment : BaseLazyFragment() {
@ -35,11 +33,11 @@ class EnergyCenterFragment : BaseLazyFragment() {
private var mUserHomeViewModel: UserHomeViewModel? = null
private var mEnergyCenterViewModel: EnergyCenterViewModel? = null
private val mTitleList = listOf("赚光能", "兑换区")
private var mTabList = arrayListOf<TextView>()
private var mFragmentsList = ArrayList<Fragment>()
private var mCategoryList = ArrayList<CommodityCategoryEntity>()
private var mUserInfo: UserInfoEntity? = null
private var mEnergy = 0
private var mAutoSign = false
private var mEnergy = 0L
private var mSignStatus: SignStatusEntity? = null
private var mInitTabIndex = 0
private var mBehavior: BottomSheetBehavior<RelativeLayout>? = null
@ -52,20 +50,6 @@ class EnergyCenterFragment : BaseLazyFragment() {
override fun onFragmentResume() {
super.onFragmentResume()
// 6:00-18:59 展示白天背景,否则展示夜晚背景
if (System.currentTimeMillis() >= TimeUtils.getTimeOfToday(6)
&& System.currentTimeMillis() < TimeUtils.getTimeOfToday(19) ) {
mBinding?.run {
background.setImageResource(R.drawable.bg_energy_center_day)
signTitle.setTextColor(R.color.theme_font.toColor())
}
} else {
mBinding?.run {
background.setImageResource(R.drawable.bg_energy_center_night)
signTitle.setTextColor(R.color.white.toColor())
}
}
if (NetworkUtils.isNetworkConnected(requireContext())) {
if (CheckLoginUtils.isLogin()) {
mUserHomeViewModel?.getUserEnergy()
@ -77,7 +61,6 @@ class EnergyCenterFragment : BaseLazyFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAutoSign = arguments?.getBoolean(EntranceUtils.KEY_IS_SIGN) ?: false
mInitTabIndex = arguments?.getInt(EntranceUtils.KEY_TAB_INDEX) ?: 0
if (mInitTabIndex != 0 && mInitTabIndex != 1) mInitTabIndex = 0
@ -107,13 +90,12 @@ class EnergyCenterFragment : BaseLazyFragment() {
mUserHomeViewModel?.energy?.observeNonNull(viewLifecycleOwner) {
mEnergy = it
mBinding?.userEnergy?.text = "${it}光能"
mBinding?.userEnergy?.text = it.toString()
}
mUserHomeViewModel?.sign?.observeNonNull(this) {
mSignStatus = it
DialogUtils.showSignSuccessDialog(requireContext()) {
initSignView(it)
mUserHomeViewModel?.getUserEnergy()
refreshTaskList()
}
@ -121,18 +103,17 @@ class EnergyCenterFragment : BaseLazyFragment() {
mUserHomeViewModel?.signStatus?.observeNonNull(this) {
mSignStatus = it
initSignView(it)
// 今天未签到且需要自动签到才调用签到接口
if (!it.todaySignIn && mAutoSign && !ClickUtils.isFastDoubleClick(990)) {
if (!it.todaySignIn && !ClickUtils.isFastDoubleClick(990)) {
mUserHomeViewModel?.signIn()
}
}
mBinding?.run {
background.layoutParams = background.layoutParams.apply {
val screenWidth = resources.displayMetrics.widthPixels
height = screenWidth * 400 / 360
}
// background.layoutParams = background.layoutParams.apply {
// val screenWidth = resources.displayMetrics.widthPixels
// height = screenWidth * 400 / 360
// }
val screenHeight = when {
Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 -> {
@ -154,15 +135,22 @@ class EnergyCenterFragment : BaseLazyFragment() {
}
mBehavior = BottomSheetBehavior.from(bottomSheet)
val toolbarHeight = screenHeight - DisplayUtils.getStatusBarHeight(resources) - 48F.dip2px()
mBehavior?.peekHeight = screenHeight - 312F.dip2px()
// val toolbarHeight = screenHeight - DisplayUtils.getStatusBarHeight(resources) - 48F.dip2px()
mBehavior?.peekHeight = screenHeight - 320F.dip2px()
val layoutParams = bottomSheet.layoutParams
layoutParams.height = toolbarHeight
bottomSheet.layoutParams = layoutParams
// val layoutParams = bottomSheet.layoutParams
// layoutParams.height = toolbarHeight
// bottomSheet.layoutParams = layoutParams
mBehavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
mBinding?.topContainer?.visibility = View.VISIBLE
} else {
mBinding?.topContainer?.visibility = View.INVISIBLE
}
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
mBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
}
@ -173,30 +161,18 @@ class EnergyCenterFragment : BaseLazyFragment() {
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
})
}
}
private fun initSignView(entity: SignStatusEntity) {
mBinding?.run {
if (entity.todaySignIn) {
signToday.visibility = View.GONE
signedContainer.visibility = View.VISIBLE
serialSignTv.text = "已连续签到${entity.serialSign}"
} else {
signToday.visibility = View.VISIBLE
signedContainer.visibility = View.GONE
}
if (entity.sevenDaySerialSign == 0) return
for (i in 1..entity.sevenDaySerialSign) {
updateSignedViewForDay(i)
if (i != 7) {
updateLineViewForDay(i, i != entity.sevenDaySerialSign)
override fun onSlide(bottomSheet: View, slideOffset: Float) {
mBinding?.run {
if (slideOffset > 0.95) {
collapsedBg.visibility = View.GONE
expandedBg.visibility = View.VISIBLE
} else {
collapsedBg.visibility = View.VISIBLE
expandedBg.visibility = View.GONE
}
}
}
}
})
}
}
@ -206,29 +182,6 @@ class EnergyCenterFragment : BaseLazyFragment() {
}
}
private fun updateSignedViewForDay(day: Int) {
mBinding?.run {
val index = (day - 1) * 2
val dayContainer = signDaysContainer.getChildAt(index) as RelativeLayout
val dayIv = dayContainer.getChildAt(0) as ImageView
dayIv.setImageResource(R.drawable.ic_energy_center_signed)
}
}
private fun updateLineViewForDay(day: Int, isStraight: Boolean) {
mBinding?.run {
val index = (day - 1) * 2 + 1
val lineContainer = signDaysContainer.getChildAt(index) as LinearLayout
val straightLine = lineContainer.getChildAt(0)
val dottedLine = lineContainer.getChildAt(1)
if (isStraight) {
straightLine.visibility = View.VISIBLE
} else {
dottedLine.visibility = View.VISIBLE
}
}
}
private fun initViewpager() {
mBinding?.run {
mFragmentsList.clear()
@ -249,33 +202,56 @@ class EnergyCenterFragment : BaseLazyFragment() {
viewpager.offscreenPageLimit = mFragmentsList.size
viewpager.adapter = FragmentAdapter(childFragmentManager, mFragmentsList, mTitleList)
viewpager.doOnScroll(
onPageSelected = { position ->
updateTabTextStyle(position, 0F)
},
onPageScrolled = { position, positionOffset, _ ->
if (position + 1 != mTabList.size) {
mTabList[position].run {
textSize = (DEFAULT_TAB_TEXT_SIZE + ((1 - positionOffset) * 4)).roundTo(1)
// setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, 1 - positionOffset))
}
mTabList[position + 1].run {
textSize = (DEFAULT_TAB_TEXT_SIZE + ((positionOffset) * 4)).roundTo(1)
// setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, positionOffset))
}
// 多 tab 切换的时候可能会出现某些 tab 的文字没有回归到原始大小的问题的问题 (positionOffset 不保证连续)
for ((index, tabTv) in mTabList.withIndex()) {
if (abs(index - position) >= 2) {
if (tabTv.textSize != DEFAULT_TAB_TEXT_SIZE) {
tabTv.textSize = DEFAULT_TAB_TEXT_SIZE
// tabTv.setTextColor(TAB_DEFAULT_COLOR)
}
}
}
}
updateTabTextStyle(position, positionOffset)
}
)
tabLayout.setupWithViewPager(viewpager)
indicatorView.run {
setupWithTabLayout(tabLayout)
setupWithViewPager(viewpager)
setIndicatorWidth(18)
}
for (i in 0 until tabLayout.tabCount) {
val tab = tabLayout.getTabAt(i) ?: continue
val tabTitle = if (tab.text != null) tab.text.toString() else ""
val tabView = getTabView(tabTitle)
tab.customView = tabView
val tabViewBinding = generateTabView(tabTitle)
mTabList.add(tabViewBinding.tabTitle)
tab.customView = tabViewBinding.root
tab.view.setPadding(0, 0, 0, 0)
}
viewpager.currentItem = mInitTabIndex
tabLayout.getTabAt(mInitTabIndex)?.let { updateTabStyle(it, true) }
tabLayout.getTabAt(mInitTabIndex)?.let { updateTabTextStyle(mInitTabIndex, 0F) }
if (mInitTabIndex == 1) setNestedScrollingEnabledForIndex(mInitTabIndex)
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
updateTabStyle(tab, true)
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
updateTabStyle(tab, false)
}
override fun onTabSelected(tab: TabLayout.Tab?) {
updateTabStyle(tab, true)
}
})
// 处理BottomSheetBehavior的ViewPager嵌套RecyclerView滑动冲突问题
viewpager.addOnPageChangeListener {
if (it == 0) {
@ -289,31 +265,44 @@ class EnergyCenterFragment : BaseLazyFragment() {
}
}
private fun updateTabTextStyle(selectedPosition: Int, positionOffset: Float) {
for ((index, titleTv) in mTabList.withIndex()) {
if (index == selectedPosition) {
// titleTv.setTextColor(TAB_SELECTED_COLOR)
if (positionOffset == 0F) {
titleTv.setTypeface(null, Typeface.NORMAL)
titleTv.setTypeface(titleTv.typeface, Typeface.BOLD)
}
} else {
// titleTv.setTextColor(TAB_DEFAULT_COLOR)
if (positionOffset == 0F) {
titleTv.setTypeface(null, Typeface.NORMAL)
}
}
}
}
private fun generateTabView(title: String): TabItemMainBinding {
val binding = TabItemMainBinding.inflate(LayoutInflater.from(requireContext()))
binding.tabTitle.run {
text = title
textSize = DEFAULT_TAB_TEXT_SIZE
setTextColor(TAB_TEXT_COLOR)
}
binding.invisibleTabTitle.run {
text = title
textSize = DEFAULT_TAB_TEXT_SIZE
}
return binding
}
private fun setNestedScrollingEnabledForIndex(index: Int) {
(mFragmentsList[0] as TaskFragment).setNestedScrollingEnabled(index == 0)
(mFragmentsList[1] as CommodityFragment).setNestedScrollingEnabled(index == 1)
mBinding?.bottomSheet?.requestLayout()
}
private fun getTabView(title: String): View {
val view = LayoutInflater.from(HaloApp.getInstance().application.baseContext).inflate(R.layout.tab_item_energy_center, null)
val tabTitle = view.findViewById<View>(R.id.tab_title)
if (tabTitle is CheckedTextView) {
tabTitle.text = title
}
return view
}
private fun updateTabStyle(tab: TabLayout.Tab?, isChecked: Boolean) {
val tabView = tab?.customView
tabView?.run {
val tabIndicator = findViewById<ImageView>(R.id.tab_indicator)
tabIndicator.visibility = if (isChecked) View.VISIBLE else View.INVISIBLE
}
}
@OnClick(R.id.backIv, R.id.userEnergyContainer, R.id.energyRuleTv, R.id.inviteFriends, R.id.signToday, R.id.signRule,
R.id.oneDay, R.id.twoDay, R.id.threeDay, R.id.fourDay, R.id.fiveDay, R.id.sixDay, R.id.sevenDay)
@OnClick(R.id.backIv, R.id.userEnergyContainer, R.id.energyRuleTv, R.id.signIv, R.id.inviteIv)
fun onViewClicked(v: View) {
when (v.id) {
R.id.backIv -> requireActivity().finish()
@ -338,7 +327,15 @@ class EnergyCenterFragment : BaseLazyFragment() {
DirectUtils.directToEnergyRulePage(requireContext())
}
R.id.inviteFriends -> {
R.id.signIv -> {
ifLogin("光能中心-每日签到") {
mSignStatus?.run {
DialogUtils.showEnergySignDialog(requireContext(), sevenDaySerialSign)
}
}
}
R.id.inviteIv -> {
IntegralLogHelper.run {
log("click_invite_friend", LOCATION)
log("view_invite_friend", "邀请好友页")
@ -348,87 +345,6 @@ class EnergyCenterFragment : BaseLazyFragment() {
DirectUtils.directToInviteFriends(requireContext())
}
}
R.id.signRule -> {
IntegralLogHelper.log("click_sign_rule", LOCATION)
DialogUtils.showSignRuleDialog(requireContext())
}
R.id.signToday -> {
ifLogin("光能中心-签到气泡") {
dealSignIn()
}
}
R.id.oneDay -> {
ifLogin("光能中心-1天") {
mSignStatus?.run {
if (!todaySignIn && sevenDaySerialSign == 0) {
dealSignIn()
}
}
}
}
R.id.twoDay -> {
ifLogin("光能中心-2天") {
mSignStatus?.run {
if (!todaySignIn && sevenDaySerialSign == 1) {
dealSignIn()
}
}
}
}
R.id.threeDay -> {
ifLogin("光能中心-3天") {
mSignStatus?.run {
if (!todaySignIn && sevenDaySerialSign == 2) {
dealSignIn()
}
}
}
}
R.id.fourDay -> {
ifLogin("光能中心-4天") {
mSignStatus?.run {
if (!todaySignIn && sevenDaySerialSign == 3) {
dealSignIn()
}
}
}
}
R.id.fiveDay -> {
ifLogin("光能中心-5天") {
mSignStatus?.run {
if (!todaySignIn && sevenDaySerialSign == 4) {
dealSignIn()
}
}
}
}
R.id.sixDay -> {
ifLogin("光能中心-6天") {
mSignStatus?.run {
if (!todaySignIn && sevenDaySerialSign == 5) {
dealSignIn()
}
}
}
}
R.id.sevenDay -> {
ifLogin("光能中心-7天") {
mSignStatus?.run {
if (!todaySignIn && sevenDaySerialSign == 6) {
dealSignIn()
}
}
}
}
}
}
@ -448,5 +364,7 @@ class EnergyCenterFragment : BaseLazyFragment() {
companion object {
const val LOCATION = "光能中心"
var TAB_TEXT_COLOR: Int = R.color.text_00DBA4.toColor()
var DEFAULT_TAB_TEXT_SIZE = 16F
}
}

View File

@ -1,10 +1,12 @@
package com.gh.gamecenter.energy
import android.graphics.Typeface
import android.os.Build
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import android.widget.CheckedTextView
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
@ -14,13 +16,14 @@ import com.gh.base.fragment.BaseLazyFragment
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentEnergyHouseBinding
import com.gh.gamecenter.databinding.TabItemCommodityBinding
import com.gh.gamecenter.entity.CommodityCategoryEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.entity.UserInfoEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.personalhome.UserHomeViewModel
import com.gh.gamecenter.user.UserViewModel
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.tabs.TabLayout
import com.halo.assistant.HaloApp
import kotlin.math.abs
@ -34,13 +37,15 @@ class EnergyHouseFragment: BaseLazyFragment() {
private var mCommodityCategories: List<CommodityCategoryEntity>? = null
private var mUserInfo: UserInfoEntity? = null
private val mTitleList = ArrayList<String>()
private var mTabList = arrayListOf<TextView>()
private val mFragments = ArrayList<Fragment>()
private val mRollNotices = ArrayList<String>()
private var mCurrentSizeIndex = 0
private var mCurrentSize = SubjectSettingEntity.Size()
private var mEnergy = 0
private var mEnergy = 0L
private var mCategoryId = ""
private var mInitIndex = 0
private var mBehavior: BottomSheetBehavior<RelativeLayout>? = null
override fun getLayoutId() = 0
@ -83,7 +88,7 @@ class EnergyHouseFragment: BaseLazyFragment() {
mEnergy = it
mBinding?.run {
userEnergyContainer.visibility = View.VISIBLE
userEnergy.text = "${it}光能"
userEnergy.text = it.toString()
}
}
@ -103,26 +108,45 @@ class EnergyHouseFragment: BaseLazyFragment() {
}
mBinding?.run {
appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
val invisibleOffset = (104F - 48F).dip2px() - DisplayUtils.getStatusBarHeight(resources)
if (abs(verticalOffset) >= invisibleOffset) {
toolbar.setBackgroundColor(R.color.white.toColor())
backIv.setImageResource(R.drawable.ic_bar_back)
title.setTextColor(R.color.text_333333.toColor())
exchangeRuleTv.setTextColor(R.color.text_333333.toColor())
EnergyRuleIv.setImageResource(R.drawable.icon_doubt_black)
tabLayout.setBackgroundColor(R.color.white.toColor())
sizeContainer.setBackgroundColor(R.color.white.toColor())
DisplayUtils.setStatusBarColor(requireActivity(), R.color.white, true)
} else {
toolbar.setBackgroundColor(R.color.transparent.toColor())
backIv.setImageResource(R.drawable.ic_bar_back_light)
title.setTextColor(R.color.white.toColor())
exchangeRuleTv.setTextColor(R.color.white.toColor())
EnergyRuleIv.setImageResource(R.drawable.icon_doubt_white)
tabLayout.setBackgroundColor(R.color.transparent.toColor())
sizeContainer.setBackgroundColor(R.color.transparent.toColor())
DisplayUtils.setStatusBarColor(requireActivity(), R.color.transparent, true)
// background.layoutParams = background.layoutParams.apply {
// val screenWidth = resources.displayMetrics.widthPixels
// height = screenWidth * 400 / 360
// }
val screenHeight = when {
Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 -> {
resources.displayMetrics.heightPixels
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
DisplayMetrics()
.apply { requireActivity().display?.getRealMetrics(this) }
.heightPixels
}
else -> {
@Suppress("DEPRECATION")
DisplayMetrics()
.apply { requireActivity().windowManager.defaultDisplay.getRealMetrics(this) }
.heightPixels
}
}
mBehavior = BottomSheetBehavior.from(bottomSheet)
mBehavior?.peekHeight = screenHeight - 288F.dip2px()
val layoutParams = bottomSheet.layoutParams
layoutParams.height = screenHeight - 40F.dip2px()
bottomSheet.layoutParams = layoutParams
mBehavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
mBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
}
})
}
@ -165,28 +189,69 @@ class EnergyHouseFragment: BaseLazyFragment() {
} else super.getPageTitle(position)
}
}
viewpager.doOnScroll(
onPageSelected = { position ->
updateTabTextStyle(position, 0F)
},
onPageScrolled = { position, positionOffset, _ ->
if (position + 1 != mTabList.size) {
mTabList[position].run {
textSize = (DEFAULT_TAB_TEXT_SIZE + ((1 - positionOffset) * 4)).roundTo(1)
// setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, 1 - positionOffset))
}
mTabList[position + 1].run {
textSize = (DEFAULT_TAB_TEXT_SIZE + ((positionOffset) * 4)).roundTo(1)
// setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, positionOffset))
}
// 多 tab 切换的时候可能会出现某些 tab 的文字没有回归到原始大小的问题的问题 (positionOffset 不保证连续)
for ((index, tabTv) in mTabList.withIndex()) {
if (abs(index - position) >= 2) {
if (tabTv.textSize != DEFAULT_TAB_TEXT_SIZE) {
tabTv.textSize = DEFAULT_TAB_TEXT_SIZE
// tabTv.setTextColor(TAB_DEFAULT_COLOR)
}
}
}
}
updateTabTextStyle(position, positionOffset)
}
)
tabLayout.setupWithViewPager(viewpager)
indicatorView.run {
setupWithTabLayout(tabLayout)
setupWithViewPager(viewpager)
setIndicatorWidth(18)
}
for (i in 0 until tabLayout.tabCount) {
val tab = tabLayout.getTabAt(i) ?: continue
val tabTitle = if (tab.text != null) tab.text.toString() else ""
val tabView = getTabView(tabTitle)
tab.customView = tabView
val tabViewBinding = generateTabView(
tabTitle,
i == 0,
i == tabLayout.tabCount - 1
)
mTabList.add(tabViewBinding.tabTitle)
tab.customView = tabViewBinding.root
tab.view.setPadding(0, 0, 0, 0)
}
viewpager.currentItem = mInitIndex
tabLayout.getTabAt(mInitIndex)?.let { updateTabStyle(it, true) }
tabLayout.getTabAt(mInitIndex)?.let { updateTabTextStyle(mInitIndex, 0F) }
setNestedScrollingEnabledForIndex(mInitIndex)
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
updateTabStyle(tab, true)
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
updateTabStyle(tab, false)
}
override fun onTabSelected(tab: TabLayout.Tab?) {
updateTabStyle(tab, true)
tab?.run {
mCommodityCategories?.get(position)?.run {
IntegralLogHelper.logCommodityCategory(
@ -200,29 +265,53 @@ class EnergyHouseFragment: BaseLazyFragment() {
}
}
})
viewpager.addOnPageChangeListener {
setNestedScrollingEnabledForIndex(it)
}
}
initSize()
}
private fun getTabView(title: String): View {
val view = LayoutInflater.from(HaloApp.getInstance().application.baseContext).inflate(R.layout.tab_item_energy_house, null)
val tabTitle = view.findViewById<View>(R.id.tab_title)
if (tabTitle is CheckedTextView) {
tabTitle.text = title
private fun setNestedScrollingEnabledForIndex(currentIndex: Int) {
mFragments.forEachIndexed { index, fragment ->
(fragment as CommodityFragment).setNestedScrollingEnabled(currentIndex == index)
}
return view
mBinding?.bottomSheet?.requestLayout()
}
private fun updateTabStyle(tab: TabLayout.Tab?, isChecked: Boolean) {
val tabView = tab?.customView
tabView?.run {
val tabIndicator = findViewById<ImageView>(R.id.tab_indicator)
tabIndicator.visibility = if (isChecked) View.VISIBLE else View.INVISIBLE
private fun updateTabTextStyle(selectedPosition: Int, positionOffset: Float) {
for ((index, titleTv) in mTabList.withIndex()) {
if (index == selectedPosition) {
// titleTv.setTextColor(TAB_SELECTED_COLOR)
if (positionOffset == 0F) {
titleTv.setTypeface(null, Typeface.NORMAL)
titleTv.setTypeface(titleTv.typeface, Typeface.BOLD)
}
} else {
// titleTv.setTextColor(TAB_DEFAULT_COLOR)
if (positionOffset == 0F) {
titleTv.setTypeface(null, Typeface.NORMAL)
}
}
}
}
private fun generateTabView(title: String, isFirst: Boolean, isLast: Boolean): TabItemCommodityBinding {
val binding = TabItemCommodityBinding.inflate(LayoutInflater.from(requireContext()))
binding.tabTitle.run {
val padLeft = if (isFirst) 16F.dip2px() else 8F.dip2px()
val padRight = if (isLast) 16F.dip2px() else 8F.dip2px()
setPadding(padLeft, 0, padRight, 0)
text = title
textSize = DEFAULT_TAB_TEXT_SIZE
setTextColor(TAB_TEXT_COLOR)
}
return binding
}
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
return arrayListOf<SubjectSettingEntity.Size>().apply {
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部"))
@ -261,11 +350,11 @@ class EnergyHouseFragment: BaseLazyFragment() {
val item = sizeContainer.getChildAt(index)
val tv = item.findViewById<TextView>(R.id.size_tv)
if (position == index) {
tv.setTextColor(R.color.theme_font.toColor())
tv.setBackgroundResource(R.drawable.button_round_e6f8fa)
tv.setTextColor(R.color.white.toColor())
tv.setBackgroundResource(R.drawable.button_round_00dba4)
} else {
tv.setTextColor(R.color.text_666666.toColor())
tv.setBackgroundResource(R.drawable.button_round_f5f5f5)
tv.setTextColor(R.color.text_333333.toColor())
tv.setBackgroundResource(R.drawable.button_round_ebf9fa)
}
}
}
@ -344,5 +433,7 @@ class EnergyHouseFragment: BaseLazyFragment() {
companion object {
const val LOCATION = "光能屋"
var TAB_TEXT_COLOR: Int = R.color.text_00DBA4.toColor()
var DEFAULT_TAB_TEXT_SIZE = 14F
}
}

View File

@ -37,12 +37,10 @@ class HorizontalTaskAdapter(context: Context,
if (task.status == "finished") {
taskBtn.text = "已完成"
taskBtn.setTextColor(R.color.text_cccccc.toColor())
taskBtn.setBackgroundResource(R.drawable.button_round_f5f5f5)
taskBtn.setBackgroundResource(R.drawable.bg_energy_task_btn_finished)
} else {
taskBtn.text = "去完成"
taskBtn.setTextColor(R.color.theme_font.toColor())
taskBtn.setBackgroundResource(R.drawable.button_round_ebfdff)
taskBtn.text = "+${task.energy}光能"
taskBtn.setBackgroundResource(R.drawable.bg_energy_task_btn_normal)
}
taskNotice.setOnClickListener {

View File

@ -16,6 +16,7 @@ import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.databinding.DailyTaskItemBinding
import com.gh.gamecenter.databinding.NoviceTasksItemBinding
import com.gh.gamecenter.databinding.TaskBottomItemBinding
import com.gh.gamecenter.databinding.TaskTitleItemBinding
import com.gh.gamecenter.gamedetail.dialog.InviteCodeDialog
import com.gh.gamecenter.manager.UserManager
@ -25,21 +26,19 @@ class TaskAdapter(context: Context) : ListAdapter<TaskItemData>(context) {
private val mEntrance = "光能中心-任务列表"
override fun getItemCount(): Int {
return if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT
return if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size
}
override fun getItemViewType(position: Int): Int {
return if (position == itemCount - 1) {
ItemViewType.ITEM_FOOTER
} else {
val item = mEntityList[position]
when {
val item = mEntityList[position]
return when {
item.noviceTasks != null -> TYPE_NOVICE
item.title != null -> TYPE_TITLE
else -> TYPE_DAILY
}
item.dailyTask != null -> TYPE_DAILY
else -> TYPE_BOTTOM
}
}
@ -59,6 +58,8 @@ class TaskAdapter(context: Context) : ListAdapter<TaskItemData>(context) {
(oldItem.dailyTask?.id == newItem.dailyTask?.id && oldItem.dailyTask?.status == newItem.dailyTask?.status)
}
oldItem?.bottom != null && newItem?.bottom != null -> true
else -> super.areItemsTheSame(oldItem, newItem)
}
}
@ -75,6 +76,8 @@ class TaskAdapter(context: Context) : ListAdapter<TaskItemData>(context) {
(oldItem.dailyTask?.id == newItem.dailyTask?.id && oldItem.dailyTask?.status == newItem.dailyTask?.status)
}
oldItem?.bottom != null && newItem?.bottom != null -> true
else -> super.areContentsTheSame(oldItem, newItem)
}
}
@ -102,6 +105,8 @@ class TaskAdapter(context: Context) : ListAdapter<TaskItemData>(context) {
TYPE_TITLE -> TaskTitleViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.task_title_item, parent, false))
TYPE_BOTTOM -> TaskBottomViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.task_bottom_item, parent, false))
else -> DailyTaskViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.daily_task_item, parent, false))
}
}
@ -119,13 +124,7 @@ class TaskAdapter(context: Context) : ListAdapter<TaskItemData>(context) {
is TaskTitleViewHolder -> {
holder.binding.run {
val titleStr = mEntityList[position].title!!
var top = if (titleStr == "新手任务") 16F.dip2px() else 32F.dip2px()
var bottom = if (titleStr == "新手任务") 16F.dip2px() else 5F.dip2px()
root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
topMargin = top
bottomMargin = bottom
}
title.text = titleStr
topPic.setImageResource(if (titleStr == "日常任务") R.drawable.pic_daily_task_title else R.drawable.pic_fix_task_title)
}
}
@ -135,7 +134,15 @@ class TaskAdapter(context: Context) : ListAdapter<TaskItemData>(context) {
entity = task
executePendingBindings()
if (task.isFixed) progress.text = ""
// if (task.isFixed) progress.text = ""
if (task.status == "finished") {
taskBtn.text = "已完成"
taskBtn.setBackgroundResource(R.drawable.bg_energy_task_btn_finished)
} else {
taskBtn.text = "+${task.energy}光能"
taskBtn.setBackgroundResource(R.drawable.bg_energy_task_btn_normal)
}
taskNotice.setOnClickListener {
DialogUtils.showEnergyTaskNoticeDialog(mContext, task.name, task.descr)
@ -178,12 +185,14 @@ class TaskAdapter(context: Context) : ListAdapter<TaskItemData>(context) {
}
}
is FooterViewHolder -> {
holder.itemView.setPadding(0, 0, 0, 40F.dip2px())
holder.itemView.layoutParams = holder.itemView.layoutParams.apply {
height = 88F.dip2px()
is TaskBottomViewHolder -> {
holder.binding.run {
val isLastBottom = mEntityList[position].bottom!!
holder.itemView.layoutParams = (holder.itemView.layoutParams as ViewGroup.MarginLayoutParams).apply {
val marginBottom = if (isLastBottom) 40F.dip2px() else 0
setMargins(16F.dip2px(), 0, 16F.dip2px(), marginBottom)
}
}
holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver)
}
}
}
@ -191,6 +200,7 @@ class TaskAdapter(context: Context) : ListAdapter<TaskItemData>(context) {
inner class NoviceTasksViewHolder(val binding: NoviceTasksItemBinding): BaseRecyclerViewHolder<Any>(binding.root)
inner class TaskTitleViewHolder(val binding: TaskTitleItemBinding): BaseRecyclerViewHolder<Any>(binding.root)
inner class DailyTaskViewHolder(val binding: DailyTaskItemBinding): BaseRecyclerViewHolder<Any>(binding.root)
inner class TaskBottomViewHolder(val binding: TaskBottomItemBinding): BaseRecyclerViewHolder<Any>(binding.root)
companion object {
private const val TYPE_NOVICE = 900
@ -198,5 +208,7 @@ class TaskAdapter(context: Context) : ListAdapter<TaskItemData>(context) {
private const val TYPE_TITLE = 901
private const val TYPE_DAILY = 902
private const val TYPE_BOTTOM = 903
}
}

View File

@ -3,5 +3,6 @@ package com.gh.gamecenter.energy
import com.gh.gamecenter.entity.TaskEntity
data class TaskItemData(var noviceTasks: List<TaskEntity>? = null,
var title: String? = null,
var dailyTask: TaskEntity? = null)
var title: String? = null,
var dailyTask: TaskEntity? = null,
var bottom: Boolean? = null)

View File

@ -44,21 +44,22 @@ class TaskViewModel(application: Application)
}
}, {}, {
if (mNoviceTasks.isNotEmpty()) {
itemDataList.add(TaskItemData(title = "新手任务"))
itemDataList.add(TaskItemData(noviceTasks = mNoviceTasks))
}
itemDataList.add(TaskItemData(title = "日常任务"))
list.forEach {
itemDataList.add(TaskItemData(dailyTask = it))
}
itemDataList.add(TaskItemData(bottom = mFixedTasks.isEmpty()))
if (mFixedTasks.isNotEmpty()) {
itemDataList.add(TaskItemData(title = "常驻任务"))
mFixedTasks.forEach {
it.isFixed = true
itemDataList.add(TaskItemData(dailyTask = it))
}
}
itemDataList.add(TaskItemData(title = "日常任务"))
list.forEach {
itemDataList.add(TaskItemData(dailyTask = it))
itemDataList.add(TaskItemData(bottom = true))
}
mResultLiveData.postValue(itemDataList)

View File

@ -9,7 +9,9 @@ data class ApplyModeratorStatusEntity(
val condition: Condition = Condition(),
val status: String = "",
@SerializedName("qq_group")
val qqGroup: String = ""
val qqGroup: String = "",
@SerializedName("qa_group_key")
val qqGroupKey: String = ""
) : Parcelable {
@Parcelize
data class Condition(

View File

@ -8,45 +8,54 @@ import kotlinx.android.parcel.Parcelize
@Parcelize
open class ForumVideoEntity(
@SerializedName("_id")
var id: String = "",
var title: String = "",
var des: String = "",
var poster: String = "",
var url: String = "",
val user: PersonalEntity = PersonalEntity(),
val me: MeEntity = MeEntity(),
val size: Long = 0,
var length: Long = 0,
// 有三种状态 pass通过fail未通过pending审核中
var status: String = "",
val format: String = "Mp4",
var game: GameEntity? = null,
@SerializedName("tag_activity_id")
var tagActivityId: String = "",//活动标签的id
@SerializedName("tag_activity_name")
var tagActivityName: String = "",
@SerializedName("bbs_id")
var bbsId: String = "",
@SerializedName("game_id")
var gameId: String = "",
var type: String = "",
var share: Int = 0,
var time: Time = Time(),
@SerializedName("video_info")
var videoInfo: VideoInfo = VideoInfo(),
@SerializedName("is_jx")
var isHighlighted: Boolean = true,
var bbs: CommunityEntity? = null,
var count: Count = Count(),
val original: String = "",//是否原创 //是否原创 yes/no 默认为空字符串
val source: String = "",//转载来源, 当 original=yes
@SerializedName("choiceness_status")
val choicenessStatus: String = "",// 精选状态 null, apply申请, cancel不予精选或未精选, pass精选)
@IgnoredOnParcel
var videoIsMuted: Boolean = false, //是否静音标记
var duration: String = ""
) : Parcelable
@SerializedName("_id")
var id: String = "",
var title: String = "",
var des: String = "",
var poster: String = "",
var url: String = "",
val user: PersonalEntity = PersonalEntity(),
val me: MeEntity = MeEntity(),
val size: Long = 0,
var length: Long = 0,
// 有三种状态 pass通过fail未通过pending审核中
var status: String = "",
val format: String = "Mp4",
var game: GameEntity? = null,
@SerializedName("tag_activity_id")
var tagActivityId: String = "",//活动标签的id
@SerializedName("tag_activity_name")
var tagActivityName: String = "",
@SerializedName("bbs_id")
var bbsId: String = "",
@SerializedName("game_id")
var gameId: String = "",
var type: String = "",
var share: Int = 0,
var time: Time = Time(),
@SerializedName("video_info")
var videoInfo: VideoInfo = VideoInfo(),
@SerializedName("is_jx")
var isHighlighted: Boolean = true,
var bbs: CommunityEntity? = null,
var count: Count = Count(),
val original: String = "",//是否原创 //是否原创 yes/no 默认为空字符串
val source: String = "",//转载来源, 当 original=yes
@SerializedName("choiceness_status")
var choicenessStatus: String = "",// apply申请, pass already已精选 cancel not_yet精选)
@IgnoredOnParcel
var videoIsMuted: Boolean = false, //是否静音标记
var duration: String = ""
) : Parcelable {
fun getSimplifyChoicenessStatus(): String {
return when (choicenessStatus) {
"already" -> "pass"
"not_yet" -> "cancel"
else -> choicenessStatus
}
}
}
@Parcelize
data class Time(val upload: Long = 0, val audit: Long = 0, val update: Long = 0) : Parcelable

View File

@ -14,7 +14,7 @@ data class TaskEntity(
var descr: String = "",
var icon: String = "",
var action: String = "",
var energy: Int = 0,
var energy: Long = 0,
var done: Int = 0,
var limit: Int = 0,
var quota: Int = 0, // 任务指标,代表需要做多少个才算完成

View File

@ -11,6 +11,7 @@ import com.gh.common.constant.ItemViewType
import com.gh.common.syncpage.ISyncAdapterHandler
import com.gh.common.util.MtaHelper
import com.gh.common.util.NewLogUtils
import com.gh.common.util.dip2px
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.baselist.ListAdapter
@ -71,6 +72,11 @@ class ForumArticleAskListAdapter(context: Context, val bbsId: String, val mEntra
val binding = answerViewHolder.binding
binding.forumNameLl.visibility = View.GONE
val contentMarginTop = if (answer.type == "answer") 3F.dip2px() else 12F.dip2px()
binding.content.layoutParams = (binding.content.layoutParams as ViewGroup.MarginLayoutParams).apply {
topMargin = contentMarginTop
}
val params = binding.includeVoteAndComment.root.layoutParams as LinearLayout.LayoutParams
params.width = LinearLayout.LayoutParams.MATCH_PARENT
params.leftMargin = 0

View File

@ -12,6 +12,7 @@ import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.baselist.ListFragment
import com.gh.gamecenter.eventbus.EBDeleteDetail
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.forum.home.ForumScrollCalculatorHelper
import com.gh.gamecenter.qa.CommunityFragment
import com.gh.gamecenter.qa.entity.AnswerEntity
@ -245,4 +246,18 @@ class ForumArticleAskListFragment : ListFragment<AnswerEntity, ForumArticleAskLi
mAdapter.entityList?.remove(currentEntity)
mAdapter.notifyItemRemoved(indexOf)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUserFollow(change: EBUserFollow) {
mAdapter.run {
var count = 0
entityList.forEach {
if (it.user.id == change.userId) {
count++
it.me.isFollower = change.isFollow
}
}
if (count > 1) notifyDataSetChanged()
}
}
}

View File

@ -404,13 +404,19 @@ class ForumDetailFragment : BaseLazyTabFragment() {
R.id.followTv -> {
debounceActionWithInterval(R.id.followTv) {
ifLogin(mEntrance) {
val forumEntity = ForumEntity(mForumDetail?.id
?: "", mForumDetail?.game!!, mForumDetail?.name ?: "")
val forumEntity = ForumEntity(
id = mForumDetail?.id ?: "",
game = mForumDetail?.game!!,
name = mForumDetail?.name ?: "",
type = mForumDetail?.type ?: "",
icon = mForumDetail?.icon ?: ""
)
if (mForumDetail?.me?.isFollower == true) {
mViewModel?.unFollowForum {
MtaHelper.onEvent("论坛详情", "顶部区域", "取消关注")
mForumDetail?.me?.isFollower = false
ToastUtils.showToast("取消成功")
initUI()
EventBus.getDefault().post(EBForumFollowChange(forumEntity, false))
}

View File

@ -367,6 +367,8 @@ class CommunityHomeFragment : LazyFragment() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBTypeChange) {
if (mBinding?.viewPager?.currentItem != 0) return
if (status.type == CommunityFragment.EB_SHOW_QUESTION_BUTTON) {
setPutQuestionButtonStatus(View.VISIBLE)
} else if (status.type == CommunityFragment.EB_HIDE_QUESTION_BUTTON) {
@ -377,6 +379,7 @@ class CommunityHomeFragment : LazyFragment() {
private fun setPutQuestionButtonStatus(visibility: Int) {
mBinding?.run {
if (communityEditBtn.visibility == visibility) return
if (visibility == View.GONE) {
val animation = AnimationUtils.loadAnimation(context, R.anim.button_anim_exit)
communityEditBtn.startAnimation(animation)

View File

@ -125,7 +125,7 @@ class ForumActivityAdapter(context: Context,
if (status == "正在评奖") ToastUtils.toast("活动正在评奖中")
if (status == "奖励发放中") ToastUtils.toast("活动奖励发放中~")
if (status == "已结束") ToastUtils.toast("活动已结束~")
DirectUtils.directToActivityDetail(mContext, activityEntity.id, mEntrance)
DirectUtils.directToActivityDetail(mContext, activityEntity.id, mViewModel.categoryId, mEntrance)
}
}
}

View File

@ -11,6 +11,7 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.entity.ForumVideoEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.answer.BaseAnswerOrArticleItemViewHolder
@ -24,6 +25,7 @@ import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
import com.shuyu.gsyvideoplayer.utils.OrientationUtils
import org.greenrobot.eventbus.EventBus
class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : BaseAnswerOrArticleItemViewHolder(binding.root) {
@ -43,16 +45,25 @@ class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : B
binding.userIcon.display(entity.user.border, entity.user.icon, entity.user.auth?.icon)
binding.forumNameTv.text = entity.bbs.name
binding.content.maxLines = if (entity.type == "answer") 3 else 2
if (entity.type == "answer") {
binding.content.goneIf(entity.content.isEmpty())
binding.content.text = entity.content
val title = " ${entity.questions.title}"
binding.questionTitle.text = SpanBuilder(title).image(0, 1, R.drawable.ic_ask_label).build()
val drawable = R.drawable.ic_ask_label.toDrawable()
drawable?.run {
setBounds(0, 0, 16F.dip2px(), 16F.dip2px())
binding.questionTitle.text = SpanBuilder(title).image(0, 1, this).build()
}
} else if (entity.type == "question") {
binding.content.goneIf(entity.questions.description.isNullOrEmpty())
binding.content.text = entity.questions.description
val title = " ${entity.questions.title}"
binding.title.text = SpanBuilder(title).image(0, 1, R.drawable.ic_ask_label).build()
val drawable = R.drawable.ic_ask_label.toDrawable()
drawable?.run {
setBounds(0, 0, 16F.dip2px(), 16F.dip2px())
binding.title.text = SpanBuilder(title).image(0, 1, this).build()
}
} else {
binding.content.visibility = View.VISIBLE
if (entity.type == "video") {
@ -137,6 +148,8 @@ class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : B
binding.concernBtn.visibility = View.GONE
binding.followedUserTv.visibility = View.VISIBLE
binding.time.text = " · ${binding.time.text}"
ToastUtils.toast("关注成功")
EventBus.getDefault().post(EBUserFollow(userId, true))
}
})
}

View File

@ -12,9 +12,7 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.LazyListFragment
import com.gh.gamecenter.databinding.FragmentForumListBinding
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.eventbus.EBDeleteDetail
import com.gh.gamecenter.eventbus.EBForumRecordChange
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.eventbus.*
import com.gh.gamecenter.forum.home.ForumScrollCalculatorHelper.Companion.getPlaySchedule
import com.gh.gamecenter.forum.home.ForumScrollCalculatorHelper.Companion.savePlaySchedule
import com.gh.gamecenter.qa.CommunityFragment
@ -309,4 +307,18 @@ class ForumArticleListFragment : LazyListFragment<ArticleEntity, ForumArticleLis
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUserFollow(change: EBUserFollow) {
mAdapter?.run {
var count = 0
entityList.forEach {
if (it.user.id == change.userId) {
count++
it.me.isFollower = change.isFollow
}
}
if (count > 1) notifyDataSetChanged()
}
}
}

View File

@ -49,6 +49,7 @@ class ForumFragment: LazyFragment(), SwipeRefreshLayout.OnRefreshListener {
mUserViewModel?.loginObsUserinfo?.observe(this, Observer {
if (!mIsFirst) {
if (it?.data == null) {
mViewModel?.followForums?.clear()
mBinding?.followForumContainer?.visibility = View.GONE
}
onRefresh()

View File

@ -101,7 +101,7 @@ class ForumViewModel(application: Application) : AndroidViewModel(application) {
@SuppressLint("CheckResult")
fun getHotForum() {
api.getHotForumWithPageSize(1, 100)
api.getHotForum(1)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<List<ForumEntity>>() {

View File

@ -59,6 +59,7 @@ class HotForumsAdapter(context: Context,
followTv.setBackgroundResource(R.drawable.button_round_f0f8fa)
followTv.setTextColor(R.color.theme_font.toColor())
followTv.text = "关注"
ToastUtils.showToast("取消成功")
EventBus.getDefault().post(EBForumFollowChange(forumEntity, false))
}
} else {

View File

@ -9,12 +9,14 @@ import com.gh.common.util.DisplayUtils
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.NormalActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.ApplyModeratorStatusEntity
class ApplyModeratorActivity : NormalActivity() {
companion object {
fun getIntent(context: Context, bbsId: String): Intent {
fun getIntent(context: Context, bbsId: String, status: ApplyModeratorStatusEntity): Intent {
val bundle = Bundle()
bundle.putString(EntranceUtils.KEY_BBS_ID, bbsId)
bundle.putParcelable("status", status)
return getTargetIntent(
context,
ApplyModeratorActivity::class.java,
@ -34,10 +36,11 @@ class ApplyModeratorActivity : NormalActivity() {
setStatusBarTransparent()
}
private fun setStatusBarTransparent(){
private fun setStatusBarTransparent() {
DisplayUtils.transparentStatusBar(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
}
}

View File

@ -30,15 +30,17 @@ class ApplyModeratorFragment : NormalFragment() {
private var mAdapter: ModeratorTaskAdapter? = null
private var mDataList = ArrayList<ApplyModeratorTaskEntity>()
private var mBbsId = ""
private var mStatus = ApplyModeratorStatusEntity()
override fun getInflatedLayout() = FragmentApplyModeratorBinding
.inflate(layoutInflater, null, false)
.apply { mBinding = this }
.root
.inflate(layoutInflater, null, false)
.apply { mBinding = this }
.root
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBbsId = arguments?.getString(EntranceUtils.KEY_BBS_ID) ?: ""
mStatus = arguments?.getParcelable("status") ?: ApplyModeratorStatusEntity()
val factory = ApplyModeratorViewModel.Factory(mBbsId)
mDataList = getModeratorTaskList()
mViewModel = viewModelProvider(factory)
@ -57,92 +59,99 @@ class ApplyModeratorFragment : NormalFragment() {
NewLogUtils.logApplyModeratorFApplyOrQQClick("click_QQ_number", UserManager.getInstance().userId)
DirectUtils.directToQqGroup(
requireContext(),
groupTv.text.toString()
mStatus.qqGroupKey
)
}
groupTv.text = mStatus.qqGroup
}
mAdapter?.setListData(mDataList)
mViewModel?.statusEntity?.observe(this, Observer {
it?.let {
checkStatus(it)
mBinding?.groupTv?.text = it.qqGroup
}
})
if (mStatus.status == "todo") {
changeToAudit()
}
}
private fun getModeratorTaskList(): ArrayList<ApplyModeratorTaskEntity> {
return arrayListOf(
ApplyModeratorTaskEntity().apply {
taskName = "通过礼仪考试"
taskIcon = R.drawable.ic_moderator_task_etiquette
taskAction = View.OnClickListener {
val taskState = if (finishedTask) "已完成" else "未完成"
NewLogUtils.logApplyModeratorFinishClick(taskName, taskState)
if (!finishedTask) {
DirectUtils.directToRegulationTestPage(requireContext())
}
}
},
ApplyModeratorTaskEntity().apply {
taskName = "完成实名认证"
taskIcon = R.drawable.ic_moderator_task_id_card
taskAction = View.OnClickListener {
val taskState = if (finishedTask) "已完成" else "未完成"
NewLogUtils.logApplyModeratorFinishClick(taskName, taskState)
if (!finishedTask) {
val currentActivity = AppManager.getInstance().currentActivity()
AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity)
.startForResult(
UserInfoEditActivity.getIntent(
context,
UserViewModel.TYPE_ID_CARD
), object :
Callback {
override fun onActivityResult(resultCode: Int, data: Intent?) {
}
})
}
}
},
ApplyModeratorTaskEntity().apply {
taskName = "论坛活跃度"
taskIcon = R.drawable.ic_moderator_task_activity
taskDescription = "活跃度=发帖数量+回帖数量+回复数量≥20"
taskAction = View.OnClickListener {
val taskState = if (finishedTask) "已完成" else "未完成"
NewLogUtils.logApplyModeratorFinishClick(taskName, taskState)
if (!finishedTask) {
startActivity(
ForumDetailActivity.getIntent(
requireContext(),
mBbsId,
"版主申请"
)
)
}
}
},
ApplyModeratorTaskEntity().apply {
taskName = "论坛精品帖≥2"
taskIcon = R.drawable.ic_moderator_task_choiceness
taskAction = View.OnClickListener {
val taskState = if (finishedTask) "已完成" else "未完成"
NewLogUtils.logApplyModeratorFinishClick(taskName, taskState)
if (!finishedTask) {
startActivity(
ForumDetailActivity.getIntent(
requireContext(),
mBbsId,
"版主申请"
)
)
}
ApplyModeratorTaskEntity().apply {
taskName = "通过礼仪考试"
taskIcon = R.drawable.ic_moderator_task_etiquette
taskAction = View.OnClickListener {
val taskState = if (finishedTask) "已完成" else "未完成"
NewLogUtils.logApplyModeratorFinishClick(taskName, taskState)
if (!finishedTask) {
DirectUtils.directToRegulationTestPage(requireContext())
}
}
finishedTask = mStatus.condition.etiquette
},
ApplyModeratorTaskEntity().apply {
taskName = "完成实名认证"
taskIcon = R.drawable.ic_moderator_task_id_card
taskAction = View.OnClickListener {
val taskState = if (finishedTask) "已完成" else "未完成"
NewLogUtils.logApplyModeratorFinishClick(taskName, taskState)
if (!finishedTask) {
val currentActivity = AppManager.getInstance().currentActivity()
AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity)
.startForResult(
UserInfoEditActivity.getIntent(
context,
UserViewModel.TYPE_ID_CARD
), object :
Callback {
override fun onActivityResult(resultCode: Int, data: Intent?) {
}
})
}
}
finishedTask = mStatus.condition.idCard
},
ApplyModeratorTaskEntity().apply {
taskName = "论坛活跃度"
taskIcon = R.drawable.ic_moderator_task_activity
taskDescription = "活跃度=发帖数量+回帖数量+回复数量≥20"
taskAction = View.OnClickListener {
val taskState = if (finishedTask) "已完成" else "未完成"
NewLogUtils.logApplyModeratorFinishClick(taskName, taskState)
if (!finishedTask) {
startActivity(
ForumDetailActivity.getIntent(
requireContext(),
mBbsId,
"版主申请"
)
)
}
}
finishedTask = mStatus.condition.activity
},
ApplyModeratorTaskEntity().apply {
taskName = "论坛精品帖≥2"
taskIcon = R.drawable.ic_moderator_task_choiceness
taskAction = View.OnClickListener {
val taskState = if (finishedTask) "已完成" else "未完成"
NewLogUtils.logApplyModeratorFinishClick(taskName, taskState)
if (!finishedTask) {
startActivity(
ForumDetailActivity.getIntent(
requireContext(),
mBbsId,
"版主申请"
)
)
}
}
finishedTask = mStatus.condition.choiceness
}
)
}
@ -172,25 +181,33 @@ class ApplyModeratorFragment : NormalFragment() {
}
mBinding?.applyTv?.alpha = if (allFinished) 1F else 0.4F
val listener = View.OnClickListener {
NewLogUtils.logApplyModeratorFApplyOrQQClick("click_apply", UserManager.getInstance().userId)
mViewModel?.applyModerator {
ApplyModeratorDialogFragment.show(
requireActivity() as AppCompatActivity,
mBinding?.groupTv?.text.toString()
) {
mViewModel?.getModeratorsApplyStatus()
if (!ClickUtils.isFastDoubleClick(R.id.applyTv)) {
NewLogUtils.logApplyModeratorFApplyOrQQClick("click_apply", UserManager.getInstance().userId)
mViewModel?.applyModerator {
ApplyModeratorDialogFragment.show(
requireActivity() as AppCompatActivity,
mStatus.qqGroup,
mStatus.qqGroupKey
) {
mViewModel?.getModeratorsApplyStatus()
changeToAudit()
}
}
}
}
mBinding?.applyTv?.setOnClickListener(if (allFinished) listener else null)
}
if (status.status == "todo") {
mBinding?.run {
applyTv.text = "审核中"
applyTv.alpha = 0.4F
applyTv.setOnClickListener(null)
addGroupContainer.visibility = View.VISIBLE
}
changeToAudit()
}
}
private fun changeToAudit() {
mBinding?.run {
applyTv.text = "审核中"
applyTv.alpha = 0.4F
applyTv.setOnClickListener(null)
addGroupContainer.visibility = View.VISIBLE
}
}

View File

@ -13,6 +13,7 @@ import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.gamecenter.NewsDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.ApplyModeratorStatusEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.normal.NormalFragment
import kotterknife.bindView
@ -24,15 +25,14 @@ class ModeratorListFragment : NormalFragment() {
private val mReuseLoading by bindView<LinearLayout>(R.id.reuse_ll_loading)
private val mNoConnection by bindView<LinearLayout>(R.id.reuse_no_connection)
private val mNoneData by bindView<LinearLayout>(R.id.reuse_none_data)
private val mGroupContainer by bindView<LinearLayout>(R.id.groupContainer)
private val mToolbar by bindView<Toolbar>(R.id.toolbar)
private val mDoubtIv by bindView<ImageView>(R.id.doubtIv)
private val mApplyTv by bindView<TextView>(R.id.applyTv)
private val mGroupTv by bindView<TextView>(R.id.groupTv)
private var mViewModel: ModeratorListViewModel? = null
private var mAdapter: ModeratorListAdapter? = null
private var mBbsId: String = ""
private var mBbsType: String = ""
private var mStatus: ApplyModeratorStatusEntity = ApplyModeratorStatusEntity()
override fun getLayoutId(): Int = R.layout.fragment_moderator_list
override fun onCreate(savedInstanceState: Bundle?) {
@ -43,10 +43,6 @@ class ModeratorListFragment : NormalFragment() {
val factory = ModeratorListViewModel.Factory(mBbsId)
mViewModel = viewModelProvider(factory)
mViewModel?.qqGroupNumber?.observe(this, Observer {
mGroupTv.text = it
})
mViewModel?.isModerators?.observe(this, Observer {
if (it) {
mApplyTv.background = R.drawable.bg_forum_follow.toDrawable()
@ -65,7 +61,6 @@ class ModeratorListFragment : NormalFragment() {
mNoConnection.visibility = View.GONE
if (it.isNotEmpty()) {
mNoneData.visibility = View.GONE
mGroupContainer.visibility = View.VISIBLE
mAdapter?.setListData(it)
} else {
mNoneData.visibility = View.VISIBLE
@ -75,6 +70,10 @@ class ModeratorListFragment : NormalFragment() {
mNoConnection.visibility = View.VISIBLE
}
})
mViewModel?.statusEntity?.observe(this, Observer {
it?.run { mStatus = this }
})
}
@ -107,17 +106,12 @@ class ModeratorListFragment : NormalFragment() {
requireContext().startActivity(
ApplyModeratorActivity.getIntent(
requireContext(),
mBbsId
mBbsId,
mStatus
)
)
}
}
mGroupTv.setOnClickListener {
DirectUtils.directToQqGroup(
requireContext(),
mGroupTv.text.toString()
)
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -130,6 +124,7 @@ class ModeratorListFragment : NormalFragment() {
override fun onResume() {
super.onResume()
mViewModel?.getModeratorsInfo()
mViewModel?.getModeratorsApplyStatus()
}
override fun onStop() {

View File

@ -7,7 +7,9 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.ApplyModeratorStatusEntity
import com.gh.gamecenter.entity.PersonalEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
@ -17,6 +19,7 @@ import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import retrofit2.HttpException
class ModeratorListViewModel(application: Application, val bbsId: String) :
@ -24,11 +27,29 @@ class ModeratorListViewModel(application: Application, val bbsId: String) :
val moderators = MutableLiveData<ArrayList<PersonalEntity>>()
val qqGroupNumber = MutableLiveData<String>()
val qqGroupKey = MutableLiveData<String>()
val isModerators = MutableLiveData<Boolean>()
val statusEntity = MutableLiveData<ApplyModeratorStatusEntity>()
init {
getModerators()
getModeratorsInfo()
}
fun getModeratorsApplyStatus() {
RetrofitManager.getInstance(getApplication()).api.getApplyModeratorStatus(bbsId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ApplyModeratorStatusEntity>() {
override fun onResponse(response: ApplyModeratorStatusEntity?) {
super.onResponse(response)
statusEntity.postValue(response)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
statusEntity.postValue(null)
}
})
}
fun getModerators() {
@ -57,6 +78,7 @@ class ModeratorListViewModel(application: Application, val bbsId: String) :
override fun onSuccess(data: JsonObject) {
isModerators.postValue(data["is_moderators"].asBoolean)
qqGroupNumber.postValue(data["moderators_qq_group"].asString)
qqGroupKey.postValue(data["moderators_qq_group_key"].asString)
}
override fun onFailure(exception: Exception) {
@ -84,6 +106,7 @@ class ModeratorListViewModel(application: Application, val bbsId: String) :
} else {
Utils.toast(getApplication(), R.string.concern_cancel)
}
EventBus.getDefault().post(EBUserFollow(userId, isFollow))
}
override fun onFailure(e: HttpException?) {

View File

@ -57,6 +57,7 @@ class UserSearchListViewModel(application: Application) : ListViewModel<Follower
Utils.toast(getApplication(), R.string.concern_already_cancel)
}
callback.invoke()
EventBus.getDefault().post(EBUserFollow(userId, isFollow))
}
override fun onFailure(e: HttpException?) {

View File

@ -418,8 +418,12 @@ LoginFragment extends NormalFragment implements LoginUtils.onCaptchaCallBackList
}
// 第三方登录方式登录后跳转绑定手机页面https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1206
if (UserManager.getInstance().getUserInfoEntity() != null
&& TextUtils.isEmpty(UserManager.getInstance().getUserInfoEntity().getLoginMobile())) {
boolean isThirdPartyLogin = LoginTag.qq.name().equals(loginType)
|| LoginTag.wechat.name().equals(loginType)
|| LoginTag.weibo.name().equals(loginType)
|| LoginTag.douyin.name().equals(loginType);
if (isThirdPartyLogin
&& TextUtils.isEmpty(response.getData().getLoginMobile())) {
startActivity(BindPhoneActivity.getLoginSuccessIntent(requireContext()));
}
}

View File

@ -51,6 +51,7 @@ import com.gh.gamecenter.forum.home.CommunityHomeFragment;
import com.gh.gamecenter.game.GameFragment;
import com.gh.gamecenter.message.MessageUnreadRepository;
import com.gh.gamecenter.message.MessageUnreadViewModel;
import com.gh.gamecenter.personal.NewPersonalFragment;
import com.gh.gamecenter.personal.PersonalFragment;
import com.gh.gamecenter.video.detail.HomeVideoFragment;
import com.halo.assistant.HaloApp;

View File

@ -297,7 +297,7 @@ public class SearchToolbarFragment extends BaseLazyFragment implements View.OnCl
IntegralLogHelper.INSTANCE.log("click_sign", mLocation);
}
startActivity(EnergyCenterActivity.Companion.getIntent(requireContext(), true));
startActivity(EnergyCenterActivity.Companion.getIntent(requireContext()));
break;
}
}

View File

@ -7,19 +7,20 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentTransaction
import com.gh.common.dialog.BaseDraggableDialogFragment
import com.gh.common.util.EnergyTaskHelper
import com.gh.common.util.ToastUtils
import com.gh.gamecenter.databinding.DialogInviteCodeBinding
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.security.BindPhoneActivity
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
class InviteCodeDialog : BaseDraggableDialogFragment() {
@ -87,7 +88,21 @@ class InviteCodeDialog : BaseDraggableDialogFragment() {
override fun onFailure(exception: Exception) {
super.onFailure(exception)
Utils.toast(HaloApp.getInstance().application, "邀请码错误")
if (exception is HttpException) {
try {
val responseBody = exception.response().errorBody()
val string = responseBody!!.string()
val content = JSONObject(string)
when (content.optInt("code")) {
403091 -> ToastUtils.showToast("你已经是老用户了")
else -> ToastUtils.showToast("填写邀请码错误")
}
} catch (e: Exception) {
e.printStackTrace()
ToastUtils.showToast("填写邀请码错误")
}
}
}
})
}

View File

@ -169,7 +169,7 @@ public class NewPersonalFragment extends BaseLazyFragment {
private NewPersonalFunctionGroupAdapter mPersonalFuncGroupAdapter;
private boolean mIsLogging = false;
private int mEnergy = 0;
private long mEnergy = 0;
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
@ -581,7 +581,7 @@ public class NewPersonalFragment extends BaseLazyFragment {
IntegralLogHelper.INSTANCE.log("click_energy", "我的光环");
if (mUserInfoEntity != null) {
MtaHelper.onEvent("我的光环_新", "领光能", "点击领光能");
startActivity(EnergyCenterActivity.Companion.getIntent(requireContext(), true));
startActivity(EnergyCenterActivity.Companion.getIntent(requireContext()));
} else {
CheckLoginUtils.checkLogin(getContext(), "我的光环-领光能", null);
}

View File

@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.entity.FollowersOrFansEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.personalhome.fans.FansActivity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
@ -16,6 +17,7 @@ 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 FollowersOrFansViewModel(application: Application,
@ -58,6 +60,7 @@ class FollowersOrFansViewModel(application: Application,
}
followingLiveData.postValue(position)
EventBus.getDefault().post(EBUserFollow(userId, isFollow))
}
override fun onFailure(e: HttpException?) {

View File

@ -239,7 +239,7 @@ class UserHomeFragment : NormalFragment() {
}
userCountContainer.post {
val newHeight = userCountContainer.bottom + (32F + 16F).dip2px()
val newHeight = userCountContainer.bottom + (12F + 16F).dip2px()
userBackgroundContainer.layoutParams = userBackgroundContainer.layoutParams.apply {
height = newHeight
}

View File

@ -34,7 +34,7 @@ class UserHomeViewModel(application: Application, var userId: String) : AndroidV
var availableBadge = MutableLiveData<BadgeEntity>()
var availableBadgeCount = MutableLiveData<Int>()
var playGamesCount = MutableLiveData<Int>()
var energy = MutableLiveData<Int>()
var energy = MutableLiveData<Long>()
var level = MutableLiveData<Int>()
var sign = MutableLiveData<SignStatusEntity>()
var signStatus = MutableLiveData<SignStatusEntity>()
@ -145,7 +145,7 @@ class UserHomeViewModel(application: Application, var userId: String) : AndroidV
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<JsonObject>() {
override fun onSuccess(data: JsonObject) {
energy.postValue(data["energy"].asInt)
energy.postValue(data["energy"].asLong)
}
})
}

View File

@ -19,6 +19,7 @@ import com.gh.gamecenter.CropImageActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentBackgroundPreviewBinding
import com.gh.gamecenter.entity.BackgroundImageEntity
import com.gh.gamecenter.entity.ErrorEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.normal.NormalFragment
import com.gh.gamecenter.user.UserViewModel
@ -29,6 +30,7 @@ import com.zhihu.matisse.engine.impl.PicassoEngine
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
import java.io.File
class BackgroundPreviewFragment : NormalFragment() {
@ -45,14 +47,20 @@ class BackgroundPreviewFragment : NormalFragment() {
override fun getLayoutId(): Int = 0
override fun getInflatedLayout(): View {
mBinding = DataBindingUtil.inflate(layoutInflater, R.layout.fragment_background_preview, null, false)
mBinding = DataBindingUtil.inflate(
layoutInflater,
R.layout.fragment_background_preview,
null,
false
)
return mBinding.root
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mLocalPath = arguments?.getString(EntranceUtils.KEY_LOCAL_PATH) ?: ""
backgroundImageEntity = arguments?.getParcelable(BackgroundImageEntity::class.java.simpleName)
backgroundImageEntity =
arguments?.getParcelable(BackgroundImageEntity::class.java.simpleName)
mUserViewModel = viewModelProvider(UserViewModel.Factory(HaloApp.getInstance().application))
mUserViewModel.uploadBackground.observeNonNull(this) {
@ -73,7 +81,8 @@ class BackgroundPreviewFragment : NormalFragment() {
}
private fun changeViewParams() {
val screenHeight = DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat())
val screenHeight =
DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat())
val picProportion = if (screenHeight > 640) 6 / 13f else 9 / 16f
val width = mBinding.previewMineIv.width
val height = mBinding.previewMineIv.height
@ -84,13 +93,16 @@ class BackgroundPreviewFragment : NormalFragment() {
mineGhIvParams.topMargin = ((height - realHeight) / 2).toInt() + 1f.dip2px()
mBinding.mineGhIv.layoutParams = mineGhIvParams
val personalHomeIvParams = mBinding.personalHomeIv.layoutParams as ConstraintLayout.LayoutParams
val personalHomeIvParams =
mBinding.personalHomeIv.layoutParams as ConstraintLayout.LayoutParams
//最后+1dp是因为预览图有1dp的边框
personalHomeIvParams.topMargin = ((height - realHeight) / 2).toInt() + 1f.dip2px()
mBinding.personalHomeIv.layoutParams = personalHomeIvParams
val changeBackgroundTvParams = mBinding.changeBackgroundTv.layoutParams as ConstraintLayout.LayoutParams
changeBackgroundTvParams.topMargin = (realHeight + (height - realHeight) / 2 + 26f.dip2px()).toInt()
val changeBackgroundTvParams =
mBinding.changeBackgroundTv.layoutParams as ConstraintLayout.LayoutParams
changeBackgroundTvParams.topMargin =
(realHeight + (height - realHeight) / 2 + 26f.dip2px()).toInt()
mBinding.changeBackgroundTv.layoutParams = changeBackgroundTvParams
mBinding.mineContainer.visibility = View.VISIBLE
@ -101,20 +113,42 @@ class BackgroundPreviewFragment : NormalFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mLocalPath = arguments?.getString(EntranceUtils.KEY_LOCAL_PATH) ?: ""
backgroundImageEntity = arguments?.getParcelable(BackgroundImageEntity::class.java.simpleName)
backgroundImageEntity =
arguments?.getParcelable(BackgroundImageEntity::class.java.simpleName)
mOriginBitmap = BitmapUtils.getBitmapByFile(mLocalPath, Bitmap.Config.ARGB_8888)
if (mOriginBitmap == null) return
mTempBitmap = Bitmap.createBitmap(mOriginBitmap!!)
mBinding.mineGhIv.setImageBitmap(mOriginBitmap)
mBinding.personalHomeIv.setImageBitmap(mOriginBitmap)
val screenHeight = DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat())
val screenHeight =
DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat())
if (screenHeight > 640) {
mBinding.previewMineIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_mine_full))
mBinding.previewHomeIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_home_full))
mBinding.previewMineIv.setImageDrawable(
ContextCompat.getDrawable(
requireContext(),
R.drawable.preview_mine_full
)
)
mBinding.previewHomeIv.setImageDrawable(
ContextCompat.getDrawable(
requireContext(),
R.drawable.preview_home_full
)
)
} else {
mBinding.previewMineIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_mine))
mBinding.previewHomeIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_home))
mBinding.previewMineIv.setImageDrawable(
ContextCompat.getDrawable(
requireContext(),
R.drawable.preview_mine
)
)
mBinding.previewHomeIv.setImageDrawable(
ContextCompat.getDrawable(
requireContext(),
R.drawable.preview_home
)
)
}
mBinding.normalTitle.text = "预览"
@ -159,14 +193,19 @@ class BackgroundPreviewFragment : NormalFragment() {
}
mBinding.commitTv.setOnClickListener {
PermissionHelper.checkStoragePermissionBeforeAction(requireContext(), object : EmptyCallback {
override fun onCallback() {
mTempBitmap?.let {
val filePath: String = "${requireContext().cacheDir.absolutePath}${File.separator}${MD5Utils.getContentMD5(mLocalPath)}.webp"
savePicture(filePath, it)
PermissionHelper.checkStoragePermissionBeforeAction(
requireContext(),
object : EmptyCallback {
override fun onCallback() {
mTempBitmap?.let {
val filePath: String =
"${requireContext().cacheDir.absolutePath}${File.separator}${
MD5Utils.getContentMD5(mLocalPath)
}.webp"
savePicture(filePath, it)
}
}
}
})
})
}
}
@ -201,51 +240,73 @@ class BackgroundPreviewFragment : NormalFragment() {
mPostDialog = WaitingDialogFragment.newInstance("加载中...")
mPostDialog?.show(childFragmentManager, null)
Single.just(bitmap)
.map {
if (mBinding.alphaSeek.progress == 100) {
it
} else {
BitmapUtils.getTransparentBitmap(bitmap, Bitmap.Config.ARGB_8888, mBinding.alphaSeek.progress)
}
.map {
if (mBinding.alphaSeek.progress == 100) {
it
} else {
BitmapUtils.getTransparentBitmap(
bitmap,
Bitmap.Config.ARGB_8888,
mBinding.alphaSeek.progress
)
}
.map {
BitmapUtils.saveBitmap(it, path)
path
}
.flatMap {
uploadImage(it)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
mPostDialog?.dismiss()
val entity = BackgroundImageEntity(backgroundImageEntity?.id
?: "", it, opacity = mBinding.alphaSeek.progress, blur = mBinding.blurSeek.progress)
mUserViewModel.changeUserInfo(GsonUtils.toJson(entity), UserViewModel.TYPE_BACKGROUND)
}, {
it.printStackTrace()
mPostDialog?.dismiss()
})
}
.map {
BitmapUtils.saveBitmap(it, path)
path
}
.flatMap {
uploadImage(it)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
mPostDialog?.dismiss()
val entity = BackgroundImageEntity(
backgroundImageEntity?.id
?: "",
it,
opacity = mBinding.alphaSeek.progress,
blur = mBinding.blurSeek.progress
)
mUserViewModel.changeUserInfo(
GsonUtils.toJson(entity),
UserViewModel.TYPE_BACKGROUND
)
}, {
it.printStackTrace()
mPostDialog?.dismiss()
})
}
private fun uploadImage(path: String): Single<String> {
return Single.create {
UploadImageUtils.uploadImage(UploadImageUtils.UploadType.user_background, path, object : UploadImageUtils.OnUploadImageListener {
override fun onSuccess(imageUrl: String) {
it.onSuccess(imageUrl)
}
UploadImageUtils.uploadImage(
UploadImageUtils.UploadType.user_background,
path,
object : UploadImageUtils.OnUploadImageListener {
override fun onSuccess(imageUrl: String) {
it.onSuccess(imageUrl)
}
override fun onError(e: Throwable?) {
it.onError(e ?: Throwable())
}
override fun onError(e: Throwable?) {
if (e is HttpException) {
val entity =
e.response()?.errorBody()?.string()?.toObject<ErrorEntity>()
if (entity?.code == 403033) {
toast("图片违规")
}
}
it.onError(e ?: Throwable())
}
override fun onProgress(total: Long, progress: Long) {
override fun onProgress(total: Long, progress: Long) {
}
}
})
})
}
}
@ -254,15 +315,15 @@ class BackgroundPreviewFragment : NormalFragment() {
PermissionHelper.checkStoragePermissionBeforeAction(activity, object : EmptyCallback {
override fun onCallback() {
Matisse.from(activity)
.choose(MimeType.ofImage())
.showSingleMediaType(true)
.countable(true)
.addFilter(GhMatisseFilter())
.maxSelectable(1)
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
.thumbnailScale(0.85f)
.imageEngine(PicassoEngine())
.forResult(MEDIA_STORE_REQUEST)
.choose(MimeType.ofImage())
.showSingleMediaType(true)
.countable(true)
.addFilter(GhMatisseFilter())
.maxSelectable(1)
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
.thumbnailScale(0.85f)
.imageEngine(PicassoEngine())
.forResult(MEDIA_STORE_REQUEST)
}
})
}
@ -273,7 +334,8 @@ class BackgroundPreviewFragment : NormalFragment() {
if (requestCode == MEDIA_STORE_REQUEST && resultCode == Activity.RESULT_OK) {
val selectedPaths = Matisse.obtainPathResult(data)
if (selectedPaths.size > 0) {
val intent = BackgroundClipActivity.getIntent(requireContext(), selectedPaths[0], mEntrance)
val intent =
BackgroundClipActivity.getIntent(requireContext(), selectedPaths[0], mEntrance)
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
}
} else if (requestCode == REQUEST_CODE_IMAGE_CROP && resultCode == Activity.RESULT_OK) {
@ -282,11 +344,12 @@ class BackgroundPreviewFragment : NormalFragment() {
mOriginBitmap = BitmapUtils.getBitmapByFile(imagePath, Bitmap.Config.ARGB_8888)
if (mOriginBitmap == null) return
val progress = mBinding.blurSeek.progress
mTempBitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && progress != 0) {
BitmapUtils.getBlurBitmap(requireContext(), mOriginBitmap, progress)
} else {
Bitmap.createBitmap(mOriginBitmap!!)
}
mTempBitmap =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && progress != 0) {
BitmapUtils.getBlurBitmap(requireContext(), mOriginBitmap, progress)
} else {
Bitmap.createBitmap(mOriginBitmap!!)
}
mBinding.mineGhIv.setImageBitmap(mTempBitmap)
mBinding.personalHomeIv.setImageBitmap(mTempBitmap)
}

View File

@ -54,6 +54,7 @@ class ChooseAvatarBorderAdapter(context: Context,
// 商品挂件但未兑换或者已过期,显示光能
!mIsFree && (borderEntity.expire == null
|| (borderEntity.expire != null
&& borderEntity.expire!! != 0L
&& borderEntity.expire!! < TimeUtil.currentTime())) -> {
isEnable = false
holder.binding.descTv.run {

View File

@ -95,8 +95,8 @@ class UserHistoryAdapter(context: Context,
}
entity = historyEntity
// userName.visibility = View.GONE
topLine.goneIf(position == 0)
forumNameLl.visibleIf(historyEntity.community.id.isNotEmpty())
userIcon.display(historyEntity.user?.border, historyEntity.user?.icon, historyEntity.user?.auth?.icon)
executePendingBindings()
@ -265,6 +265,7 @@ class UserHistoryAdapter(context: Context,
"community_article_vote" -> "赞同了帖子"
"community_article" -> if (isEdit) "修改了帖子" else "发布了帖子"
"update-answer" -> "更新了回答"
"video" -> "发布了视频"
else -> ""
}
}
@ -278,6 +279,7 @@ class UserHistoryAdapter(context: Context,
"community_article_vote" -> "赞同了帖子"
"community_article" -> "发布了帖子"
"update-answer" -> "更新了回答"
"video" -> "发布了视频"
else -> ""
}
}

View File

@ -13,6 +13,7 @@ import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SpecialColumn
import com.gh.gamecenter.entity.VoteEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.qa.entity.AnswerDetailEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
@ -23,6 +24,7 @@ import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
import retrofit2.HttpException
import java.util.*
@ -237,6 +239,7 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica
// 取消关注成功
mFollowLiveData.postValue(false)
}
EventBus.getDefault().post(EBUserFollow(targetUserId, isFollow))
}
override fun onFailure(e: HttpException?) {

View File

@ -2,14 +2,10 @@ package com.gh.gamecenter.qa.article.detail
import android.annotation.SuppressLint
import android.app.Activity
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.animation.LinearInterpolator
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.DefaultUrlHandler
@ -18,14 +14,10 @@ import com.gh.common.util.*
import com.gh.common.view.RichEditor
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.ArticleDetailFourmTagItemBinding
import com.gh.gamecenter.databinding.ItemArticleDetailContentBinding
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.column.detail.AskColumnDetailActivity
import com.gh.gamecenter.qa.editor.OnLinkClickListener
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
import com.google.android.flexbox.FlexboxLayout
import java.util.*
class ArticleDetailContentViewHolder(
@ -142,7 +134,7 @@ class ArticleDetailContentViewHolder(
"帖子详情"
)
}
titleTv.text = if (article.choicenessStatus == "pass") {
titleTv.text = if (article.getSimplifyChoicenessStatus() == "pass") {
SpanBuilder(" ${article.title}").image(0, 1, R.drawable.ic_essence).build()
} else {
article.title
@ -250,30 +242,25 @@ class ArticleDetailContentViewHolder(
runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) }
}
else -> {
if (status == "pending") {
ToastUtils.showToast("内容审核中")
return
} else if (status == "fail") {
ToastUtils.showToast("内容审核不通过")
return
}
var current = 0
var i = 0
val size = articleImgUrlList.size
while (i < size) {
if (url.contains(articleImgUrlList.get(i))) {
current = i
clickToastByStatus(status) {
var current = 0
var i = 0
val size = articleImgUrlList.size
while (i < size) {
if (url.contains(articleImgUrlList.get(i))) {
current = i
}
i++
}
i++
val intent = ImageViewerActivity.getIntent(
binding.root.context, articleImgUrlList, current,
mEntrance + "+(帖子详情[" + binding.titleTv.text.toString() + "])"
)
(binding.root.context as Activity).startActivityForResult(
intent,
ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE
)
}
val intent = ImageViewerActivity.getIntent(
binding.root.context, articleImgUrlList, current,
mEntrance + "+(帖子详情[" + binding.titleTv.text.toString() + "])"
)
(binding.root.context as Activity).startActivityForResult(
intent,
ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE
)
}
}
}

View File

@ -8,8 +8,6 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
@ -64,7 +62,11 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
override fun getLayoutId() = 0
override fun getInflatedLayout(): View {
return FragmentArticleDetailBinding.inflate(LayoutInflater.from(requireContext()), null, false).apply {
return FragmentArticleDetailBinding.inflate(
LayoutInflater.from(requireContext()),
null,
false
).apply {
mBinding = this
}.root
}
@ -73,10 +75,11 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
mViewModel = provideListViewModel()
super.onCreate(savedInstanceState)
mScrollToCommentArea = arguments?.getBoolean(EntranceUtils.KEY_SCROLL_TO_COMMENT_AREA, false)
mScrollToCommentArea =
arguments?.getBoolean(EntranceUtils.KEY_SCROLL_TO_COMMENT_AREA, false)
?: false
mIsRecommendsContent = arguments?.getBoolean(EntranceUtils.KEY_RECOMMENDS_CONTENTS, false)
?: false
?: false
NewLogUtils.logArticleDetailClick("view_article_detail")
}
@ -95,14 +98,16 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == ArticleDetailActivity.ARTICLE_PATCH_REQUEST && resultCode == Activity.RESULT_OK) {
data?.getParcelableExtra<ArticleDetailEntity>(ArticleDetailEntity::class.java.simpleName)?.let {
mViewModel.detailEntity = it
mAdapter?.articleDetailVH?.bindView(it)
updateView()
}
data?.getParcelableExtra<ArticleDraftEntity>(ArticleDraftEntity::class.java.simpleName)?.let {
mViewModel.detailEntity?.me?.articleDraft = it
}
data?.getParcelableExtra<ArticleDetailEntity>(ArticleDetailEntity::class.java.simpleName)
?.let {
mViewModel.detailEntity = it
mAdapter?.articleDetailVH?.bindView(it)
updateView()
}
data?.getParcelableExtra<ArticleDraftEntity>(ArticleDraftEntity::class.java.simpleName)
?.let {
mViewModel.detailEntity?.me?.articleDraft = it
}
mReuseNoConn?.performClick() //重新刷新
} else if (requestCode == ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE && resultCode == Activity.RESULT_OK) {
val imageSet = data?.extras?.get(ImageViewerActivity.VIEWED_IMAGE) as HashSet<Integer>
@ -123,8 +128,10 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
if (commentCount != 0 && commentCount != null) {
mViewModel.detailEntity?.count?.comment = commentCount
mViewModel.commentCount = commentCount
mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText(mViewModel.detailEntity?.count?.comment
?: 0, "评论")
mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText(
mViewModel.detailEntity?.count?.comment
?: 0, "评论"
)
updateFilterView()
if (EntranceUtils.ENTRANCE_WELCOME == mEntrance) {
LogUtils.uploadCommentFromWelcomeDialog()
@ -141,36 +148,57 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
val path = arguments?.getString(EntranceUtils.KEY_PATH)
val elapsedTime = mElapsedHelper?.elapsedTime ?: 0
val combinedTitleAndId = StringUtils.combineTwoString(mViewModel.detailEntity?.title, mViewModel.detailEntity?.id)
val combinedTitleAndId = StringUtils.combineTwoString(
mViewModel.detailEntity?.title,
mViewModel.detailEntity?.id
)
MtaHelper.onEventWithTime("帖子阅读量_社区加位置", elapsedTime, mViewModel.detailEntity?.community?.name, path)
MtaHelper.onEventWithTime(
"帖子阅读量_社区加位置",
elapsedTime,
mViewModel.detailEntity?.community?.name,
path
)
MtaHelper.onEventWithTime("帖子阅读量_按位置", elapsedTime, path, combinedTitleAndId)
LogUtils.uploadCommunityArticle(mEntrance,
mViewModel.articleId,
mViewModel.detailEntity?.title,
elapsedTime,
mViewModel.detailEntity?.community,
mSpecialColumn)
LogUtils.uploadCommunityArticle(
mEntrance,
mViewModel.articleId,
mViewModel.detailEntity?.title,
elapsedTime,
mViewModel.detailEntity?.community,
mSpecialColumn
)
}
}
override fun provideListViewModel(): ArticleDetailViewModel {
return viewModelProvider(
ArticleDetailViewModel.Factory(
HaloApp.getInstance().application,
arguments?.getString(EntranceUtils.KEY_COMMUNITY_ARTICLE_ID) ?: "",
arguments?.getParcelable<CommunityEntity>(EntranceUtils.KEY_COMMUNITY_DATA)?.id
?: ""))
ArticleDetailViewModel.Factory(
HaloApp.getInstance().application,
arguments?.getString(EntranceUtils.KEY_COMMUNITY_ARTICLE_ID) ?: "",
arguments?.getParcelable<CommunityEntity>(EntranceUtils.KEY_COMMUNITY_DATA)?.id
?: ""
)
)
}
override fun provideListAdapter(): ListAdapter<*> {
return mAdapter
?: ArticleDetailAdapter(requireContext(), mViewModel, BaseCommentAdapter.AdapterType.COMMENT, mEntrance).apply { mAdapter = this }
?: ArticleDetailAdapter(
requireContext(),
mViewModel,
BaseCommentAdapter.AdapterType.COMMENT,
mEntrance
).apply { mAdapter = this }
}
override fun onBackPressed(): Boolean {
if (SyncDataBetweenPageHelper.setResultAndFinish(requireContext(), mViewModel.detailEntity)) {
if (SyncDataBetweenPageHelper.setResultAndFinish(
requireContext(),
mViewModel.detailEntity
)
) {
return true
}
@ -183,20 +211,20 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
mBinding.reuseNoneData.reuseTvNoneData.setText(R.string.content_delete_hint)
ViewCompat.setOnApplyWindowInsetsListener(mBinding.toolbar) { _, insets ->
(mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop
(mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin =
insets.systemWindowInsetTop
insets.consumeSystemWindowInsets()
}
mSkeletonScreen = Skeleton.bind(skeletonView).shimmer(false).load(R.layout.fragment_article_detail_skeleton).show()
mSkeletonScreen = Skeleton.bind(skeletonView).shimmer(false)
.load(R.layout.fragment_article_detail_skeleton).show()
mBinding.inputContainer.bottomLikeIv.setOnClickListener {
MtaHelper.onEvent("帖子详情", "底部", "点赞")
requireContext().ifLogin("帖子详情-赞同") {
if (mViewModel.detailEntity?.me?.isCommunityArticleVote == false) {
if (mViewModel.detailEntity?.status == "pass") {
clickToastByStatus(mViewModel.detailEntity?.status ?: "") {
mViewModel.likeArticle()
} else {
ToastUtils.showToast("内容审核中")
}
if (EntranceUtils.ENTRANCE_WELCOME == mEntrance) {
LogUtils.uploadLikeFromWelcomeDialog()
@ -211,17 +239,19 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
mBinding.inputContainer.bottomStarIv.setOnClickListener {
MtaHelper.onEvent("帖子详情", "内容区域", "收藏")
requireContext().ifLogin(entrance = "帖子详情-收藏") {
if (mViewModel.detailEntity?.status == "pass") {
mViewModel.collectionCommand(mViewModel.detailEntity?.me?.isCommunityArticleFavorite == false, callback = {
mViewModel.detailEntity?.me?.isCommunityArticleFavorite = it
updateCollectView(it)
})
} else {
ToastUtils.showToast("内容审核中")
clickToastByStatus(mViewModel.detailEntity?.status ?: "") {
mViewModel.collectionCommand(
mViewModel.detailEntity?.me?.isCommunityArticleFavorite == false,
callback = {
mViewModel.detailEntity?.me?.isCommunityArticleFavorite = it
updateCollectView(it)
})
}
NewLogUtils.logCommentClick("click_comment_area_collect", mViewModel.detailEntity?.user?.id
NewLogUtils.logCommentClick(
"click_comment_area_collect", mViewModel.detailEntity?.user?.id
?: "", "帖子", mViewModel.detailEntity?.id
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType)
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType
)
}
}
mBinding.inputContainer.bottomStarTv.setOnClickListener { mBinding.inputContainer.bottomStarIv.performClick() }
@ -230,13 +260,13 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
mBinding.inputContainer.replyTv.setRoundedColorBackground(R.color.text_F5F5F5, 19F)
mBinding.inputContainer.replyTv.setDebouncedClickListener {
MtaHelper.onEvent("帖子详情", "底部", "评论输入框")
NewLogUtils.logCommentClick("click_comment_area_comment_input_box", mViewModel.detailEntity?.user?.id
NewLogUtils.logCommentClick(
"click_comment_area_comment_input_box", mViewModel.detailEntity?.user?.id
?: "", "帖子", mViewModel.detailEntity?.id
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType)
if (mViewModel.detailEntity?.status == "pass") {
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType
)
clickToastByStatus(mViewModel.detailEntity?.status ?: "") {
startCommentActivity()
} else {
ToastUtils.showToast("内容审核中")
}
}
@ -278,9 +308,17 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
val data = Intent()
data.putExtra(EntranceUtils.KEY_ANSWER_ID, mViewModel.articleId)
requireActivity().setResult(Activity.RESULT_OK, data)
DialogUtils.showAlertDialog(requireContext(), "提示", "很抱歉,内容可能已被删除", "关闭", null, {
requireActivity().finish()
}, null)
DialogUtils.showAlertDialog(
requireContext(),
"提示",
"很抱歉,内容可能已被删除",
"关闭",
null,
{
requireActivity().finish()
},
null
)
} else {
toast(R.string.content_delete_toast)
}
@ -311,8 +349,9 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
mViewModel.articleRenderedLiveData.observeNonNull(this) {
showSkeleton(false)
if (mViewModel.detailEntity?.images.isNullOrEmpty()
&& mViewModel.detailEntity?.videos.isNullOrEmpty()
&& mScrollToCommentArea) {
&& mViewModel.detailEntity?.videos.isNullOrEmpty()
&& mScrollToCommentArea
) {
mBinding.inputContainer.bottomCommentIv.performClick()
}
}
@ -329,7 +368,10 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
} else {
mAdapter?.articleDetailVH?.updateFollowBtn(false)
}
updateFollowMenu(isFollowed, mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId)
updateFollowMenu(
isFollowed,
mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId
)
}
mViewModel.like.observeNonNull(this) {
@ -338,16 +380,21 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
} else {
ToastUtils.showToast("取消赞同")
}
updateLikeView(mViewModel.detailEntity!!.me.isCommunityArticleVote, mViewModel.detailEntity!!.count.vote)
updateLikeView(
mViewModel.detailEntity!!.me.isCommunityArticleVote,
mViewModel.detailEntity!!.count.vote
)
}
mViewModel.highlight.observeNonNull(this) { isHighlighted ->
if (isHighlighted) {
if (mViewModel.detailEntity!!.me.moderatorPermissions.highlightCommunityArticle == Permissions.REPORTER) {
toast("提交成功")
mViewModel.detailEntity?.choicenessStatus = "apply"
} else {
toast("操作成功")
requireActivity().finish()
mViewModel.detailEntity?.choicenessStatus = "pass"
mViewModel.updateDetailLiveData.postValue(mViewModel.detailEntity)
}
} else {
toast("权限错误,请刷新后重试")
@ -356,7 +403,7 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
mViewModel.applyHighlight.observeNonNull(this) {
if (it) {
toast("提交成功")
requireActivity().finish()
mViewModel.detailEntity?.choicenessStatus = "apply"
} else {
toast("提交失败")
}
@ -433,8 +480,17 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
private fun showMoreItemDialog() {
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) || mViewModel.detailEntity != null) {
val entities = ArrayList<MenuItemEntity>()
if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId && !mViewModel.detailEntity?.me!!.isModerator && mViewModel.detailEntity?.status == "pass" && mViewModel.detailEntity?.choicenessStatus != "pass") {
entities.add(MenuItemEntity("申请加精", R.drawable.icon_more_panel_essence))
if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId && !mViewModel.detailEntity?.me!!.isModerator && mViewModel.detailEntity?.status == "pass") {
val isEnable =
mViewModel.detailEntity?.getSimplifyChoicenessStatus() != "pass"
entities.add(
MenuItemEntity(
"申请加精",
if (isEnable)
R.drawable.icon_more_panel_essence else R.drawable.icon_more_panel_essence_unenable,
isEnable = isEnable
)
)
}
if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId && mViewModel.detailEntity?.status == "pass") {
entities.add(MenuItemEntity("修改", R.drawable.icon_more_panel_edit))
@ -442,19 +498,38 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
if (mViewModel.detailEntity?.user?.id != UserManager.getInstance().userId) {
entities.add(MenuItemEntity("投诉", R.drawable.icon_gamedetail_copyright))
}
if (mViewModel.detailEntity?.me!!.isModerator) {
val isEnable = mViewModel.detailEntity?.isHighlighted == true
entities.add(MenuItemEntity("加精选", if (isEnable)
R.drawable.icon_more_panel_essence_unenable else R.drawable.icon_more_panel_essence, isEnable = !isEnable))
if (mViewModel.detailEntity?.me!!.isModerator && mViewModel.detailEntity?.status == "pass") {
val isEnable =
mViewModel.detailEntity?.getSimplifyChoicenessStatus() != "pass"
entities.add(
MenuItemEntity(
"加精选",
if (isEnable)
R.drawable.icon_more_panel_essence else R.drawable.icon_more_panel_essence_unenable,
isEnable = isEnable
)
)
entities.add(MenuItemEntity("修改活动标签", R.drawable.icon_more_panel_modify_label))
}
if (mViewModel.detailEntity?.me!!.isModerator || mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId) {
entities.add(MenuItemEntity("删除", R.drawable.icon_more_panel_delete))
if (mViewModel.detailEntity?.me!!.isModerator) {
entities.add(MenuItemEntity("隐藏", R.drawable.icon_more_panel_delete))
} else {
if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId) {
entities.add(MenuItemEntity("删除", R.drawable.icon_more_panel_delete))
}
}
val shareUrl = if (isPublishEnv()) {
requireContext().getString(R.string.share_community_article_url, mViewModel.communityId, mViewModel.detailEntity?.id)
requireContext().getString(
R.string.share_community_article_url,
mViewModel.communityId,
mViewModel.detailEntity?.id
)
} else {
requireContext().getString(R.string.share_community_article_url_dev, mViewModel.communityId, mViewModel.detailEntity?.id)
requireContext().getString(
R.string.share_community_article_url_dev,
mViewModel.communityId,
mViewModel.detailEntity?.id
)
}
val shareIcon: String = if (mViewModel.detailEntity?.images?.isNotEmpty() == true) {
@ -462,68 +537,113 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
} else {
requireContext().getString(R.string.share_ghzs_logo)
}
val title = requireContext().getString(R.string.share_community_article_title, mViewModel.detailEntity?.user?.name,
mViewModel.detailEntity?.title, mViewModel.detailEntity?.count?.vote ?: 0)
val title = requireContext().getString(
R.string.share_community_article_title, mViewModel.detailEntity?.user?.name,
mViewModel.detailEntity?.title, mViewModel.detailEntity?.count?.vote ?: 0
)
val shareUtils = ShareUtils.getInstance(requireContext())
shareUtils.shareParamsDetail(requireActivity(),
shareUrl,
shareIcon,
title,
HtmlUtils.stripHtml(mViewModel.detailEntity?.content),
ShareUtils.ShareEntrance.communityArticle,
mViewModel.detailEntity?.id, null)
shareUtils.shareParamsDetail(
requireActivity(),
shareUrl,
shareIcon,
title,
HtmlUtils.stripHtml(mViewModel.detailEntity?.content),
ShareUtils.ShareEntrance.communityArticle,
mViewModel.detailEntity?.id, null
)
val bbsType = if (mViewModel.detailEntity?.type == "game_bbs") "游戏论坛" else "综合论坛"
MoreFunctionPanelDialog.showMoreDialog(requireActivity() as AppCompatActivity, entities, mViewModel.detailEntity?.title
?: "", shareUtils) {
MoreFunctionPanelDialog.showMoreDialog(
requireActivity() as AppCompatActivity, entities, mViewModel.detailEntity?.title
?: "", shareUtils
) {
when (it.text) {
"修改" -> {
startActivityForResult(ArticleEditActivity.getPatchIntent(requireContext(), mViewModel.detailEntity!!), ArticleDetailActivity.ARTICLE_PATCH_REQUEST)
NewLogUtils.logSharePanelClick("click_modification", mViewModel.detailEntity?.user?.id
startActivityForResult(
ArticleEditActivity.getPatchIntent(
requireContext(),
mViewModel.detailEntity!!
), ArticleDetailActivity.ARTICLE_PATCH_REQUEST
)
NewLogUtils.logSharePanelClick(
"click_modification", mViewModel.detailEntity?.user?.id
?: "", "帖子", mViewModel.detailEntity?.id
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType)
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType
)
}
"投诉" -> {
ifLogin("帖子详情") {
BbsReportHelper.showReportDialog(mViewModel.detailEntity?.id ?: "")
}
NewLogUtils.logSharePanelClick("click_report", mViewModel.detailEntity?.user?.id
NewLogUtils.logSharePanelClick(
"click_report", mViewModel.detailEntity?.user?.id
?: "", "帖子", mViewModel.detailEntity?.id
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType)
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType
)
}
"申请加精" -> {
if (mViewModel.detailEntity?.choicenessStatus == "apply") {
if (mViewModel.detailEntity?.getSimplifyChoicenessStatus() == "apply") {
ToastUtils.showToast("申请加精审核中")
return@showMoreDialog
}
mViewModel.doApplyHighlightThisArticle(mViewModel.articleId)
NewLogUtils.logSharePanelClick("click_apply_essence", mViewModel.detailEntity?.user?.id
NewLogUtils.logSharePanelClick(
"click_apply_essence", mViewModel.detailEntity?.user?.id
?: "", "帖子", mViewModel.detailEntity?.id
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType)
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType
)
}
"加精选" -> {
if (mViewModel.detailEntity?.getSimplifyChoicenessStatus() == "apply") {
ToastUtils.showToast("加精审核中")
return@showMoreDialog
}
addEssenceForum(mViewModel.detailEntity!!)
NewLogUtils.logSharePanelClick("click_essence", mViewModel.detailEntity?.user?.id
NewLogUtils.logSharePanelClick(
"click_essence", mViewModel.detailEntity?.user?.id
?: "", "帖子", mViewModel.detailEntity?.id
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType)
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType
)
}
"修改活动标签" -> {
ChooseActivityDialogFragment.show(requireActivity() as AppCompatActivity, ChooseActivityDialogFragment.ActivityLabelLocation.BBS_ARTICLE, mViewModel.detailEntity?.tagActivityId) { label ->
if (label != null) {
mViewModel.modifyArticleActivityTag(mViewModel.detailEntity?.community?.id
?: "", mViewModel.articleId, label)
NewLogUtils.logSharePanelClick("click_modification_activity_tag", mViewModel.detailEntity?.user?.id
?: "", "帖子", mViewModel.detailEntity?.id
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType)
}
ChooseActivityDialogFragment.show(
requireActivity() as AppCompatActivity,
ChooseActivityDialogFragment.ActivityLabelLocation.BBS_ARTICLE,
mViewModel.detailEntity?.tagActivityId
) { label ->
mViewModel.modifyArticleActivityTag(
mViewModel.detailEntity?.community?.id ?: "",
mViewModel.articleId,
label
)
NewLogUtils.logSharePanelClick(
"click_modification_activity_tag",
mViewModel.detailEntity?.user?.id ?: "",
"帖子",
mViewModel.detailEntity?.id ?: "",
mViewModel.detailEntity?.community?.id ?: "",
bbsType
)
}
}
"删除" -> {
DialogUtils.showNewAlertDialog(requireContext(), "提示", "删除帖子后,其中的所有评论及回复都将被删除", "取消", "删除", {}, {
mViewModel.doHideThisArticle(mViewModel.detailEntity!!.community.id, mViewModel.articleId)
})
NewLogUtils.logSharePanelClick("click_delete", mViewModel.detailEntity?.user?.id
"删除", "隐藏" -> {
DialogUtils.showNewAlertDialog(
requireContext(),
"提示",
"${it.text}帖子后,其中的所有评论及回复都将被${it.text}",
"取消",
it.text,
{},
{
mViewModel.doHideThisArticle(
mViewModel.detailEntity!!.community.id,
mViewModel.articleId
)
})
NewLogUtils.logSharePanelClick(
"click_delete", mViewModel.detailEntity?.user?.id
?: "", "帖子", mViewModel.detailEntity?.id
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType)
?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType
)
}
}
}
@ -534,36 +654,51 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
var highlightDialogHintContent = ""
val permissions = article.me.moderatorPermissions
if (permissions.highlightCommunityArticle > Permissions.GUEST) {
highlightDialogHintContent = if (permissions.highlightCommunityArticle == Permissions.REPORTER) {
"你的操作将提交给小编审核,确定提交吗?"
} else {
"你的操作将立即生效,确定提交吗?(你的管理权限为:高级)"
}
}
when {
article.isHighlighted -> toast("帖子已经加精")
else -> DialogUtils.showAlertDialog(requireContext(), "加精帖子", highlightDialogHintContent,
"确定", "取消",
{ mViewModel.doHighlightThisArticle(mViewModel.detailEntity!!.community.id, mViewModel.articleId) }, null)
highlightDialogHintContent =
if (permissions.highlightCommunityArticle == Permissions.REPORTER) {
"你的操作将提交给小编审核,确定提交吗?"
} else {
"你的操作将立即生效,确定提交吗?"
}
}
DialogUtils.showAlertDialog(
requireContext(),
"加精帖子",
highlightDialogHintContent,
"确定",
"取消",
{
mViewModel.doHighlightThisArticle(
mViewModel.detailEntity!!.community.id,
mViewModel.articleId
)
},
null
)
}
private fun updateView() {
val articleDetail = mViewModel.detailEntity ?: return
updateFollowMenu(articleDetail.me.isFollower, articleDetail.user.id == UserManager.getInstance().userId)
updateFollowMenu(
articleDetail.me.isFollower,
articleDetail.user.id == UserManager.getInstance().userId
)
mReuseNoConn?.visibility = View.GONE
mListLoading?.visibility = View.GONE
mBinding.inputContainer.bottomContainer.visibility = View.VISIBLE
mBinding.bottomShadowView.visibility = View.VISIBLE
mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText(mViewModel.detailEntity?.count?.comment
?: 0, "评论")
mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText(
mViewModel.detailEntity?.count?.comment
?: 0, "评论"
)
val community = articleDetail.community
val icon = if (!community.icon.isNullOrEmpty()) community.icon else community.game?.getIcon()
val iconSubscript = if (!community.iconSubscript.isNullOrEmpty()) community.iconSubscript else community.game?.iconSubscript
val icon =
if (!community.icon.isNullOrEmpty()) community.icon else community.game?.getIcon()
val iconSubscript =
if (!community.iconSubscript.isNullOrEmpty()) community.iconSubscript else community.game?.iconSubscript
mBinding.forumGameIv.displayGameIcon(icon, iconSubscript)
ImageUtils.display(mBinding.userAvatar, articleDetail.user.icon)
mBinding.forumGameIv.visibility = View.VISIBLE
@ -574,7 +709,8 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
if (!mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() > 56F.dip2px()) {
mBinding.forumGameIv.visibility = View.GONE
mBinding.userAvatar.visibility = View.VISIBLE
mAttentionMenu?.isVisible = articleDetail.user.id != UserManager.getInstance().userId
mAttentionMenu?.isVisible =
articleDetail.user.id != UserManager.getInstance().userId
mBinding.forumTitleTv.text = articleDetail.user.name
mIsToolbarUserShow = true
} else if (mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() <= 56F.dip2px()) {
@ -590,8 +726,10 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
val filterView = mLayoutManager.findViewByPosition(1)
NewLogUtils.logSlideArticleOrQuestionDetail("帖子详情页", "slide_article_detail_page", (filterView?.top
?: 0) > 0)
NewLogUtils.logSlideArticleOrQuestionDetail(
"帖子详情页", "slide_article_detail_page", (filterView?.top
?: 0) > 0
)
if ((filterView?.top ?: 0) > 0) {
NewLogUtils.logCommentAreaEnter("帖子")
}
@ -609,10 +747,20 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
mViewModel.detailEntity?.me?.isCommunityArticleVote = alreadyLiked
if (alreadyLiked) {
mBinding.inputContainer.bottomLikeIv.setImageResource(R.drawable.ic_article_detail_liked_bottom_bar)
mBinding.inputContainer.bottomLikeTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.theme_font))
mBinding.inputContainer.bottomLikeTv.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.theme_font
)
)
} else {
mBinding.inputContainer.bottomLikeIv.setImageResource(R.drawable.ic_article_detail_like_bottom_bar)
mBinding.inputContainer.bottomLikeTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_666666))
mBinding.inputContainer.bottomLikeTv.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.text_666666
)
)
}
}
@ -620,11 +768,21 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
if (isCollected) {
mBinding.inputContainer.bottomStarTv.text = "已收藏"
mBinding.inputContainer.bottomStarIv.setImageResource(R.drawable.ic_article_detail_stared_bottom_bar)
mBinding.inputContainer.bottomStarTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.theme_font))
mBinding.inputContainer.bottomStarTv.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.theme_font
)
)
} else {
mBinding.inputContainer.bottomStarTv.text = "收藏"
mBinding.inputContainer.bottomStarIv.setImageResource(R.drawable.ic_article_detail_star_bottom_bar)
mBinding.inputContainer.bottomStarTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_666666))
mBinding.inputContainer.bottomStarTv.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.text_666666
)
)
}
}
@ -635,13 +793,14 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
private fun startCommentActivity(commentEntity: CommentEntity? = null) {
mViewModel.detailEntity?.let {
val intent = CommentActivity.getArticleCommentIntent(
requireContext(),
mViewModel.articleId,
it.count.comment,
true,
it.community.id,
commentEntity,
true)
requireContext(),
mViewModel.articleId,
it.count.comment,
true,
it.community.id,
commentEntity,
true
)
startActivityForResult(intent, CommentActivity.REQUEST_CODE)
}
}
@ -660,13 +819,18 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
mAdapter?.notifyItemChanged(1)
//同步上级列表数据
SyncPageRepository.postSyncData(SyncDataEntity(mViewModel.articleId,
SyncPageRepository.postSyncData(
SyncDataEntity(
mViewModel.articleId,
SyncFieldConstants.ARTICLE_COMMENT_COUNT,
mViewModel.commentCount,
checkFieldEntity = true))
checkFieldEntity = true
)
)
//删除列表数据
val findEntity = mAdapter?.entityList?.find { it.commentNormal != null && it.commentNormal?.id == entity.id }
val findEntity =
mAdapter?.entityList?.find { it.commentNormal != null && it.commentNormal?.id == entity.id }
val index = mAdapter?.entityList?.indexOf(findEntity)
if (findEntity != null) {
mAdapter?.entityList?.remove(findEntity)
@ -682,8 +846,10 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
super.onStop()
val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
val bbsType = if (mViewModel.detailEntity?.type == "game_bbs") "游戏论坛" else "综合论坛"
NewLogUtils.logActivityPause("帖子详情页", "jump_article_detail", stayTime,
mViewModel.detailEntity?.community?.id ?: "", bbsType, "帖子",
mViewModel.detailEntity?.id ?: "")
NewLogUtils.logActivityPause(
"帖子详情页", "jump_article_detail", stayTime,
mViewModel.detailEntity?.community?.id ?: "", bbsType, "帖子",
mViewModel.detailEntity?.id ?: ""
)
}
}

View File

@ -15,6 +15,7 @@ import com.gh.gamecenter.entity.CommentEntity
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.entity.VoteEntity
import com.gh.gamecenter.eventbus.EBCollectionChanged
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
@ -28,10 +29,17 @@ import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import retrofit2.HttpException
class ArticleDetailViewModel(application: Application,
articleId: String = "",
communityId: String = "")
: BaseCommentViewModel(application, articleId = articleId, communityId = communityId, videoId = "", questionId = "") {
class ArticleDetailViewModel(
application: Application,
articleId: String = "",
communityId: String = ""
) : BaseCommentViewModel(
application,
articleId = articleId,
communityId = communityId,
videoId = "",
questionId = ""
) {
var detailEntity: ArticleDetailEntity? = null
@ -50,7 +58,12 @@ class ArticleDetailViewModel(application: Application,
var articlePageFinishedLiveData = MutableLiveData<Boolean>()
override fun provideDataObservable(page: Int): Observable<List<CommentEntity>> {
return RetrofitManager.getInstance(getApplication()).api.getCommunityArticleCommentList(communityId, articleId, currentSortType.value, page)
return RetrofitManager.getInstance(getApplication()).api.getCommunityArticleCommentList(
communityId,
articleId,
currentSortType.value,
page
)
}
override fun mergeResultLiveData() {
@ -59,167 +72,193 @@ class ArticleDetailViewModel(application: Application,
fun getArticleDetail() {
mApi.getCommunityArticleDetail(communityId, articleId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ArticleDetailEntity>() {
override fun onResponse(response: ArticleDetailEntity?) {
detailEntity = response
topItemData = CommentItemData(articleDetail = response)
commentCount = response?.count?.comment ?: 0
loadResultLiveData.postValue(LoadResult.SUCCESS)
mergeListData(mListLiveData.value, displayFloor = true)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ArticleDetailEntity>() {
override fun onResponse(response: ArticleDetailEntity?) {
detailEntity = response
topItemData = CommentItemData(articleDetail = response)
commentCount = response?.count?.comment ?: 0
loadResultLiveData.postValue(LoadResult.SUCCESS)
mergeListData(mListLiveData.value, displayFloor = true)
NewLogUtils.logForumContentBrowser(articleId, "bbs_article")
}
NewLogUtils.logForumContentBrowser(articleId, "bbs_article")
}
override fun onFailure(e: HttpException?) {
if (e?.code().toString().startsWith("404")) {
loadResultLiveData.postValue(LoadResult.DELETED)
} else {
loadResultLiveData.postValue(LoadResult.NETWORK_ERROR)
}
override fun onFailure(e: HttpException?) {
if (e?.code().toString().startsWith("404")) {
loadResultLiveData.postValue(LoadResult.DELETED)
} else {
loadResultLiveData.postValue(LoadResult.NETWORK_ERROR)
}
})
}
})
}
fun cancelLikeArticle() {
mApi.postCommunityArticleUnVote(communityId, articleId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<VoteEntity>() {
override fun onResponse(response: VoteEntity?) {
// 赞同减一
detailEntity?.me?.isCommunityArticleVote = false
detailEntity!!.count.vote--
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<VoteEntity>() {
override fun onResponse(response: VoteEntity?) {
// 赞同减一
detailEntity?.me?.isCommunityArticleVote = false
detailEntity!!.count.vote--
like.postValue(response)
like.postValue(response)
syncVoteData()
}
syncVoteData()
}
override fun onFailure(e: HttpException?) {
ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
}
})
override fun onFailure(e: HttpException?) {
ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
}
})
}
fun likeArticle() {
mApi.postCommunityArticleVote(communityId, articleId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<VoteEntity>() {
override fun onResponse(response: VoteEntity?) {
// 赞同加一
detailEntity?.me?.isCommunityArticleOppose = false
detailEntity?.me?.isCommunityArticleVote = true
detailEntity!!.count.vote++
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<VoteEntity>() {
override fun onResponse(response: VoteEntity?) {
// 赞同加一
detailEntity?.me?.isCommunityArticleOppose = false
detailEntity?.me?.isCommunityArticleVote = true
detailEntity!!.count.vote++
like.postValue(response)
like.postValue(response)
syncVoteData()
syncVoteData()
EnergyTaskHelper.postEnergyTask("vote_community_article", articleId)
}
EnergyTaskHelper.postEnergyTask("vote_community_article", articleId)
}
override fun onFailure(e: HttpException?) {
ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
}
})
override fun onFailure(e: HttpException?) {
ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
}
})
}
fun dislikeArticle() {
mApi.postCommunityArticleOppose(communityId, articleId)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
if (detailEntity?.me?.isCommunityArticleVote == true) {
detailEntity!!.count.vote--
}
detailEntity?.me?.isCommunityArticleOppose = true
detailEntity?.me?.isCommunityArticleVote = false
dislike.postValue(true)
syncVoteData()
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
if (detailEntity?.me?.isCommunityArticleVote == true) {
detailEntity!!.count.vote--
}
detailEntity?.me?.isCommunityArticleOppose = true
detailEntity?.me?.isCommunityArticleVote = false
override fun onFailure(e: HttpException?) {
ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
}
})
dislike.postValue(true)
syncVoteData()
}
override fun onFailure(e: HttpException?) {
ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
}
})
}
fun cancelDislikeArticle() {
mApi.postCommunityArticleUnoppose(communityId, articleId)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
detailEntity?.me?.isCommunityArticleOppose = false
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
detailEntity?.me?.isCommunityArticleOppose = false
dislike.postValue(false)
dislike.postValue(false)
syncVoteData()
}
syncVoteData()
}
override fun onFailure(e: HttpException?) {
ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
}
})
override fun onFailure(e: HttpException?) {
ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
}
})
}
private fun syncVoteData() {
articleId.apply {
SyncPageRepository.postSyncData(SyncDataEntity(this,
SyncPageRepository.postSyncData(
SyncDataEntity(
this,
SyncFieldConstants.ARTICLE_VOTE_COUNT,
detailEntity?.count?.vote,
checkFieldEntity = true))
SyncPageRepository.postSyncData(SyncDataEntity(this,
checkFieldEntity = true
)
)
SyncPageRepository.postSyncData(
SyncDataEntity(
this,
SyncFieldConstants.ARTICLE_VOTE,
detailEntity?.me?.isCommunityArticleVote,
checkFieldEntity = true))
checkFieldEntity = true
)
)
}
}
private fun syncFollowData(isFollow: Boolean) {
articleId.apply {
SyncPageRepository.postSyncData(SyncDataEntity(this,
SyncPageRepository.postSyncData(
SyncDataEntity(
this,
SyncFieldConstants.IS_FOLLOWER,
isFollow,
checkFieldEntity = true))
checkFieldEntity = true
)
)
}
}
fun collectionCommand(isCollection: Boolean, callback: (isFollow: Boolean) -> Unit) {
val observable = if (isCollection) {
mApi.postCommunityArticleFavorites(UserManager.getInstance().userId, communityId, articleId)
mApi.postCommunityArticleFavorites(
UserManager.getInstance().userId,
communityId,
articleId
)
} else {
mApi.deleteCommunityArticleFavorites(UserManager.getInstance().userId, communityId, articleId)
mApi.deleteCommunityArticleFavorites(
UserManager.getInstance().userId,
communityId,
articleId
)
}
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
EventBus.getDefault().post(EBCollectionChanged(articleId, true, CollectionUtils.CollectionType.communityArticle))
if (isCollection) {
// 收藏成功
callback(true)
ToastUtils.showToast(getApplication<Application>().getString(R.string.collection_success))
} else {
// 取消收藏成功
callback(false)
ToastUtils.showToast(getApplication<Application>().getString(R.string.collection_cancel))
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
EventBus.getDefault().post(
EBCollectionChanged(
articleId,
true,
CollectionUtils.CollectionType.communityArticle
)
)
if (isCollection) {
// 收藏成功
callback(true)
ToastUtils.showToast(getApplication<Application>().getString(R.string.collection_success))
} else {
// 取消收藏成功
callback(false)
ToastUtils.showToast(getApplication<Application>().getString(R.string.collection_cancel))
}
}
override fun onFailure(e: HttpException?) {
if (isCollection) {
ToastUtils.showToast(getApplication<Application>().getString(R.string.collection_failure))
} else {
ToastUtils.showToast(getApplication<Application>().getString(R.string.collection_cancel_failure))
}
override fun onFailure(e: HttpException?) {
if (isCollection) {
ToastUtils.showToast(getApplication<Application>().getString(R.string.collection_failure))
} else {
ToastUtils.showToast(getApplication<Application>().getString(R.string.collection_cancel_failure))
}
})
}
})
}
fun follow() {
@ -237,98 +276,104 @@ class ArticleDetailViewModel(application: Application,
mApi.deleteFollowing(targetUserId)
}
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
if (isFollow) {
// 关注成功
mFollowLiveData.postValue(true)
syncFollowData(true)
} else {
// 取消关注成功
mFollowLiveData.postValue(false)
syncFollowData(false)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
if (isFollow) {
// 关注成功
mFollowLiveData.postValue(true)
syncFollowData(true)
} else {
// 取消关注成功
mFollowLiveData.postValue(false)
syncFollowData(false)
}
EventBus.getDefault().post(EBUserFollow(targetUserId, isFollow))
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
Utils.toast(getApplication(), R.string.loading_failed_hint)
}
})
override fun onFailure(e: HttpException?) {
super.onFailure(e)
Utils.toast(getApplication(), R.string.loading_failed_hint)
}
})
}
fun doHighlightThisArticle(communityId: String, articleId: String?) {
mApi.highlightCommunityArticle(communityId, articleId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
highlight.postValue(true)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
highlight.postValue(true)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
highlight.postValue(false)
}
})
override fun onFailure(e: HttpException?) {
super.onFailure(e)
highlight.postValue(false)
}
})
}
fun doApplyHighlightThisArticle(articleId: String?) {
mApi.applyHighlightCommunityArticle(articleId)
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
applyHighlight.postValue(true)
}
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
applyHighlight.postValue(true)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
applyHighlight.postValue(false)
}
})
override fun onFailure(e: HttpException?) {
super.onFailure(e)
applyHighlight.postValue(false)
}
})
}
fun doHideThisArticle(communityId: String, articleId: String?) {
mApi.hideCommunityArticle(communityId, articleId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
hide.postValue(true)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
hide.postValue(true)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
hide.postValue(false)
}
})
override fun onFailure(e: HttpException?) {
super.onFailure(e)
hide.postValue(false)
}
})
}
fun modifyArticleActivityTag(communityId: String, articleId: String, label: ActivityLabelEntity) {
val body = json { "tag_activity_id" to label.id }.toRequestBody()
fun modifyArticleActivityTag(
communityId: String,
articleId: String,
label: ActivityLabelEntity?
) {
val body = json { "tag_activity_id" to label?.id }.toRequestBody()
mApi.modifyArticleActivityTag(communityId, articleId, body)
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
detailEntity?.apply {
tagActivityId = label.id
tagActivityName = label.name
updateDetailLiveData.postValue(this)
}
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
detailEntity?.apply {
tagActivityId = label?.id ?: ""
tagActivityName = label?.name ?: ""
updateDetailLiveData.postValue(this)
ToastUtils.showToast("修改活动标签成功")
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
ToastUtils.showToast("修改活动标签失败")
}
})
override fun onFailure(e: HttpException?) {
super.onFailure(e)
ToastUtils.showToast("修改活动标签失败")
}
})
}
override fun hideCommentSuccess() {
@ -355,15 +400,18 @@ class ArticleDetailViewModel(application: Application,
// })
// }
class Factory(private val application: Application,
private val articleId: String = "",
private val communityId: String = "") : ViewModelProvider.NewInstanceFactory() {
class Factory(
private val application: Application,
private val articleId: String = "",
private val communityId: String = ""
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ArticleDetailViewModel(
application = application,
articleId = articleId,
communityId = communityId) as T
application = application,
articleId = articleId,
communityId = communityId
) as T
}
}

View File

@ -69,6 +69,7 @@ abstract class BaseCommentAdapter(
&& oldItem?.commentNormal?.floor == newItem?.commentNormal?.floor
&& oldItem?.commentNormal?.isTop == newItem?.commentNormal?.isTop
&& oldItem?.commentNormal?.accept == newItem?.commentNormal?.accept
&& oldItem?.commentNormal?.choiceness == newItem?.commentNormal?.choiceness
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {

View File

@ -324,6 +324,7 @@ abstract class BaseCommentViewModel(
val cloneComment = comment.clone()
cloneComment.choiceness = true
updateComment(cloneComment)
ToastUtils.showToast("加精成功")
}
override fun onFailure(e: HttpException?) {

View File

@ -27,9 +27,9 @@ class MoreFunctionPanelDialog : BaseDraggableDialogFragment() {
var onItemClickCallback: ((menuItem: MenuItemEntity) -> Unit)? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DialogGameDetailMoreBinding.inflate(inflater, container, false)
return binding.root
@ -82,25 +82,40 @@ class MoreFunctionPanelDialog : BaseDraggableDialogFragment() {
menuItems.forEachIndexed { _, menuItemEntity ->
val itemView = createItemView(menuItemEntity)
itemView.setOnClickListener {
onItemClickCallback?.invoke(menuItemEntity)
dismissAllowingStateLoss()
if (menuItemEntity.isEnable) {
onItemClickCallback?.invoke(menuItemEntity)
dismissAllowingStateLoss()
}
}
binding.actionContainer.addView(itemView)
}
}
private fun createItemView(itemEntity: MenuItemEntity): View {
val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
val params = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
params.leftMargin = 16F.dip2px()
return TextView(requireContext()).apply {
textSize = 11F
text = itemEntity.text
setTextColor(ContextCompat.getColor(requireContext(), if (itemEntity.isEnable) R.color.text_666666 else R.color.text_999999))
setTextColor(
ContextCompat.getColor(
requireContext(),
if (itemEntity.isEnable) R.color.text_666666 else R.color.text_999999
)
)
includeFontPadding = false
gravity = Gravity.CENTER
layoutParams = params
compoundDrawablePadding = 8F.dip2px()
setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(requireContext(), itemEntity.normalIcon), null, null)
setCompoundDrawablesWithIntrinsicBounds(
null,
ContextCompat.getDrawable(requireContext(), itemEntity.normalIcon),
null,
null
)
}
}
@ -109,22 +124,33 @@ class MoreFunctionPanelDialog : BaseDraggableDialogFragment() {
companion object {
@JvmStatic
fun showMoreDialog(activity: AppCompatActivity, menuItems: ArrayList<MenuItemEntity>, title: String, shareUtils: ShareUtils, onItemClickCallback: (menuItem: MenuItemEntity) -> Unit) {
fun showMoreDialog(
activity: AppCompatActivity,
menuItems: ArrayList<MenuItemEntity>,
title: String,
shareUtils: ShareUtils,
onItemClickCallback: (menuItem: MenuItemEntity) -> Unit
) {
if (menuItems.isNullOrEmpty()) return
var fragment = activity.supportFragmentManager.findFragmentByTag(MoreFunctionPanelDialog::class.java.name) as? MoreFunctionPanelDialog
var fragment =
activity.supportFragmentManager.findFragmentByTag(MoreFunctionPanelDialog::class.java.name) as? MoreFunctionPanelDialog
if (fragment == null) {
fragment = MoreFunctionPanelDialog()
fragment.menuItems = menuItems
fragment.title = title
fragment.shareUtils = shareUtils
fragment.onItemClickCallback = onItemClickCallback
fragment.show(activity.supportFragmentManager, MoreFunctionPanelDialog::class.java.name)
fragment.show(
activity.supportFragmentManager,
MoreFunctionPanelDialog::class.java.name
)
} else {
fragment.menuItems = menuItems
fragment.title = title
fragment.shareUtils = shareUtils
fragment.onItemClickCallback = onItemClickCallback
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
val transaction: FragmentTransaction =
activity.supportFragmentManager.beginTransaction()
transaction.show(fragment)
transaction.commit()
}

View File

@ -62,22 +62,8 @@ class OnLinkClickListener(val context: Context,
tryWithDefaultCatch {
if (mtaEvent != null) MtaHelper.onEvent(mtaEvent.name, mtaEvent.key, mtaEvent.value)
val videoEntity = GsonUtils.fromJson(content, MyVideoEntity::class.java)
when (videoEntity.status) {
"pass" -> {
// DirectUtils.directToVideoDetail(context,
// videoEntity.id,
// VideoDetailContainerViewModel.Location.VIDEO_HOT.value,
// showComment = false,
// entrance = entrance,
// path = "$path-视频")
FullScreenVideoActivity.start(context, title, videoEntity.url, videoEntity.poster)
}
"fail" -> {
Utils.toast(context, "视频审核未通过")
}
"pending" -> {
Utils.toast(context, "视频正在审核中")
}
clickToastByStatus(videoEntity.status){
FullScreenVideoActivity.start(context, title, videoEntity.url, videoEntity.poster)
}
}
}
@ -85,11 +71,8 @@ class OnLinkClickListener(val context: Context,
@JavascriptInterface
fun onVideoClick(url: String, poster: String) {
when (status) {
"pending" -> ToastUtils.showToast("内容审核中")
"fail" -> ToastUtils.showToast("内容审核不通过")
else -> FullScreenVideoActivity.start(context, title, url, poster)
clickToastByStatus(status){
FullScreenVideoActivity.start(context, title, url, poster)
}
}
}

View File

@ -10,35 +10,44 @@ import kotlinx.android.parcel.Parcelize
@Parcelize
data class ArticleDetailEntity(
@SerializedName("_id")
val id: String = "",
var title: String = "",
var content: String = "",
var tags: List<String> = ArrayList(),
val count: Count = Count(),
var user: UserEntity = UserEntity(),
var me: MeEntity = MeEntity(),
val time: TimeEntity = TimeEntity(),
var community: CommunityEntity = CommunityEntity(),
var commentable: Boolean? = true,
@SerializedName("is_jx")
var isHighlighted: Boolean = true,
@SerializedName("community_id")
var communityId: String = "",
var images: List<String> = ArrayList(),
@SerializedName("images_info")
var imagesInfo: List<ImageInfo> = ArrayList(),
var videos: List<CommunityVideoEntity> = ArrayList(),
@SerializedName("tag_activity_id")
var tagActivityId: String = "",
@SerializedName("tag_activity_name")
var tagActivityName: String = "",
var type: String = "",
var gameEntity: GameEntity? = null,
@SerializedName("choiceness_status")
val choicenessStatus: String = "",// 精选状态 null, apply申请, cancel不予精选或未精选, pass精选)
var status: String = "pass",//pass通过fail未通过pending审核中
var original: String = ""
) : Parcelable
@SerializedName("_id")
val id: String = "",
var title: String = "",
var content: String = "",
var tags: List<String> = ArrayList(),
val count: Count = Count(),
var user: UserEntity = UserEntity(),
var me: MeEntity = MeEntity(),
val time: TimeEntity = TimeEntity(),
var community: CommunityEntity = CommunityEntity(),
var commentable: Boolean? = true,
@SerializedName("is_jx")
var isHighlighted: Boolean = true,
@SerializedName("community_id")
var communityId: String = "",
var images: List<String> = ArrayList(),
@SerializedName("images_info")
var imagesInfo: List<ImageInfo> = ArrayList(),
var videos: List<CommunityVideoEntity> = ArrayList(),
@SerializedName("tag_activity_id")
var tagActivityId: String = "",
@SerializedName("tag_activity_name")
var tagActivityName: String = "",
var type: String = "",
var gameEntity: GameEntity? = null,
@SerializedName("choiceness_status")
var choicenessStatus: String = "",// 精选状态 apply申请, pass already已精选 cancel not_yet精选)
var status: String = "pass",//pass通过fail未通过pending审核中
var original: String = ""
) : Parcelable {
fun getSimplifyChoicenessStatus(): String {
return when (choicenessStatus) {
"already" -> "pass"
"not_yet" -> "cancel"
else -> choicenessStatus
}
}
}

View File

@ -46,7 +46,6 @@ data class QuestionsDetailEntity(
var gameEntity: GameEntity? = null,
var time: TimeEntity = TimeEntity(),
var count: Count = Count(),
val choicenessStatus: String = "",// 精选状态 null, apply申请, cancel不予精选或未精选, pass已精选
var status: String = "pass",//pass通过fail未通过pending审核中
var finish: Boolean = false,
//提交问题用

View File

@ -48,7 +48,8 @@ import org.json.JSONObject
/**
* Created by khy on 28/04/18.
*/
class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), KeyboardHeightObserver {
class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(),
KeyboardHeightObserver {
private lateinit var mBinding: ActivityQuestionsEditBinding
@ -74,14 +75,16 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK) return
if (requestCode == QUESTION_DRAFT_REQUEST_CODE) {
val draftEntity = data.getParcelableExtra<QuestionDraftEntity>(QuestionDraftEntity::class.java.simpleName)
val draftEntity =
data.getParcelableExtra<QuestionDraftEntity>(QuestionDraftEntity::class.java.simpleName)
if (draftEntity != null) {
mViewModel.questionDraftEntity = draftEntity
setQuestionDraft(draftEntity)
mViewModel.getQuestionDraftContent(draftEntity.id)
}
} else if (requestCode == ChooseForumActivity.CHOOSE_FORUM_REQUEST) {
val community = data.getParcelableExtra<CommunityEntity>(EntranceUtils.KEY_COMMUNITY_DATA)
val community =
data.getParcelableExtra<CommunityEntity>(EntranceUtils.KEY_COMMUNITY_DATA)
mViewModel.communityEntity = community
mViewModel.type = community?.type ?: ""
if (mViewModel.questionEntity != null) {
@ -106,7 +109,8 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
super.handleMessage(msg)
if (msg.what == 1) {
if (!mViewModel.title.isNullOrEmpty()
&& !mViewModel.content.isNullOrEmpty()) {
&& !mViewModel.content.isNullOrEmpty()
) {
mViewModel.title = mBinding.questionseditTitle.text.toString()
mViewModel.content = getReplaceRealContent()
mViewModel.saveQuestionDraft(SaveDraftType.AUTO)
@ -148,7 +152,11 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
// TitleTip
if (mViewModel.questionEntity == null) {
val titleTipAdapter = QuestionTitleTipAdapter(this, mBinding.questionseditTitle, mViewModel.communityEntity?.id)
val titleTipAdapter = QuestionTitleTipAdapter(
this,
mBinding.questionseditTitle,
mViewModel.communityEntity?.id
)
mBinding.questionseditTitle.setAdapter(titleTipAdapter)
}
@ -179,11 +187,14 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
mBinding.questionseditTitle.requestFocus()
mBinding.backBtn.setOnClickListener {
val bbsType = if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else ""
NewLogUtils.logQuestionEditClick("click_question_cancel", mViewModel.communityEntity?.id
val bbsType =
if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else ""
NewLogUtils.logQuestionEditClick(
"click_question_cancel", mViewModel.communityEntity?.id
?: "",
bbsType, mViewModel.selectActivityLabelEntity?.name
?: "", mViewModel.quoteCountEntity)
bbsType, mViewModel.selectActivityLabelEntity?.name
?: "", mViewModel.quoteCountEntity
)
onBackPressed()
}
mBinding.chooseForumTv.setOnClickListener {
@ -195,8 +206,10 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
200L
} else 0L
AppExecutor.uiExecutor.executeWithDelay(Runnable {
ChooseActivityDialogFragment.show(this, ChooseActivityDialogFragment.ActivityLabelLocation.BBS_QUESTION,
mViewModel.selectActivityLabelEntity?.id) {
ChooseActivityDialogFragment.show(
this, ChooseActivityDialogFragment.ActivityLabelLocation.BBS_QUESTION,
mViewModel.selectActivityLabelEntity?.id
) {
mViewModel.selectActivityLabelEntity = it
mBinding.activityTitle.text = it?.name
mBinding.activityTitle.setTextColor(if (it != null) R.color.text_FA8500.toColor() else R.color.text_333333.toColor())
@ -210,9 +223,12 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
}, 50)
if (intent != null) {
val communityEntity = intent.getParcelableExtra<CommunityEntity>(CommunityEntity::class.java.simpleName)
val detailEntity = intent.getParcelableExtra<QuestionsDetailEntity>(QuestionsDetailEntity::class.java.simpleName)
val draftEntity = intent.getParcelableExtra<QuestionDraftEntity>(QuestionDraftEntity::class.java.simpleName)
val communityEntity =
intent.getParcelableExtra<CommunityEntity>(CommunityEntity::class.java.simpleName)
val detailEntity =
intent.getParcelableExtra<QuestionsDetailEntity>(QuestionsDetailEntity::class.java.simpleName)
val draftEntity =
intent.getParcelableExtra<QuestionDraftEntity>(QuestionDraftEntity::class.java.simpleName)
when {
detailEntity != null -> { // 问题编辑
setPatchContent(detailEntity)
@ -226,9 +242,11 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
else -> { // 新增问题
var searchKey = intent.getStringExtra(EntranceUtils.KEY_QUESTIONS_SEARCH_KEY)
if (!searchKey.isNullOrEmpty() && searchKey.length > QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH)
searchKey = searchKey.substring(0, QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH)
searchKey =
searchKey.substring(0, QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH)
if (mViewModel.title.isNullOrEmpty()) mViewModel.title = searchKey
mViewModel.isFromSearch = intent.getBooleanExtra(QuestionEditViewModel.QUESTION_FORM_SEARCH, false)
mViewModel.isFromSearch =
intent.getBooleanExtra(QuestionEditViewModel.QUESTION_FORM_SEARCH, false)
mViewModel.type = intent?.getStringExtra(BbsType::class.java.simpleName) ?: ""
mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME.toLong())
if (communityEntity != null) {
@ -236,7 +254,12 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
setForumName()
if (mViewModel.type == BbsType.GAME_BBS.value) {
mBinding.chooseForumTv.isEnabled = false
mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(
null,
null,
null,
null
)
}
}
showUploadVideoGuide()
@ -261,13 +284,15 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
mViewModel.communityEntity?.iconSubscript = detailEntity.community.game?.iconSubscript
mViewModel.gameEntity = detailEntity.gameEntity
if (detailEntity.tagActivityId.isNotEmpty() && detailEntity.tagActivityName.isNotEmpty()) {
mViewModel.selectActivityLabelEntity = ActivityLabelEntity(detailEntity.tagActivityId, detailEntity.tagActivityName)
mViewModel.selectActivityLabelEntity =
ActivityLabelEntity(detailEntity.tagActivityId, detailEntity.tagActivityName)
mBinding.activityTitle.text = detailEntity.tagActivityName
mBinding.activityTitle.setTextColor(R.color.text_FA8500.toColor())
}
mBinding.chooseActivityContainer.isEnabled = false
mViewModel.isModeratorPatch = intent.getBooleanExtra(EntranceUtils.KEY_QUESTION_MODERATOR_PATCH, false)
mViewModel.isModeratorPatch =
intent.getBooleanExtra(EntranceUtils.KEY_QUESTION_MODERATOR_PATCH, false)
// 编辑问题时可能存在草稿
if (mViewModel.questionDraftEntity != null) {
@ -289,7 +314,8 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
mViewModel.communityEntity?.iconSubscript = draftEntity.bbs?.game?.iconSubscript
mViewModel.type = draftEntity.type
if (draftEntity.tagActivityId.isNotEmpty() && draftEntity.tagActivityName.isNotEmpty()) {
mViewModel.selectActivityLabelEntity = ActivityLabelEntity(draftEntity.tagActivityId, draftEntity.tagActivityName)
mViewModel.selectActivityLabelEntity =
ActivityLabelEntity(draftEntity.tagActivityId, draftEntity.tagActivityName)
mBinding.activityTitle.text = draftEntity.tagActivityName
mBinding.activityTitle.setTextColor(R.color.text_FA8500.toColor())
}
@ -309,7 +335,10 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
} else {
toast("操作成功")
val data = Intent()
data.putExtra(QuestionsDetailEntity::class.java.simpleName, mViewModel.questionEntity)
data.putExtra(
QuestionsDetailEntity::class.java.simpleName,
mViewModel.questionEntity
)
setResult(Activity.RESULT_OK, data)
}
finish()
@ -323,11 +352,13 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
val errorJson = JSONObject(string)
val errorCode = errorJson.getInt("code")
if (errorCode == 403059) {
DialogUtils.showAlertDialog(this, "提交失败", "权限错误,请刷新后重试",
"确定", null, DialogUtils.ConfirmListener {
setResult(Activity.RESULT_CANCELED)
finish()
}, null)
DialogUtils.showAlertDialog(
this, "提交失败", "权限错误,请刷新后重试",
"确定", null, DialogUtils.ConfirmListener {
setResult(Activity.RESULT_CANCELED)
finish()
}, null
)
return@Observer
}
}
@ -341,7 +372,10 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
if (pair.second) {
if (mViewModel.questionDraftEntity != null) {
val intent = Intent()
intent.putExtra(QuestionDraftEntity::class.java.simpleName, mViewModel.questionDraftEntity)
intent.putExtra(
QuestionDraftEntity::class.java.simpleName,
mViewModel.questionDraftEntity
)
setResult(Activity.RESULT_OK, intent)
if (mViewModel.checkIsAllUploadedAndToast()) {
Utils.toast(this, "已保存!")
@ -351,7 +385,8 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
Utils.toast(this, "问题已保存到草稿箱")
}
}
EventBus.getDefault().post(EBReuse(ArticleEditActivity.ARTICLE_DRAFT_CHANGE_TAG))
EventBus.getDefault()
.post(EBReuse(ArticleEditActivity.ARTICLE_DRAFT_CHANGE_TAG))
finish()
}
}
@ -368,7 +403,10 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
SaveDraftType.SKIP -> {
if (pair.second) {
Utils.toast(this, "问题已保存到草稿箱")
startActivityForResult(ArticleDraftActivity.getIntent(this), ArticleEditActivity.ARTICLE_DRAFT_REQUEST_CODE)
startActivityForResult(
ArticleDraftActivity.getIntent(this),
ArticleEditActivity.ARTICLE_DRAFT_REQUEST_CODE
)
} else {
Utils.toast(this, "问题草稿保存失败")
}
@ -392,13 +430,19 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
mProcessingDialog = WaitingDialogFragment.newInstance(it.msg, false)
mProcessingDialog?.show(supportFragmentManager, null) {
if (mViewModel.uploadImageSubscription != null && !mViewModel.uploadImageSubscription!!.isDisposed) {
mUploadImageCancelDialog = DialogUtils.showAlertDialog(this, "提示"
, "图片正在上传中,确定取消吗?"
, "确定", "取消", {
mViewModel.uploadImageSubscription!!.dispose()
mUploadImageCancelDialog?.dismiss()
mProcessingDialog?.dismiss()
}, null)
mUploadImageCancelDialog = DialogUtils.showAlertDialog(
this,
"提示",
"图片正在上传中,确定取消吗?",
"确定",
"取消",
{
mViewModel.uploadImageSubscription!!.dispose()
mUploadImageCancelDialog?.dismiss()
mProcessingDialog?.dismiss()
},
null
)
}
}
}
@ -427,28 +471,41 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
if (checkSameFromQuestionData()) {
toast("内容没有变化")
} else {
//版主不是作者时,仅能修改用户的标题内容,正文不能修改
if (mViewModel.questionEntity?.user?.id != UserManager.getInstance().userId && mViewModel.questionEntity?.description != mViewModel.content) {
toast("不能修改正文")
return true
}
mViewModel.selectedTags.addAll(mViewModel.questionEntity?.tags!!)
DialogUtils.showAlertDialog(this, "修改问题",
if (mViewModel.questionEntity!!.me.moderatorPermissions.updateQuestion == Permissions.REPORTER)
"你的操作将提交给小编审核,确定提交吗?" else "你的操作将立即生效,确定提交吗?(你的管理权限为:高级)",
"确定", "取消", DialogUtils.ConfirmListener {
mViewModel.uploadPicAndPatchQuestion(false)
}, null)
DialogUtils.showAlertDialog(
this, "修改问题",
if (mViewModel.questionEntity!!.me.moderatorPermissions.updateQuestion == Permissions.REPORTER)
"你的操作将提交给小编审核,确定提交吗?" else "你的操作将立即生效,确定提交吗?",
"确定", "取消", DialogUtils.ConfirmListener {
mViewModel.uploadPicAndPatchQuestion(false)
}, null
)
}
} else {
if (mViewModel.checkTitleAndLoadTitleTag(mIsKeyBoardShow)) {
mTagsSelectFragment?.postQuestion()
}
}
val bbsType = if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else ""
NewLogUtils.logQuestionEditClick("click_question_post_button", mViewModel.communityEntity?.id
val bbsType =
if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else ""
NewLogUtils.logQuestionEditClick(
"click_question_post_button", mViewModel.communityEntity?.id
?: "",
bbsType, mViewModel.selectActivityLabelEntity?.name
?: "", mViewModel.quoteCountEntity)
bbsType, mViewModel.selectActivityLabelEntity?.name
?: "", mViewModel.quoteCountEntity
)
} else if (menuItem?.itemId == R.id.menu_draft) {
if (checkDraft(SaveDraftType.SKIP)) {
NewLogUtils.logQuestionDraftClick()
startActivityForResult(QuestionDraftActivity.getIntent(this), QUESTION_DRAFT_REQUEST_CODE)
startActivityForResult(
QuestionDraftActivity.getIntent(this),
QUESTION_DRAFT_REQUEST_CODE
)
}
}
@ -476,7 +533,10 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
private fun showSelectGameDialog() {
if (mViewModel.type == BbsType.OFFICIAL_BBS.value) {
startActivityForResult(GameActivity.getIntent(this, GameActivity.SELECT_GAME_TITLE), VideoPublishFragment.REQUEST_GAME_CODE)
startActivityForResult(
GameActivity.getIntent(this, GameActivity.SELECT_GAME_TITLE),
VideoPublishFragment.REQUEST_GAME_CODE
)
} else {
val delayTime = if (mIsKeyBoardShow) {
Util_System_Keyboard.hideSoftKeyboard(this)
@ -534,22 +594,31 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
if (checkSameFromQuestionData()) {
return false
}
DialogUtils.showCancelAlertDialog(this, "提示"
, "确定退出修改?已编辑的内容将丢失"
, "继续编辑", " 退出", null) { finish() }
DialogUtils.showCancelAlertDialog(
this, "提示", "确定退出修改?已编辑的内容将丢失", "继续编辑", " 退出", null
) { finish() }
return true
}
//问题发布
if (mViewModel.questionEntity == null && mViewModel.questionDraftEntity == null) {
if (!mBinding.questionseditTitle.text.isNullOrEmpty() || !mBinding.richEditor.html.isNullOrEmpty()) {
DialogUtils.showNewAlertDialog(this, "提示", "是否保存内容再退出?", "不保存", "保存并退出", Gravity.CENTER, true, {
finish()
}, {
mViewModel.title = mBinding.questionseditTitle.text.toString()
mViewModel.content = getReplaceRealContent()
mViewModel.saveQuestionDraft(SaveDraftType.EXIT)
})
DialogUtils.showNewAlertDialog(
this,
"提示",
"是否保存内容再退出?",
"不保存",
"保存并退出",
Gravity.CENTER,
true,
{
finish()
},
{
mViewModel.title = mBinding.questionseditTitle.text.toString()
mViewModel.content = getReplaceRealContent()
mViewModel.saveQuestionDraft(SaveDraftType.EXIT)
})
return true
}
}
@ -557,7 +626,8 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
//问题编辑,需要判断是否修改过
if (mViewModel.questionEntity != null && mViewModel.questionDraftEntity == null) {
return if (mViewModel.questionEntity?.title != mBinding.questionseditTitle.text.toString()
|| mViewModel.questionEntity?.description != mBinding.richEditor.html) {
|| mViewModel.questionEntity?.description != mBinding.richEditor.html
) {
showBackDialog()
true
} else false
@ -572,7 +642,8 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
if (saveType == SaveDraftType.SKIP) {
//判断是否修改了草稿,修改了需自动保存无需提示
if (draftEntity.title != mBinding.questionseditTitle.text.toString()
|| draftEntity.description != mBinding.richEditor.html) {
|| draftEntity.description != mBinding.richEditor.html
) {
mViewModel.title = mBinding.questionseditTitle.text.toString()
mViewModel.content = getReplaceRealContent()
mViewModel.saveQuestionDraft(SaveDraftType.AUTO)
@ -581,7 +652,8 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
} else if (saveType == SaveDraftType.EXIT) {
//退出页面需判断是否修改了草稿,修改了需弹窗提示
if (draftEntity.title != mBinding.questionseditTitle.text.toString()
|| draftEntity.description != mBinding.richEditor.html) {
|| draftEntity.description != mBinding.richEditor.html
) {
showBackDialog()
return false
}
@ -590,13 +662,22 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
}
private fun showBackDialog() {
DialogUtils.showNewAlertDialog(this, "提示", "是否保存修改内容用于下次编辑?", "不保存", "保存并退出", Gravity.CENTER, true, {
finish()
}, {
mViewModel.title = mBinding.questionseditTitle.text.toString()
mViewModel.content = getReplaceRealContent()
mViewModel.saveQuestionDraft(SaveDraftType.EXIT)
})
DialogUtils.showNewAlertDialog(
this,
"提示",
"是否保存修改内容用于下次编辑?",
"不保存",
"保存并退出",
Gravity.CENTER,
true,
{
finish()
},
{
mViewModel.title = mBinding.questionseditTitle.text.toString()
mViewModel.content = getReplaceRealContent()
mViewModel.saveQuestionDraft(SaveDraftType.EXIT)
})
}
private fun checkSameFromQuestionData(): Boolean {
@ -616,14 +697,20 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
if (mViewModel.communityEntity != null) {
if (mViewModel.type == BbsType.GAME_BBS.value) {
mBinding.chooseForumTv.text = mViewModel.communityEntity?.name
mBinding.forumIconView.displayGameIcon(mViewModel.communityEntity?.icon, mViewModel.communityEntity?.iconSubscript)
mBinding.forumIconView.displayGameIcon(
mViewModel.communityEntity?.icon,
mViewModel.communityEntity?.iconSubscript
)
setForumUI()
} else if (mViewModel.type == BbsType.OFFICIAL_BBS.value) {
if (mViewModel.gameEntity == null) {
mBinding.chooseForumTv.text = "选择游戏"
} else {
mBinding.chooseForumTv.text = mViewModel.gameEntity?.name
mBinding.forumIconView.displayGameIcon(mViewModel.gameEntity?.icon, mViewModel.gameEntity?.iconSubscript)
mBinding.forumIconView.displayGameIcon(
mViewModel.gameEntity?.icon,
mViewModel.gameEntity?.iconSubscript
)
setForumUI()
}
}
@ -637,7 +724,11 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
val beginTransaction = supportFragmentManager.beginTransaction()
mTagsSelectFragment = TagsSelectFragment.getInstance()
beginTransaction.replace(R.id.tagsContainer, mTagsSelectFragment!!, TagsSelectFragment::javaClass.name)
beginTransaction.replace(
R.id.tagsContainer,
mTagsSelectFragment!!,
TagsSelectFragment::javaClass.name
)
beginTransaction.commitAllowingStateLoss()
mViewModel.selectedTags.clear()
mViewModel.selectedTagsChange.postValue(true)
@ -646,8 +737,14 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
private fun setForumUI() {
mBinding.forumIconView.visibility = View.VISIBLE
mBinding.forumContainer.background = ContextCompat.getDrawable(this, R.drawable.bg_shape_f5_radius_999)
mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(this, R.drawable.ic_article_edit_choose_forum_arrow_gray), null)
mBinding.forumContainer.background =
ContextCompat.getDrawable(this, R.drawable.bg_shape_f5_radius_999)
mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(
null,
null,
ContextCompat.getDrawable(this, R.drawable.ic_article_edit_choose_forum_arrow_gray),
null
)
mBinding.chooseForumTv.setTextColor(ContextCompat.getColor(this, R.color.text_333333))
}
@ -691,7 +788,11 @@ class QuestionEditActivity : BaseRichEditorActivity<QuestionEditViewModel>(), Ke
return intent
}
fun getIntent(context: Context, communityEntity: CommunityEntity, type: String = ""): Intent {
fun getIntent(
context: Context,
communityEntity: CommunityEntity,
type: String = ""
): Intent {
val intent = Intent(context, QuestionEditActivity::class.java)
intent.putExtra(CommunityEntity::class.java.simpleName, communityEntity)
intent.putExtra(BbsType::class.java.simpleName, type)

View File

@ -219,14 +219,15 @@ class QuestionEditViewModel(application: Application) : BaseRichEditorViewModel(
postLiveData.postValue(Resource.success(data))
EventBus.getDefault().post(EBReuse(QuestionEditActivity.QUESTION_POSTED_TAG))
if (!questionDraftEntity?.id.isNullOrEmpty()) {
EventBus.getDefault().post(EBReuse(QuestionEditActivity.QUESTION_DRAFT_CHANGE_TAG))
}
if (questionEntity == null) {
tryWithDefaultCatch {
EnergyTaskHelper.postEnergyTask("post_question", JSONObject(data).optString("_id"))
}
}
if (!questionDraftEntity?.id.isNullOrEmpty()) {
EventBus.getDefault().post(EBReuse(QuestionEditActivity.QUESTION_DRAFT_CHANGE_TAG))
}
}
override fun onFailure(e: HttpException?) {

View File

@ -39,7 +39,8 @@ import org.greenrobot.eventbus.EventBus
import java.util.*
import kotlin.collections.ArrayList
class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuestionDetailViewModel>() {
class NewQuestionDetailFragment :
BaseCommentFragment<CommentItemData, NewQuestionDetailViewModel>() {
private var mScrollToCommentArea: Boolean = false
private var mIsRecommendsContent: Boolean = false
private lateinit var mViewModel: NewQuestionDetailViewModel
@ -51,7 +52,11 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
override fun getLayoutId() = 0
override fun getInflatedLayout(): View {
return FragmentArticleDetailBinding.inflate(LayoutInflater.from(requireContext()), null, false).apply {
return FragmentArticleDetailBinding.inflate(
LayoutInflater.from(requireContext()),
null,
false
).apply {
mBinding = this
}.root
}
@ -60,10 +65,11 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
mViewModel = provideListViewModel()
super.onCreate(savedInstanceState)
mScrollToCommentArea = arguments?.getBoolean(EntranceUtils.KEY_SCROLL_TO_COMMENT_AREA, false)
mScrollToCommentArea =
arguments?.getBoolean(EntranceUtils.KEY_SCROLL_TO_COMMENT_AREA, false)
?: false
mIsRecommendsContent = arguments?.getBoolean(EntranceUtils.KEY_RECOMMENDS_CONTENTS, false)
?: false
?: false
NewLogUtils.logQuestionDetailClick("view_question_detail")
}
@ -81,11 +87,12 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != Activity.RESULT_OK || data == null) return
if (requestCode == QuestionsDetailFragment.QUESTIONS_EDIT_REQUEST) {
data.getParcelableExtra<QuestionsDetailEntity>(QuestionsDetailEntity::class.java.simpleName)?.let {
mViewModel.questionDetail = it
mAdapter?.questionDetailVH?.bindView(it)
updateView()
}
data.getParcelableExtra<QuestionsDetailEntity>(QuestionsDetailEntity::class.java.simpleName)
?.let {
mViewModel.questionDetail = it
mAdapter?.questionDetailVH?.bindView(it)
updateView()
}
mReuseNoConn?.performClick() //重新刷新
} else if (requestCode == ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE && resultCode == Activity.RESULT_OK) {
val imageSet = data.extras?.get(ImageViewerActivity.VIEWED_IMAGE) as HashSet<Integer>
@ -105,11 +112,14 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
val commentCount = data.getIntExtra(CommentActivity.COMMENT_COUNT, 0)
if (commentCount != 0) {
// 因为answer赋值会默认加上reply数量所以要减去reply数量才能得出真实的answer数量
mViewModel.questionDetail?.count?.answer = commentCount - (mViewModel.questionDetail?.count?.reply
mViewModel.questionDetail?.count?.answer =
commentCount - (mViewModel.questionDetail?.count?.reply
?: 0)
mViewModel.commentCount = commentCount
mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText(mViewModel.questionDetail?.count?.answer
?: 0, "回答")
mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText(
mViewModel.questionDetail?.count?.answer
?: 0, "回答"
)
updateFilterView()
if (EntranceUtils.ENTRANCE_WELCOME == mEntrance) {
LogUtils.uploadCommentFromWelcomeDialog()
@ -138,20 +148,26 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
private fun initView() {
mBinding.reuseNoneData.reuseTvNoneData.text = getString(R.string.content_delete_hint)
ViewCompat.setOnApplyWindowInsetsListener(mBinding.toolbar) { _, insets ->
(mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop
(mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin =
insets.systemWindowInsetTop
insets.consumeSystemWindowInsets()
}
mSkeletonScreen = Skeleton.bind(skeletonView).shimmer(false).load(R.layout.fragment_article_detail_skeleton).show()
mSkeletonScreen = Skeleton.bind(skeletonView).shimmer(false)
.load(R.layout.fragment_article_detail_skeleton).show()
val bbsType = if (mViewModel.questionDetail?.type == "game_bbs") "游戏论坛" else "综合论坛"
mBinding.inputContainer.replyTv.text = "说点什么吧"
mBinding.inputContainer.replyTv.setRoundedColorBackground(R.color.text_F5F5F5, 19F)
mBinding.inputContainer.replyTv.setDebouncedClickListener {
startCommentActivity()
NewLogUtils.logCommentClick("click_comment_area_comment_input_box", mViewModel.questionDetail?.user?.id
?: "", "提问帖", mViewModel.questionDetail?.id
?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType)
clickToastByStatus(mViewModel.questionDetail?.status ?: "") {
startCommentActivity()
NewLogUtils.logCommentClick(
"click_comment_area_comment_input_box", mViewModel.questionDetail?.user?.id
?: "", "提问帖", mViewModel.questionDetail?.id
?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType
)
}
}
mBinding.inputContainer.bottomCommentTv.text = "回答"
mBinding.inputContainer.bottomLikeTv.text = "邀请"
@ -159,17 +175,29 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
updateStartButton()
mBinding.inputContainer.bottomLikeIv.setOnClickListener {
mViewModel.questionDetail?.let {
startActivity(QuestionsInviteActivity.getIntent(requireContext(), it, "$mEntrance+(问题详情)"))
clickToastByStatus(mViewModel.questionDetail?.status ?: "") {
startActivity(
QuestionsInviteActivity.getIntent(
requireContext(),
it,
"$mEntrance+(问题详情)"
)
)
}
}
}
mBinding.inputContainer.bottomLikeTv.setOnClickListener { mBinding.inputContainer.bottomLikeIv.performClick() }
mBinding.inputContainer.bottomStarIv.setOnClickListener {
debounceActionWithInterval(it.id) {
ifLogin("问题详情") {
mViewModel.postFavoriteQuestion()
NewLogUtils.logCommentClick("click_comment_area_collect", mViewModel.questionDetail?.user?.id
?: "", "提问帖", mViewModel.questionDetail?.id
?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType)
clickToastByStatus(mViewModel.questionDetail?.status ?: "") {
mViewModel.postFavoriteQuestion()
NewLogUtils.logCommentClick(
"click_comment_area_collect", mViewModel.questionDetail?.user?.id
?: "", "提问帖", mViewModel.questionDetail?.id
?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType
)
}
}
}
}
@ -205,9 +233,17 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
val data = Intent()
data.putExtra(EntranceUtils.KEY_ANSWER_ID, mViewModel.questionId)
requireActivity().setResult(Activity.RESULT_OK, data)
DialogUtils.showAlertDialog(requireContext(), "提示", "很抱歉,内容可能已被删除", "关闭", null, {
requireActivity().finish()
}, null)
DialogUtils.showAlertDialog(
requireContext(),
"提示",
"很抱歉,内容可能已被删除",
"关闭",
null,
{
requireActivity().finish()
},
null
)
} else {
toast(R.string.content_delete_toast)
}
@ -238,8 +274,9 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
mViewModel.questionRenderedLiveData.observeNonNull(this) {
showSkeleton(false)
if (mViewModel.questionDetail?.images.isNullOrEmpty()
&& mViewModel.questionDetail?.videos.isNullOrEmpty()
&& mScrollToCommentArea) {
&& mViewModel.questionDetail?.videos.isNullOrEmpty()
&& mScrollToCommentArea
) {
mBinding.inputContainer.bottomCommentIv.performClick()
}
}
@ -256,7 +293,10 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
} else {
mAdapter?.questionDetailVH?.updateFollowBtn(false)
}
updateFollowMenu(isFollowed, mViewModel.questionDetail?.user?.id == UserManager.getInstance().userId)
updateFollowMenu(
isFollowed,
mViewModel.questionDetail?.user?.id == UserManager.getInstance().userId
)
}
mViewModel.moderatorsHideLiveData.observeNonNull(this) {
EventBus.getDefault().post(EBDeleteDetail(mViewModel.questionId))
@ -273,28 +313,39 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
}
private fun updateStartButton() {
mBinding.inputContainer.bottomStarIv.setImageDrawable(if (mViewModel.questionDetail?.me?.isQuestionFavorite == true)
R.drawable.ic_article_detail_stared_bottom_bar.toDrawable() else R.drawable.ic_article_detail_star_bottom_bar.toDrawable())
mBinding.inputContainer.bottomStarTv.setTextColor(if (mViewModel.questionDetail?.me?.isQuestionFavorite == true)
R.color.theme_font.toColor() else R.color.text_666666.toColor())
mBinding.inputContainer.bottomStarTv.text = if (mViewModel.questionDetail?.me?.isQuestionFavorite == true) "已收藏" else "收藏"
mBinding.inputContainer.bottomStarIv.setImageDrawable(
if (mViewModel.questionDetail?.me?.isQuestionFavorite == true)
R.drawable.ic_article_detail_stared_bottom_bar.toDrawable() else R.drawable.ic_article_detail_star_bottom_bar.toDrawable()
)
mBinding.inputContainer.bottomStarTv.setTextColor(
if (mViewModel.questionDetail?.me?.isQuestionFavorite == true)
R.color.theme_font.toColor() else R.color.text_666666.toColor()
)
mBinding.inputContainer.bottomStarTv.text =
if (mViewModel.questionDetail?.me?.isQuestionFavorite == true) "已收藏" else "收藏"
}
private fun updateView() {
val questionDetail = mViewModel.questionDetail ?: return
updateStartButton()
updateFollowMenu(questionDetail.me.isFollower, questionDetail.user.id == UserManager.getInstance().userId)
updateFollowMenu(
questionDetail.me.isFollower,
questionDetail.user.id == UserManager.getInstance().userId
)
mReuseNoConn?.visibility = View.GONE
mListLoading?.visibility = View.GONE
mBinding.inputContainer.bottomContainer.visibility = View.VISIBLE
mBinding.bottomShadowView.visibility = View.VISIBLE
mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText(questionDetail.count.answer, "回答")
mBinding.inputContainer.bottomCommentTv.text =
mViewModel.getCommentText(questionDetail.count.answer, "回答")
val community = questionDetail.community
val icon = if (!community.icon.isNullOrEmpty()) community.icon else community.game?.getIcon()
val iconSubscript = if (!community.iconSubscript.isNullOrEmpty()) community.iconSubscript else community.game?.iconSubscript
val icon =
if (!community.icon.isNullOrEmpty()) community.icon else community.game?.getIcon()
val iconSubscript =
if (!community.iconSubscript.isNullOrEmpty()) community.iconSubscript else community.game?.iconSubscript
mBinding.forumGameIv.displayGameIcon(icon, iconSubscript)
ImageUtils.display(mBinding.userAvatar, questionDetail.user.icon)
mBinding.forumGameIv.visibility = View.VISIBLE
@ -305,7 +356,8 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
if (!mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() > 56F.dip2px()) {
mBinding.forumGameIv.visibility = View.GONE
mBinding.userAvatar.visibility = View.VISIBLE
mAttentionMenu?.isVisible = questionDetail.user.id != UserManager.getInstance().userId
mAttentionMenu?.isVisible =
questionDetail.user.id != UserManager.getInstance().userId
mBinding.forumTitleTv.text = questionDetail.user.name
mIsToolbarUserShow = true
} else if (mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() <= 56F.dip2px()) {
@ -321,8 +373,10 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
val filterView = mLayoutManager.findViewByPosition(1)
NewLogUtils.logSlideArticleOrQuestionDetail("提问帖详情", "slide_question_detail_page",
(filterView?.top ?: 0) > 0)
NewLogUtils.logSlideArticleOrQuestionDetail(
"提问帖详情", "slide_question_detail_page",
(filterView?.top ?: 0) > 0
)
if ((filterView?.top ?: 0) > 0) {
NewLogUtils.logCommentAreaEnter("提问帖")
}
@ -355,12 +409,12 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
private fun startCommentActivity() {
mViewModel.questionDetail?.let {
val intent = CommentActivity.getQuestionCommentIntent(
requireContext(),
it.id ?: "",
it.count.answer,
true,
it.community.id,
true
requireContext(),
it.id ?: "",
it.count.answer,
true,
it.community.id,
true
)
startActivityForResult(intent, CommentActivity.REQUEST_CODE)
}
@ -368,23 +422,34 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
override fun provideListViewModel(): NewQuestionDetailViewModel {
return viewModelProvider(
NewQuestionDetailViewModel.Factory(
HaloApp.getInstance().application,
arguments?.getString(EntranceUtils.KEY_QUESTIONS_ID) ?: "",
arguments?.getParcelable<CommunityEntity>(EntranceUtils.KEY_COMMUNITY_DATA)?.id
?: "",
arguments?.getString(EntranceUtils.KEY_ANSWER_ID) ?: ""))
NewQuestionDetailViewModel.Factory(
HaloApp.getInstance().application,
arguments?.getString(EntranceUtils.KEY_QUESTIONS_ID) ?: "",
arguments?.getParcelable<CommunityEntity>(EntranceUtils.KEY_COMMUNITY_DATA)?.id
?: "",
arguments?.getString(EntranceUtils.KEY_ANSWER_ID) ?: ""
)
)
}
override fun provideListAdapter(): ListAdapter<*> {
return mAdapter
?: NewQuestionDetailAdapter(requireContext(), mViewModel, BaseCommentAdapter.AdapterType.COMMENT, mEntrance).apply {
mAdapter = this
}
?: NewQuestionDetailAdapter(
requireContext(),
mViewModel,
BaseCommentAdapter.AdapterType.COMMENT,
mEntrance
).apply {
mAdapter = this
}
}
override fun onBackPressed(): Boolean {
if (SyncDataBetweenPageHelper.setResultAndFinish(requireContext(), mViewModel.questionDetail)) {
if (SyncDataBetweenPageHelper.setResultAndFinish(
requireContext(),
mViewModel.questionDetail
)
) {
return true
}
@ -404,13 +469,22 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
entities.add(MenuItemEntity("投诉", R.drawable.icon_gamedetail_copyright))
}
if (questionEntity.user.id == UserManager.getInstance().userId && questionEntity.status == "pass") {
entities.add(MenuItemEntity(if (!questionEntity.finish) "解决" else "已解决", R.drawable.icon_more_panel_solve))
entities.add(
MenuItemEntity(
if (!questionEntity.finish) "解决" else "已解决",
R.drawable.icon_more_panel_solve
)
)
}
if ((questionEntity.me.isModerator || questionEntity.user.id == UserManager.getInstance().userId) && questionEntity.status == "pass") {
entities.add(MenuItemEntity("编辑", R.drawable.icon_more_panel_edit))
}
if (questionEntity.me.isModerator || questionEntity.user.id == UserManager.getInstance().userId) {
entities.add(MenuItemEntity("删除", R.drawable.icon_more_panel_delete))
if (questionEntity.me.isModerator) {
entities.add(MenuItemEntity("隐藏", R.drawable.icon_more_panel_delete))
} else {
if (questionEntity.user.id == UserManager.getInstance().userId) {
entities.add(MenuItemEntity("删除", R.drawable.icon_more_panel_delete))
}
}
val shareIcon = if (questionEntity.images.isNotEmpty()) {
questionEntity.images[0]
@ -428,55 +502,91 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
}
val shareUtils = ShareUtils.getInstance(activity)
shareUtils.shareParamsDetail(
activity,
shareUrl,
shareIcon,
getString(R.string.ask_share_questions_title, questionEntity.title, questionEntity.count.answer),
description,
ShareUtils.ShareEntrance.askNormal,
questionEntity.id, null)
activity,
shareUrl,
shareIcon,
getString(
R.string.ask_share_questions_title,
questionEntity.title,
questionEntity.count.answer
),
description,
ShareUtils.ShareEntrance.askNormal,
questionEntity.id, null
)
val bbsType = if (mViewModel.questionDetail?.type == "game_bbs") "游戏论坛" else "综合论坛"
MoreFunctionPanelDialog.showMoreDialog(requireActivity() as AppCompatActivity, entities, questionEntity.title
?: "", shareUtils) {
MoreFunctionPanelDialog.showMoreDialog(
requireActivity() as AppCompatActivity, entities, questionEntity.title
?: "", shareUtils
) {
when (it.text) {
"投诉" -> {
ifLogin("提问贴") {
BbsReportHelper.showReportDialog(mViewModel.questionDetail?.id
?: "")
BbsReportHelper.showReportDialog(
mViewModel.questionDetail?.id
?: ""
)
}
NewLogUtils.logSharePanelClick("click_report", mViewModel.questionDetail?.user?.id
NewLogUtils.logSharePanelClick(
"click_report", mViewModel.questionDetail?.user?.id
?: "", "提问帖", mViewModel.questionDetail?.id
?: "", mViewModel.questionDetail?.community?.id
?: "", bbsType)
?: "", bbsType
)
}
"编辑" -> {
val intent = if (questionEntity.me.isModerator) {
QuestionEditActivity.getManagerIntent(requireContext(), questionEntity)
QuestionEditActivity.getManagerIntent(
requireContext(),
questionEntity
)
} else {
QuestionEditActivity.getIntent(requireContext(), questionEntity)
}
startActivityForResult(intent, QuestionsDetailFragment.QUESTIONS_EDIT_REQUEST)
NewLogUtils.logSharePanelClick("click_modification_question", mViewModel.questionDetail?.user?.id
startActivityForResult(
intent,
QuestionsDetailFragment.QUESTIONS_EDIT_REQUEST
)
NewLogUtils.logSharePanelClick(
"click_modification_question", mViewModel.questionDetail?.user?.id
?: "", "提问帖", mViewModel.questionDetail?.id
?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType)
?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType
)
}
"删除" -> {
DialogUtils.showNewAlertDialog(requireContext(), "提示", "删除问题后,其中的所有回答都将被删除", "取消", "删除", {}, {
mListViewModel.moderatorsHideQuestion()
})
NewLogUtils.logSharePanelClick("click_delete", mViewModel.questionDetail?.user?.id
"删除", "隐藏" -> {
DialogUtils.showNewAlertDialog(
requireContext(),
"提示",
"${it.text}问题后,其中的所有回答都将被${it.text}",
"取消",
it.text,
{},
{
mListViewModel.moderatorsHideQuestion()
})
NewLogUtils.logSharePanelClick(
"click_delete", mViewModel.questionDetail?.user?.id
?: "", "提问帖", mViewModel.questionDetail?.id
?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType)
?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType
)
}
"解决", "已解决" -> {
val content = if (!questionEntity.finish) "该问题确定标记已解决?" else "该问题确定标记未解决?"
val content =
if (!questionEntity.finish) "该问题确定标记已解决?" else "该问题确定标记未解决?"
DialogHelper.showDialog(requireContext(), "提示", content, "确定", "取消", {
mListViewModel.postSolveQuestion(!questionEntity.finish)
})
NewLogUtils.logSharePanelClick(if (!questionEntity.finish) "click_solve" else "click_resolved", mViewModel.questionDetail?.user?.id
?: "", "提问帖", mViewModel.questionDetail?.id
?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType)
NewLogUtils.logSharePanelClick(
if (!questionEntity.finish) "click_solve" else "click_resolved",
mViewModel.questionDetail?.user?.id
?: "",
"提问帖",
mViewModel.questionDetail?.id
?: "",
mViewModel.questionDetail?.community?.id ?: "",
bbsType
)
}
}
}
@ -488,8 +598,10 @@ class NewQuestionDetailFragment : BaseCommentFragment<CommentItemData, NewQuesti
super.onStop()
val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
val bbsType = if (mViewModel.questionDetail?.type == "game_bbs") "游戏论坛" else "综合论坛"
NewLogUtils.logActivityPause("提问帖详情", "jump_question_detail", stayTime,
mViewModel.questionDetail?.community?.id ?: "", bbsType, "提问帖",
mViewModel.questionDetail?.id ?: "")
NewLogUtils.logActivityPause(
"提问帖详情", "jump_question_detail", stayTime,
mViewModel.questionDetail?.community?.id ?: "", bbsType, "提问帖",
mViewModel.questionDetail?.id ?: ""
)
}
}

View File

@ -15,6 +15,7 @@ import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.entity.CommentEntity
import com.gh.gamecenter.entity.Permissions
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.article.detail.CommentItemData
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
@ -26,6 +27,7 @@ import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
import retrofit2.HttpException
@ -115,6 +117,7 @@ class NewQuestionDetailViewModel(application: Application, questionId: String =
SyncFieldConstants.IS_FOLLOWER,
isFollow,
checkFieldEntity = true))
EventBus.getDefault().post(EBUserFollow(targetUserId, isFollow))
}
override fun onFailure(e: HttpException?) {

View File

@ -84,7 +84,8 @@ class QuestionDetailContentViewHolder(
if (followBtn.text == "关注") {
viewModel.follow()
} else {
DialogUtils.showAlertDialog(root.context,
DialogUtils.showAlertDialog(
root.context,
"取消关注",
"确定要取消关注 ${question.user.name} 吗?",
"确定取消",
@ -229,30 +230,25 @@ class QuestionDetailContentViewHolder(
runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) }
}
else -> {
if (status == "pending") {
ToastUtils.showToast("内容审核中")
return
} else if (status == "fail") {
ToastUtils.showToast("内容审核不通过")
return
}
var current = 0
var i = 0
val size = questionImgUrlList.size
while (i < size) {
if (url.contains(questionImgUrlList.get(i))) {
current = i
clickToastByStatus(status) {
var current = 0
var i = 0
val size = questionImgUrlList.size
while (i < size) {
if (url.contains(questionImgUrlList.get(i))) {
current = i
}
i++
}
i++
val intent = ImageViewerActivity.getIntent(
binding.root.context, questionImgUrlList, current,
mEntrance + "+(问题详情[" + binding.titleTv.text.toString() + "])"
)
(binding.root.context as Activity).startActivityForResult(
intent,
ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE
)
}
val intent = ImageViewerActivity.getIntent(
binding.root.context, questionImgUrlList, current,
mEntrance + "+(问题详情[" + binding.titleTv.text.toString() + "])"
)
(binding.root.context as Activity).startActivityForResult(
intent,
ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE
)
}
}
}

View File

@ -8,6 +8,7 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.baselist.OnDataObservable
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
@ -15,6 +16,7 @@ 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 UserViewModel(application: Application,
@ -53,6 +55,7 @@ class UserViewModel(application: Application,
}
followingLiveData.postValue(position)
EventBus.getDefault().post(EBUserFollow(targetUserId, isFollow))
}
override fun onFailure(e: HttpException?) {

View File

@ -39,7 +39,7 @@ class ForumTopVideoView @JvmOverloads constructor(context: Context, attrs: Attri
var viewModel: ForumVideoDetailViewModel? = null
var uuid = UUID.randomUUID().toString()
var thumbImage: SimpleDraweeView = findViewById(R.id.thumbImage)
var pendingView: View = findViewById(R.id.pendingView)
var pendingView: TextView = findViewById(R.id.pendingView)
var titleTv: TextView = findViewById(R.id.title)
init {
@ -411,8 +411,9 @@ class ForumTopVideoView @JvmOverloads constructor(context: Context, attrs: Attri
uploadVideoStreamingPlaying("暂停播放")
}
fun setPendingStatus(isPending: Boolean) {
if (isPending) {
fun setVideoStatus(status: String) {
if (status == "pending" || status == "fail") {
pendingView.text = if (status == "pending") "审核中...请耐心等待" else "审核不通过"
pendingView.visibility = View.VISIBLE
mBottomContainer?.visibility = View.GONE
mStartButton?.visibility = View.GONE

View File

@ -83,7 +83,11 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
override fun getLayoutId(): Int = 0
override fun getInflatedLayout(): View {
mBinding = FragmentForumVideoDetailBinding.inflate(LayoutInflater.from(requireContext()), null, false)
mBinding = FragmentForumVideoDetailBinding.inflate(
LayoutInflater.from(requireContext()),
null,
false
)
return mBinding.root
}
@ -114,12 +118,14 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
mBinding.toolbar.inflateMenu(R.menu.menu_forum_video_detail)
mMoreMenuItem = mBinding.toolbar.menu.findItem(R.id.menu_more)
ViewCompat.setOnApplyWindowInsetsListener(mBinding.appbar) { _, insets ->
(mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop
(mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin =
insets.systemWindowInsetTop
insets.consumeSystemWindowInsets()
}
mViewModel = viewModelProviderFromParent(ForumVideoDetailViewModel.Factory(mVideoId))
mSkeleton = Skeleton.bind(mBinding.skeleton).shimmer(false).load(R.layout.fragment_video_detail_skeleton).show()
mSkeleton = Skeleton.bind(mBinding.skeleton).shimmer(false)
.load(R.layout.fragment_video_detail_skeleton).show()
mBinding.toolbar.setNavigationOnClickListener { requireActivity().finish() }
mOrientationUtils = OrientationUtils(requireActivity(), mBinding.topVideoView)
mOrientationUtils?.isEnable = false
@ -203,6 +209,7 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
} else {
updateToolbarParams(mVideoHeight / 2)
}
mViewModel.addHistoryRecord(entity)
} else {
mBinding.container.visibility = View.GONE
if (it.exception != null && it.exception.code() == 404) {
@ -229,9 +236,11 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
if (isHighlighted) {
if (mForumVideoEntity!!.me.moderatorPermissions.highlightVideo == Permissions.REPORTER) {
toast("提交成功")
mForumVideoEntity?.choicenessStatus = "apply"
} else {
toast("操作成功")
requireActivity().finish()
mForumVideoEntity?.choicenessStatus = "pass"
mViewModel.updateDetailLiveData.postValue(mForumVideoEntity)
}
} else {
toast("权限错误,请刷新后重试")
@ -240,7 +249,7 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
mViewModel.applyHighlight.observeNonNull(this) {
if (it) {
toast("提交成功")
requireActivity().finish()
mForumVideoEntity?.choicenessStatus = "apply"
} else {
toast("提交失败")
}
@ -258,8 +267,10 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
mBinding.gameScoreTv.text = gameEntity.star.toString()
mBinding.game = gameEntity
mBinding.gameInfoContainer.setOnClickListener {
NewLogUtils.logVideoDetailGameClick("click_game", gameEntity.id, gameEntity.category
?: "", "")
NewLogUtils.logVideoDetailGameClick(
"click_game", gameEntity.id, gameEntity.category
?: "", ""
)
GameDetailActivity.startGameDetailActivity(requireContext(), gameEntity, "视频详情")
}
setDownloadButton(gameEntity)
@ -279,7 +290,12 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
mBinding.toolbar.setNavigationIcon(R.drawable.ic_bar_back_light)
mMoreMenuItem?.setIcon(R.drawable.ic_menu_gamedetail_more_light)
mBinding.toolbar.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.transparent))
mBinding.toolbar.setBackgroundColor(
ContextCompat.getColor(
requireContext(),
R.color.transparent
)
)
}
private fun updateVideoParams() {
@ -303,25 +319,25 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
private fun setUpTopVideo(entity: ForumVideoEntity) {
GSYVideoOptionBuilder()
.setIsTouchWigetFull(false)
.setIsTouchWiget(false)
.setRotateViewAuto(false)
.setShowFullAnimation(false)
.setSeekRatio(1f)
.setUrl(entity.url)
.setCacheWithPlay(true)
.setVideoAllCallBack(object : GSYSampleCallBack() {
override fun onQuitFullscreen(url: String?, vararg objects: Any) {
mOrientationUtils?.backToProtVideo()
mBinding.topVideoView.uploadVideoStreamingPlaying("退出全屏")
}
})
.build(mBinding.topVideoView)
.setIsTouchWigetFull(false)
.setIsTouchWiget(false)
.setRotateViewAuto(false)
.setShowFullAnimation(false)
.setSeekRatio(1f)
.setUrl(entity.url)
.setCacheWithPlay(true)
.setVideoAllCallBack(object : GSYSampleCallBack() {
override fun onQuitFullscreen(url: String?, vararg objects: Any) {
mOrientationUtils?.backToProtVideo()
mBinding.topVideoView.uploadVideoStreamingPlaying("退出全屏")
}
})
.build(mBinding.topVideoView)
mBinding.topVideoView.viewModel = mViewModel
mBinding.topVideoView.updateThumb(entity.poster)
mBinding.topVideoView.setPendingStatus(entity.status == "pending" || entity.status == "fail")
mBinding.topVideoView.setVideoStatus(entity.status)
if (entity.status == "pass" && NetworkUtils.isWifiConnected(requireContext())) {
if (mViewModel.isTopVideoPartlyCached(entity.url)) {
mBinding.topVideoView.startPlayLogic(isAutoPlay = true)
@ -336,7 +352,11 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
}
mBinding.topVideoView.fullscreenButton.setOnClickListener {
val horizontalVideoView = mBinding.topVideoView.startWindowFullscreen(requireContext(), true, true) as? ForumTopVideoView
val horizontalVideoView = mBinding.topVideoView.startWindowFullscreen(
requireContext(),
true,
true
) as? ForumTopVideoView
if (horizontalVideoView == null) {
toastInInternalRelease("全屏失败,请向技术人员提供具体的操作步骤")
return@setOnClickListener
@ -355,7 +375,8 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
}
override fun provideTabView(position: Int, title: String?): View {
val view = LayoutInflater.from(requireContext()).inflate(R.layout.tab_item_forum_video_detail, null)
val view = LayoutInflater.from(requireContext())
.inflate(R.layout.tab_item_forum_video_detail, null)
val tabTitle = view.findViewById<View>(R.id.tab_title)
val tabCount = view.findViewById<TextView>(R.id.tab_count)
if (tabTitle is CheckedTextView) {
@ -372,17 +393,20 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
private fun setDownloadButton(gameEntity: GameEntity?) {
if (gameEntity == null) return
DownloadItemUtils.setOnClickListener(requireContext(), mBinding.downloadBtn,
gameEntity, 0, null,
mEntrance, "视频详情", null, object : EmptyCallback {
override fun onCallback() {
NewLogUtils.logVideoDetailGameClick("click_game", gameEntity.id, gameEntity.category
?: "", mBinding.downloadBtn.text.toString())
}
}, object : EmptyCallback {
override fun onCallback() {
setDownloadButton(gameEntity)
}
}, null)
gameEntity, 0, null,
mEntrance, "视频详情", null, object : EmptyCallback {
override fun onCallback() {
NewLogUtils.logVideoDetailGameClick(
"click_game", gameEntity.id, gameEntity.category
?: "", mBinding.downloadBtn.text.toString()
)
}
}, object : EmptyCallback {
override fun onCallback() {
setDownloadButton(gameEntity)
}
}, null
)
// 显示预约
if (gameEntity.isReservable) {
@ -414,28 +438,52 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
when (offStatus) {
"dialog" -> {
mBinding.downloadBtn.text = "查看"
mBinding.downloadBtn.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
mBinding.downloadBtn.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.white
)
)
}
"updating" -> {
mBinding.downloadBtn.text = "更新中"
mBinding.downloadBtn.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
mBinding.downloadBtn.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.white
)
)
mBinding.downloadBtn.setBackgroundResource(R.drawable.download_button_updating_style)
}
else -> {
mBinding.downloadBtn.text = "暂无"
mBinding.downloadBtn.setTextColor(ContextCompat.getColor(requireContext(), R.color.button_gray))
mBinding.downloadBtn.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.button_gray
)
)
mBinding.downloadBtn.setBackgroundResource(R.drawable.news_detail_comment)
}
}
mBinding.downloadBtn.isClickable = false
}
} else if (gameEntity.getApk().size == 1) {
setDownloadBtnStatus(requireContext(), gameEntity, mBinding.downloadBtn, PluginLocation.only_game)
val downloadEntity = DownloadManager.getInstance(requireContext()).getDownloadEntityByUrl(gameEntity.getApk()[0].url)
setDownloadBtnStatus(
requireContext(),
gameEntity,
mBinding.downloadBtn,
PluginLocation.only_game
)
val downloadEntity = DownloadManager.getInstance(requireContext())
.getDownloadEntityByUrl(gameEntity.getApk()[0].url)
if (downloadEntity != null) {
if (downloadEntity.status == DownloadStatus.done) {
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
val isInstalled = PackageUtils.isInstalled(context, gameEntity.simulator?.apk?.packageName)
val isInstalled = PackageUtils.isInstalled(
context,
gameEntity.simulator?.apk?.packageName
)
if (isInstalled) {
mBinding.downloadBtn.setText(R.string.launch)
} else {
@ -458,15 +506,30 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
mBinding.downloadBtn.setText(R.string.downloading)
}
mBinding.downloadBtn.setBackgroundResource(R.drawable.textview_concern_red_up_round)
mBinding.downloadBtn.setTextColor(ContextCompat.getColorStateList(requireContext(), R.color.white))
mBinding.downloadBtn.setTextColor(
ContextCompat.getColorStateList(
requireContext(),
R.color.white
)
)
}
}
} else {
setDownloadBtnStatus(requireContext(), gameEntity, mBinding.downloadBtn, PluginLocation.only_game)
setDownloadBtnStatus(
requireContext(),
gameEntity,
mBinding.downloadBtn,
PluginLocation.only_game
)
}
}
private fun setDownloadBtnStatus(context: Context, gameEntity: GameEntity, downloadBtn: TextView, pluginLocation: PluginLocation) {
private fun setDownloadBtnStatus(
context: Context,
gameEntity: GameEntity,
downloadBtn: TextView,
pluginLocation: PluginLocation
) {
val status = GameUtils.getDownloadBtnText(context, gameEntity, pluginLocation)
downloadBtn.setTextColor(Color.WHITE)
downloadBtn.text = status
@ -483,8 +546,16 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
private fun showMoreItemDialog() {
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) || mForumVideoEntity != null) {
val entities = ArrayList<MenuItemEntity>()
if (mForumVideoEntity?.user?.id == UserManager.getInstance().userId && !mForumVideoEntity?.me!!.isModerator && mForumVideoEntity?.status == "pass" && mForumVideoEntity?.choicenessStatus != "pass") {
entities.add(MenuItemEntity("申请加精", R.drawable.icon_more_panel_essence))
if (mForumVideoEntity?.user?.id == UserManager.getInstance().userId && !mForumVideoEntity?.me!!.isModerator && mForumVideoEntity?.status == "pass") {
val isEnable =
mForumVideoEntity?.getSimplifyChoicenessStatus() != "pass"
entities.add(
MenuItemEntity(
"申请加精", if (isEnable)
R.drawable.icon_more_panel_essence else R.drawable.icon_more_panel_essence_unenable,
isEnable = isEnable
)
)
}
if (mForumVideoEntity?.user?.id == UserManager.getInstance().userId && mForumVideoEntity?.status == "pass") {
entities.add(MenuItemEntity("修改", R.drawable.icon_more_panel_edit))
@ -492,14 +563,25 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
if (mForumVideoEntity?.user?.id != UserManager.getInstance().userId) {
entities.add(MenuItemEntity("投诉", R.drawable.icon_gamedetail_copyright))
}
if (mForumVideoEntity?.me!!.isModerator) {
val isEnable = mForumVideoEntity?.isHighlighted == true
entities.add(MenuItemEntity("加精选", if (isEnable)
R.drawable.icon_more_panel_essence_unenable else R.drawable.icon_more_panel_essence, isEnable = !isEnable))
if (mForumVideoEntity?.me!!.isModerator && mForumVideoEntity?.status == "pass") {
val isEnable =
mForumVideoEntity?.getSimplifyChoicenessStatus() != "pass"
entities.add(
MenuItemEntity(
"加精选",
if (isEnable)
R.drawable.icon_more_panel_essence else R.drawable.icon_more_panel_essence_unenable,
isEnable = isEnable
)
)
entities.add(MenuItemEntity("修改活动标签", R.drawable.icon_more_panel_modify_label))
}
if (mForumVideoEntity?.me!!.isModerator || mForumVideoEntity?.user?.id == UserManager.getInstance().userId) {
entities.add(MenuItemEntity("删除", R.drawable.icon_more_panel_delete))
if (mForumVideoEntity?.me!!.isModerator) {
entities.add(MenuItemEntity("隐藏", R.drawable.icon_more_panel_delete))
} else {
if (mForumVideoEntity?.user?.id == UserManager.getInstance().userId) {
entities.add(MenuItemEntity("删除", R.drawable.icon_more_panel_delete))
}
}
val shareUrl = if (isPublishEnv()) {
"https://m.ghzs666.com/video/${mForumVideoEntity?.id}"
@ -513,62 +595,98 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
requireContext().getString(R.string.share_ghzs_logo)
}
val shareUtils = ShareUtils.getInstance(requireContext())
shareUtils.shareParamsDetail(requireActivity(),
shareUrl,
shareIcon,
mForumVideoEntity?.title ?: "",
mForumVideoEntity?.des ?: "",
ShareUtils.ShareEntrance.communityArticle,
mForumVideoEntity?.id, null)
shareUtils.shareParamsDetail(
requireActivity(),
shareUrl,
shareIcon,
mForumVideoEntity?.title ?: "",
mForumVideoEntity?.des ?: "",
ShareUtils.ShareEntrance.video,
mForumVideoEntity?.id, null
)
val bbsType = if (mForumVideoEntity?.type == "game_bbs") "游戏论坛" else "综合论坛"
MoreFunctionPanelDialog.showMoreDialog(requireActivity() as AppCompatActivity, entities, mForumVideoEntity?.title
?: "", shareUtils) {
MoreFunctionPanelDialog.showMoreDialog(
requireActivity() as AppCompatActivity, entities, mForumVideoEntity?.title
?: "", shareUtils
) {
when (it.text) {
"修改" -> {
startActivityForResult(VideoPublishActivity.getIntent(requireContext(), mForumVideoEntity!!, mEntrance, "视频详情"), ForumVideoDetailActivity.VIDEO_PATCH_REQUEST)
NewLogUtils.logSharePanelClick("click_modification", mForumVideoEntity?.user?.id
startActivityForResult(
VideoPublishActivity.getIntent(
requireContext(),
mForumVideoEntity!!,
mEntrance,
"视频详情"
), ForumVideoDetailActivity.VIDEO_PATCH_REQUEST
)
NewLogUtils.logSharePanelClick(
"click_modification", mForumVideoEntity?.user?.id
?: "", "视频帖", mForumVideoEntity?.id
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType)
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType
)
}
"投诉" -> {
BbsReportHelper.showReportDialog(mForumVideoEntity?.id ?: "")
NewLogUtils.logSharePanelClick("click_report", mForumVideoEntity?.user?.id
NewLogUtils.logSharePanelClick(
"click_report", mForumVideoEntity?.user?.id
?: "", "视频帖", mForumVideoEntity?.id
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType)
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType
)
}
"申请加精" -> {
if (mForumVideoEntity?.choicenessStatus == "apply") {
if (mForumVideoEntity?.getSimplifyChoicenessStatus() == "apply") {
ToastUtils.showToast("申请加精审核中")
return@showMoreDialog
}
mViewModel.doApplyHighlightCommunityVideo(mVideoId)
NewLogUtils.logSharePanelClick("click_apply_essence", mForumVideoEntity?.user?.id
NewLogUtils.logSharePanelClick(
"click_apply_essence", mForumVideoEntity?.user?.id
?: "", "视频帖", mForumVideoEntity?.id
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType)
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType
)
}
"加精选" -> {
if (mForumVideoEntity?.getSimplifyChoicenessStatus() == "apply") {
ToastUtils.showToast("加精审核中")
return@showMoreDialog
}
addEssenceForum()
NewLogUtils.logSharePanelClick("click_essence", mForumVideoEntity?.user?.id
NewLogUtils.logSharePanelClick(
"click_essence", mForumVideoEntity?.user?.id
?: "", "视频帖", mForumVideoEntity?.id
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType)
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType
)
}
"修改活动标签" -> {
ChooseActivityDialogFragment.show(requireActivity() as AppCompatActivity, ChooseActivityDialogFragment.ActivityLabelLocation.BBS_ARTICLE, mForumVideoEntity?.tagActivityId) { label ->
if (label != null) {
mViewModel.modifyVideoActivityTag(mForumVideoEntity, label)
NewLogUtils.logSharePanelClick("click_modification_activity_tag", mForumVideoEntity?.user?.id
?: "", "视频帖", mForumVideoEntity?.id
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType)
}
ChooseActivityDialogFragment.show(
requireActivity() as AppCompatActivity,
ChooseActivityDialogFragment.ActivityLabelLocation.BBS_ARTICLE,
mForumVideoEntity?.tagActivityId
) { label ->
mViewModel.modifyVideoActivityTag(mForumVideoEntity, label)
NewLogUtils.logSharePanelClick(
"click_modification_activity_tag", mForumVideoEntity?.user?.id
?: "", "视频帖", mForumVideoEntity?.id
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType
)
}
}
"删除" -> {
DialogUtils.showNewAlertDialog(requireContext(), "提示", "删除视频后,其中的所有评论及回复都将被删除", "取消", "删除", {}, {
mViewModel.deleteVideo(mForumVideoEntity?.id ?: "")
})
NewLogUtils.logSharePanelClick("click_delete", mForumVideoEntity?.user?.id
"删除", "隐藏" -> {
DialogUtils.showNewAlertDialog(
requireContext(),
"提示",
"${it.text}视频后,其中的所有评论及回复都将被${it.text}",
"取消",
it.text,
{},
{
mViewModel.deleteVideo(mForumVideoEntity?.id ?: "")
})
NewLogUtils.logSharePanelClick(
"click_delete", mForumVideoEntity?.user?.id
?: "", "视频帖", mForumVideoEntity?.id
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType)
?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType
)
}
}
}
@ -583,25 +701,24 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
highlightDialogHintContent = if (permissions.highlightVideo == Permissions.REPORTER) {
"你的操作将提交给小编审核,确定提交吗?"
} else {
"你的操作将立即生效,确定提交吗?(你的管理权限为:高级)"
"你的操作将立即生效,确定提交吗?"
}
}
if (mForumVideoEntity?.isHighlighted == true) {
toast("帖子已经加精")
} else {
DialogUtils.showAlertDialog(requireContext(), "加精视频", highlightDialogHintContent,
"确定", "取消",
{
mViewModel.doHighlightThisVideo(mForumVideoEntity?.bbsId ?: "", mVideoId)
}, null)
}
DialogUtils.showAlertDialog(
requireContext(), "加精视频", highlightDialogHintContent,
"确定", "取消",
{
mViewModel.doHighlightThisVideo(mForumVideoEntity?.bbsId ?: "", mVideoId)
}, null
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK) return
if (requestCode == ForumVideoDetailActivity.VIDEO_PATCH_REQUEST) {
val entity = data.getParcelableExtra<ForumVideoEntity>(ForumVideoEntity::class.java.simpleName)
val entity =
data.getParcelableExtra<ForumVideoEntity>(ForumVideoEntity::class.java.simpleName)
mForumVideoEntity?.let {
it.title = entity?.title ?: ""
it.des = entity?.des ?: ""
@ -638,7 +755,12 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
super.onPause()
mBinding.topVideoView.onVideoPause()
val currentPosition = mBinding.topVideoView.getCurrentPosition()
ForumScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(mForumVideoEntity?.url), currentPosition)
mForumVideoEntity?.let {
ForumScrollCalculatorHelper.savePlaySchedule(
MD5Utils.getContentMD5(it.url),
currentPosition
)
}
DownloadManager.getInstance(requireContext()).removeObserver(dataWatcher)
}
@ -648,9 +770,11 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
mBinding.topVideoView.disposableTimer()
val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
val bbsType = if (mForumVideoEntity?.type == "game_bbs") "游戏论坛" else "综合论坛"
NewLogUtils.logActivityPause("视频帖详情页", "jump_video_detail ", stayTime,
mForumVideoEntity?.bbs?.id ?: "", bbsType, "视频帖",
mForumVideoEntity?.id ?: "")
NewLogUtils.logActivityPause(
"视频帖详情页", "jump_video_detail ", stayTime,
mForumVideoEntity?.bbs?.id ?: "", bbsType, "视频帖",
mForumVideoEntity?.id ?: ""
)
}
override fun onBackPressed(): Boolean {

View File

@ -6,14 +6,19 @@ import android.net.Uri
import android.text.TextUtils
import androidx.lifecycle.*
import com.gh.common.constant.Constants
import com.gh.common.history.HistoryDatabase
import com.gh.common.json.json
import com.gh.common.runOnIoThread
import com.gh.common.util.*
import com.gh.gamecenter.entity.ActivityLabelEntity
import com.gh.gamecenter.entity.ForumVideoEntity
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.entity.User
import com.gh.gamecenter.mvvm.Resource
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import com.google.gson.JsonObject
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
@ -21,7 +26,8 @@ import okhttp3.ResponseBody
import retrofit2.HttpException
import tv.danmaku.ijk.media.exo2.ExoSourceManager
class ForumVideoDetailViewModel(application: Application, val videoId: String) : AndroidViewModel(application) {
class ForumVideoDetailViewModel(application: Application, val videoId: String) :
AndroidViewModel(application) {
private val mApi = RetrofitManager.getInstance(getApplication()).api
var videoIsMuted = SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true)
val detailLiveData = MediatorLiveData<Resource<ForumVideoEntity>>()
@ -38,112 +44,132 @@ class ForumVideoDetailViewModel(application: Application, val videoId: String) :
fun getVideoDetail() {
mApi.getBbsVideoDetail(videoId)
.compose(observableToMain())
.subscribe(object : Response<ForumVideoEntity>() {
override fun onResponse(response: ForumVideoEntity?) {
super.onResponse(response)
if (response != null) {
detailLiveData.postValue(Resource.success(response))
.compose(observableToMain())
.subscribe(object : Response<ForumVideoEntity>() {
override fun onResponse(response: ForumVideoEntity?) {
super.onResponse(response)
if (response != null) {
detailLiveData.postValue(Resource.success(response))
NewLogUtils.logForumContentBrowser(videoId, "bbs_video")
}
NewLogUtils.logForumContentBrowser(videoId, "bbs_video")
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
detailLiveData.postValue(Resource.error(e))
}
})
override fun onFailure(e: HttpException?) {
super.onFailure(e)
detailLiveData.postValue(Resource.error(e))
}
})
}
@SuppressLint("CheckResult")
fun shareVideoStatistics(videoEntity: ForumVideoEntity?) {
if (videoEntity == null) return
mApi.shareVideoStatistics(videoEntity.id)
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<JsonObject>() {
override fun onSuccess(data: JsonObject) {
val msg = data.get("msg").asString
if ("success" == msg) {
videoEntity.let {
it.share++
}
needToUpdateShareCount.postValue(videoEntity.share)
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<JsonObject>() {
override fun onSuccess(data: JsonObject) {
val msg = data.get("msg").asString
if ("success" == msg) {
videoEntity.let {
it.share++
}
needToUpdateShareCount.postValue(videoEntity.share)
}
})
}
})
}
fun deleteVideo(videoId: String) {
mApi.deleteVideo(videoId)
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
deleteLiveData.postValue(true)
}
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
deleteLiveData.postValue(true)
}
override fun onFailure(e: HttpException?) {
val string = e?.response()?.errorBody()?.string() ?: ""
ErrorHelper.handleError(getApplication(), string)
}
})
override fun onFailure(e: HttpException?) {
val string = e?.response()?.errorBody()?.string() ?: ""
ErrorHelper.handleError(getApplication(), string)
}
})
}
//版主加精
fun doHighlightThisVideo(bbsId: String, videoId: String) {
mApi.highlightCommunityVideo(bbsId, videoId)
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
highlight.postValue(true)
}
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
highlight.postValue(true)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
highlight.postValue(false)
}
})
override fun onFailure(e: HttpException?) {
super.onFailure(e)
highlight.postValue(false)
}
})
}
//用户申请加精
fun doApplyHighlightCommunityVideo(videoId: String) {
mApi.applyHighlightCommunityVideo(videoId)
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
applyHighlight.postValue(true)
}
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
applyHighlight.postValue(true)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
applyHighlight.postValue(false)
}
})
override fun onFailure(e: HttpException?) {
super.onFailure(e)
applyHighlight.postValue(false)
}
})
}
fun modifyVideoActivityTag(videoEntity: ForumVideoEntity?, label: ActivityLabelEntity) {
val body = json { "tag_activity_id" to label.id }.toRequestBody()
mApi.modifyVideoActivityTag(videoEntity?.bbsId,videoId,body)
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
videoEntity?.apply {
tagActivityId = label.id
tagActivityName = label.name
updateDetailLiveData.postValue(this)
}
fun modifyVideoActivityTag(videoEntity: ForumVideoEntity?, label: ActivityLabelEntity?) {
val body = json { "tag_activity_id" to label?.id }.toRequestBody()
mApi.modifyVideoActivityTag(videoEntity?.bbsId, videoId, body)
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
videoEntity?.apply {
tagActivityId = label?.id ?: ""
tagActivityName = label?.name ?: ""
updateDetailLiveData.postValue(this)
ToastUtils.showToast("修改活动标签成功")
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
ToastUtils.showToast("修改活动标签失败")
}
})
override fun onFailure(e: HttpException?) {
super.onFailure(e)
ToastUtils.showToast("修改活动标签失败")
}
})
}
fun addHistoryRecord(videoEntity: ForumVideoEntity) {
val videoHistory = MyVideoEntity().apply {
id = videoEntity.id
poster = videoEntity.poster
url = videoEntity.url
vote = videoEntity.count.vote
length = videoEntity.length
time = System.currentTimeMillis()
title = videoEntity.title
user = User(
videoEntity.user.id, videoEntity.user.name, videoEntity.user.icon
)
commentCount = videoEntity.count.comment
videoStreamRecord = 0
}
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().addVideo(videoHistory) } }
}
fun isTopVideoPartlyCached(topVideoUrl: String): Boolean {

View File

@ -40,8 +40,10 @@ class VideoCommentFragment : LazyListFragment<CommentItemData, VideoCommentViewM
override fun getRealLayoutId(): Int = R.layout.fragment_video_comment_list
override fun getItemDecoration(): RecyclerView.ItemDecoration {
val insetDivider = ContextCompat.getDrawable(requireContext(), R.drawable.divider_item_line_space_16)
val itemDecoration = CustomDividerItemDecoration(requireContext(), notDecorateTheLastItem = true)
val insetDivider =
ContextCompat.getDrawable(requireContext(), R.drawable.divider_item_line_space_16)
val itemDecoration =
CustomDividerItemDecoration(requireContext(), notDecorateTheLastItem = true)
itemDecoration.setDrawable(insetDivider!!)
return itemDecoration
}
@ -78,7 +80,8 @@ class VideoCommentFragment : LazyListFragment<CommentItemData, VideoCommentViewM
mVideoDetailViewModel.detailLiveData.observeNonNull(this) {
if (it.status == Status.SUCCESS) {
mListViewModel.videoDetail = it.data as ForumVideoEntity
mBinding.allCommentCountTv.text = mListViewModel.videoDetail?.count?.comment.toString()
mBinding.allCommentCountTv.text =
mListViewModel.videoDetail?.count?.comment.toString()
onRefresh()
}
}
@ -94,7 +97,8 @@ class VideoCommentFragment : LazyListFragment<CommentItemData, VideoCommentViewM
private fun updateSortType() {
mBinding.run {
val isLatestSelected = mListViewModel.currentSortType == BaseCommentViewModel.SortType.LATEST
val isLatestSelected =
mListViewModel.currentSortType == BaseCommentViewModel.SortType.LATEST
val selectedTextView = if (isLatestSelected) filterLatestTv else filterOldestTv
val unselectedTextView = if (!isLatestSelected) filterLatestTv else filterOldestTv
@ -104,23 +108,23 @@ class VideoCommentFragment : LazyListFragment<CommentItemData, VideoCommentViewM
}
fun startCommentActivity() {
if (mListViewModel.videoDetail?.status != "pass") {
ToastUtils.showToast("内容审核中")
return
}
mListViewModel.videoDetail?.let {
val intent = CommentActivity.getVideoCommentIntent(
clickToastByStatus(mListViewModel.videoDetail?.status ?: "") {
mListViewModel.videoDetail?.let {
val intent = CommentActivity.getVideoCommentIntent(
requireContext(),
it.id,
it.count.comment,
it.user.id == UserManager.getInstance().userId,
true, true, false
)
startActivityForResult(intent, CommentActivity.REQUEST_CODE)
val bbsType = if (mListViewModel.videoDetail?.type == "game_bbs") "游戏论坛" else "综合论坛"
NewLogUtils.logCommentClick("click_comment_area_comment_input_box", mListViewModel.videoDetail?.user?.id
?: "", "视频帖", mListViewModel.videoDetail?.id
?: "", mListViewModel.videoDetail?.bbs?.id ?: "", bbsType)
)
startActivityForResult(intent, CommentActivity.REQUEST_CODE)
val bbsType = if (mListViewModel.videoDetail?.type == "game_bbs") "游戏论坛" else "综合论坛"
NewLogUtils.logCommentClick(
"click_comment_area_comment_input_box", mListViewModel.videoDetail?.user?.id
?: "", "视频帖", mListViewModel.videoDetail?.id
?: "", mListViewModel.videoDetail?.bbs?.id ?: "", bbsType
)
}
}
}
@ -137,7 +141,14 @@ class VideoCommentFragment : LazyListFragment<CommentItemData, VideoCommentViewM
mBinding.allCommentCountTv.text = it.count.comment.toString()
mVideoDetailViewModel.updateDetailLiveData.postValue(it)
mListViewModel.load(LoadType.REFRESH)
SyncPageRepository.postSyncData(SyncDataEntity(mVideoId, SyncFieldConstants.ARTICLE_COMMENT_COUNT, it.count.comment, checkFieldEntity = true))
SyncPageRepository.postSyncData(
SyncDataEntity(
mVideoId,
SyncFieldConstants.ARTICLE_COMMENT_COUNT,
it.count.comment,
checkFieldEntity = true
)
)
}
}
}

View File

@ -4,6 +4,7 @@ import android.view.View
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.NewLogUtils
import com.gh.common.util.ShareUtils
import com.gh.common.util.observeNonNull
import com.gh.common.util.viewModelProviderFromParent
import com.gh.gamecenter.R
@ -11,8 +12,11 @@ import com.gh.gamecenter.baselist.LazyListFragment
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.entity.ForumVideoEntity
import com.gh.gamecenter.entity.VideoDescItemEntity
import com.gh.gamecenter.eventbus.EBShare
import com.gh.gamecenter.mvvm.Status
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailViewModel
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class VideoDescFragment : LazyListFragment<VideoDescItemEntity, VideoDescViewModel>() {
@ -68,4 +72,13 @@ class VideoDescFragment : LazyListFragment<VideoDescItemEntity, VideoDescViewMod
}
override fun isAutomaticLoad(): Boolean = false
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(share: EBShare?) {
postDelayedRunnable({
if (share != null && share.shareEntrance == ShareUtils.ShareEntrance.video && isSupportVisible) {
mVideoDetailViewModel.shareVideoStatistics(mListViewModel.topVideoDetail)
}
}, 200)
}
}

View File

@ -16,9 +16,16 @@ import com.gh.gamecenter.databinding.ItemVideoDescTopBinding
import com.gh.gamecenter.entity.ForumVideoEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailViewModel
import kotlin.math.max
class VideoDescTopViewHolder(val binding: ItemVideoDescTopBinding, var mIsExpand: Boolean, var mShrinkHeight: Int, var mExpandHeight: Int,
val mVideoDetailViewModel: ForumVideoDetailViewModel, val mViewModel: VideoDescViewModel) : BaseRecyclerViewHolder<Any>(binding.root) {
class VideoDescTopViewHolder(
val binding: ItemVideoDescTopBinding,
var mIsExpand: Boolean,
var mShrinkHeight: Int,
var mExpandHeight: Int,
val mVideoDetailViewModel: ForumVideoDetailViewModel,
val mViewModel: VideoDescViewModel
) : BaseRecyclerViewHolder<Any>(binding.root) {
private var mIsAnimationFinish = true
fun bindData(entity: ForumVideoEntity) {
binding.entity = entity
@ -26,53 +33,79 @@ class VideoDescTopViewHolder(val binding: ItemVideoDescTopBinding, var mIsExpand
binding.executePendingBindings()
if (entity.original == "yes") {
binding.originalTv.visibility = View.VISIBLE
binding.activityNameTv.layoutParams = (binding.activityNameTv.layoutParams as ConstraintLayout.LayoutParams).apply {
leftMargin = 8f.dip2px()
}
binding.activityNameTv.layoutParams =
(binding.activityNameTv.layoutParams as ConstraintLayout.LayoutParams).apply {
leftMargin = 8f.dip2px()
}
}
if (entity.choicenessStatus == "pass") {
binding.titleTv.text = SpanBuilder(" ${entity.title}").image(0, 1, R.drawable.ic_essence).build()
if (entity.getSimplifyChoicenessStatus() == "pass") {
binding.titleTv.text =
SpanBuilder(" ${entity.title}").image(0, 1, R.drawable.ic_essence).build()
}
initAnimation(entity)
val bbsType = if (entity.bbs?.type == "game_bbs") "游戏论坛" else "综合论坛"
binding.userAvatar.setOnClickListener {
DirectUtils.directToHomeActivity(binding.root.context, entity.user.id, "视频详情", "")
NewLogUtils.logVideoDetailClick("click_detail_tab_profile_photo", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType)
NewLogUtils.logVideoDetailClick(
"click_detail_tab_profile_photo", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType
)
}
binding.userNameTv.setOnClickListener {
DirectUtils.directToHomeActivity(binding.root.context, entity.user.id, "视频详情", "")
NewLogUtils.logVideoDetailClick("click_detail_tab_nickname", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType)
NewLogUtils.logVideoDetailClick(
"click_detail_tab_nickname", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType
)
}
binding.likeContainer.setOnClickListener {
debounceActionWithInterval(it.id, 2000) {
mViewModel.postVote()
NewLogUtils.logVideoDetailClick("click_detail_tab_like", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType, entity.id)
NewLogUtils.logVideoDetailClick(
"click_detail_tab_like", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType, entity.id
)
}
}
binding.collectContainer.setOnClickListener {
debounceActionWithInterval(it.id) {
mViewModel.postFavorite()
NewLogUtils.logVideoDetailClick("click_detail_tab_collect", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType, entity.id)
NewLogUtils.logVideoDetailClick(
"click_detail_tab_collect", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType, entity.id
)
}
}
binding.concernBtn.setOnClickListener {
if (entity.user.id != UserManager.getInstance().userId) {
debounceActionWithInterval(it.id) {
mViewModel.followCommand()
NewLogUtils.logVideoDetailClick("click_detail_tab_follow", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType)
if (!entity.me.isFollower) {
mViewModel.followCommand()
} else {
DialogHelper.showDialog(
binding.concernBtn.context,
"提示",
"确定要取消关注 ${entity.user.name} 吗?",
"确定取消",
"暂不取消",
{
mViewModel.followCommand()
})
}
NewLogUtils.logVideoDetailClick(
"click_detail_tab_follow", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType
)
}
}
}
binding.shareContainer.setOnClickListener {
share(entity)
NewLogUtils.logVideoDetailClick("click_detail_tab_share", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType, entity.id)
NewLogUtils.logVideoDetailClick(
"click_detail_tab_share", entity.user.id,
"视频贴", entity.bbs?.id ?: "", bbsType, entity.id
)
}
}
@ -83,9 +116,17 @@ class VideoDescTopViewHolder(val binding: ItemVideoDescTopBinding, var mIsExpand
} else mShrinkHeight
mExpandHeight = if (mExpandHeight == 0) {
getTextViewHeight(binding.titleTv) + getTextViewHeight(binding.desTv) + getTextViewHeight(binding.activityNameTv) +
var height = getTextViewHeight(binding.titleTv) +
getTextViewHeight(binding.desTv) +
(if (binding.desTv.visibility == View.VISIBLE) binding.desTv.marginTop else 0) +
(if (binding.activityNameTv.visibility == View.VISIBLE) binding.activityNameTv.marginTop else 0)
(if (binding.activityNameTv.visibility == View.VISIBLE || binding.originalTv.visibility == View.VISIBLE) binding.activityNameTv.marginTop else 0)
if (binding.activityNameTv.visibility == View.VISIBLE || binding.originalTv.visibility == View.VISIBLE) {
height += max(
getTextViewHeight(binding.activityNameTv),
binding.originalTv.measuredHeight
)
}
height
} else mExpandHeight
if (mIsExpand) {
@ -96,9 +137,10 @@ class VideoDescTopViewHolder(val binding: ItemVideoDescTopBinding, var mIsExpand
updateTitleContainerHeight(mShrinkHeight)
}
//若标题未超过一行或无描述内容活动标签,箭头不显示
val ellipsisCount = binding.titleTv.layout.getEllipsisCount(binding.titleTv.lineCount - 1)
binding.expandMoreIv.goneIf(entity.des.isEmpty() && entity.tagActivityName.isEmpty() && ellipsisCount == 0)
//若标题未超过一行或无描述内容活动标签、原创标签,箭头不显示
val ellipsisCount =
binding.titleTv.layout.getEllipsisCount(binding.titleTv.lineCount - 1)
binding.expandMoreIv.goneIf(entity.des.isEmpty() && entity.tagActivityName.isEmpty() && entity.original != "yes" && ellipsisCount == 0)
}
binding.expandMoreIv.setOnClickListener {
NewLogUtils.logVideoDetailClick(if (!mIsExpand) "click_detail_tab_down" else "click_detail_tab_up")
@ -139,20 +181,23 @@ class VideoDescTopViewHolder(val binding: ItemVideoDescTopBinding, var mIsExpand
} else {
"https://resource.ghzs.com/page/video_play/video/video.html?video=${entity.id}"
}
ShareUtils.getInstance(binding.root.context).showShareWindowsCallback(binding.root.context as Activity,
ShareUtils.getInstance(binding.root.context)
.showShareWindowsCallback(binding.root.context as Activity,
(binding.root.context as Activity).window.decorView,
shareUrl,
shareIcon,
entity.title,
entity.des,
ShareUtils.ShareEntrance.video, entity.id, object : ShareUtils.ShareCallBack {
override fun onSuccess(label: String) {
if ("短信" == label || "复制链接" == label) mVideoDetailViewModel.shareVideoStatistics(entity)
}
override fun onSuccess(label: String) {
if ("短信" == label || "复制链接" == label) mVideoDetailViewModel.shareVideoStatistics(
entity
)
}
override fun onCancel() {
}
})
override fun onCancel() {
}
})
}
private fun updateTitleContainerHeight(newHeight: Int) {

View File

@ -12,23 +12,30 @@ import com.gh.common.util.*
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.entity.ForumVideoEntity
import com.gh.gamecenter.entity.VideoDescItemEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
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 VideoDescViewModel(application: Application) : ListViewModel<ForumVideoEntity, VideoDescItemEntity>(application) {
class VideoDescViewModel(application: Application) :
ListViewModel<ForumVideoEntity, VideoDescItemEntity>(application) {
var topVideoDetail: ForumVideoEntity? = null
var handleSuccessLiveData = MutableLiveData<Boolean>()
override fun provideDataObservable(page: Int): Observable<MutableList<ForumVideoEntity>>? {
return RetrofitManager.getInstance(getApplication()).api.getRecommendVideo(topVideoDetail?.id, page)
return RetrofitManager.getInstance(getApplication()).api.getRecommendVideo(
topVideoDetail?.id,
page
)
}
override fun mergeResultLiveData() {
@ -60,10 +67,8 @@ class VideoDescViewModel(application: Application) : ListViewModel<ForumVideoEnt
if (topVideoDetail!!.me.isVoted) {
undoVoteVideo(topVideoDetail?.id ?: "")
} else {
if (topVideoDetail?.status == "pass") {
clickToastByStatus(topVideoDetail?.status ?: "") {
voteVideo(topVideoDetail?.id ?: "")
} else {
ToastUtils.toast("内容审核中")
}
}
}
@ -71,47 +76,87 @@ class VideoDescViewModel(application: Application) : ListViewModel<ForumVideoEnt
@SuppressLint("CheckResult")
private fun voteVideo(videoId: String) {
RetrofitManager.getInstance(getApplication())
.api.voteVideo(videoId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
topVideoDetail?.let {
it.me.isVoted = true
it.count.vote = it.count.vote + 1
handleSuccessLiveData.postValue(true)
ToastUtils.showToast("点赞爆棚,视频能让更多人看见!")
SyncPageRepository.postSyncData(SyncDataEntity(videoId, SyncFieldConstants.ARTICLE_VOTE, true, checkFieldEntity = true))
SyncPageRepository.postSyncData(SyncDataEntity(videoId, SyncFieldConstants.ARTICLE_VOTE_COUNT, it.count.vote, checkFieldEntity = true))
}
.api.voteVideo(videoId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
topVideoDetail?.let {
it.me.isVoted = true
it.count.vote = it.count.vote + 1
handleSuccessLiveData.postValue(true)
ToastUtils.showToast("点赞爆棚,视频能让更多人看见!")
SyncPageRepository.postSyncData(
SyncDataEntity(
videoId,
SyncFieldConstants.ARTICLE_VOTE,
true,
checkFieldEntity = true
)
)
SyncPageRepository.postSyncData(
SyncDataEntity(
videoId,
SyncFieldConstants.ARTICLE_VOTE_COUNT,
it.count.vote,
checkFieldEntity = true
)
)
}
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
override fun onFailure(exception: Exception) {
super.onFailure(exception)
if (exception is HttpException) {
ErrorHelper.handleError(
HaloApp.getInstance(),
exception.response()?.errorBody()?.string()
)
}
})
}
})
}
@SuppressLint("CheckResult")
private fun undoVoteVideo(videoId: String) {
RetrofitManager.getInstance(getApplication())
.api.undoVoteVideo(videoId)
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
topVideoDetail?.let {
it.me.isVoted = false
it.count.vote = it.count.vote - 1
handleSuccessLiveData.postValue(true)
SyncPageRepository.postSyncData(SyncDataEntity(videoId, SyncFieldConstants.ARTICLE_VOTE, false, checkFieldEntity = true))
SyncPageRepository.postSyncData(SyncDataEntity(videoId, SyncFieldConstants.ARTICLE_VOTE_COUNT, it.count.vote, checkFieldEntity = true))
}
.api.undoVoteVideo(videoId)
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
topVideoDetail?.let {
it.me.isVoted = false
it.count.vote = it.count.vote - 1
handleSuccessLiveData.postValue(true)
SyncPageRepository.postSyncData(
SyncDataEntity(
videoId,
SyncFieldConstants.ARTICLE_VOTE,
false,
checkFieldEntity = true
)
)
SyncPageRepository.postSyncData(
SyncDataEntity(
videoId,
SyncFieldConstants.ARTICLE_VOTE_COUNT,
it.count.vote,
checkFieldEntity = true
)
)
}
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
override fun onFailure(exception: Exception) {
super.onFailure(exception)
if (exception is HttpException) {
ErrorHelper.handleError(
HaloApp.getInstance(),
exception.response()?.errorBody()?.string()
)
}
})
}
})
}
fun postFavorite() {
@ -123,10 +168,8 @@ class VideoDescViewModel(application: Application) : ListViewModel<ForumVideoEnt
if (topVideoDetail!!.me.isVideoFavorite) {
undoFavoriteVideo(topVideoDetail?.id ?: "")
} else {
if (topVideoDetail?.status == "pass") {
clickToastByStatus(topVideoDetail?.status ?: "") {
favoriteVideo(topVideoDetail?.id ?: "")
} else {
ToastUtils.toast("内容审核中")
}
}
}
@ -134,45 +177,45 @@ class VideoDescViewModel(application: Application) : ListViewModel<ForumVideoEnt
@SuppressLint("CheckResult")
private fun favoriteVideo(videoId: String) {
RetrofitManager.getInstance(getApplication())
.api.collectVideo(UserManager.getInstance().userId, videoId)
.compose(singleToMain())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
topVideoDetail?.let {
it.me.isVideoFavorite = true
it.count.favorite++
handleSuccessLiveData.postValue(true)
}
ToastUtils.toast("收藏成功")
.api.collectVideo(UserManager.getInstance().userId, videoId)
.compose(singleToMain())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
topVideoDetail?.let {
it.me.isVideoFavorite = true
it.count.favorite++
handleSuccessLiveData.postValue(true)
}
ToastUtils.toast("收藏成功")
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
Utils.toast(getApplication(), exception.localizedMessage)
}
})
override fun onFailure(exception: Exception) {
super.onFailure(exception)
Utils.toast(getApplication(), exception.localizedMessage)
}
})
}
@SuppressLint("CheckResult")
private fun undoFavoriteVideo(videoId: String) {
RetrofitManager.getInstance(getApplication())
.api.undoCollectVideo(UserManager.getInstance().userId, videoId)
.compose(singleToMain())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
topVideoDetail?.let {
it.me.isVideoFavorite = false
it.count.favorite--
handleSuccessLiveData.postValue(true)
}
ToastUtils.toast("取消收藏")
.api.undoCollectVideo(UserManager.getInstance().userId, videoId)
.compose(singleToMain())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
topVideoDetail?.let {
it.me.isVideoFavorite = false
it.count.favorite--
handleSuccessLiveData.postValue(true)
}
ToastUtils.toast("取消收藏")
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
Utils.toast(getApplication(), exception.localizedMessage)
}
})
override fun onFailure(exception: Exception) {
super.onFailure(exception)
Utils.toast(getApplication(), exception.localizedMessage)
}
})
}
fun followCommand() {
@ -187,30 +230,35 @@ class VideoDescViewModel(application: Application) : ListViewModel<ForumVideoEnt
RetrofitManager.getInstance(getApplication()).api.deleteFollowing(topVideoDetail?.user?.id)
}
observable
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
topVideoDetail?.let {
if (!it.me.isFollower) {
ToastUtils.showToast("关注成功")
}
it.me.isFollower = !it.me.isFollower
}
handleSuccessLiveData.postValue(true)
topVideoDetail?.run {
SyncPageRepository.postSyncData(SyncDataEntity(id,
SyncFieldConstants.IS_FOLLOWER,
me.isFollower,
checkFieldEntity = true))
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
topVideoDetail?.let {
if (!it.me.isFollower) {
ToastUtils.showToast("关注成功")
}
it.me.isFollower = !it.me.isFollower
}
handleSuccessLiveData.postValue(true)
override fun onFailure(e: HttpException?) {
super.onFailure(e)
ToastUtils.showToast("加载失败,请检查网络状态")
topVideoDetail?.run {
SyncPageRepository.postSyncData(
SyncDataEntity(
id,
SyncFieldConstants.IS_FOLLOWER,
me.isFollower,
checkFieldEntity = true
)
)
EventBus.getDefault().post(EBUserFollow(user.id, me.isFollower))
}
})
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
ToastUtils.showToast("加载失败,请检查网络状态")
}
})
}
}

View File

@ -59,7 +59,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
override fun getLayoutId(): Int = 0
override fun getInflatedLayout(): View {
mBinding = FragmentVideoPublishBinding.inflate(LayoutInflater.from(requireContext()), null, false)
mBinding =
FragmentVideoPublishBinding.inflate(LayoutInflater.from(requireContext()), null, false)
return mBinding.root
}
@ -72,8 +73,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
mViewModel = viewModelProvider()
mViewModel.videoDraft = arguments?.getParcelable(VideoDraftEntity::class.java.simpleName)
mViewModel.videoPatch = arguments?.getParcelable(ForumVideoEntity::class.java.simpleName)
mViewModel.communityEntity = arguments?.getParcelable(CommunityEntity::class.java.simpleName)
mViewModel.selectActivityLabelEntity = arguments?.getParcelable(ActivityLabelEntity::class.java.simpleName)
mViewModel.communityEntity =
arguments?.getParcelable(CommunityEntity::class.java.simpleName)
mViewModel.selectActivityLabelEntity =
arguments?.getParcelable(ActivityLabelEntity::class.java.simpleName)
mViewModel.type = arguments?.getString(BbsType::class.java.simpleName) ?: ""
mIsForumSelectionDisabled = arguments?.getBoolean(IS_FORUM_SELECTION_DISABLED) ?: false
@ -102,17 +105,31 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
}
mBinding.uploadButton.setOnClickListener {
PermissionHelper.checkStoragePermissionBeforeAction(requireActivity(), object : EmptyCallback {
override fun onCallback() {
startActivityForResult(LocalMediaActivity.getIntent(requireContext(), LocalMediaActivity.ChooseType.VIDEO, 1, "发视频帖"), BaseRichEditorActivity.INSERT_VIDEO_CODE)
NewLogUtils.logChooseMedia("view_media", "视频帖", "视频")
}
})
PermissionHelper.checkStoragePermissionBeforeAction(
requireActivity(),
object : EmptyCallback {
override fun onCallback() {
startActivityForResult(
LocalMediaActivity.getIntent(
requireContext(),
LocalMediaActivity.ChooseType.VIDEO,
1,
"发视频帖"
), BaseRichEditorActivity.INSERT_VIDEO_CODE
)
NewLogUtils.logChooseMedia("view_media", "视频帖", "视频")
}
})
}
mBinding.videoPosterPatchHint.setOnClickListener { startMediaStore() }
mBinding.forumContainer.setOnClickListener {
if (mViewModel.type == BbsType.OFFICIAL_BBS.value) {
startActivityForResult(GameActivity.getIntent(requireContext(), GameActivity.SELECT_GAME_TITLE), REQUEST_GAME_CODE)
startActivityForResult(
GameActivity.getIntent(
requireContext(),
GameActivity.SELECT_GAME_TITLE
), REQUEST_GAME_CODE
)
} else {
ChooseForumActivity.startChooseForumActivity(requireActivity())
NewLogUtils.logChooseForumPanelEnter("发视频帖")
@ -125,9 +142,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
} else 0L
AppExecutor.uiExecutor.executeWithDelay(Runnable {
ChooseActivityDialogFragment.show(
requireActivity() as AppCompatActivity,
ChooseActivityDialogFragment.ActivityLabelLocation.BBS_VIDEO,
mViewModel.selectActivityLabelEntity?.id) {
requireActivity() as AppCompatActivity,
ChooseActivityDialogFragment.ActivityLabelLocation.BBS_VIDEO,
mViewModel.selectActivityLabelEntity?.id
) {
mViewModel.selectActivityLabelEntity = it
mBinding.activityTitle.text = it?.name
mBinding.activityTitle.setTextColor(if (it != null) R.color.text_FA8500.toColor() else R.color.text_333333.toColor())
@ -156,7 +174,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
}
}
mBinding.reprintUrlTv.setOnClickListener {
InputUrlDialogFragment.show(requireActivity() as AppCompatActivity, mBinding.reprintUrlTv.text.toString()) {
InputUrlDialogFragment.show(
requireActivity() as AppCompatActivity,
mBinding.reprintUrlTv.text.toString()
) {
mBinding.reprintUrlTv.text = it
}
}
@ -180,7 +201,12 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
setForumName()
if (mIsForumSelectionDisabled && mViewModel.type == BbsType.GAME_BBS.value) {
mBinding.forumContainer.isEnabled = false
mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(
null,
null,
null,
null
)
}
}
if (mViewModel.selectActivityLabelEntity != null) {
@ -188,11 +214,20 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
mBinding.activityTitle.setTextColor(if (mViewModel.selectActivityLabelEntity != null) R.color.text_FA8500.toColor() else R.color.text_333333.toColor())
}
PermissionHelper.checkStoragePermissionBeforeAction(requireActivity(), object : EmptyCallback {
override fun onCallback() {
startActivityForResult(LocalMediaActivity.getIntent(requireContext(), LocalMediaActivity.ChooseType.VIDEO, 1, "发视频帖"), BaseRichEditorActivity.INSERT_VIDEO_CODE)
}
})
PermissionHelper.checkStoragePermissionBeforeAction(
requireActivity(),
object : EmptyCallback {
override fun onCallback() {
startActivityForResult(
LocalMediaActivity.getIntent(
requireContext(),
LocalMediaActivity.ChooseType.VIDEO,
1,
"发视频帖"
), BaseRichEditorActivity.INSERT_VIDEO_CODE
)
}
})
}
}
}
@ -215,7 +250,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
toast("保存成功")
requireActivity().finish()
} else if (it.status == Status.ERROR) {
ErrorHelper.handleError(requireContext(), it.exception?.response()?.errorBody()?.string())
ErrorHelper.handleError(
requireContext(),
it.exception?.response()?.errorBody()?.string()
)
}
}
mViewModel.postLiveData.observeNonNull(this) {
@ -233,7 +271,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
}, 1000)
UploadManager.deleteUploadData(mVideoFileEntity?.path)
} else if (it.status == Status.ERROR) {
ErrorHelper.handleError(requireContext(), it.exception?.response()?.errorBody()?.string())
ErrorHelper.handleError(
requireContext(),
it.exception?.response()?.errorBody()?.string()
)
}
}
}
@ -248,7 +289,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK) return
if (requestCode == BaseRichEditorActivity.INSERT_VIDEO_CODE) {
val localVideoList = data.getParcelableArrayListExtra<LocalVideoEntity>(LocalVideoEntity::class.java.name)
val localVideoList =
data.getParcelableArrayListExtra<LocalVideoEntity>(LocalVideoEntity::class.java.name)
?: arrayListOf()
if (localVideoList.isNotEmpty()) {
initUpload(localVideoList[0].filePath, localVideoList[0].poster)
@ -258,7 +300,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
mBinding.videoPoster.setImageURI("file://$imagePath")
mUpdatedPosterPath = imagePath ?: ""
} else if (requestCode == ChooseForumActivity.CHOOSE_FORUM_REQUEST) {
val community = data.getParcelableExtra<CommunityEntity>(EntranceUtils.KEY_COMMUNITY_DATA)
val community =
data.getParcelableExtra<CommunityEntity>(EntranceUtils.KEY_COMMUNITY_DATA)
mViewModel.communityEntity = community
mViewModel.type = community?.type ?: ""
if (mViewModel.type == BbsType.GAME_BBS.value) {
@ -272,7 +315,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
setForumName()
}
} else if (requestCode == REQUEST_CHOOSE_DRAFT) {
val draftEntity = data.getParcelableExtra<VideoDraftEntity>(VideoDraftEntity::class.java.simpleName)
val draftEntity =
data.getParcelableExtra<VideoDraftEntity>(VideoDraftEntity::class.java.simpleName)
if (draftEntity != null) {
mViewModel.videoDraft = draftEntity
setVideoDraft()
@ -304,7 +348,14 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
mBinding.reprintUrlTv.isEnabled = false
}
if (mVideoFileEntity == null) {
mVideoFileEntity = VideoFileEntity("", videoPatch.url, videoPatch.poster, videoPatch.length, videoPatch.length, videoPatch.format)
mVideoFileEntity = VideoFileEntity(
"",
videoPatch.url,
videoPatch.poster,
videoPatch.length,
videoPatch.length,
videoPatch.format
)
}
handleUploadSuccess(videoPatch.url)
mBinding.deleteVideoIv.visibility = View.GONE
@ -314,8 +365,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
private fun setVideoDraft() {
mViewModel.videoDraft?.let {
if (it.bbsId.isNotEmpty() && it.game != null) {
mViewModel.communityEntity = CommunityEntity(it.bbsId, it.game?.name
?: "", icon = it.game?.icon, iconSubscript = it.game?.iconSubscript)
mViewModel.communityEntity = CommunityEntity(
it.bbsId, it.game?.name
?: "", icon = it.game?.icon, iconSubscript = it.game?.iconSubscript
)
mViewModel.gameEntity = it.game
}
mViewModel.gameEntity = it.game
@ -325,7 +378,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
if (it.tagActivityId.isNotEmpty() && it.tagActivityName.isNotEmpty()) {
mBinding.activityTitle.text = it.tagActivityName
mBinding.activityTitle.setTextColor(R.color.text_FA8500.toColor())
mViewModel.selectActivityLabelEntity = ActivityLabelEntity(it.tagActivityId, it.tagActivityName)
mViewModel.selectActivityLabelEntity =
ActivityLabelEntity(it.tagActivityId, it.tagActivityName)
}
if (it.url.isNotEmpty()) {
ImageUtils.display(mBinding.videoPoster, it.poster)
@ -350,7 +404,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
if (poster.isNotEmpty()) {
ImageUtils.display(mBinding.videoPoster, poster)
} else {
val thumbnail = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Images.Thumbnails.MINI_KIND)
val thumbnail = ThumbnailUtils.createVideoThumbnail(
videoPath,
MediaStore.Images.Thumbnails.MINI_KIND
)
mBinding.videoPoster.setImageBitmap(thumbnail)
}
@ -400,20 +457,31 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
}
}
mVideoFileEntity = VideoFileEntity(videoPath, null, poster, timeInSecond, videoFile.length(), format)
mVideoFileEntity =
VideoFileEntity(videoPath, null, poster, timeInSecond, videoFile.length(), format)
createUploadTask(videoPath)
}
private fun createUploadTask(videoPath: String) {
mBinding.uploadStatus.text = "视频上传中..."
UploadManager.createUploadTask(videoPath, object : OnUploadListener {
override fun onProgressChanged(uploadFilePath: String, currentSize: Long, totalSize: Long, speed: Long) {
override fun onProgressChanged(
uploadFilePath: String,
currentSize: Long,
totalSize: Long,
speed: Long
) {
runOnUiThread {
mBinding.uploadInfoContainer.visibility = View.VISIBLE
mBinding.uploadStatus.text = "视频上传中..."
mBinding.uploadSpeed.visibility = View.VISIBLE
mBinding.pauseButton.visibility = View.VISIBLE
mBinding.uploadSpeed.text = (SpeedUtils.getSpeed(speed) + "预计还需" + SpeedUtils.getRemainTime(totalSize, currentSize, speed))
mBinding.uploadSpeed.text =
(SpeedUtils.getSpeed(speed) + "预计还需" + SpeedUtils.getRemainTime(
totalSize,
currentSize,
speed
))
mBinding.uploadProgress.update(((360 * currentSize) / totalSize).toInt(), "")
}
}
@ -471,14 +539,20 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
if (mViewModel.communityEntity != null) {
if (mViewModel.type == BbsType.GAME_BBS.value) {
mBinding.chooseForumTv.text = mViewModel.communityEntity?.name
mBinding.forumIconView.displayGameIcon(mViewModel.communityEntity?.icon, mViewModel.communityEntity?.iconSubscript)
mBinding.forumIconView.displayGameIcon(
mViewModel.communityEntity?.icon,
mViewModel.communityEntity?.iconSubscript
)
setForumUI()
} else if (mViewModel.type == BbsType.OFFICIAL_BBS.value) {
if (mViewModel.gameEntity == null) {
mBinding.chooseForumTv.text = "选择游戏"
} else {
mBinding.chooseForumTv.text = mViewModel.gameEntity?.name
mBinding.forumIconView.displayGameIcon(mViewModel.gameEntity?.icon, mViewModel.gameEntity?.iconSubscript)
mBinding.forumIconView.displayGameIcon(
mViewModel.gameEntity?.icon,
mViewModel.gameEntity?.iconSubscript
)
setForumUI()
}
}
@ -495,7 +569,12 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
private fun setForumUI() {
mBinding.forumIconView.visibility = View.VISIBLE
mBinding.forumContainer.background = R.drawable.bg_shape_f5_radius_999.toDrawable()
mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(null, null, R.drawable.ic_article_edit_choose_forum_arrow_gray.toDrawable(), null)
mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(
null,
null,
R.drawable.ic_article_edit_choose_forum_arrow_gray.toDrawable(),
null
)
mBinding.chooseForumTv.setTextColor(R.color.text_333333.toColor())
}
@ -525,7 +604,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
}
R.id.menu_draft -> {
NewLogUtils.logVideoDraftClick()
startActivityForResult(VideoDraftActivity.getIntent(requireContext()), REQUEST_CHOOSE_DRAFT)
startActivityForResult(
VideoDraftActivity.getIntent(requireContext()),
REQUEST_CHOOSE_DRAFT
)
}
}
}
@ -546,26 +628,35 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
private fun startMediaStore() {
try {
PermissionHelper.checkStoragePermissionBeforeAction(requireContext(), object : EmptyCallback {
override fun onCallback() {
var intent: Intent? = null
when {
mVideoFileEntity?.url?.isNotEmpty() == true -> {
val videoEntity = VideoEntity(length = mVideoFileEntity?.length
?: 0, url = mVideoFileEntity?.url ?: "")
intent = PosterEditActivity.getIntentByVideo(requireContext(), videoEntity)
}
mVideoFileEntity?.path?.isNotEmpty() == true -> {
intent = PosterEditActivity.getIntentByPath(requireContext(), mVideoFileEntity?.url
?: "")
}
else -> {
throwExceptionInDebug("video not found")
PermissionHelper.checkStoragePermissionBeforeAction(
requireContext(),
object : EmptyCallback {
override fun onCallback() {
var intent: Intent? = null
when {
mVideoFileEntity?.url?.isNotEmpty() == true -> {
val videoEntity = VideoEntity(
length = mVideoFileEntity?.length
?: 0, url = mVideoFileEntity?.url ?: ""
)
intent = PosterEditActivity.getIntentByVideo(
requireContext(),
videoEntity
)
}
mVideoFileEntity?.path?.isNotEmpty() == true -> {
intent = PosterEditActivity.getIntentByPath(
requireContext(), mVideoFileEntity?.url
?: ""
)
}
else -> {
throwExceptionInDebug("video not found")
}
}
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
}
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
}
})
})
} catch (e: Exception) {
toast(R.string.media_image_hint)
e.printStackTrace()
@ -578,18 +669,28 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
if (mViewModel.videoPatch == null && mViewModel.videoDraft == null) {
if (mBinding.title.text.isNotEmpty() || mBinding.videoDes.text.isNotEmpty()) {
DialogUtils.showNewAlertDialog(requireContext(), "提示", "是否保存内容再退出?", "不保存", "保存并退出", Gravity.CENTER, true, {
requireActivity().finish()
}, {
verifyData(true)
})
DialogUtils.showNewAlertDialog(
requireContext(),
"提示",
"是否保存内容再退出?",
"不保存",
"保存并退出",
Gravity.CENTER,
true,
{
requireActivity().finish()
},
{
verifyData(true)
})
return true
}
}
if (mViewModel.videoPatch != null && mViewModel.videoDraft == null) {
return if (mViewModel.videoPatch?.title != mBinding.title.text.toString() ||
mViewModel.videoPatch?.des != mBinding.videoDes.text.toString()) {
mViewModel.videoPatch?.des != mBinding.videoDes.text.toString()
) {
showBackDialog()
true
} else false
@ -600,7 +701,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
}
private fun logButtonClick(event: String) {
val bbsType = if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else ""
val bbsType =
if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else ""
val originalType = if (mBinding.originalTv.isChecked && !mBinding.reprintTv.isChecked) {
"原创"
} else if (!mBinding.originalTv.isChecked && mBinding.reprintTv.isChecked) {
@ -608,14 +710,17 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
} else {
"未勾选"
}
NewLogUtils.logPublishVideoClick(event, mViewModel.communityEntity?.id
NewLogUtils.logPublishVideoClick(
event, mViewModel.communityEntity?.id
?: "", bbsType, mViewModel.selectActivityLabelEntity?.name
?: "", mBinding.videoDes.text.toString().count(), originalType)
?: "", mBinding.videoDes.text.toString().count(), originalType
)
}
private fun checkDraft(): Boolean {
if (mViewModel.videoDraft != null && (mViewModel.videoDraft?.title != mBinding.title.text.toString()
|| mViewModel.videoDraft?.des != mBinding.videoDes.text.toString())) {
|| mViewModel.videoDraft?.des != mBinding.videoDes.text.toString())
) {
showBackDialog()
return true
}
@ -623,18 +728,28 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
}
private fun showBackDialog() {
DialogUtils.showNewAlertDialog(requireContext(), "提示", "是否保存修改内容用于下次编辑?", "不保存", "保存并退出", Gravity.CENTER, true, {
requireActivity().finish()
}, {
verifyData(true)
})
DialogUtils.showNewAlertDialog(
requireContext(),
"提示",
"是否保存修改内容用于下次编辑?",
"不保存",
"保存并退出",
Gravity.CENTER,
true,
{
requireActivity().finish()
},
{
verifyData(true)
})
}
private fun verifyData(isDraft: Boolean) {
if (ClickUtils.isFastDoubleClick()) return
if (mViewModel.videoPatch == null) {
if (!isDraft && mVideoFileEntity != null &&
!File(mVideoFileEntity?.path ?: "").exists()) {
!File(mVideoFileEntity?.path ?: "").exists()
) {
toast("提交失败,视频文件不存在")
handleFileNotFound()
return
@ -655,7 +770,6 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
toast("请填写标题")
return
}
if (!isDraft && !mBinding.originalTv.isChecked && !mBinding.reprintTv.isChecked) {
toast("请选择内容来源")
return
@ -680,22 +794,21 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
mViewModel.videoPatch!!
} else {
ForumVideoEntity(
id = mViewModel.videoDraft?.id ?: "",
title = title.toString(),
des = des.toString(),
url = mVideoFileEntity?.url ?: "",
size = mVideoFileEntity?.size ?: 0,
format = mVideoFileEntity?.format ?: "",
length = mVideoFileEntity?.length ?: 0,
poster = mViewModel.videoDraft?.poster ?: "",
bbsId = mViewModel.communityEntity?.id ?: "",
type = mViewModel.type,
gameId = mViewModel.gameEntity?.id ?: mViewModel.communityEntity?.game?.id
?: "",
original = if (mBinding.originalTv.isChecked) "yes" else if (mBinding.reprintTv.isChecked) "no" else "",
source = if (mBinding.reprintTv.isChecked) mBinding.reprintUrlTv.text.toString() else "",
tagActivityId = mViewModel.selectActivityLabelEntity?.id ?: "",
tagActivityName = mViewModel.selectActivityLabelEntity?.name ?: ""
id = mViewModel.videoDraft?.id ?: "",
title = title.toString(),
des = des.toString(),
url = mVideoFileEntity?.url ?: "",
size = mVideoFileEntity?.size ?: 0,
format = mVideoFileEntity?.format ?: "",
length = mVideoFileEntity?.length ?: 0,
poster = mViewModel.videoDraft?.poster ?: "",
bbsId = mViewModel.communityEntity?.id ?: "",
type = mViewModel.type,
gameId = mViewModel.gameEntity?.id ?: mViewModel.communityEntity?.game?.id ?: "",
original = if (mBinding.originalTv.isChecked) "yes" else if (mBinding.reprintTv.isChecked) "no" else "",
source = if (mBinding.reprintTv.isChecked) mBinding.reprintUrlTv.text.toString() else "",
tagActivityId = mViewModel.selectActivityLabelEntity?.id ?: "",
tagActivityName = mViewModel.selectActivityLabelEntity?.name ?: ""
)
}
if (mUpdatedPosterPath.isEmpty() && videoData.poster.isNotEmpty()) {
@ -709,10 +822,13 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
val posterPath = if (mUpdatedPosterPath.isNotEmpty()) {
mUpdatedPosterPath
} else {
val localVideoPoster = requireActivity().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg"
val localVideoPoster =
requireActivity().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg"
try {
val bmp = ThumbnailUtils.createVideoThumbnail(mVideoFileEntity?.path
?: "", MediaStore.Images.Thumbnails.MINI_KIND)
val bmp = ThumbnailUtils.createVideoThumbnail(
mVideoFileEntity?.path
?: "", MediaStore.Images.Thumbnails.MINI_KIND
)
// bmp 可能为空
FileOutputStream(localVideoPoster).use { out ->
bmp?.compress(Bitmap.CompressFormat.PNG, 100, out)
@ -724,7 +840,12 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver {
}
localVideoPoster
}
mViewModel.postVideoPosterAndContent(isDraft, videoData, posterPath, mVideoFileEntity?.path)
mViewModel.postVideoPosterAndContent(
isDraft,
videoData,
posterPath,
mVideoFileEntity?.path
)
}
}

View File

@ -7,6 +7,7 @@ import android.content.Intent;
import android.os.Bundle;
import com.gh.base.fragment.BaseFragment_ViewPager;
import com.gh.common.AppExecutor;
import com.gh.common.constant.Constants;
import com.gh.common.util.DownloadNotificationHelper;
import com.gh.common.util.EntranceUtils;
@ -44,42 +45,49 @@ public class InstallReceiver extends BroadcastReceiver {
}
updateNotification(downloadEntity);
if (PackageUtils.isCanLaunchSetup(context, path)) {
if (downloadEntity != null) {
PackageInstaller.install(context, downloadEntity);
DownloadEntity finalDownloadEntity = downloadEntity;
AppExecutor.getIoExecutor().execute(() -> {
if (PackageUtils.isInstallable(context, path)) {
AppExecutor.getUiExecutor().execute(() -> {
if (finalDownloadEntity != null) {
PackageInstaller.install(context, finalDownloadEntity);
} else {
PackageInstaller.install(context, false, path);
}
});
} else {
PackageInstaller.install(context, false, path);
}
} else {
if (RunningUtils.isRunning(context)) {
if (RunningUtils.isEqualsTop(context, DownloadManagerActivity.class.getName())) {
// 这里是指从后台返回到前台 前两个的是关键
Intent intent2 = new Intent();
intent2.setAction(Intent.ACTION_MAIN);
intent2.addCategory(Intent.CATEGORY_LAUNCHER);
intent2.setComponent(new ComponentName(context, DownloadManagerActivity.class));
intent2.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
context.startActivity(intent2);
AppExecutor.getUiExecutor().execute(() -> {
if (RunningUtils.isRunning(context)) {
if (RunningUtils.isEqualsTop(context, DownloadManagerActivity.class.getName())) {
// 这里是指从后台返回到前台 前两个的是关键
Intent intent2 = new Intent();
intent2.setAction(Intent.ACTION_MAIN);
intent2.addCategory(Intent.CATEGORY_LAUNCHER);
intent2.setComponent(new ComponentName(context, DownloadManagerActivity.class));
intent2.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
context.startActivity(intent2);
EventBus.getDefault().post(new EBMiPush("plugin_install", path));
} else {
Intent intent2 = new Intent(context, DownloadManagerActivity.class);
intent2.putExtra(BaseFragment_ViewPager.ARGS_INDEX, 0);
intent2.putExtra(EntranceUtils.KEY_PATH, path);
intent2.putExtra(EntranceUtils.KEY_ENTRANCE, "(安装跳转)");
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
}
} else {
// 应用未在运行
Bundle bundle = new Bundle();
bundle.putString(KEY_TO, DownloadManagerActivity.TAG);
bundle.putInt(BaseFragment_ViewPager.ARGS_INDEX, 0);
bundle.putString(EntranceUtils.KEY_PATH, path);
bundle.putString(EntranceUtils.KEY_ENTRANCE, "(安装跳转)");
context.startActivity(SplashScreenActivity.getSplashScreenIntent(context, bundle));
EventBus.getDefault().post(new EBMiPush("plugin_install", path));
} else {
Intent intent2 = new Intent(context, DownloadManagerActivity.class);
intent2.putExtra(BaseFragment_ViewPager.ARGS_INDEX, 0);
intent2.putExtra(EntranceUtils.KEY_PATH, path);
intent2.putExtra(EntranceUtils.KEY_ENTRANCE, "(安装跳转)");
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
}
} else {
// 应用未在运行
Bundle bundle = new Bundle();
bundle.putString(KEY_TO, DownloadManagerActivity.TAG);
bundle.putInt(BaseFragment_ViewPager.ARGS_INDEX, 0);
bundle.putString(EntranceUtils.KEY_PATH, path);
bundle.putString(EntranceUtils.KEY_ENTRANCE, "(安装跳转)");
context.startActivity(SplashScreenActivity.getSplashScreenIntent(context, bundle));
}
});
}
}
});
});
}

View File

@ -109,7 +109,7 @@ class BindPhoneViewModel(application: Application) : AndroidViewModel(applicatio
400302 -> finishLiveData.postValue(false)
403092 -> ToastUtils.showToast("邀请码错误")
403092 -> ToastUtils.showToast("填写邀请码错误")
else -> LoginUtils.outputErrorHint(context, code)
}
@ -201,7 +201,7 @@ class BindPhoneViewModel(application: Application) : AndroidViewModel(applicatio
400302 -> finishLiveData.postValue(false)
403092 -> ToastUtils.showToast("邀请码错误")
403092 -> ToastUtils.showToast("填写邀请码错误")
else -> LoginUtils.outputErrorHint(context, code)
}

View File

@ -1,16 +1,19 @@
package com.gh.gamecenter.setting
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.preference.PreferenceManager
import android.text.TextUtils
import android.util.Log
import android.view.View
import androidx.core.content.FileProvider
import butterknife.OnClick
import com.gh.common.util.MtaHelper.onEvent
import com.gh.common.util.PackageUtils
import com.gh.common.util.SPUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.CleanApkActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentGameDownloadSettingBinding
@ -20,6 +23,7 @@ import java.io.File
class GameDownloadSettingFragment: NormalFragment() {
private var mBinding: FragmentGameDownloadSettingBinding? = null
private var mSP: SharedPreferences? = null
override fun getLayoutId() = 0
@ -27,14 +31,17 @@ class GameDownloadSettingFragment: NormalFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mSP = PreferenceManager.getDefaultSharedPreferences(requireContext())
initStatus()
}
private fun initStatus() {
mBinding?.run {
autoInstallSwitch.isChecked = SPUtils.getBoolean(AUTO_INSTALL_SP_KEY)
concernGameSwitch.isChecked = SPUtils.getBoolean(CONCERN_GAME_SP_KEY)
trafficSwitch.isChecked = SPUtils.getBoolean(getTrafficDownloadHintKey())
mSP?.run {
autoInstallSwitch.isChecked = getBoolean(AUTO_INSTALL_SP_KEY, false)
concernGameSwitch.isChecked = getBoolean(CONCERN_GAME_SP_KEY, false)
trafficSwitch.isChecked = getBoolean(getTrafficDownloadHintKey(), false)
}
}
}
@ -48,19 +55,19 @@ class GameDownloadSettingFragment: NormalFragment() {
onEvent("我的光环_设置", "设置功能", "下载完成自动安装游戏")
onEvent("我的光环_设置", "自动安装游戏", if (autoInstallSwitch.isChecked) "关闭" else "打开")
autoInstallSwitch.isChecked = !autoInstallSwitch.isChecked
SPUtils.setBoolean(AUTO_INSTALL_SP_KEY, autoInstallSwitch.isChecked)
mSP?.edit()?.putBoolean(AUTO_INSTALL_SP_KEY, autoInstallSwitch.isChecked)?.apply()
}
R.id.concernGameContainer -> {
onEvent("我的光环_设置", "设置功能", "安装完成自动关注游戏")
onEvent("我的光环_设置", "自动关注游戏", if (concernGameSwitch.isChecked) "关闭" else "打开")
concernGameSwitch.isChecked = !concernGameSwitch.isChecked
SPUtils.setBoolean(CONCERN_GAME_SP_KEY, concernGameSwitch.isChecked)
mSP?.edit()?.putBoolean(CONCERN_GAME_SP_KEY, concernGameSwitch.isChecked)?.apply()
}
R.id.trafficContainer -> {
trafficSwitch.isChecked = !trafficSwitch.isChecked
SPUtils.setBoolean(getTrafficDownloadHintKey(), trafficSwitch.isChecked)
mSP?.edit()?.putBoolean(getTrafficDownloadHintKey(), trafficSwitch.isChecked)?.apply()
}
R.id.downloadPathContainer -> {
@ -87,7 +94,12 @@ class GameDownloadSettingFragment: NormalFragment() {
private fun startFilePath(dirPath: String) {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.setDataAndType(Uri.fromFile(File(dirPath)), "file/*")
val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(requireContext(), BuildConfig.APPLICATION_ID, File(dirPath))
} else {
Uri.fromFile(File(dirPath))
}
intent.setDataAndType(uri, "file/*")
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
try {

View File

@ -268,7 +268,7 @@ public class UserRepository {
if (httpException.code() == 400) {
LoginUtils.outputErrorHint(mContext, code);
} else if (code == 403092) {
Utils.toast(mContext, "邀请码错误");
Utils.toast(mContext, "填写邀请码错误");
} else {
Utils.toast(mContext, mContext.getString(R.string.login_failure_hint_code, code));
}
@ -458,6 +458,14 @@ public class UserRepository {
MessageUnreadRepository.INSTANCE.loadMessageUnreadData();
}
if (UserManager.getInstance().getLoginTokenEntity() != null) {
if (UserManager.getInstance().getLoginTokenEntity().isFirstLogin()) {
EnergyTaskHelper.postEnergyTask("register");
} else {
EnergyTaskHelper.postEnergyTask("login");
}
}
}
@Override

View File

@ -14,6 +14,7 @@ import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.entity.User
import com.gh.gamecenter.entity.VideoEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
@ -23,6 +24,7 @@ import com.lightgame.utils.Utils
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import java.lang.ref.WeakReference
import java.util.*
import kotlin.collections.ArrayList
@ -560,6 +562,7 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel
videoEntity.me.isFollower = true
followVideoInfo.postValue(videoEntity)
Utils.toast(getApplication(), "关注成功")
EventBus.getDefault().post(EBUserFollow(videoEntity.user.id, true))
}
})

View File

@ -15,6 +15,8 @@ import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@ -133,6 +135,7 @@ public class WebFragment extends LazyFragment implements IScrollable {
private boolean mIsWebPageHandleBackPressed;
private boolean mIsOpenNativePage;//网页打开新页面是否重新打开一个原生页面
private boolean mIsHorizontalDispatcherEnabled;
private boolean mIsWebPageSuccessfullyLoaded = true; // 页面是否成功加载
private String mBackConfirmationContent;
private String mGameName;
private String mIsCloseButton;//h5游戏是否显示关闭按钮 hide(隐藏)、open(开启)
@ -408,6 +411,16 @@ public class WebFragment extends LazyFragment implements IScrollable {
}
}, 100);
}
if (!"Webpage not available".equals(mWebView.getTitle())) {
mIsWebPageSuccessfullyLoaded = true;
}
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
mIsWebPageSuccessfullyLoaded = false;
}
});
@ -571,12 +584,12 @@ public class WebFragment extends LazyFragment implements IScrollable {
return false;
} else if (!TextUtils.isEmpty(mGameName)) {
return false;
} else if (mIsWebPageHandleBackPressed) {
} else if (mWebView != null && mIsWebPageHandleBackPressed && mIsWebPageSuccessfullyLoaded) {
mWebView.callHandler("onBackPressed", retValue -> {
// do nothing
});
return true;
} else if (mWebView.canGoBack()) {
} else if (mWebView != null && mWebView.canGoBack()) {
mWebView.goBack();
return true;
} else if (isDisplayingLogoutPage()) {
@ -612,6 +625,8 @@ public class WebFragment extends LazyFragment implements IScrollable {
.equals(Constants.EB_QUIT_LOGIN)) {
mWebView.reload();
}
} else {
mJsApi.onLogin();
}
}
}
@ -632,7 +647,9 @@ public class WebFragment extends LazyFragment implements IScrollable {
@Override
public void scrollToTop() {
mWebView.scrollTo(0, 0);
if (mWebView != null) {
mWebView.scrollTo(0, 0);
}
}
/**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Some files were not shown because too many files have changed in this diff Show More