初次代码上传
This commit is contained in:
commit
058e46bae8
109
app/build.gradle.kts
Normal file
109
app/build.gradle.kts
Normal file
@ -0,0 +1,109 @@
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
// id("com.google.gms.google-services")
|
||||
// id("com.google.firebase.firebase-perf")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.jia.er.nebuluxe.app"
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.jia.er.nebuluxe.app"
|
||||
minSdk = 24
|
||||
targetSdk = 35
|
||||
versionCode = 1
|
||||
versionName = "1.0.0"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
// signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
viewBinding = true
|
||||
}
|
||||
android.applicationVariants.all {
|
||||
val buildType = this.buildType.name
|
||||
val date = SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format(Date())
|
||||
outputs.all {
|
||||
if (this is com.android.build.gradle
|
||||
.internal.api.ApkVariantOutputImpl
|
||||
) {
|
||||
this.outputFileName = "Nebuluxe" +
|
||||
"_${android.defaultConfig.versionName}_${android.defaultConfig.versionCode}_${date}_${buildType}.apk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar"))))
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.androidx.lifecycle.viewmodel.ktx)
|
||||
implementation(libs.material)
|
||||
implementation(libs.com.github.wuao.flycotablayout2)
|
||||
implementation(libs.io.github.youth5201314.banner)
|
||||
implementation(libs.io.github.cymchad.baserecyclerviewadapterhelper4)
|
||||
implementation(libs.com.github.bumptech.glide.glide2)
|
||||
implementation(libs.org.greenrobot.eventbus3)
|
||||
implementation(libs.androidx.media3.media3.exoplayer2)
|
||||
implementation(libs.androidx.media3.media3.exoplayer.dash2)
|
||||
implementation(libs.androidx.media3.media3.ui2)
|
||||
implementation(libs.androidx.media3.media3.exoplayer.hls2)
|
||||
implementation(libs.androidx.media3.media3.exoplayer.rtsp2)
|
||||
implementation(libs.squareup.okhttp)
|
||||
implementation(libs.squareup.logging.interceptor)
|
||||
implementation(libs.squareup.retrofit)
|
||||
implementation(libs.squareup.converter.gson)
|
||||
implementation(libs.com.tencent.mmkv)
|
||||
implementation(libs.androidx.lifecycle.lifecycle.livedata.ktx3)
|
||||
implementation(libs.androidx.lifecycle.lifecycle.extensions4)
|
||||
implementation(libs.scwang90.refresh.layout.kernel)
|
||||
implementation(libs.scwang90.refresh.header.material)
|
||||
implementation(libs.scwang90.refresh.footer.classics)
|
||||
implementation(libs.com.getkeepsafe.relinker.relinker)
|
||||
implementation(libs.utilcodex)
|
||||
implementation(libs.shapeblurview)
|
||||
implementation(libs.com.google.android.flexbox.flexbox)
|
||||
implementation(libs.play.services.ads.identifier)
|
||||
implementation("com.github.getActivity:ShapeView:9.8")
|
||||
// implementation(libs.android.billing)
|
||||
// implementation(platform(libs.google.firebase.bom))
|
||||
// implementation(libs.google.firebase.messaging.ktx)
|
||||
// implementation(libs.google.firebase.analytics.ktx)
|
||||
// implementation(libs.firebase.perf)
|
||||
// implementation(libs.adjust.android)
|
||||
// implementation(libs.adjust.android.webbridge)
|
||||
// implementation(libs.com.android.installreferrer.installreferrer)
|
||||
// implementation("com.facebook.android:facebook-android-sdk:17.0.2")
|
||||
}
|
21
app/proguard-rules.pro
vendored
Normal file
21
app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
61
app/src/main/AndroidManifest.xml
Normal file
61
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<application
|
||||
android:name=".basics.MyApplication"
|
||||
android:allowBackup="false"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:networkSecurityConfig="@xml/net"
|
||||
android:theme="@style/Theme.Nebuluxe"
|
||||
tools:targetApi="31">
|
||||
<provider
|
||||
android:name=".basics.MyContentProvider"
|
||||
android:authorities="${applicationId}.mycontentprovider"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".main.SplashActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Splash">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".main.MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter
|
||||
android:autoVerify="true"
|
||||
tools:ignore="AppLinkUrlError">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="nebuluxe" />
|
||||
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.jia.er.nebuluxe.app.video.PlayerDetailActivity" />
|
||||
<activity android:name="com.jia.er.nebuluxe.app.me.AboutActivity" />
|
||||
<activity android:name="com.jia.er.nebuluxe.app.me.SettingActivity" />
|
||||
<activity android:name="com.jia.er.nebuluxe.app.home.HotActivity" />
|
||||
<activity android:name="com.jia.er.nebuluxe.app.home.RankActivity" />
|
||||
<activity android:name="com.jia.er.nebuluxe.app.home.FreshActivity" />
|
||||
<activity android:name="com.jia.er.nebuluxe.app.home.GenresActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
141
app/src/main/java/com/jia/er/nebuluxe/app/basics/BaseActivity.kt
Normal file
141
app/src/main/java/com/jia/er/nebuluxe/app/basics/BaseActivity.kt
Normal file
@ -0,0 +1,141 @@
|
||||
package com.jia.er.nebuluxe.app.basics
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.EditText
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.blankj.utilcode.util.BarUtils
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
|
||||
abstract class BaseActivity<BV : ViewBinding> : AppCompatActivity() {
|
||||
lateinit var binding: BV
|
||||
private var networkErrorView: View? = null
|
||||
private var noDramaView: View? = null
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = getViewBinding()
|
||||
val container = FrameLayout(this).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
addView(
|
||||
binding.root,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
setContentView(container)
|
||||
networkErrorView =
|
||||
layoutInflater.inflate(R.layout.layout_network_error, container, false).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
visibility = View.INVISIBLE
|
||||
findViewById<AppCompatTextView>(R.id.tv_example_retry)?.setOnClickListener {
|
||||
onRetry()
|
||||
}
|
||||
}
|
||||
container.addView(networkErrorView)
|
||||
noDramaView =
|
||||
layoutInflater.inflate(R.layout.layout_no_drama, container, false).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
visibility = View.INVISIBLE
|
||||
findViewById<AppCompatTextView>(R.id.tv_example_retry)?.setOnClickListener {
|
||||
onReturn()
|
||||
}
|
||||
}
|
||||
container.addView(noDramaView)
|
||||
BarUtils.transparentStatusBar(this)
|
||||
BarUtils.setStatusBarLightMode(this, false)
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
top()
|
||||
center()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(container) { v, insets ->
|
||||
val systemInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
||||
v.setPadding(0, 0, 0, systemInsets.bottom)
|
||||
window.navigationBarColor = ContextCompat.getColor(this, R.color.black)
|
||||
insets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun top()
|
||||
protected abstract fun center()
|
||||
protected abstract fun getViewBinding(): BV
|
||||
|
||||
protected open fun onRetry() {
|
||||
}
|
||||
|
||||
protected open fun onReturn() {
|
||||
}
|
||||
|
||||
fun showNetError() {
|
||||
networkErrorView?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun hideNetError() {
|
||||
networkErrorView?.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
fun showNoDrama(){
|
||||
noDramaView?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private var loadingDialog: Dialog? = null
|
||||
|
||||
protected open fun showLoading(
|
||||
message: String = "Loading..."
|
||||
) {
|
||||
if (loadingDialog?.isShowing == true) return
|
||||
|
||||
loadingDialog = Dialog(this, R.style.FullScreenLoadingDialog).apply {
|
||||
setContentView(R.layout.dialog_loading)
|
||||
window?.apply {
|
||||
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
decorView.setBackgroundColor(Color.argb(150, 0, 0, 0))
|
||||
}
|
||||
setCancelable(true)
|
||||
findViewById<TextView>(R.id.tv_loading_text)?.text = message
|
||||
}
|
||||
loadingDialog?.show()
|
||||
}
|
||||
|
||||
protected open fun hideLoading() {
|
||||
loadingDialog?.takeIf { it.isShowing }?.dismiss()
|
||||
loadingDialog = null
|
||||
}
|
||||
|
||||
fun showKeyBord(mEditText: EditText, mContext: Context) {
|
||||
val imm = mContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN)
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY)
|
||||
}
|
||||
|
||||
fun hideKeyBord(mEditText: EditText, mContext: Context) {
|
||||
val imm = mContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(mEditText.windowToken, 0)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package com.jia.er.nebuluxe.app.basics
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
|
||||
abstract class BaseFragment<VB : ViewBinding> : Fragment() {
|
||||
lateinit var binding: VB
|
||||
var networkErrorView: View? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = getViewBinding()
|
||||
val layout = FrameLayout(requireContext()).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
addView(
|
||||
binding.root,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
networkErrorView =
|
||||
layoutInflater.inflate(R.layout.layout_network_error, layout, false).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
visibility = View.INVISIBLE
|
||||
findViewById<AppCompatTextView>(R.id.tv_example_retry)?.setOnClickListener {
|
||||
onRetry()
|
||||
}
|
||||
}
|
||||
layout.addView(networkErrorView)
|
||||
return layout
|
||||
}
|
||||
|
||||
protected open fun onRetry() {
|
||||
}
|
||||
|
||||
fun showNetError() {
|
||||
networkErrorView?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun hideNetError() {
|
||||
networkErrorView?.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
top()
|
||||
center()
|
||||
}
|
||||
|
||||
protected abstract fun top()
|
||||
protected abstract fun center()
|
||||
protected abstract fun getViewBinding(): VB
|
||||
|
||||
private var loadingDialog: Dialog? = null
|
||||
|
||||
protected open fun showLoading(
|
||||
message: String = "Loading..."
|
||||
) {
|
||||
if (loadingDialog?.isShowing == true) return
|
||||
|
||||
loadingDialog = Dialog(requireContext(), R.style.FullScreenLoadingDialog).apply {
|
||||
setContentView(R.layout.dialog_loading)
|
||||
window?.apply {
|
||||
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
decorView.setBackgroundColor(Color.argb(150, 0, 0, 0))
|
||||
}
|
||||
setCancelable(true)
|
||||
|
||||
findViewById<TextView>(R.id.tv_loading_text)?.text = message
|
||||
}
|
||||
loadingDialog?.show()
|
||||
}
|
||||
|
||||
protected open fun hideLoading() {
|
||||
loadingDialog?.takeIf { it.isShowing }?.dismiss()
|
||||
loadingDialog = null
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.jia.er.nebuluxe.app.basics
|
||||
|
||||
|
||||
object Constants {
|
||||
var isUat = false
|
||||
const val Constants_BASE_URL_RES = "https://api-nebuluxetv.nebuluxetv.com/xe/"
|
||||
const val CONSTANTS_AuthorizationExample = "Authorization"
|
||||
const val CONSTANTS_device_id = "device-id"
|
||||
const val CONSTANTS_device_gaid = "device-gaid"
|
||||
const val CONSTANTS_app_name = "app-name"
|
||||
const val CONSTANTS_app_version = "app-version"
|
||||
const val CONSTANTS_system_type = "system-type"
|
||||
const val CONSTANTS_lang_key = "lang-key"
|
||||
const val CONSTANTS_time_zone = "time-zone"
|
||||
const val CONSTANTS_model = "model"
|
||||
const val CONSTANTS_brand = "brand"
|
||||
const val CONSTANTS_edit = "CONSTANTS_edit"
|
||||
const val CONSTANTS_system_version = "system-version"
|
||||
const val CONSTANTS_auth_refresh = "CONSTANTS_auth_refresh"
|
||||
const val CONSTANTS_User_STRING = "CONSTANTS_User_STRING"
|
||||
const val CONSTANTS_SEARCH_STRINGExample = "searchString"
|
||||
const val CONSTANTS_main_stop = "CONSTANTS_main_stop"
|
||||
const val CONSTANTS_short_play_id = "CONSTANTS_short_play_id"
|
||||
const val Constants_Episodes_Series_Data_currentPositionExample =
|
||||
"Constants_Episodes_Series_Data_currentPositionExample"
|
||||
const val Constants_Episodes_Series_Data_ListExample =
|
||||
"Constants_Episodes_Series_Data_ListExample"
|
||||
const val Constants_Episodes_Series_DataExample = "Constants_Episodes_Series_DataExample"
|
||||
const val CONSTANTS_activity_id = "activity_id"
|
||||
const val CONSTANTS_refresh_me = "CONSTANTS_refresh_me"
|
||||
const val Constants_DDL_Url = "Constants_DDL_Url"
|
||||
const val CONSTANTS_leaveApp = "CONSTANTS_leaveApp"
|
||||
const val CONSTANTS_enterTheApp = "CONSTANTS_enterTheApp"
|
||||
const val CONSTANTS_onLine = "CONSTANTS_onLine"
|
||||
const val CONSTANTS_examplePayReq = "CONSTANTS_examplePayReq"
|
||||
const val CONSTANTS_Episode = "CONSTANTS_Episode"
|
||||
const val CONSTANTS_pay_refresh = "CONSTANTS_pay_refresh"
|
||||
const val CONSTANTS_collect_refresh = "CONSTANTS_collect_refresh"
|
||||
const val Constants_onTokenRefresh = "onTokenRefresh"
|
||||
const val Constants_getClip = "Constants_getClip"
|
||||
const val CONSTANTS_web_Login = "CONSTANTS_web_Login"
|
||||
const val CONSTANTS_PREF_LAST_POPUP_TIME_Notification =
|
||||
"CONSTANTS_PREF_LAST_POPUP_TIME_Notification"
|
||||
const val ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000L
|
||||
var CanNotification: Boolean = false
|
||||
const val CONSTANTS_Detail_id = "CONSTANTS_Detail_id"
|
||||
const val Constants_requestPermissions_photo = "Constants_requestPermissions_photo"
|
||||
const val Constants_requestPermissions_photo_detail =
|
||||
"Constants_requestPermissions_photo_detail"
|
||||
const val Constants_openFeedbackDetail = "Constants_openFeedbackDetail"
|
||||
const val Constants_openFeedback = "Constants_openFeedback"
|
||||
const val CONSTANTS_web_notification = "CONSTANTS_web_notification"
|
||||
const val feedback_URL_res: String = "https://campaign.nebuluxetv.com/pages/leave/index"
|
||||
const val feedback_list_URL_res: String = "https://campaign.nebuluxetv.com/pages/leave/list"
|
||||
const val feedback_detail_URL_res: String = "https://campaign.nebuluxetv.com/pages/leave/detail"
|
||||
const val Constants_Main_Video_status = "Constants_Main_Video_status"
|
||||
const val Constants_Main_Video_info = "Constants_Main_Video_info"
|
||||
var WebRefresh: Boolean = false
|
||||
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package com.jia.er.nebuluxe.app.basics
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import com.jia.er.nebuluxe.app.BuildConfig.DEBUG
|
||||
//import com.adjust.sdk.Adjust
|
||||
//import com.adjust.sdk.AdjustConfig
|
||||
//import com.adjust.sdk.LogLevel
|
||||
//import com.adjust.sdk.OnEventTrackingFailedListener
|
||||
//import com.adjust.sdk.OnEventTrackingSucceededListener
|
||||
//import com.facebook.FacebookSdk
|
||||
//import com.facebook.LoggingBehavior
|
||||
//import com.facebook.appevents.AppEventsLogger
|
||||
//import com.facebook.applinks.AppLinkData
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
|
||||
class MyApplication : Application() {
|
||||
private val LOG_TAG: String = "MyApplication"
|
||||
|
||||
companion object {
|
||||
lateinit var context: Context
|
||||
var isAppInBackground = true
|
||||
var countActivity = 0
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
context = this
|
||||
// initAdjust()
|
||||
if (DEBUG) {
|
||||
registerActivityLifecycleCallbacks(AdjustLifecycleCallbacks())
|
||||
}
|
||||
// registerActivityLifecycleCallbacks({
|
||||
// fun onActivityResumed(activity: Activity) {
|
||||
// Log.d("onResume", activity.javaClass.simpleName)
|
||||
// }
|
||||
//
|
||||
// } as ActivityLifecycleCallbacks?)
|
||||
// GlobalScope.launch(Dispatchers.Main) {
|
||||
// initFacebookSdk()
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
// private fun initAdjust() {
|
||||
// val appToken = "dmq04yk7ftvk"
|
||||
// val environment = AdjustConfig.ENVIRONMENT_PRODUCTION
|
||||
// val config = AdjustConfig(context, appToken, environment)
|
||||
// config.setLogLevel(LogLevel.VERBOSE)
|
||||
// config.onEventTrackingSucceededListener =
|
||||
// OnEventTrackingSucceededListener { adjustEventSuccess ->
|
||||
// Log.d(LOG_TAG, "Event recorded at " + adjustEventSuccess.timestamp)
|
||||
// }
|
||||
// config.onEventTrackingFailedListener =
|
||||
// OnEventTrackingFailedListener { adjustEventFailure ->
|
||||
// Log.v(
|
||||
// LOG_TAG,
|
||||
// "Event recording failed. Response: " + adjustEventFailure.message
|
||||
// )
|
||||
// }
|
||||
// config.setOnDeferredDeeplinkResponseListener { deeplink ->
|
||||
// Log.d(LOG_TAG, "Deferred deep link callback called!")
|
||||
// Log.d(LOG_TAG, "Deep link URL: $deeplink")
|
||||
// Memory.getMMKV()
|
||||
// .putString(Constants.Constants_DDL_Url, deeplink.toString())
|
||||
// EventBus.getDefault().post(Constants.Constants_DDL_Url)
|
||||
// true
|
||||
// }
|
||||
// Adjust.initSdk(config)
|
||||
// }
|
||||
//
|
||||
inner class AdjustLifecycleCallbacks : ActivityLifecycleCallbacks {
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
// countActivity++
|
||||
// if (countActivity == 1 && isAppInBackground) {
|
||||
// isAppInBackground = false
|
||||
// Log.d("Lifecycle", "onActivityStarted")
|
||||
// EventBus.getDefault().post(Constants.CONSTANTS_enterTheApp)
|
||||
// }
|
||||
}
|
||||
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
// Adjust.onResume()
|
||||
Log.d("onResume", "=========" + activity.javaClass.simpleName + "=========")
|
||||
}
|
||||
|
||||
override fun onActivityPaused(activity: Activity) {
|
||||
// Adjust.onPause()
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
// countActivity--
|
||||
// if (countActivity <= 0 && !isAppInBackground) {
|
||||
// isAppInBackground = true
|
||||
// Log.d("Lifecycle", "onActivityStopped")
|
||||
// EventBus.getDefault().post(Constants.CONSTANTS_leaveApp)
|
||||
// }
|
||||
}
|
||||
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
|
||||
override fun onActivityDestroyed(activity: Activity) {}
|
||||
}
|
||||
//
|
||||
// private fun initFacebookSdk() {
|
||||
// FacebookSdk.setAutoInitEnabled(true)
|
||||
// FacebookSdk.fullyInitialize()
|
||||
// if (Constants.isUat) {
|
||||
// FacebookSdk.setIsDebugEnabled(true)
|
||||
// FacebookSdk.addLoggingBehavior(LoggingBehavior.APP_EVENTS)
|
||||
// }
|
||||
// AppEventsLogger.activateApp(this)
|
||||
// AppLinkData.fetchDeferredAppLinkData(
|
||||
// this
|
||||
// ) {
|
||||
// // Process app link data
|
||||
// if (null != it) {
|
||||
// Memory.getMMKV()
|
||||
// .putString(Constants.Constants_DDL_Url, it.targetUri.toString())
|
||||
// Log.d(
|
||||
// "initFacebookSdk",
|
||||
// "fetchDeferredAppLinkData callback called!====${it.targetUri}"
|
||||
// )
|
||||
// EventBus.getDefault().post(Constants.Constants_DDL_Url)
|
||||
// }
|
||||
// Log.d("initFacebookSdk", "fetchDeferredAppLinkData callback called!")
|
||||
// }
|
||||
// }
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.jia.er.nebuluxe.app.basics
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import com.getkeepsafe.relinker.ReLinker
|
||||
import com.tencent.mmkv.MMKV
|
||||
|
||||
class MyContentProvider : ContentProvider() {
|
||||
override fun onCreate(): Boolean {
|
||||
initMMKV()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun initMMKV() {
|
||||
try {
|
||||
context?.let { MMKV.initialize(it) }
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
try {
|
||||
val dir: String = context?.filesDir?.absolutePath + "/mmkv"
|
||||
MMKV.initialize(context, dir) { libName -> ReLinker.loadLibrary(
|
||||
context, libName) }
|
||||
} catch (e2: Exception) {
|
||||
e2.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
override fun query(
|
||||
uri: Uri,
|
||||
projection: Array<out String>?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?,
|
||||
sortOrder: String?
|
||||
): Cursor? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getType(uri: Uri): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun update(
|
||||
uri: Uri,
|
||||
values: ContentValues?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?
|
||||
): Int {
|
||||
return 0
|
||||
}
|
||||
}
|
130
app/src/main/java/com/jia/er/nebuluxe/app/data/AndroidBridge.kt
Normal file
130
app/src/main/java/com/jia/er/nebuluxe/app/data/AndroidBridge.kt
Normal file
@ -0,0 +1,130 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.webkit.JavascriptInterface
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.jia.er.nebuluxe.app.net.Retrofit.getCurrentTimeZone
|
||||
import com.jia.er.nebuluxe.app.utils.Memory
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.video.PlayerDetailActivity
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
class AndroidBridge(private val context: Context) {
|
||||
@JavascriptInterface
|
||||
fun getUserInfo(): String {
|
||||
val jsInfo = ReelCrushJsInfo(
|
||||
Memory.getMMKV()
|
||||
.getString(Constants.CONSTANTS_AuthorizationExample, "")
|
||||
.toString(),
|
||||
getCurrentTimeZone(),
|
||||
Memory.getMMKV().getString(Constants.CONSTANTS_lang_key, "en")
|
||||
.toString(),
|
||||
"android",
|
||||
Memory.getMMKV().getString(Constants.CONSTANTS_Detail_id, "")
|
||||
.toString(),"theme_1"
|
||||
)
|
||||
return Gson().toJson(jsInfo)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun js2app(string: String) {
|
||||
val parser = JsonParser()
|
||||
val rootJson = parser.parse(string) as JsonObject
|
||||
when (rootJson.get("type").asString) {
|
||||
|
||||
"open_notify" -> {
|
||||
singleClick {
|
||||
EventBus.getDefault().post(Constants.CONSTANTS_web_notification)
|
||||
}
|
||||
}
|
||||
|
||||
"watch_video" -> {
|
||||
singleClick {
|
||||
val fromJson = Gson().fromJson(string, JsonInfo::class.java)
|
||||
context.startActivity(
|
||||
Intent(
|
||||
context,
|
||||
PlayerDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(
|
||||
Constants.CONSTANTS_short_play_id,
|
||||
fromJson.data?.short_play_id
|
||||
)
|
||||
putExtra(
|
||||
Constants.CONSTANTS_activity_id,
|
||||
fromJson.data?.activity_id
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun openFeedbackDetail(id: String) {
|
||||
EventBus.getDefault()
|
||||
.post(BaseEventBus(Constants.Constants_openFeedbackDetail, id))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun openFeedbackList() {
|
||||
EventBus.getDefault()
|
||||
.post(Constants.Constants_openFeedback)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun openPhotoPicker() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
openFilePicker()
|
||||
} else {
|
||||
EventBus.getDefault().post(Constants.Constants_requestPermissions_photo)
|
||||
}
|
||||
} else {
|
||||
if ((ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.CAMERA
|
||||
) == PackageManager.PERMISSION_GRANTED)
|
||||
) {
|
||||
openFilePicker()
|
||||
} else {
|
||||
EventBus.getDefault().post(Constants.Constants_requestPermissions_photo)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private val REQUEST_PICK_FILE: Int = 1002
|
||||
|
||||
private fun openFilePicker() {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "image/*"
|
||||
}
|
||||
(context as? Activity)?.startActivityForResult(intent, REQUEST_PICK_FILE)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.webkit.JavascriptInterface
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.jia.er.nebuluxe.app.utils.Memory
|
||||
import com.google.gson.Gson
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.net.Retrofit.getCurrentTimeZone
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
class AndroidBridgeDetail(private val context: Context) {
|
||||
@JavascriptInterface
|
||||
fun getUserInfo(): String {
|
||||
val moviaJsInfo = ReelCrushJsInfo(
|
||||
Memory.getMMKV()
|
||||
.getString(Constants.CONSTANTS_AuthorizationExample, "")
|
||||
.toString(),
|
||||
getCurrentTimeZone(),
|
||||
Memory.getMMKV().getString(Constants.CONSTANTS_lang_key, "en")
|
||||
.toString(),
|
||||
"android",
|
||||
Memory.getMMKV().getString(Constants.CONSTANTS_Detail_id, "")
|
||||
.toString(),"theme_1"
|
||||
)
|
||||
return Gson().toJson(moviaJsInfo)
|
||||
}
|
||||
|
||||
|
||||
@JavascriptInterface
|
||||
fun openPhotoPicker() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
openFilePicker()
|
||||
} else {
|
||||
EventBus.getDefault().post(Constants.Constants_requestPermissions_photo_detail)
|
||||
}
|
||||
} else {
|
||||
if ((ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.CAMERA
|
||||
) == PackageManager.PERMISSION_GRANTED)
|
||||
) {
|
||||
openFilePicker()
|
||||
} else {
|
||||
EventBus.getDefault().post(Constants.Constants_requestPermissions_photo_detail)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private val REQUEST_PICK_FILE: Int = 1003
|
||||
|
||||
private fun openFilePicker() {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "image/*"
|
||||
}
|
||||
(context as? Activity)?.startActivityForResult(intent, REQUEST_PICK_FILE)
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class BaseEventBus<T>(val code: String, val data: T)
|
@ -0,0 +1,6 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class BaseRes<T>(
|
||||
val code: Int,
|
||||
val msg: String,
|
||||
val data: T?)
|
@ -0,0 +1,7 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class BuyVideoRes(
|
||||
val status: String,
|
||||
val coin_left_total: Int,
|
||||
val send_coin_left_total: Int
|
||||
)
|
@ -0,0 +1,11 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class CategoriesDataRes(
|
||||
val list: ArrayList<Item8>
|
||||
) {
|
||||
|
||||
data class Item8(
|
||||
val id: Int,
|
||||
val name: String
|
||||
)
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class CollectionRes(
|
||||
val list: List<CollectionData>,
|
||||
val pagination: Pagination
|
||||
) {
|
||||
|
||||
data class CollectionData(
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val short_play_id: Int,
|
||||
val current_episode: Int,
|
||||
val short_play_video_id: Int
|
||||
)
|
||||
|
||||
data class Pagination(
|
||||
val current_page: Int,
|
||||
val page_size: Int,
|
||||
val page_total: Int,
|
||||
val total_size: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class CreateOrderReq(
|
||||
val pay_setting_id: String,
|
||||
val payment_channel: String,
|
||||
val short_play_id: Int,
|
||||
val video_id: Int
|
||||
)
|
@ -0,0 +1,5 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class CreateOrderRes(
|
||||
val order_code: String
|
||||
)
|
@ -0,0 +1,18 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class CustomerBuyRecordsRes(
|
||||
val list: List<Data>
|
||||
) {
|
||||
|
||||
data class Data(
|
||||
val coin_type: Int,
|
||||
val coins: Int,
|
||||
val created_at: String,
|
||||
val episode: Int,
|
||||
val image_url: String,
|
||||
val is_grounding: Int,
|
||||
val name: String,
|
||||
val short_play_id: Int,
|
||||
val short_play_video_id: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class CustomerOrderRes(
|
||||
val list: List<Item0>,
|
||||
val pagination: Pagination
|
||||
) {
|
||||
|
||||
data class Item0(
|
||||
val created_at: String,
|
||||
val type: String,
|
||||
val value: String
|
||||
)
|
||||
|
||||
data class Pagination(
|
||||
val current_page: Int,
|
||||
val page_size: Int,
|
||||
val page_total: Int,
|
||||
val total_size: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class DetailsRecommendRes(
|
||||
val brief: String,
|
||||
val description: String,
|
||||
val list: List<Item>,
|
||||
val tag: String,
|
||||
val title: String
|
||||
) {
|
||||
|
||||
data class Item(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val video_url: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int?,
|
||||
val tag_type: String,
|
||||
val watch_total: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class ExampleKeywordDataRes(
|
||||
val list: List<KeywordData>,
|
||||
) {
|
||||
|
||||
data class KeywordData(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val categoryList: List<Category>,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Long,
|
||||
val search_click_total: Int,
|
||||
)
|
||||
|
||||
data class Category(
|
||||
val id: Int,
|
||||
val name: String
|
||||
)
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class FbNotificationReq(val is_open_notice: String)
|
@ -0,0 +1,24 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class FreeSeriesMoreRes(
|
||||
val list: List<Item9>
|
||||
) {
|
||||
|
||||
data class Item9(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class HistoryDataRes(
|
||||
val list: List<Data>,
|
||||
val pagination: Pagination
|
||||
) {
|
||||
|
||||
data class Data(
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val category: List<String>,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val short_play_id: Int,
|
||||
var is_collect: Int,
|
||||
val current_episode: Int,
|
||||
val short_play_video_id: Int
|
||||
)
|
||||
|
||||
data class Pagination(
|
||||
val current_page: Int,
|
||||
val page_size: Int,
|
||||
val page_total: Int,
|
||||
val total_size: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class HomeBannerAndNineSquarepRes(
|
||||
val arrangement: String,
|
||||
val list: List<Item0>,
|
||||
val title: String
|
||||
) {
|
||||
|
||||
data class Item0(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val category: List<String>,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val ffmpeg_id: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val jump_ffmpeg_id: Int,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val video_url: String,
|
||||
val watch_total: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class HomeBannerBean(
|
||||
val all_coins: Any,
|
||||
val buy_type: Int,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val video_url: String,
|
||||
val watch_total: Int,
|
||||
val category: List<String>
|
||||
)
|
@ -0,0 +1,28 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
|
||||
class HomeBestSellersData : ArrayList<HomeBestSellersData.HomeBestSellersDataItem>() {
|
||||
data class HomeBestSellersDataItem(
|
||||
val all_coins: String,
|
||||
val buy_type: Int,
|
||||
val categoryList: List<Category>,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Int
|
||||
)
|
||||
|
||||
data class Category(
|
||||
val id: Int,
|
||||
val name: String
|
||||
)
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
|
||||
|
||||
class HomeModuleBean(
|
||||
val list: List<RecommandDataBean>,
|
||||
) {
|
||||
data class RecommandDataBean(
|
||||
val module_key :String,
|
||||
val data: JsonElement
|
||||
)
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class HomeNewShortPlayNoPaginateRes(
|
||||
val list: List<Item8>
|
||||
) {
|
||||
|
||||
data class Item8(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val category: List<String>,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class HomeNewShortPlayRes(
|
||||
val category_list: List<Category>,
|
||||
val pagination: Pagination,
|
||||
val ranking_list: List<Ranking>,
|
||||
val short_play_list: MutableList<ShortPlay>
|
||||
) {
|
||||
|
||||
data class Category(
|
||||
val category_id: Int,
|
||||
val category_name: String
|
||||
)
|
||||
|
||||
data class Pagination(
|
||||
val current_page: Int,
|
||||
val page_size: Int,
|
||||
val page_total: Int,
|
||||
val total_size: Int
|
||||
)
|
||||
|
||||
data class Ranking(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Int
|
||||
)
|
||||
|
||||
data class ShortPlay(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val category: List<String>,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
var view_type: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Int,
|
||||
var ranking_list: List<Ranking>,
|
||||
var category_list: List<Category>
|
||||
)
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class HomeRankingRes(
|
||||
val list: List<Item7>
|
||||
) {
|
||||
|
||||
data class Item7(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val category: List<String>,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Long
|
||||
)
|
||||
}
|
30
app/src/main/java/com/jia/er/nebuluxe/app/data/HomeTopRes.kt
Normal file
30
app/src/main/java/com/jia/er/nebuluxe/app/data/HomeTopRes.kt
Normal file
@ -0,0 +1,30 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class HomeTopRes(
|
||||
val category: List<Category>,
|
||||
val hotData: List<HotData>
|
||||
) {
|
||||
|
||||
data class Category(
|
||||
val category_id: Int,
|
||||
val category_name: String
|
||||
)
|
||||
|
||||
data class HotData(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class HomeTopWeekRes(
|
||||
val list: List<Item8>
|
||||
){
|
||||
|
||||
data class Item8(
|
||||
val all_coins: String,
|
||||
val buy_type: Int,
|
||||
val category: List<String>,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val search_click_total: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val video_url: String,
|
||||
val watch_total: Int
|
||||
)}
|
14
app/src/main/java/com/jia/er/nebuluxe/app/data/JsonInfo.kt
Normal file
14
app/src/main/java/com/jia/er/nebuluxe/app/data/JsonInfo.kt
Normal file
@ -0,0 +1,14 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class JsonInfo(
|
||||
val `data`: Data?,
|
||||
val is_complete: Boolean,
|
||||
val is_show: Int,
|
||||
val type: String
|
||||
) {
|
||||
|
||||
data class Data(
|
||||
val activity_id: Int,
|
||||
val short_play_id: Int?
|
||||
)
|
||||
}
|
10
app/src/main/java/com/jia/er/nebuluxe/app/data/LoginReq.kt
Normal file
10
app/src/main/java/com/jia/er/nebuluxe/app/data/LoginReq.kt
Normal file
@ -0,0 +1,10 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class LoginReq(
|
||||
val avator: String,
|
||||
val email: String,
|
||||
val family_name: String,
|
||||
val giving_name: String,
|
||||
val platform: String,
|
||||
val third_id: String
|
||||
)
|
@ -0,0 +1,6 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class LoginRes(
|
||||
val customer_id: String,
|
||||
val token: String
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class MainDataHis(
|
||||
val episode_total: String,
|
||||
val video_id: Int,
|
||||
val video_last: String,
|
||||
val video_img: String
|
||||
)
|
@ -0,0 +1,5 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class NoticeNumRes(
|
||||
val feedback_notice_num: Int
|
||||
)
|
11
app/src/main/java/com/jia/er/nebuluxe/app/data/PayReq.kt
Normal file
11
app/src/main/java/com/jia/er/nebuluxe/app/data/PayReq.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class PayReq(
|
||||
val order_code: String,
|
||||
val pay_setting_id: String,//id
|
||||
val pkg_name: String,
|
||||
val product_id: String,//template id
|
||||
val purchases_token: String,
|
||||
val transaction_id: String,
|
||||
val show_money: String,
|
||||
)
|
8
app/src/main/java/com/jia/er/nebuluxe/app/data/PayRes.kt
Normal file
8
app/src/main/java/com/jia/er/nebuluxe/app/data/PayRes.kt
Normal file
@ -0,0 +1,8 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class PayRes(
|
||||
val is_backhaul: Int,
|
||||
val money: String,
|
||||
val order_code: String,
|
||||
val status: String
|
||||
)
|
@ -0,0 +1,68 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class PaySettingRes(
|
||||
val list_coins: List<Coins>,
|
||||
val sort: List<String>,
|
||||
val list_sub_vip: List<Vip>,
|
||||
) {
|
||||
|
||||
data class Coins(
|
||||
val android_template_id: String,
|
||||
val backhaul_price: String,
|
||||
val brief: String,
|
||||
val buy_type: String,
|
||||
val coins: Int,
|
||||
val created_at: String,
|
||||
val currency: String,
|
||||
var currency_goolge: String?,
|
||||
val description: String,
|
||||
val id: Int,
|
||||
val ios_template_id: String,
|
||||
val corner_marker: String,
|
||||
val lang_id: Int,
|
||||
val origin_price: String,
|
||||
val platform: String,
|
||||
val price: String,
|
||||
var price_google: String?,
|
||||
val send_coins: Int,
|
||||
val sort: Int,
|
||||
val status: String,
|
||||
val title: String,
|
||||
val size: String,
|
||||
val translate_key: String,
|
||||
val updated_at: String,
|
||||
val vip_type: String
|
||||
)
|
||||
|
||||
data class Vip(
|
||||
val android_template_id: String,
|
||||
val backhaul_price: String,
|
||||
val brief: String,
|
||||
val short_type: String,
|
||||
val buy_type: String,
|
||||
val coins: Int,
|
||||
val corner_marker: String,
|
||||
val created_at: String,
|
||||
val currency: String,
|
||||
var currency_goolge: String?,
|
||||
val description: String,
|
||||
val id: Int,
|
||||
val ios_template_id: String,
|
||||
val lang_id: Int,
|
||||
val origin_price: String,
|
||||
val platform: String,
|
||||
val price: String,
|
||||
var price_google: String?,
|
||||
val send_coins: Int,
|
||||
val send_coin_ttl: Int,
|
||||
val sort: Int,
|
||||
var show: Int,
|
||||
val status: String,
|
||||
val title: String,
|
||||
val translate_key: String,
|
||||
val updated_at: String,
|
||||
val auto_sub: String,
|
||||
var vip_type: String,
|
||||
var vip_type_key: String,
|
||||
)
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
data class PlayerDetailDataRes(
|
||||
val episodeList: List<Episode>,
|
||||
val is_collect: Boolean,
|
||||
val show_share_coin: Boolean,
|
||||
val share_coin: Int,
|
||||
val install_coins: Int,
|
||||
val unlock_video_ad_count: Int,
|
||||
val revolution: Int,
|
||||
val discount: Int,
|
||||
var jump_type: Int,
|
||||
var jump_short_play_id: Int,
|
||||
var business_model: String,
|
||||
val shortPlayInfo: ShortPlayInfo,
|
||||
val video_info: VideoInfo
|
||||
) {
|
||||
|
||||
data class Episode(
|
||||
val coins: Int,
|
||||
val episode: Int,
|
||||
val id: Int,
|
||||
var is_lock: Boolean,
|
||||
val is_vip: Int,
|
||||
val short_play_id: Int,
|
||||
val short_play_video_id: Int,
|
||||
val video_url: String,
|
||||
val vip_coins: Int,
|
||||
var play_seconds: String?,
|
||||
var shortPlayInfo: ShortPlayInfo?,
|
||||
var promise_view_ad: Int,
|
||||
): Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readString().toString(),
|
||||
parcel.readInt(),
|
||||
parcel.readString(),
|
||||
parcel.readParcelable(ShortPlayInfo::class.java.classLoader),
|
||||
parcel.readInt()
|
||||
) {
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(coins)
|
||||
parcel.writeInt(episode)
|
||||
parcel.writeInt(id)
|
||||
parcel.writeByte(if (is_lock) 1 else 0)
|
||||
parcel.writeInt(is_vip)
|
||||
parcel.writeInt(short_play_id)
|
||||
parcel.writeInt(short_play_video_id)
|
||||
parcel.writeString(video_url)
|
||||
parcel.writeInt(vip_coins)
|
||||
parcel.writeString(play_seconds)
|
||||
parcel.writeParcelable(shortPlayInfo, flags)
|
||||
parcel.writeInt(promise_view_ad)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<Episode> {
|
||||
override fun createFromParcel(parcel: Parcel): Episode {
|
||||
return Episode(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<Episode?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
data class ShortPlayInfo(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
var collect_total: Int,
|
||||
val description: String,
|
||||
val category: ArrayList<String>?,
|
||||
val episode_total: Int,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
var is_collect: Boolean,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val short_id: Int,
|
||||
val watch_total: Int
|
||||
): Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readString().toString(),
|
||||
parcel.createStringArrayList(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readString().toString(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readString().toString(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt()
|
||||
) {
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(all_coins)
|
||||
parcel.writeInt(buy_type)
|
||||
parcel.writeInt(collect_total)
|
||||
parcel.writeString(description)
|
||||
parcel.writeStringList(category)
|
||||
parcel.writeInt(episode_total)
|
||||
parcel.writeInt(id)
|
||||
parcel.writeString(image_url)
|
||||
parcel.writeByte(if (is_collect) 1 else 0)
|
||||
parcel.writeString(name)
|
||||
parcel.writeInt(process)
|
||||
parcel.writeInt(short_id)
|
||||
parcel.writeInt(watch_total)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<ShortPlayInfo> {
|
||||
override fun createFromParcel(parcel: Parcel): ShortPlayInfo {
|
||||
return ShortPlayInfo(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ShortPlayInfo?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class VideoInfo(
|
||||
val coins: Int,
|
||||
val episode: Int,
|
||||
val id: Int,
|
||||
val is_vip: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val short_play_video_id: Int,
|
||||
val promise_view_ad: Int,
|
||||
val video_url: String,
|
||||
val vip_coins: Int
|
||||
)
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class RecommendDataRes(
|
||||
val list: List<Data>,
|
||||
val pagination: Pagination
|
||||
) {
|
||||
|
||||
data class Data(
|
||||
val all_price_total: Int,
|
||||
val buy_type: Int,
|
||||
var collect_total: Int?,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
var is_collect: Boolean,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val video_info: VideoInfo?,
|
||||
val watch_total: Int
|
||||
)
|
||||
|
||||
data class Pagination(
|
||||
val current_page: Int,
|
||||
val page_size: Int,
|
||||
val page_total: Int,
|
||||
val total_size: Int
|
||||
)
|
||||
|
||||
data class VideoInfo(
|
||||
val episode: Int,
|
||||
val id: Int,
|
||||
val is_vip: Int,
|
||||
val short_play_id: Int,
|
||||
val short_play_video_id: Int,
|
||||
val video_url: String,
|
||||
val image_url: String
|
||||
)
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class ReelCrushJsInfo(
|
||||
val token: String,
|
||||
val time_zone: String,
|
||||
val lang: String,
|
||||
val type: String,
|
||||
val id: String,
|
||||
val theme: String
|
||||
)
|
@ -0,0 +1,14 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class RewardCoinsRes(val list: List<ExampleRewardCoinsResItem>) {
|
||||
data class ExampleRewardCoinsResItem(
|
||||
val coins: Int,
|
||||
val created_at: String,
|
||||
val diff_datetime: String,
|
||||
val expired_time: Int,
|
||||
val id: Int,
|
||||
val is_effective: Int,
|
||||
val left_coins: String,
|
||||
val type: String
|
||||
)
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
|
||||
class ShortListCategoryDataInfo(
|
||||
val list: List<CategoryListData>,
|
||||
) {
|
||||
|
||||
data class CategoryListData(
|
||||
|
||||
val id: Int,
|
||||
val category_name: String,
|
||||
val short_play_list: List<ShortPlayListData>
|
||||
|
||||
)
|
||||
|
||||
data class ShortPlayListData(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Long
|
||||
)
|
||||
}
|
20
app/src/main/java/com/jia/er/nebuluxe/app/data/TabEntity.kt
Normal file
20
app/src/main/java/com/jia/er/nebuluxe/app/data/TabEntity.kt
Normal file
@ -0,0 +1,20 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
import com.flyco.tablayout.listener.CustomTabEntity
|
||||
|
||||
class TabEntity(var s1: String, var i1: Int, var i2: Int) :
|
||||
CustomTabEntity {
|
||||
|
||||
override fun getTabTitle(): String {
|
||||
return s1
|
||||
}
|
||||
|
||||
override fun getTabSelectedIcon(): Int {
|
||||
return i1
|
||||
}
|
||||
|
||||
override fun getTabUnselectedIcon(): Int {
|
||||
return i2
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class UploadHistoryReq(
|
||||
val play_seconds: Long?,
|
||||
val short_play_id: Int,
|
||||
val video_id: Int?
|
||||
)
|
@ -0,0 +1,30 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class UserInfoRes(
|
||||
val avator: String = "",
|
||||
val coin_left_total: Int = 0,
|
||||
val country: String = "",
|
||||
val country_code: String = "",
|
||||
val customer_id: String = "",
|
||||
val email: String = "",
|
||||
val family_name: String = "",
|
||||
val fn: String = "",
|
||||
val giving_name: String = "",
|
||||
val id: String = "",
|
||||
val ip_address: String = "0.0.0.0",
|
||||
val is_guide_vip: Boolean = false,
|
||||
val is_tourist: Boolean = true,
|
||||
val is_vip: Boolean = false,
|
||||
val ln: String = "",
|
||||
val registered_days: Int = 0,
|
||||
val send_coin_left_total: Int = 0,
|
||||
val third_access_platform: String = "",
|
||||
val vip_end_time: Int = 0,
|
||||
val vip_type: String = ""
|
||||
) {
|
||||
companion object {
|
||||
fun createWithDefaults(): UserInfoRes {
|
||||
return UserInfoRes()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
data class UserRegisterRes(val customer_id: String,
|
||||
val token: String)
|
@ -0,0 +1,29 @@
|
||||
package com.jia.er.nebuluxe.app.data
|
||||
|
||||
class VideoListDataRes(
|
||||
val list: List<VideoListData>,
|
||||
) {
|
||||
|
||||
data class VideoListData(
|
||||
val all_coins: Int,
|
||||
val buy_type: Int,
|
||||
val categoryList: List<Category>,
|
||||
val collect_total: Int,
|
||||
val description: String,
|
||||
val episode_total: Int,
|
||||
val horizontally_img: String,
|
||||
val id: Int,
|
||||
val image_url: String,
|
||||
val name: String,
|
||||
val process: Int,
|
||||
val short_id: Int,
|
||||
val short_play_id: Int,
|
||||
val tag_type: String,
|
||||
val watch_total: Long
|
||||
)
|
||||
|
||||
data class Category(
|
||||
val id: Int,
|
||||
val name: String
|
||||
)
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.blankj.utilcode.util.NetworkUtils
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseActivity
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.data.HomeRankingRes
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivityFreshBinding
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivityRankingsBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import com.jia.er.nebuluxe.app.utils.toast
|
||||
import com.jia.er.nebuluxe.app.video.PlayerDetailActivity
|
||||
|
||||
|
||||
class FreshActivity : BaseActivity<ActivityFreshBinding>() {
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
private var type = "new_releases"
|
||||
|
||||
override fun top() {
|
||||
binding?.exampleIvBack?.setOnClickListener { finish() }
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.homeRanking(type)
|
||||
} else {
|
||||
showNetError()
|
||||
}
|
||||
binding.srRank.setOnRefreshListener {
|
||||
mViewModel.homeRanking(type)
|
||||
}
|
||||
}
|
||||
|
||||
override fun center() {
|
||||
mViewModel.homeRankingData.observe(this) {
|
||||
if (it != null) {
|
||||
if (it.data?.list?.isNotEmpty() == true) {
|
||||
val homeRankTrendingAdapter = FreshAdapter()
|
||||
val manager1 = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
binding?.rvRanks?.layoutManager = manager1
|
||||
binding?.rvRanks?.adapter = homeRankTrendingAdapter
|
||||
homeRankTrendingAdapter?.submitList(it.data.list)
|
||||
homeRankTrendingAdapter?.isStateViewEnable = true
|
||||
homeRankTrendingAdapter?.setStateViewLayout(this, R.layout.layout_emptyview)
|
||||
homeRankTrendingAdapter?.setOnItemClickListener { adapter, view, position ->
|
||||
val data = adapter.getItem(position) as HomeRankingRes.Item7
|
||||
startActivity(Intent(
|
||||
this, PlayerDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(
|
||||
Constants.CONSTANTS_short_play_id, data.short_play_id
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
binding.srRank.finishRefresh()
|
||||
hideNetError()
|
||||
hideLoading()
|
||||
} else {
|
||||
showNetError()
|
||||
toast(getString(R.string.network_error))
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewBinding(): ActivityFreshBinding {
|
||||
return ActivityFreshBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun onRetry() {
|
||||
super.onRetry()
|
||||
singleClick {
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.homeRanking(type)
|
||||
} else {
|
||||
toast(getString(R.string.example_no_network))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.fullspan.FullSpanAdapterType
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.HomeRankingRes
|
||||
import com.jia.er.nebuluxe.app.ui.CustomRoundedCorners
|
||||
import com.jia.er.nebuluxe.app.utils.dpToPxByFloat
|
||||
|
||||
|
||||
class FreshAdapter :
|
||||
BaseQuickAdapter<HomeRankingRes.Item7, QuickViewHolder>(),
|
||||
FullSpanAdapterType {
|
||||
override fun onBindViewHolder(
|
||||
holder: QuickViewHolder,
|
||||
position: Int,
|
||||
item: HomeRankingRes.Item7?
|
||||
) {
|
||||
Glide.with(context).load(item?.image_url).placeholder(R.drawable.iv_placeholder_v)
|
||||
.into(holder.getView(R.id.iv_cover))
|
||||
holder.setText(R.id.tv_rank_name, item?.name)
|
||||
if (item?.category?.isNotEmpty() == true) {
|
||||
val string = item.category[0]
|
||||
holder.setText(R.id.tv_rank_tag, string)
|
||||
holder.setVisible(R.id.tv_rank_tag, true)
|
||||
} else {
|
||||
holder.setVisible(R.id.tv_rank_tag, false)
|
||||
}
|
||||
val view = holder.getView<AppCompatImageView>(R.id.example_iv_icon_ceo)
|
||||
Glide.with(context)
|
||||
.load(item?.image_url).placeholder(R.drawable.iv_placeholder_v)
|
||||
.transform(
|
||||
CenterCrop(),
|
||||
CustomRoundedCorners(
|
||||
dpToPxByFloat(20, context),
|
||||
0f,
|
||||
dpToPxByFloat(20, context),
|
||||
dpToPxByFloat(20, context)
|
||||
)
|
||||
)
|
||||
.into(view)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
context: Context,
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuickViewHolder {
|
||||
return QuickViewHolder(R.layout.item_fresh, parent)
|
||||
}
|
||||
}
|
101
app/src/main/java/com/jia/er/nebuluxe/app/home/GenresActivity.kt
Normal file
101
app/src/main/java/com/jia/er/nebuluxe/app/home/GenresActivity.kt
Normal file
@ -0,0 +1,101 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.blankj.utilcode.util.NetworkUtils
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseActivity
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.data.HomeRankingRes
|
||||
import com.jia.er.nebuluxe.app.data.ShortListCategoryDataInfo
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivityFreshBinding
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivityRankingsBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import com.jia.er.nebuluxe.app.utils.toast
|
||||
import com.jia.er.nebuluxe.app.video.PlayerDetailActivity
|
||||
|
||||
|
||||
class GenresActivity : BaseActivity<ActivityFreshBinding>() {
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
|
||||
override fun top() {
|
||||
binding?.exampleIvBack?.setOnClickListener { finish() }
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.userCenterRecommend()
|
||||
} else {
|
||||
showNetError()
|
||||
}
|
||||
binding.srRank.setOnRefreshListener {
|
||||
mViewModel.userCenterRecommend()
|
||||
}
|
||||
}
|
||||
|
||||
override fun center() {
|
||||
mViewModel.userCenterRecommendData.observe(this) {
|
||||
if (it != null) {
|
||||
if (it.data?.list?.isNotEmpty() == true) {
|
||||
val homeRankTrendingAdapter = GenresAdapter()
|
||||
val manager1 = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
binding?.rvRanks?.layoutManager = manager1
|
||||
binding?.rvRanks?.adapter = homeRankTrendingAdapter
|
||||
homeRankTrendingAdapter?.submitList(it.data.list)
|
||||
binding?.rvRanks?.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
if (parent.getChildPosition(view) != (it.data.list.size - 1)) {
|
||||
outRect.bottom = -100
|
||||
}
|
||||
}
|
||||
})
|
||||
homeRankTrendingAdapter?.isStateViewEnable = true
|
||||
homeRankTrendingAdapter?.setStateViewLayout(this, R.layout.layout_emptyview)
|
||||
homeRankTrendingAdapter?.setOnItemClickListener { adapter, view, position ->
|
||||
val data =
|
||||
adapter.getItem(position) as ShortListCategoryDataInfo.CategoryListData
|
||||
// startActivity(Intent(
|
||||
// this, PlayerDetailActivity::class.java
|
||||
// ).apply {
|
||||
// putExtra(
|
||||
// Constants.CONSTANTS_short_play_id, data.short_play_id
|
||||
// )
|
||||
// })
|
||||
}
|
||||
}
|
||||
binding.srRank.finishRefresh()
|
||||
hideNetError()
|
||||
hideLoading()
|
||||
} else {
|
||||
showNetError()
|
||||
toast(getString(R.string.network_error))
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewBinding(): ActivityFreshBinding {
|
||||
return ActivityFreshBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun onRetry() {
|
||||
super.onRetry()
|
||||
singleClick {
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.userCenterRecommend()
|
||||
} else {
|
||||
toast(getString(R.string.example_no_network))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.fullspan.FullSpanAdapterType
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.ShortListCategoryDataInfo
|
||||
|
||||
|
||||
class GenresAdapter :
|
||||
BaseQuickAdapter<ShortListCategoryDataInfo.CategoryListData, QuickViewHolder>(),
|
||||
FullSpanAdapterType {
|
||||
override fun onBindViewHolder(
|
||||
holder: QuickViewHolder,
|
||||
position: Int,
|
||||
item: ShortListCategoryDataInfo.CategoryListData?
|
||||
) {
|
||||
when (position) {
|
||||
0 -> {
|
||||
holder.setBackgroundResource(R.id.rl, R.drawable.iv_genres_1)
|
||||
holder.setBackgroundResource(R.id.line, R.color.E3D4FF)
|
||||
}
|
||||
|
||||
1 -> {
|
||||
holder.setBackgroundResource(R.id.rl, R.drawable.iv_genres_2)
|
||||
holder.setBackgroundResource(R.id.line, R.color.BDF5E2)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
holder.setBackgroundResource(R.id.rl, R.drawable.iv_genres_3)
|
||||
holder.setBackgroundResource(R.id.line, R.color.FFFA80)
|
||||
}
|
||||
|
||||
else -> {
|
||||
holder.setBackgroundResource(R.id.rl, R.drawable.iv_genres_4)
|
||||
holder.setBackgroundResource(R.id.line, R.color.F0C2E1)
|
||||
}
|
||||
}
|
||||
val view = holder.getView<RecyclerView>(R.id.rv_genres_item)
|
||||
holder.setText(R.id.tv_type, item?.category_name)
|
||||
holder.setText(
|
||||
R.id.tv_num,
|
||||
item?.short_play_list?.size.toString().plus("\n").plus("Dramas")
|
||||
)
|
||||
val homeRankTrendingAdapter = GenresItemAdapter()
|
||||
val manager1 = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
view?.layoutManager = manager1
|
||||
view?.adapter = homeRankTrendingAdapter
|
||||
homeRankTrendingAdapter?.submitList(item?.short_play_list)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
context: Context,
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuickViewHolder {
|
||||
return QuickViewHolder(R.layout.item_genres, parent)
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.Glide
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.fullspan.FullSpanAdapterType
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.ShortListCategoryDataInfo
|
||||
|
||||
|
||||
class GenresItemAdapter :
|
||||
BaseQuickAdapter<ShortListCategoryDataInfo.ShortPlayListData, QuickViewHolder>(),
|
||||
FullSpanAdapterType {
|
||||
override fun onBindViewHolder(
|
||||
holder: QuickViewHolder,
|
||||
position: Int,
|
||||
item: ShortListCategoryDataInfo.ShortPlayListData?
|
||||
) {
|
||||
Glide.with(context).load(item?.image_url).placeholder(R.drawable.iv_placeholder_v)
|
||||
.into(holder.getView(R.id.iv_cover))
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
context: Context,
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuickViewHolder {
|
||||
return QuickViewHolder(R.layout.item_genres_img, parent)
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.HomeBannerAndNineSquarepRes
|
||||
import com.youth.banner.adapter.BannerAdapter
|
||||
|
||||
class HomeBannerAdapter(items: List<HomeBannerAndNineSquarepRes.Item0?>?) :
|
||||
BannerAdapter<HomeBannerAndNineSquarepRes.Item0?, HomeBannerAdapter.BannerViewHolder?>(
|
||||
items
|
||||
) {
|
||||
override fun onCreateHolder(parent: ViewGroup, viewType: Int): BannerViewHolder {
|
||||
val view: View = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.custom_banner_view, parent, false)
|
||||
view.layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
return BannerViewHolder(view)
|
||||
}
|
||||
|
||||
|
||||
override fun onBindView(
|
||||
holder: BannerViewHolder?,
|
||||
data: HomeBannerAndNineSquarepRes.Item0?,
|
||||
position: Int,
|
||||
size: Int
|
||||
) {
|
||||
val findViewById =
|
||||
holder?.view?.findViewById<AppCompatImageView>(R.id.iv_icon_banner)
|
||||
val tv_name = holder?.view?.findViewById<AppCompatTextView>(R.id.tv_name)
|
||||
val tv_tag = holder?.view?.findViewById<AppCompatTextView>(R.id.tv_tag)
|
||||
if (findViewById != null) {
|
||||
Glide.with(holder.itemView.context)
|
||||
.load(data?.image_url).placeholder(R.drawable.iv_placeholder_v)
|
||||
.into(findViewById)
|
||||
}
|
||||
tv_name?.text = data?.name
|
||||
if (data?.category?.isNotEmpty() == true) {
|
||||
tv_tag?.visibility = View.VISIBLE
|
||||
tv_tag?.text = data?.category[0]
|
||||
} else {
|
||||
tv_tag?.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
inner class BannerViewHolder(var view: View) : RecyclerView.ViewHolder(
|
||||
view
|
||||
)
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.HomeBannerAndNineSquarepRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeTopWeekRes
|
||||
import com.youth.banner.adapter.BannerAdapter
|
||||
|
||||
class HomeBannerBottomAdapter(items: List<HomeTopWeekRes.Item8?>?) :
|
||||
BannerAdapter<HomeTopWeekRes.Item8?, HomeBannerBottomAdapter.BannerViewHolder?>(
|
||||
items
|
||||
) {
|
||||
override fun onCreateHolder(parent: ViewGroup, viewType: Int): BannerViewHolder {
|
||||
val view: View = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.custom_banner_view_bottom, parent, false)
|
||||
view.layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
return BannerViewHolder(view)
|
||||
}
|
||||
|
||||
|
||||
override fun onBindView(
|
||||
holder: BannerViewHolder?,
|
||||
data: HomeTopWeekRes.Item8?,
|
||||
position: Int,
|
||||
size: Int
|
||||
) {
|
||||
val findViewById =
|
||||
holder?.view?.findViewById<AppCompatImageView>(R.id.iv_icon_banner)
|
||||
val tv_name = holder?.view?.findViewById<AppCompatTextView>(R.id.tv_name)
|
||||
val tv_tag = holder?.view?.findViewById<AppCompatTextView>(R.id.tv_tag)
|
||||
val tv_des = holder?.view?.findViewById<AppCompatTextView>(R.id.tv_des)
|
||||
if (findViewById != null) {
|
||||
Glide.with(holder.itemView.context)
|
||||
.load(data?.image_url).placeholder(R.drawable.iv_placeholder_v)
|
||||
.into(findViewById)
|
||||
}
|
||||
tv_name?.text = data?.name
|
||||
tv_des?.text = data?.description
|
||||
if (data?.category?.isNotEmpty() == true) {
|
||||
tv_tag?.visibility = View.VISIBLE
|
||||
tv_tag?.text = data?.category[0]
|
||||
} else {
|
||||
tv_tag?.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
inner class BannerViewHolder(var view: View) : RecyclerView.ViewHolder(
|
||||
view
|
||||
)
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.Glide
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.RecommendDataRes
|
||||
|
||||
class HomeForYouAdapter :
|
||||
BaseQuickAdapter<RecommendDataRes.Data, QuickViewHolder>() {
|
||||
override fun onBindViewHolder(
|
||||
holder: QuickViewHolder,
|
||||
position: Int,
|
||||
item: RecommendDataRes.Data?
|
||||
) {
|
||||
Glide.with(context).load(item?.image_url)
|
||||
.into(holder.getView(R.id.iv_icon))
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
context: Context,
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuickViewHolder {
|
||||
return QuickViewHolder(R.layout.item_home_for_you, parent)
|
||||
}
|
||||
}
|
265
app/src/main/java/com/jia/er/nebuluxe/app/home/HomeFragment.kt
Normal file
265
app/src/main/java/com/jia/er/nebuluxe/app/home/HomeFragment.kt
Normal file
@ -0,0 +1,265 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.view.View
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.blankj.utilcode.util.NetworkUtils
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.gson.Gson
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseFragment
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.data.HomeBannerAndNineSquarepRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeBannerBean
|
||||
import com.jia.er.nebuluxe.app.data.HomeTopWeekRes
|
||||
import com.jia.er.nebuluxe.app.databinding.FragmentHomeBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.ui.RotateDownPageTransformer
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import com.jia.er.nebuluxe.app.utils.toast
|
||||
import com.jia.er.nebuluxe.app.video.PlayerDetailActivity
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
|
||||
class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
private var page: Int = 1
|
||||
private val gson = Gson()
|
||||
override fun top() {
|
||||
if (NetworkUtils.isConnected()) {
|
||||
mViewModel.allModules()
|
||||
} else {
|
||||
EventBus.getDefault().post(Constants.CONSTANTS_main_stop)
|
||||
showNetError()
|
||||
}
|
||||
binding?.srHome?.setOnRefreshListener {
|
||||
page = 1
|
||||
mViewModel.allModules()
|
||||
}
|
||||
binding.tvHot.setOnClickListener {
|
||||
singleClick {
|
||||
startActivity(
|
||||
Intent(
|
||||
context,
|
||||
HotActivity::class.java
|
||||
))
|
||||
}
|
||||
}
|
||||
binding.tvTop.setOnClickListener {
|
||||
singleClick {
|
||||
startActivity(
|
||||
Intent(
|
||||
context,
|
||||
RankActivity::class.java
|
||||
))
|
||||
}
|
||||
}
|
||||
binding.tvFresh.setOnClickListener {
|
||||
singleClick {
|
||||
startActivity(
|
||||
Intent(
|
||||
context,
|
||||
FreshActivity::class.java
|
||||
))
|
||||
}
|
||||
}
|
||||
binding.tvFresh.setOnClickListener {
|
||||
singleClick {
|
||||
startActivity(
|
||||
Intent(
|
||||
context,
|
||||
GenresActivity::class.java
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var dataList: MutableList<String> = mutableListOf()
|
||||
|
||||
override fun center() {
|
||||
mViewModel.allModulesData.observe(this) {
|
||||
if (it != null) {
|
||||
if (it?.data?.list?.isNotEmpty() == true) {
|
||||
for (item in it.data.list) {
|
||||
when (item.module_key) {
|
||||
"marquee" -> {
|
||||
binding.root.postDelayed({
|
||||
dataList.clear()
|
||||
val marqueeList =
|
||||
gson.fromJson(item.data, Array<HomeBannerBean>::class.java)
|
||||
.toList()
|
||||
marqueeList?.forEach { it1 ->
|
||||
dataList.add(it1.name)
|
||||
}
|
||||
if (dataList.isNotEmpty()) {
|
||||
binding?.tvText?.setData(dataList)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
"home_banner" -> {
|
||||
val bannerList =
|
||||
gson.fromJson(item.data, Array<HomeBannerBean>::class.java)
|
||||
.toList()
|
||||
if (bannerList?.isNotEmpty() == true) {
|
||||
binding?.clFs?.visibility = View.VISIBLE
|
||||
val exampleDominantCeoAdapter = HomeMostAdapter()
|
||||
val layoutManager =
|
||||
LinearLayoutManager(
|
||||
context,
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
binding?.rvFs?.layoutManager = layoutManager
|
||||
binding?.rvFs?.adapter = exampleDominantCeoAdapter
|
||||
binding?.rvFs?.isNestedScrollingEnabled = false
|
||||
exampleDominantCeoAdapter.submitList(bannerList)
|
||||
val video = bannerList[0]
|
||||
Glide.with(requireContext()).load(video?.horizontally_img)
|
||||
.placeholder(R.drawable.iv_placeholder_h)
|
||||
.into(binding.ivFs)
|
||||
binding.tvName.text = video.name
|
||||
if (video.category.isNotEmpty()) {
|
||||
binding.tvTag.visibility = View.VISIBLE
|
||||
binding.tvTag.text = video.category[0]
|
||||
} else {
|
||||
binding.tvTag.visibility = View.INVISIBLE
|
||||
}
|
||||
binding.ivFs.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(
|
||||
context,
|
||||
PlayerDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(
|
||||
Constants.CONSTANTS_short_play_id,
|
||||
video.short_play_id
|
||||
)
|
||||
})
|
||||
}
|
||||
exampleDominantCeoAdapter.setOnItemClickListener { adapter, view, position ->
|
||||
exampleDominantCeoAdapter.currentPosition = position
|
||||
val video =
|
||||
adapter.getItem(position) as HomeBannerBean
|
||||
Glide.with(requireContext()).load(video?.horizontally_img)
|
||||
.placeholder(R.drawable.iv_placeholder_h)
|
||||
.into(binding.ivFs)
|
||||
binding.tvName.text = video.name
|
||||
if (video.category.isNotEmpty()) {
|
||||
binding.tvTag.visibility = View.VISIBLE
|
||||
binding.tvTag.text = video.category[0]
|
||||
} else {
|
||||
binding.tvTag.visibility = View.INVISIBLE
|
||||
}
|
||||
binding.ivFs.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(
|
||||
context,
|
||||
PlayerDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(
|
||||
Constants.CONSTANTS_short_play_id,
|
||||
video.short_play_id
|
||||
)
|
||||
})
|
||||
}
|
||||
exampleDominantCeoAdapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
} else {
|
||||
binding?.clFs?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
"home_v3_recommand" -> {
|
||||
val homeBannerAndNineSquarepRes =
|
||||
gson.fromJson(
|
||||
item.data,
|
||||
HomeBannerAndNineSquarepRes::class.java
|
||||
)
|
||||
if (homeBannerAndNineSquarepRes?.list?.isNotEmpty() == true) {
|
||||
binding?.clBanner?.visibility = View.VISIBLE
|
||||
val exampleHomeBannerAdapter =
|
||||
HomeBannerAdapter(homeBannerAndNineSquarepRes?.list)
|
||||
binding?.bannerHome?.apply {
|
||||
setAdapter(exampleHomeBannerAdapter)
|
||||
setBannerGalleryEffect(65, 10, 1f)
|
||||
setPageTransformer(RotateDownPageTransformer(10.5f))
|
||||
}
|
||||
exampleHomeBannerAdapter.setOnBannerListener { data, position ->
|
||||
startActivity(
|
||||
Intent(
|
||||
context,
|
||||
PlayerDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(
|
||||
Constants.CONSTANTS_short_play_id,
|
||||
data?.short_play_id
|
||||
)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
binding?.clBanner?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
"new_recommand" -> {
|
||||
val cagetoryBean =
|
||||
gson.fromJson(item.data, HomeTopWeekRes::class.java)
|
||||
if (cagetoryBean.list.isNotEmpty()) {
|
||||
binding?.clBannerB?.visibility = View.VISIBLE
|
||||
val exampleHomeBannerAdapter =
|
||||
HomeBannerBottomAdapter(cagetoryBean.list)
|
||||
binding?.bannerHomeB?.setBannerGalleryEffect(24, 10, 1f)
|
||||
binding?.bannerHomeB?.setAdapter(
|
||||
exampleHomeBannerAdapter
|
||||
)?.addBannerLifecycleObserver(this)
|
||||
?.setIndicator(binding.indicatorHome, false)
|
||||
exampleHomeBannerAdapter.setOnBannerListener { data, position ->
|
||||
startActivity(
|
||||
Intent(
|
||||
context,
|
||||
PlayerDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(
|
||||
Constants.CONSTANTS_short_play_id,
|
||||
data?.short_play_id
|
||||
)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
binding?.clBannerB?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hideLoading()
|
||||
hideNetError()
|
||||
binding?.srHome?.finishRefresh()
|
||||
EventBus.getDefault().post(Constants.CONSTANTS_main_stop)
|
||||
}
|
||||
} else {
|
||||
toast(getString(R.string.network_error))
|
||||
hideLoading()
|
||||
binding?.srHome?.finishRefresh()
|
||||
EventBus.getDefault().post(Constants.CONSTANTS_main_stop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewBinding(): FragmentHomeBinding {
|
||||
return FragmentHomeBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun onRetry() {
|
||||
super.onRetry()
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.allModules()
|
||||
} else {
|
||||
toast(getString(R.string.example_no_network))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.Outline
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewOutlineProvider
|
||||
import android.widget.ImageView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.google.android.material.imageview.ShapeableImageView
|
||||
import com.google.android.material.shape.RelativeCornerSize
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.HomeBannerBean
|
||||
|
||||
class HomeMostAdapter :
|
||||
BaseQuickAdapter<HomeBannerBean, QuickViewHolder>() {
|
||||
var currentPosition = 0
|
||||
override fun onBindViewHolder(
|
||||
holder: QuickViewHolder,
|
||||
position: Int,
|
||||
item: HomeBannerBean?
|
||||
) {
|
||||
val view = holder.getView<ShapeableImageView>(R.id.example_iv_icon_ceo)
|
||||
Glide.with(context).load(item?.image_url).placeholder(R.drawable.iv_placeholder_v)
|
||||
.into(view)
|
||||
view.scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
view.shapeAppearanceModel = view.shapeAppearanceModel
|
||||
.toBuilder()
|
||||
.setAllCornerSizes(RelativeCornerSize(0.5f))
|
||||
.build()
|
||||
view.elevation = 0f
|
||||
view.clipToOutline = true
|
||||
view.outlineProvider = object : ViewOutlineProvider() {
|
||||
override fun getOutline(view: View, outline: Outline) {
|
||||
val size = minOf(view.width, view.height)
|
||||
outline.setOval(0, 0, size, size)
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPosition == position) {
|
||||
holder.setVisible(R.id.view, false)
|
||||
} else {
|
||||
holder.setVisible(R.id.view, true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
context: Context,
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuickViewHolder {
|
||||
return QuickViewHolder(R.layout.item_dominant_ceo, parent)
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.blankj.utilcode.util.NetworkUtils
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseActivity
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.data.VideoListDataRes
|
||||
import com.jia.er.nebuluxe.app.databinding.FragmentHotBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import com.jia.er.nebuluxe.app.utils.toast
|
||||
import com.jia.er.nebuluxe.app.video.PlayerDetailActivity
|
||||
|
||||
class HotActivity : BaseActivity<FragmentHotBinding>() {
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
|
||||
private var hotAdapter: HotAdapter? = null
|
||||
private var isLoad = false
|
||||
override fun top() {
|
||||
binding?.exampleIvBack?.setOnClickListener { finish() }
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.homeHot(1, 10)
|
||||
} else {
|
||||
showNetError()
|
||||
}
|
||||
binding?.srFree?.setOnRefreshListener {
|
||||
mViewModel.homeHot(1, 10)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun center() {
|
||||
mViewModel.homeHotData.observe(this) {
|
||||
if (it != null) {
|
||||
hotAdapter = HotAdapter()
|
||||
val layoutManager =
|
||||
StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||
binding?.rvDataFree?.layoutManager = layoutManager
|
||||
binding?.rvDataFree?.adapter = hotAdapter
|
||||
binding?.rvDataFree?.isNestedScrollingEnabled = false
|
||||
hotAdapter?.submitList(it.data?.list)
|
||||
hotAdapter?.isStateViewEnable = true
|
||||
hotAdapter?.setStateViewLayout(
|
||||
this,
|
||||
R.layout.layout_emptyview
|
||||
)
|
||||
hotAdapter?.setOnItemClickListener { adapter, _, position ->
|
||||
val videoListData =
|
||||
adapter.getItem(position) as VideoListDataRes.VideoListData
|
||||
startActivity(
|
||||
Intent(
|
||||
this,
|
||||
PlayerDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(
|
||||
Constants.CONSTANTS_short_play_id,
|
||||
videoListData.id
|
||||
)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
toast(getString(R.string.network_error))
|
||||
}
|
||||
binding?.srFree?.finishRefresh()
|
||||
hideLoading()
|
||||
hideNetError()
|
||||
isLoad = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewBinding(): FragmentHotBinding {
|
||||
return FragmentHotBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun onRetry() {
|
||||
super.onRetry()
|
||||
singleClick {
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.freeMoreVideo()
|
||||
} else {
|
||||
toast(getString(R.string.example_no_network))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
62
app/src/main/java/com/jia/er/nebuluxe/app/home/HotAdapter.kt
Normal file
62
app/src/main/java/com/jia/er/nebuluxe/app/home/HotAdapter.kt
Normal file
@ -0,0 +1,62 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.VideoListDataRes
|
||||
import com.jia.er.nebuluxe.app.ui.PosterStyleImageView
|
||||
|
||||
class HotAdapter :
|
||||
BaseQuickAdapter<VideoListDataRes.VideoListData, QuickViewHolder>() {
|
||||
override fun onBindViewHolder(
|
||||
holder: QuickViewHolder,
|
||||
position: Int,
|
||||
item: VideoListDataRes.VideoListData?
|
||||
) {
|
||||
val posterView = holder.getView<PosterStyleImageView>(R.id.iv_hot)
|
||||
posterView.loadImage(
|
||||
url = item?.image_url.toString(),
|
||||
placeholderRes = R.drawable.iv_placeholder_v,
|
||||
errorRes = R.drawable.iv_placeholder_v
|
||||
)
|
||||
if (0 == position) {
|
||||
holder.setGone(R.id.iv_top, false)
|
||||
posterView.apply {
|
||||
// 顶部倾斜程度(左侧更低)
|
||||
setTopSlantOffsetDp(25f)
|
||||
|
||||
// 左上小圆角,其他正常
|
||||
setTopLeftShortStyle(topLeftDp = 12f, otherDp = 18f)
|
||||
|
||||
// 如果还需更贴合
|
||||
setCornerRadiiDp(12f, 18f, 18f, 18f)
|
||||
}
|
||||
} else {
|
||||
holder.setGone(R.id.iv_top, true)
|
||||
posterView.apply {
|
||||
// 顶部倾斜程度(左侧更低)
|
||||
setTopSlantOffsetDp(0f)
|
||||
|
||||
// 左上小圆角,其他正常
|
||||
setTopLeftShortStyle(topLeftDp = 18f, otherDp = 18f)
|
||||
// 如果还需更贴合
|
||||
setCornerRadiiDp(18f, 18f, 18f, 18f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
context: Context,
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuickViewHolder {
|
||||
return QuickViewHolder(R.layout.item_hot, parent)
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.blankj.utilcode.util.NetworkUtils
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseActivity
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.data.HomeRankingRes
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivityRankingsBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import com.jia.er.nebuluxe.app.utils.toast
|
||||
import com.jia.er.nebuluxe.app.video.PlayerDetailActivity
|
||||
|
||||
|
||||
class RankActivity : BaseActivity<ActivityRankingsBinding>() {
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
private var type = "most_trending"
|
||||
|
||||
override fun top() {
|
||||
binding?.exampleIvBack?.setOnClickListener { finish() }
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.homeRanking(type)
|
||||
} else {
|
||||
showNetError()
|
||||
}
|
||||
binding.srRank.setOnRefreshListener {
|
||||
mViewModel.homeRanking(type)
|
||||
}
|
||||
}
|
||||
|
||||
override fun center() {
|
||||
mViewModel.homeRankingData.observe(this) {
|
||||
if (it != null) {
|
||||
if (it.data?.list?.isNotEmpty() == true) {
|
||||
val homeRankTrendingAdapter = RankAdapter()
|
||||
val manager1 = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
binding?.rvRanks?.layoutManager = manager1
|
||||
binding?.rvRanks?.adapter = homeRankTrendingAdapter
|
||||
homeRankTrendingAdapter?.submitList(it.data.list)
|
||||
homeRankTrendingAdapter?.isStateViewEnable = true
|
||||
homeRankTrendingAdapter?.setStateViewLayout(this, R.layout.layout_emptyview)
|
||||
homeRankTrendingAdapter?.setOnItemClickListener { adapter, view, position ->
|
||||
val data = adapter.getItem(position) as HomeRankingRes.Item7
|
||||
startActivity(Intent(
|
||||
this, PlayerDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(
|
||||
Constants.CONSTANTS_short_play_id, data.short_play_id
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
binding.srRank.finishRefresh()
|
||||
hideNetError()
|
||||
hideLoading()
|
||||
} else {
|
||||
showNetError()
|
||||
toast(getString(R.string.network_error))
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewBinding(): ActivityRankingsBinding {
|
||||
return ActivityRankingsBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun onRetry() {
|
||||
super.onRetry()
|
||||
singleClick {
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.homeRanking(type)
|
||||
} else {
|
||||
toast(getString(R.string.example_no_network))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.fullspan.FullSpanAdapterType
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.HomeRankingRes
|
||||
import com.jia.er.nebuluxe.app.utils.formatNumberByLong
|
||||
|
||||
class RankAdapter :
|
||||
BaseQuickAdapter<HomeRankingRes.Item7, QuickViewHolder>(),
|
||||
FullSpanAdapterType {
|
||||
override fun onBindViewHolder(
|
||||
holder: QuickViewHolder,
|
||||
position: Int,
|
||||
item: HomeRankingRes.Item7?
|
||||
) {
|
||||
Glide.with(context).load(item?.image_url).placeholder(R.drawable.iv_placeholder_v)
|
||||
.into(holder.getView(R.id.iv_cover))
|
||||
holder.setText(R.id.tv_rank_name, item?.name)
|
||||
holder.setText(R.id.tv_des, item?.description)
|
||||
if (item?.category?.isNotEmpty() == true) {
|
||||
val string = item.category[0]
|
||||
holder.setText(R.id.tv_rank_tag, string)
|
||||
holder.setVisible(R.id.tv_rank_tag, true)
|
||||
} else {
|
||||
holder.setVisible(R.id.tv_rank_tag, false)
|
||||
}
|
||||
val view = holder.getView<AppCompatTextView>(R.id.tv_rank_watch)
|
||||
holder.setText(R.id.tv_num, (position + 1).toString())
|
||||
when (position) {
|
||||
0 -> {
|
||||
holder.setBackgroundResource(R.id.tv_num, R.drawable.bg_rank_1)
|
||||
holder.setTextColor(R.id.tv_num,Color.parseColor("#4F2500"))
|
||||
holder.setTextColor(R.id.tv_rank_tag,Color.parseColor("#FFE8C4"))
|
||||
view?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
context?.getDrawable(R.drawable.iv_item_rank_heat),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
1 -> {
|
||||
holder.setBackgroundResource(R.id.tv_num, R.drawable.bg_rank_2)
|
||||
holder.setTextColor(R.id.tv_num,Color.parseColor("#424242"))
|
||||
holder.setTextColor(R.id.tv_rank_tag,Color.parseColor("#FFE8C4"))
|
||||
view?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
context?.getDrawable(R.drawable.iv_item_rank_heat),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
holder.setBackgroundResource(R.id.tv_num, R.drawable.bg_rank_3)
|
||||
holder.setTextColor(R.id.tv_num,Color.parseColor("#79471B"))
|
||||
holder.setTextColor(R.id.tv_rank_tag,Color.parseColor("#FFE8C4"))
|
||||
view?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
context?.getDrawable(R.drawable.iv_item_rank_heat),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
holder.setBackgroundResource(R.id.tv_num, R.drawable.bg_rank_other)
|
||||
holder.setTextColor(R.id.tv_num,Color.parseColor("#0F0F0F"))
|
||||
holder.setTextColor(R.id.tv_rank_tag,Color.parseColor("#F0C2E1"))
|
||||
view?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
context?.getDrawable(R.drawable.iv_item_rank_heat_1),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
holder.setText(R.id.tv_rank_watch, item?.watch_total?.let { formatNumberByLong(it) })
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
context: Context,
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuickViewHolder {
|
||||
return QuickViewHolder(R.layout.item_ranks, parent)
|
||||
}
|
||||
}
|
464
app/src/main/java/com/jia/er/nebuluxe/app/home/ReelsFragment.kt
Normal file
464
app/src/main/java/com/jia/er/nebuluxe/app/home/ReelsFragment.kt
Normal file
@ -0,0 +1,464 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.AppCompatSeekBar
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.datasource.DataSource
|
||||
import androidx.media3.datasource.DefaultDataSourceFactory
|
||||
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.hls.HlsMediaSource
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.exoplayer.source.ProgressiveMediaSource
|
||||
import androidx.media3.ui.PlayerView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.PagerSnapHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.jia.er.nebuluxe.app.data.RecommendDataRes
|
||||
import com.jia.er.nebuluxe.app.ui.FfmpegRenderersFactory
|
||||
import com.jia.er.nebuluxe.app.ui.LoadingLine
|
||||
import com.jia.er.nebuluxe.app.ui.OnSnapHelperCurrentListener
|
||||
import com.jia.er.nebuluxe.app.ui.RecyclerViewScrollerDetection
|
||||
import com.blankj.utilcode.util.NetworkUtils
|
||||
import com.blankj.utilcode.util.ViewUtils
|
||||
import com.bumptech.glide.Glide
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseFragment
|
||||
import com.jia.er.nebuluxe.app.databinding.FragmentReelsBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.appendWithStyle
|
||||
import com.jia.er.nebuluxe.app.utils.formatTimestamp
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import com.jia.er.nebuluxe.app.utils.toast
|
||||
import com.jia.er.nebuluxe.app.utils.DialogUtils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
class ReelsFragment : BaseFragment<FragmentReelsBinding>(),
|
||||
OnSnapHelperCurrentListener {
|
||||
private var builder: ExoPlayer.Builder? = null
|
||||
private var player: ExoPlayer? = null
|
||||
private val pagerSnapHelper = PagerSnapHelper()
|
||||
private val recyclerViewScrollerDetection = RecyclerViewScrollerDetection()
|
||||
private var homeForYouAdapter: HomeForYouAdapter? = null
|
||||
private var playerView: PlayerView? = null
|
||||
private var currentView: View? = null
|
||||
private var loadingLine: LoadingLine? = null
|
||||
private var tvName: AppCompatTextView? = null
|
||||
private var tvTime: AppCompatTextView? = null
|
||||
private var play: AppCompatImageView? = null
|
||||
private var collection: AppCompatImageView? = null
|
||||
private var ivIconPlayer: AppCompatImageView? = null
|
||||
private var ivCover: AppCompatImageView? = null
|
||||
private var exampleSeekbarPlayerController: AppCompatSeekBar? = null
|
||||
private var exampleProgressJob: Job? = null
|
||||
private var isDragging = false
|
||||
private var isPlaying = false
|
||||
private var currentPage = 1
|
||||
private val currentSize = 10
|
||||
private var dataRes: RecommendDataRes.Data? = null
|
||||
private var currentPosition = 0
|
||||
private var tvEpTotal: AppCompatTextView? = null
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
private var isCanPlay = false
|
||||
|
||||
override fun top() {
|
||||
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
builder = ExoPlayer.Builder(requireContext(), FfmpegRenderersFactory(requireContext()))
|
||||
.setRenderersFactory(
|
||||
DefaultRenderersFactory(requireContext()).setEnableDecoderFallback(
|
||||
true
|
||||
)
|
||||
)
|
||||
player = builder?.build()
|
||||
playerView = ViewUtils.layoutId2View(R.layout.include_player_view) as PlayerView
|
||||
playerView?.player = player
|
||||
loadingLine = playerView?.findViewById(R.id.load_line)
|
||||
tvName = playerView?.findViewById(R.id.example_tv_title_player_controller)
|
||||
tvTime = playerView?.findViewById(R.id.tv_player_seek_time)
|
||||
tvEpTotal = playerView?.findViewById(R.id.tv_ep_total)
|
||||
play = playerView?.findViewById(R.id.example_iv_play_player_controller)
|
||||
collection = playerView?.findViewById(R.id.example_iv_collection_controller)
|
||||
ivIconPlayer = playerView?.findViewById(R.id.iv_icon_player)
|
||||
exampleSeekbarPlayerController =
|
||||
playerView?.findViewById(R.id.example_seekBar_player_controller)
|
||||
play?.setOnClickListener {
|
||||
singleClick {
|
||||
if (isPlaying) {
|
||||
pause()
|
||||
} else {
|
||||
play()
|
||||
}
|
||||
}
|
||||
}
|
||||
player?.addListener(object : Player.Listener {
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
super.onPlaybackStateChanged(playbackState)
|
||||
when (playbackState) {
|
||||
Player.STATE_BUFFERING -> {
|
||||
if (!isHidden) {
|
||||
ivIconPlayer?.visibility = View.VISIBLE
|
||||
loadingLine?.visibility = View.VISIBLE
|
||||
loadingLine?.postDelayed({ loadingLine?.startAnimation() }, 200)
|
||||
}
|
||||
}
|
||||
|
||||
Player.STATE_READY -> {
|
||||
if (isCanPlay) {
|
||||
canPlay()
|
||||
}
|
||||
}
|
||||
|
||||
Player.STATE_ENDED -> {
|
||||
val plus = currentPosition.plus(1)
|
||||
binding.rvRecommend.smoothScrollToPosition(plus)
|
||||
}
|
||||
|
||||
Player.STATE_IDLE -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
super.onPlayerError(error)
|
||||
|
||||
}
|
||||
})
|
||||
collection?.setOnClickListener {
|
||||
singleClick {
|
||||
if (dataRes?.is_collect == true) {
|
||||
dataRes?.video_info?.short_play_id?.let { it1 ->
|
||||
dataRes?.video_info?.short_play_video_id?.let { it2 ->
|
||||
DialogUtils.unFavoriteDialog(
|
||||
requireContext(),
|
||||
it1, it2, mViewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dataRes?.video_info?.short_play_id?.let {
|
||||
dataRes?.video_info?.short_play_video_id.let { it1 ->
|
||||
if (it1 != null) {
|
||||
mViewModel.doCollect(
|
||||
it, it1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.srFy.apply {
|
||||
setOnRefreshListener {
|
||||
recyclerViewScrollerDetection.isFirstAttached = false
|
||||
player?.stop()
|
||||
mViewModel.getRecommands(currentPage, currentSize, "")
|
||||
}
|
||||
}
|
||||
binding.rvRecommend.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
|
||||
var isSlidingUp = false
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
isSlidingUp = dy > 0
|
||||
}
|
||||
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
super.onScrollStateChanged(recyclerView, newState)
|
||||
|
||||
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
|
||||
val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
|
||||
val totalItemCount = layoutManager.itemCount
|
||||
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
if (isSlidingUp &&
|
||||
lastVisibleItemPosition == totalItemCount - 1
|
||||
) {
|
||||
currentPage++
|
||||
mViewModel.getRecommands(currentPage, currentSize, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
exampleSeekbarPlayerController?.setOnSeekBarChangeListener(object :
|
||||
SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(
|
||||
seekBar: SeekBar?,
|
||||
progress: Int,
|
||||
fromUser: Boolean
|
||||
) {
|
||||
if (fromUser) {
|
||||
seekTo(progress)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar?) {
|
||||
tvTime?.visibility = FrameLayout.VISIBLE
|
||||
isDragging = true
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar?) {
|
||||
isDragging = false
|
||||
tvTime?.visibility = FrameLayout.INVISIBLE
|
||||
}
|
||||
})
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.getRecommands(currentPage, currentSize, "")
|
||||
} else {
|
||||
showNetError()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setProgress() {
|
||||
exampleProgressJob?.cancel()
|
||||
val duration = player!!.duration
|
||||
exampleSeekbarPlayerController?.max = duration.toInt()
|
||||
exampleSeekbarPlayerController?.progress = player!!.currentPosition.toInt()
|
||||
exampleProgressJob = lifecycleScope.launch {
|
||||
while (isActive) {
|
||||
if (!isDragging) {
|
||||
withContext(Dispatchers.Main) {
|
||||
exampleSeekbarPlayerController?.progress =
|
||||
player!!.currentPosition.toInt()
|
||||
}
|
||||
}
|
||||
delay(1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun play() {
|
||||
player?.play()
|
||||
play?.setImageResource(R.drawable.iv_example_stop)
|
||||
isPlaying = true
|
||||
isDragging = false
|
||||
}
|
||||
|
||||
fun pause() {
|
||||
player?.pause()
|
||||
play?.setImageResource(R.drawable.iv_example_play)
|
||||
isPlaying = false
|
||||
isDragging = true
|
||||
}
|
||||
|
||||
private fun seekTo(progress: Int) {
|
||||
player?.seekTo(progress.toLong())
|
||||
seekTime()
|
||||
}
|
||||
|
||||
private fun seekTime() {
|
||||
val currentPosition = player!!.currentPosition
|
||||
val currentTime = formatTimestamp(currentPosition / 1000)
|
||||
val totalDuration = player!!.duration
|
||||
val totalTime = formatTimestamp(totalDuration / 1000)
|
||||
tvTime?.text = "$currentTime/$totalTime"
|
||||
}
|
||||
|
||||
override fun center() {
|
||||
mViewModel.recommendData.observe(this) {
|
||||
if (it != null) {
|
||||
if (it.data?.list?.isNotEmpty() == true) {
|
||||
if (currentPage == 1) {
|
||||
homeForYouAdapter = HomeForYouAdapter()
|
||||
val layoutManager =
|
||||
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
binding?.rvRecommend?.layoutManager = layoutManager
|
||||
binding?.rvRecommend?.adapter = homeForYouAdapter
|
||||
binding?.rvRecommend?.isNestedScrollingEnabled = false
|
||||
pagerSnapHelper.attachToRecyclerView(binding?.rvRecommend)
|
||||
recyclerViewScrollerDetection.setCurrentListener(this)
|
||||
recyclerViewScrollerDetection.attachToSnapHelper(pagerSnapHelper)
|
||||
binding?.rvRecommend?.let { it1 ->
|
||||
recyclerViewScrollerDetection.addOnScrollListener(
|
||||
it1
|
||||
)
|
||||
}
|
||||
it.data?.list?.forEach { item ->
|
||||
Glide.with(requireContext()).load(item.image_url).preload()
|
||||
}
|
||||
homeForYouAdapter?.submitList(it.data.list)
|
||||
} else {
|
||||
homeForYouAdapter?.addAll(it.data.list)
|
||||
}
|
||||
hideLoading()
|
||||
} else {
|
||||
toast(getString(R.string.no_more_data))
|
||||
}
|
||||
hideNetError()
|
||||
} else {
|
||||
toast(getString(R.string.network_error))
|
||||
hideLoading()
|
||||
}
|
||||
binding.srFy.finishRefresh()
|
||||
}
|
||||
|
||||
mViewModel.collectData.observe(this) {
|
||||
if (it != null) {
|
||||
collection?.setImageResource(R.drawable.iv_example_collection_h)
|
||||
dataRes?.collect_total = dataRes?.collect_total?.plus(1)
|
||||
homeForYouAdapter?.getItem(currentPosition)?.is_collect = true
|
||||
homeForYouAdapter?.getItem(currentPosition)?.collect_total =
|
||||
dataRes?.collect_total
|
||||
toast(getString(R.string.success))
|
||||
} else {
|
||||
toast(getString(R.string.network_error))
|
||||
}
|
||||
}
|
||||
mViewModel.cancelCollectData.observe(this) {
|
||||
if (it != null) {
|
||||
collection?.setImageResource(R.drawable.iv_example_collection_n)
|
||||
dataRes?.collect_total = dataRes?.collect_total?.minus(1)
|
||||
homeForYouAdapter?.getItem(currentPosition)?.is_collect = false
|
||||
homeForYouAdapter?.getItem(currentPosition)?.collect_total =
|
||||
dataRes?.collect_total
|
||||
toast(getString(R.string.success))
|
||||
} else {
|
||||
toast(getString(R.string.network_error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildMediaSource(videoPath: String): MediaSource {
|
||||
val dataSourceFactory: DataSource.Factory =
|
||||
DefaultDataSourceFactory(requireContext(), "loopdrama")
|
||||
|
||||
return if (videoPath.endsWith(".m3u8")) {
|
||||
HlsMediaSource.Factory(dataSourceFactory)
|
||||
.createMediaSource(MediaItem.fromUri(Uri.parse(videoPath)))
|
||||
} else {
|
||||
ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||
.createMediaSource(MediaItem.fromUri(Uri.parse(videoPath)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewBinding(): FragmentReelsBinding {
|
||||
return FragmentReelsBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
isCanPlay = false
|
||||
binding.root.postDelayed({ pause() }, 300)
|
||||
}
|
||||
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (isVisible) {
|
||||
isCanPlay = true
|
||||
canPlay()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
override fun setActive(
|
||||
currentView: View?, position: Int, previousView: View?, previousPosition: Int
|
||||
) {
|
||||
isCanPlay = true
|
||||
currentPosition = position
|
||||
this.currentView = currentView
|
||||
val frameLayout = currentView?.findViewById<FrameLayout>(R.id.video)
|
||||
(playerView?.parent as FrameLayout?)?.removeView(playerView)
|
||||
frameLayout?.removeAllViews()
|
||||
frameLayout?.addView(playerView)
|
||||
playerView?.showController()
|
||||
dataRes = homeForYouAdapter?.getItem(position)
|
||||
dataRes?.video_info?.video_url?.let { buildMediaSource(it) }
|
||||
?.let { player?.setMediaSource(it) }
|
||||
player?.prepare()
|
||||
setUI()
|
||||
}
|
||||
|
||||
private fun setUI() {
|
||||
ivIconPlayer?.let { it1 ->
|
||||
Glide.with(this).load(dataRes?.image_url).into(it1)
|
||||
}
|
||||
tvName?.text = dataRes?.name
|
||||
val builder = SpannableStringBuilder()
|
||||
builder.appendWithStyle(
|
||||
"Ep.".plus(dataRes?.video_info?.episode),
|
||||
Color.parseColor("#50FFFFFF"),
|
||||
isBold = true
|
||||
)
|
||||
.appendWithStyle(
|
||||
"/Ep.".plus(dataRes?.episode_total),
|
||||
Color.parseColor("#50FFFFFF"),
|
||||
isBold = false
|
||||
)
|
||||
tvEpTotal?.text = builder
|
||||
collection?.setImageResource(if (dataRes?.is_collect == true) R.drawable.iv_example_collection_h else R.drawable.iv_example_collection_n)
|
||||
}
|
||||
|
||||
override fun disActive(detachedView: View?, detachedPosition: Int) {
|
||||
if (null == detachedView) return
|
||||
ivCover = detachedView.findViewById(R.id.iv_icon)
|
||||
ivCover?.visibility = View.VISIBLE
|
||||
if (player?.isPlaying == true) {
|
||||
pause()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHiddenChanged(hidden: Boolean) {
|
||||
super.onHiddenChanged(hidden)
|
||||
if (hidden) {
|
||||
isCanPlay = false
|
||||
binding.root.postDelayed({ pause() }, 200)
|
||||
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
} else {
|
||||
isCanPlay = true
|
||||
canPlay()
|
||||
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
}
|
||||
|
||||
private fun canPlay() {
|
||||
loadingLine?.endAnimation()
|
||||
loadingLine?.visibility = View.INVISIBLE
|
||||
ivCover = currentView?.findViewById(R.id.iv_icon)
|
||||
ivCover?.visibility = View.INVISIBLE
|
||||
ivIconPlayer?.visibility = View.INVISIBLE
|
||||
play()
|
||||
setProgress()
|
||||
}
|
||||
|
||||
override fun onRetry() {
|
||||
super.onRetry()
|
||||
singleClick {
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
mViewModel.getRecommands(currentPage, currentSize, "")
|
||||
} else {
|
||||
toast(getString(R.string.example_no_network))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
player?.stop()
|
||||
player?.release()
|
||||
recyclerViewScrollerDetection.detachToSnapHelper()
|
||||
}
|
||||
|
||||
}
|
142
app/src/main/java/com/jia/er/nebuluxe/app/home/SavedFragment.kt
Normal file
142
app/src/main/java/com/jia/er/nebuluxe/app/home/SavedFragment.kt
Normal file
@ -0,0 +1,142 @@
|
||||
package com.jia.er.nebuluxe.app.home
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.jia.er.nebuluxe.app.data.CollectionRes
|
||||
import com.blankj.utilcode.util.NetworkUtils
|
||||
import com.chad.library.adapter4.layoutmanager.QuickGridLayoutManager
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseFragment
|
||||
import com.jia.er.nebuluxe.app.databinding.FragmentSavedBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import com.jia.er.nebuluxe.app.utils.toast
|
||||
|
||||
class SavedFragment : BaseFragment<FragmentSavedBinding>() {
|
||||
private var page: Int = 1
|
||||
// private var myListAdapter: MyListAdapter? = null
|
||||
private var edit = false
|
||||
private var current: Int = 0
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
override fun top() {
|
||||
// if (NetworkUtils.isConnected()) {
|
||||
// showLoading()
|
||||
// mViewModel.getCollections(page)
|
||||
// } else {
|
||||
// showNetError()
|
||||
// }
|
||||
// binding?.srMyList?.setOnRefreshListener {
|
||||
// page = 1
|
||||
// mViewModel.getCollections(page)
|
||||
// }
|
||||
// binding?.srMyList?.setOnLoadMoreListener {
|
||||
// page++
|
||||
// mViewModel.getCollections(page)
|
||||
// }
|
||||
// binding?.exampleIvEditMyFavorites?.setOnClickListener {
|
||||
// if (!edit) {
|
||||
// edit = true
|
||||
// binding?.exampleIvEditMyFavorites?.setImageResource(R.drawable.iv_edit_favorites_complete)
|
||||
// myListAdapter?.eidt = true
|
||||
// binding?.tvTitle?.text = "Delete"
|
||||
// binding.tvTitle.background = context?.getDrawable(R.drawable.iv_list_title_bg_h)
|
||||
// myListAdapter?.notifyDataSetChanged()
|
||||
// } else {
|
||||
// edit = false
|
||||
// binding?.exampleIvEditMyFavorites?.setImageResource(R.drawable.iv_edit_favorites)
|
||||
// binding.tvTitle.background = context?.getDrawable(R.drawable.iv_list_title_bg)
|
||||
// myListAdapter?.eidt = false
|
||||
// binding?.tvTitle?.text = "Favorites"
|
||||
// myListAdapter?.notifyDataSetChanged()
|
||||
// }
|
||||
// }
|
||||
// binding.ivHis.setOnClickListener {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// requireContext(),
|
||||
// HistoryActivity::class.java
|
||||
// ))
|
||||
// }
|
||||
}
|
||||
|
||||
override fun center() {
|
||||
// mViewModel.collectionsData.observe(this) {
|
||||
// if (it != null) {
|
||||
// if (page == 1) {
|
||||
// myListAdapter = MyListAdapter()
|
||||
// val manager = QuickGridLayoutManager(requireContext(), 3)
|
||||
// binding?.rvMyList?.layoutManager = manager
|
||||
// binding?.rvMyList?.adapter = myListAdapter
|
||||
// myListAdapter?.submitList(it.data?.list)
|
||||
// myListAdapter?.isStateViewEnable = true
|
||||
// myListAdapter?.setStateViewLayout(requireContext(), R.layout.layout_emptyview)
|
||||
// myListAdapter?.addOnItemChildClickListener(R.id.iv_favorites_delete) { adapter, view, position ->
|
||||
// current = position
|
||||
// val collectionData =
|
||||
// adapter.getItem(position) as CollectionRes.CollectionData
|
||||
// DialogUtils.unFavoriteDialog(
|
||||
// requireContext(),
|
||||
// collectionData.short_play_id,
|
||||
// collectionData.short_play_video_id,
|
||||
// mViewModel
|
||||
// )
|
||||
// }
|
||||
// myListAdapter?.setOnItemClickListener { adapter, view, position ->
|
||||
// val data = adapter.getItem(position) as CollectionRes.CollectionData
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// requireContext(),
|
||||
// PlayerDetailActivity::class.java
|
||||
// ).apply {
|
||||
// putExtra(
|
||||
// Constants.CONSTANTS_short_play_id,
|
||||
// data.short_play_id
|
||||
// )
|
||||
// })
|
||||
// }
|
||||
// } else {
|
||||
// if (it.data?.list?.isNotEmpty() == true) {
|
||||
// myListAdapter?.addAll(it.data.list)
|
||||
// } else {
|
||||
// toast(getString(R.string.no_more_data))
|
||||
// }
|
||||
// }
|
||||
// hideLoading()
|
||||
// hideNetError()
|
||||
// } else {
|
||||
// hideLoading()
|
||||
// toast(getString(R.string.network_error))
|
||||
// }
|
||||
// binding?.srMyList?.finishRefresh()
|
||||
// binding?.srMyList?.finishLoadMore()
|
||||
// }
|
||||
//
|
||||
// mViewModel.cancelCollectData.observe(this) {
|
||||
// if (it != null) {
|
||||
// toast(getString(R.string.success))
|
||||
// myListAdapter?.removeAt(current)
|
||||
// myListAdapter?.notifyDataSetChanged()
|
||||
// } else {
|
||||
// toast(getString(R.string.network_error))
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
override fun getViewBinding(): FragmentSavedBinding {
|
||||
return FragmentSavedBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun onRetry() {
|
||||
super.onRetry()
|
||||
singleClick {
|
||||
if (NetworkUtils.isConnected()) {
|
||||
showLoading()
|
||||
page = 1
|
||||
mViewModel.getCollections(page)
|
||||
} else {
|
||||
toast(getString(R.string.example_no_network))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
705
app/src/main/java/com/jia/er/nebuluxe/app/main/MainActivity.kt
Normal file
705
app/src/main/java/com/jia/er/nebuluxe/app/main/MainActivity.kt
Normal file
@ -0,0 +1,705 @@
|
||||
package com.jia.er.nebuluxe.app.main
|
||||
|
||||
import android.view.KeyEvent
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.jia.er.nebuluxe.app.home.HomeFragment
|
||||
import com.jia.er.nebuluxe.app.home.ReelsFragment
|
||||
import com.jia.er.nebuluxe.app.home.SavedFragment
|
||||
import com.flyco.tablayout.listener.CustomTabEntity
|
||||
import com.flyco.tablayout.listener.OnTabSelectListener
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseActivity
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.data.TabEntity
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivityMainBinding
|
||||
import com.jia.er.nebuluxe.app.me.MeFragment
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.Memory
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
|
||||
class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
|
||||
private var titles = arrayOf(
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""
|
||||
)
|
||||
private val iconUnSelectIds by lazy {
|
||||
intArrayOf(
|
||||
R.drawable.iv_home_n,
|
||||
R.drawable.iv_reels_n,
|
||||
R.drawable.iv_saved_n,
|
||||
R.drawable.iv_me_n
|
||||
)
|
||||
}
|
||||
private val iconSelectIds by lazy {
|
||||
intArrayOf(
|
||||
R.drawable.iv_home_h,
|
||||
R.drawable.iv_reels_h,
|
||||
R.drawable.iv_saved_h,
|
||||
R.drawable.iv_me_h
|
||||
)
|
||||
}
|
||||
private val tabEntities = ArrayList<CustomTabEntity>()
|
||||
private var homeFragment: HomeFragment? = null
|
||||
private var reelsFragment: ReelsFragment? = null
|
||||
private var myListFragment: SavedFragment? = null
|
||||
private var meFragment: MeFragment? = null
|
||||
private var index = 0
|
||||
private var shortVideoId: Int = 0
|
||||
// private var notificationDialog: NotificationDialog? = null
|
||||
// private var path = ""
|
||||
// private var short_play_id = ""
|
||||
// private var message_id = ""
|
||||
// private var title = ""
|
||||
// private var scheduler: ScheduledExecutorService? = Executors.newSingleThreadScheduledExecutor()
|
||||
// private val scope = CoroutineScope(Dispatchers.Main)
|
||||
|
||||
// override fun onNewIntent(intent: Intent?) {
|
||||
// super.onNewIntent(intent)
|
||||
// val webpageURL = intent?.data
|
||||
// uploadDDL(webpageURL)
|
||||
// path = intent?.getStringExtra("path").toString()
|
||||
// short_play_id = intent?.getStringExtra("short_play_id").toString()
|
||||
// message_id = intent?.getStringExtra("message_id").toString()
|
||||
// title = intent?.getStringExtra("title").toString()
|
||||
// notificationGo()
|
||||
// }
|
||||
|
||||
override fun top() {
|
||||
// val webpageURL = intent.data
|
||||
// uploadDDL(webpageURL)
|
||||
// path = intent?.getStringExtra("path").toString()
|
||||
// short_play_id = intent?.getStringExtra("short_play_id").toString()
|
||||
// message_id = intent?.getStringExtra("message_id").toString()
|
||||
// title = intent?.getStringExtra("title").toString()
|
||||
showLoading()
|
||||
EventBus.getDefault().register(this)
|
||||
(titles.indices).mapTo(tabEntities) {
|
||||
TabEntity(
|
||||
titles[it], iconSelectIds[it], iconUnSelectIds[it]
|
||||
)
|
||||
}
|
||||
binding.tabLayout.setTabData(tabEntities)
|
||||
binding?.tabLayout?.setOnTabSelectListener(object : OnTabSelectListener {
|
||||
override fun onTabSelect(position: Int) {
|
||||
switchFragment(position)
|
||||
// when (position) {
|
||||
// 0 -> {
|
||||
// binding?.dialogHistory?.root?.postDelayed(
|
||||
// {
|
||||
// val string = Memory.getMMKV()
|
||||
// .getString(Constants.Constants_Main_Video_info, "")
|
||||
// if (string?.isNotEmpty() == true && NetworkUtils.isConnected()) {
|
||||
// val fromJson = Gson().fromJson(string, MainDataHis::class.java)
|
||||
// showHistoryDialog(fromJson)
|
||||
// }
|
||||
// }, 500
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// else -> {
|
||||
// binding?.dialogHistory?.root?.visibility = View.INVISIBLE
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
override fun onTabReselect(position: Int) {
|
||||
|
||||
}
|
||||
})
|
||||
// Constants.CanNotification = NotificationUtils.isNotificationEnabled(this)
|
||||
// mViewModel.uploadNoticeStatus(
|
||||
// FbNotificationReq(
|
||||
// if (Constants.CanNotification) "1" else "0"
|
||||
// )
|
||||
// )
|
||||
mViewModel.getInfo()
|
||||
switchFragment(index)
|
||||
// GoogleApiAvailability.getInstance().makeGooglePlayServicesAvailable(this)
|
||||
// .addOnCompleteListener {
|
||||
// if (it.isSuccessful) {
|
||||
// askNotificationPermission()
|
||||
// }
|
||||
// }
|
||||
// binding?.root?.postDelayed({ notificationGo() }, 700)
|
||||
// mViewModel.enterTheApp()
|
||||
// val intervalMillis = 10 * 60 * 1000
|
||||
// scheduler?.scheduleWithFixedDelay({
|
||||
// try {
|
||||
// lifecycleScope.launch {
|
||||
// mViewModel.onLine()
|
||||
// }
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// }, 0, intervalMillis.toLong(), TimeUnit.MILLISECONDS)
|
||||
// binding?.root?.postDelayed({
|
||||
// if (Memory.getOrder().isNotEmpty()) {
|
||||
// val string = Memory.getOrder()
|
||||
// scope.launch {
|
||||
// flow {
|
||||
// for (item in string) {
|
||||
// emit(item)
|
||||
// }
|
||||
// }.onEach { item ->
|
||||
// upError(
|
||||
// "pay restore",
|
||||
// mViewModel,
|
||||
// "restore",
|
||||
// "pay_restore",
|
||||
// "auto", GsonUtils.toJson(item), 0, 0
|
||||
// )
|
||||
// mViewModel.restorePaid(item)
|
||||
// }.debounce(1000).collect {}
|
||||
// }
|
||||
// }
|
||||
// }, 3000)
|
||||
}
|
||||
|
||||
override fun center() {
|
||||
// mViewModel.restorePaidData.observe(this) {
|
||||
// if (it != null) {
|
||||
// it.data?.order_code?.let { it1 -> Memory.removeOrderString(it1) }
|
||||
// }
|
||||
// }
|
||||
mViewModel.infoData.observe(this) {
|
||||
if (it != null) {
|
||||
it.data?.let { it1 ->
|
||||
Memory.saveUserInfo(it1)
|
||||
}
|
||||
}
|
||||
}
|
||||
mViewModel.userRegisterData.observe(this) {
|
||||
if (it != null) {
|
||||
Memory.getMMKV()
|
||||
.putString(Constants.CONSTANTS_AuthorizationExample, it.data?.token)
|
||||
EventBus.getDefault().post(Constants.CONSTANTS_refresh_me)
|
||||
}
|
||||
}
|
||||
// mViewModel.loginData.observe(this) {
|
||||
// if (it != null) {
|
||||
// toast(getString(R.string.success))
|
||||
// Memory.getMMKV()
|
||||
// .putString(Constants.CONSTANTS_AuthorizationExample, it.data?.token)
|
||||
// EventBus.getDefault()
|
||||
// .post(Constants.CONSTANTS_enterTheApp)
|
||||
// EventBus.getDefault()
|
||||
// .post(Constants.CONSTANTS_onLine)
|
||||
// mViewModel.getInfo()
|
||||
// EventBus.getDefault()
|
||||
// .post(Constants.CONSTANTS_refresh_me)
|
||||
// hideLoading()
|
||||
// loginDialog?.dismiss()
|
||||
// } else {
|
||||
// hideLoading()
|
||||
// toast(getString(R.string.network_error))
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// override fun onResume() {
|
||||
// super.onResume()
|
||||
// if (index == 0) {
|
||||
// binding?.dialogHistory?.root?.postDelayed(
|
||||
// {
|
||||
// val string = Memory.getMMKV()
|
||||
// .getString(Constants.Constants_Main_Video_info, "")
|
||||
// if (string?.isNotEmpty() == true && NetworkUtils.isConnected()) {
|
||||
// val fromJson = Gson().fromJson(string, MainDataHis::class.java)
|
||||
// showHistoryDialog(fromJson)
|
||||
// }
|
||||
// }, 500
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
// private fun showHistoryDialog(data: MainDataHis) {
|
||||
// binding?.dialogHistory?.ivCloseHistory?.setOnClickListener {
|
||||
// Memory.getMMKV()
|
||||
// .putBoolean(Constants.Constants_Main_Video_status, false)
|
||||
// binding?.dialogHistory?.root?.visibility = View.INVISIBLE
|
||||
// }
|
||||
// if (Memory.getMMKV()
|
||||
// .getBoolean(Constants.Constants_Main_Video_status, false)
|
||||
// ) {
|
||||
// binding?.dialogHistory?.ivVideo?.let {
|
||||
// if (!isFinishing && !isDestroyed) {
|
||||
// Glide.with(this).load(
|
||||
// data.video_img
|
||||
// ).placeholder(R.drawable.iv_placeholder_v).into(it)
|
||||
// }
|
||||
// }
|
||||
// binding?.dialogHistory?.cl?.setOnClickListener {
|
||||
// singleClick {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// this, PlayerDetailActivity::class.java
|
||||
// ).apply {
|
||||
// putExtra(
|
||||
// Constants.CONSTANTS_short_play_id, data.video_id
|
||||
// )
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// binding?.dialogHistory?.root?.post {
|
||||
// binding?.dialogHistory?.tvEp?.text =
|
||||
// "Ep.".plus(data.video_last).plus("/").plus("Ep.").plus(data.episode_total)
|
||||
// }
|
||||
// binding?.dialogHistory?.root?.visibility = View.VISIBLE
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun askNotificationPermission() {
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
// if (ContextCompat.checkSelfPermission(
|
||||
// this, Manifest.permission.POST_NOTIFICATIONS
|
||||
// ) == PackageManager.PERMISSION_GRANTED
|
||||
// ) {
|
||||
// NotificationUtils.firebase(mViewModel)
|
||||
// } else {
|
||||
// if (Constants.isUat) {
|
||||
// openNotification()
|
||||
// } else {
|
||||
// if (shouldShowNotification()) {
|
||||
// openNotification()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// if (NotificationUtils.isNotificationEnabled(this)) {
|
||||
// NotificationUtils.firebase(mViewModel)
|
||||
// } else {
|
||||
// if (Constants.isUat) {
|
||||
// openNotification()
|
||||
// } else {
|
||||
// if (shouldShowNotification()) {
|
||||
// openNotification()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun openNotification() {
|
||||
// notificationDialog = NotificationDialog(this)
|
||||
// val example_tv_later =
|
||||
// notificationDialog?.findViewById<AppCompatTextView>(R.id.example_tv_unfavorite)
|
||||
// val iv_close_notification =
|
||||
// notificationDialog?.findViewById<AppCompatImageView>(R.id.iv_close_notification)
|
||||
// val example_open =
|
||||
// notificationDialog?.findViewById<AppCompatTextView>(R.id.example_tv_think_again)
|
||||
// notificationDialog?.setOnDismissListener {
|
||||
// Memory.getMMKV().putLong(
|
||||
// Constants.CONSTANTS_PREF_LAST_POPUP_TIME_Notification,
|
||||
// System.currentTimeMillis()
|
||||
// )
|
||||
// }
|
||||
// example_tv_later?.setOnClickListener { notificationDialog?.dismiss() }
|
||||
// iv_close_notification?.setOnClickListener { notificationDialog?.dismiss() }
|
||||
// example_open?.setOnClickListener {
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
// requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||
// notificationDialog?.dismiss()
|
||||
// } else {
|
||||
// NotificationUtils.openNotificationSettings(this)
|
||||
// notificationDialog?.dismiss()
|
||||
// }
|
||||
// }
|
||||
// notificationDialog?.show()
|
||||
// }
|
||||
//
|
||||
// private val requestPermissionLauncher = registerForActivityResult(
|
||||
// ActivityResultContracts.RequestPermission(),
|
||||
// ) { isGranted: Boolean ->
|
||||
// Constants.CanNotification = isGranted
|
||||
// if (isGranted) {
|
||||
// NotificationUtils.firebase(mViewModel)
|
||||
// mViewModel.uploadNoticeStatus(
|
||||
// FbNotificationReq(
|
||||
// if (Constants.CanNotification) "1" else "0"
|
||||
// )
|
||||
// )
|
||||
// notificationDialog?.dismiss()
|
||||
// } else {
|
||||
// NotificationUtils.openNotificationSettings(this)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
// super.onActivityResult(requestCode, resultCode, data)
|
||||
// if (index == 0) {
|
||||
// if (requestCode == NotificationUtils.NOTIFICATION_SETTINGS_REQUEST_CODE) {
|
||||
// Constants.CanNotification =
|
||||
// NotificationUtils.isNotificationEnabled(this)
|
||||
// if (Constants.CanNotification) {
|
||||
// NotificationUtils.firebase(mViewModel)
|
||||
// }
|
||||
// mViewModel.uploadNoticeStatus(
|
||||
// FbNotificationReq(
|
||||
// if (Constants.CanNotification) "1" else "0"
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// } else {
|
||||
// val fragments: List<Fragment> = supportFragmentManager.fragments
|
||||
// if (fragments.isNotEmpty()) {
|
||||
// for (fragment in fragments) {
|
||||
// if (fragment.isAdded && !fragment.isDetached) {
|
||||
// fragment.onActivityResult(requestCode, resultCode, data)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun notificationGo() {
|
||||
// if (message_id.isNotBlank() && !message_id.contentEquals("null")) {
|
||||
// if ("0" != message_id) {
|
||||
// mViewModel.sendReport(message_id, title)
|
||||
// }
|
||||
// }
|
||||
// when (path) {
|
||||
// "detail" -> {
|
||||
// if (short_play_id.isNotEmpty() && "null" != short_play_id) {
|
||||
// try {
|
||||
// val toInt = short_play_id.toInt()
|
||||
// binding?.root?.postDelayed({
|
||||
// startActivity(Intent(
|
||||
// this, PlayerDetailActivity::class.java
|
||||
// ).apply {
|
||||
// putExtra(
|
||||
// Constants.CONSTANTS_short_play_id, toInt
|
||||
// )
|
||||
// })
|
||||
// }, 700)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// "orderDetail" -> {
|
||||
// binding?.root?.postDelayed({
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// this, StoreActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// }, 500)
|
||||
// }
|
||||
//
|
||||
// "feedback" -> {
|
||||
// binding?.root?.postDelayed({
|
||||
// if (message_id.isNotBlank() && message_id != "null") {
|
||||
// Memory.getMMKV()
|
||||
// .putString(Constants.CONSTANTS_Detail_id, message_id)
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// this, FeedBackDetailActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// } else {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// this, FeedBackListActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }, 500)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private fun uploadDDL(webpageURL: Uri?) {
|
||||
// val ddl = webpageURL.toString()
|
||||
// if (ddl.isNotEmpty() && !ddl.contentEquals("null")) {
|
||||
// w2aSelfAttribution(ddl)
|
||||
// val regex = """short_play_id=(\d+).*""".toRegex()
|
||||
// val matchResult = regex.find(ddl)
|
||||
// if (matchResult != null) {
|
||||
// val shortPlayId = matchResult.groupValues[1]
|
||||
// shortVideoId = shortPlayId.toInt()
|
||||
// if (shortVideoId != 0) {
|
||||
// binding.root.postDelayed({
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// this, PlayerDetailActivity::class.java
|
||||
// ).apply {
|
||||
// putExtra(
|
||||
// Constants.CONSTANTS_short_play_id, shortVideoId
|
||||
// )
|
||||
// })
|
||||
// }, 1000)
|
||||
// }
|
||||
// Memory.getMMKV()
|
||||
// .putString(Constants.Constants_DDL_Url, "")
|
||||
// clearClipboardContent(this)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun getClip() {
|
||||
// this.window.decorView.post {
|
||||
// val clipContent = getClipContent()
|
||||
// if (clipContent.isNotEmpty()) {
|
||||
// if (clipContent.startsWith("[QJ]")) {
|
||||
// val urlString = clipContent.removePrefix("[QJ]").trim()
|
||||
// val extractVideoInfo = parseVideoAndShortPlayIds(urlString)
|
||||
// if (urlString.contains("reelcrush")) {
|
||||
// shortVideoId = extractVideoInfo.second?.toInt() ?: 0
|
||||
// w2aSelfAttribution(clipContent)
|
||||
// if (shortVideoId != 0) {
|
||||
// binding.root.postDelayed({
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// this, PlayerDetailActivity::class.java
|
||||
// ).apply {
|
||||
// putExtra(
|
||||
// Constants.CONSTANTS_short_play_id, shortVideoId
|
||||
// )
|
||||
// })
|
||||
// }, 3000)
|
||||
// }
|
||||
// Memory.getMMKV()
|
||||
// .putString(Constants.Constants_DDL_Url, "")
|
||||
// clearClipboardContent(this)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun switchFragment(position: Int) {
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
hideFragments(transaction)
|
||||
when (position) {
|
||||
0 -> homeFragment?.let {
|
||||
transaction.show(it)
|
||||
} ?: HomeFragment().let {
|
||||
homeFragment = it
|
||||
transaction.add(R.id.container, it, "HomeFragment")
|
||||
}
|
||||
|
||||
1 -> reelsFragment?.let {
|
||||
transaction.show(it)
|
||||
} ?: ReelsFragment().let {
|
||||
reelsFragment = it
|
||||
transaction.add(
|
||||
R.id.container, it, "ReelsFragment"
|
||||
)
|
||||
}
|
||||
|
||||
2 -> myListFragment?.let {
|
||||
transaction.show(it)
|
||||
} ?: SavedFragment().let {
|
||||
myListFragment = it
|
||||
transaction.add(R.id.container, it, "SavedFragment")
|
||||
}
|
||||
|
||||
|
||||
3 -> meFragment?.let {
|
||||
transaction.show(it)
|
||||
} ?: MeFragment().let {
|
||||
meFragment = it
|
||||
transaction.add(R.id.container, it, "MeFragment")
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
index = position
|
||||
binding?.tabLayout?.currentTab = index
|
||||
transaction.commitAllowingStateLoss()
|
||||
}
|
||||
|
||||
|
||||
private fun hideFragments(transaction: FragmentTransaction) {
|
||||
homeFragment?.let { transaction.hide(it) }
|
||||
reelsFragment?.let { transaction.hide(it) }
|
||||
myListFragment?.let { transaction.hide(it) }
|
||||
meFragment?.let { transaction.hide(it) }
|
||||
}
|
||||
|
||||
// private fun getClipContent(): String {
|
||||
// val manager: ClipboardManager = getSystemService(
|
||||
// CLIPBOARD_SERVICE
|
||||
// ) as ClipboardManager
|
||||
// val primaryClip = manager.primaryClip
|
||||
// val itemCount = primaryClip?.itemCount
|
||||
// if (itemCount != null) {
|
||||
// if (manager.hasPrimaryClip() && itemCount > 0) {
|
||||
// val itemAt = manager.primaryClip?.getItemAt(0)
|
||||
// val addedText: CharSequence = itemAt?.text.toString()
|
||||
// val addedTextString = addedText.toString()
|
||||
// if (!TextUtils.isEmpty(addedTextString)) {
|
||||
// return addedTextString
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return ""
|
||||
// }
|
||||
//
|
||||
// private fun w2aSelfAttribution(data: String?) {
|
||||
// data?.let { mViewModel.w2aSelfAttribution(it) }
|
||||
// }
|
||||
//
|
||||
// private fun clearClipboardContent(context: Context) {
|
||||
// val clipboardManager =
|
||||
// context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
//
|
||||
// val emptyClip = ClipData.newPlainText("", "")
|
||||
//
|
||||
// clipboardManager.setPrimaryClip(emptyClip)
|
||||
// }
|
||||
//
|
||||
// private fun parseVideoAndShortPlayIds(clipboardContent: String): Pair<String?, String?> {
|
||||
//
|
||||
// val queryStartIndex = clipboardContent.indexOf('?')
|
||||
// val queryString =
|
||||
// if (queryStartIndex != -1) clipboardContent.substring(queryStartIndex + 1) else ""
|
||||
//
|
||||
// val videoIdRegex = Regex("video_id=(\\d+)")
|
||||
// val shortPlayIdRegex = Regex("short_play_id=(\\d+)")
|
||||
//
|
||||
// val videoIdMatch = videoIdRegex.find(queryString)?.groupValues?.get(1)
|
||||
// val shortPlayIdMatch = shortPlayIdRegex.find(queryString)?.groupValues?.get(1)
|
||||
//
|
||||
// return Pair(videoIdMatch, shortPlayIdMatch)
|
||||
// }
|
||||
|
||||
override fun getViewBinding(): ActivityMainBinding {
|
||||
return ActivityMainBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEvent(event: String) {
|
||||
if (Constants.CONSTANTS_auth_refresh == event) {
|
||||
mViewModel.createUserAccount()
|
||||
}
|
||||
if (Constants.CONSTANTS_main_stop == event) {
|
||||
binding?.root?.postDelayed({ hideLoading() }, 300)
|
||||
}
|
||||
// if (Constants.CONSTANTS_enterTheApp == event) {
|
||||
// mViewModel.enterTheApp()
|
||||
// }
|
||||
// if (Constants.CONSTANTS_leaveApp == event) {
|
||||
// mViewModel.leaveApp()
|
||||
// }
|
||||
// if (Constants.CONSTANTS_onLine == event) {
|
||||
// mViewModel.onLine()
|
||||
// }
|
||||
// if (Constants.Constants_onTokenRefresh == event) {
|
||||
// NotificationUtils.firebase(mViewModel)
|
||||
// }
|
||||
// if (Constants.Constants_getClip == event) {
|
||||
// getClip()
|
||||
// }
|
||||
// if (Constants.CONSTANTS_web_Login == event) {
|
||||
// if (!NetworkUtils.isConnected()) {
|
||||
// toast(getString(R.string.example_no_network))
|
||||
// return
|
||||
// }
|
||||
// showLogin()
|
||||
// }
|
||||
}
|
||||
|
||||
// private var callbackManager: CallbackManager? = null
|
||||
// private var loginDialog: LoginDialog? = null
|
||||
//
|
||||
// private fun showLogin() {
|
||||
// callbackManager = CallbackManager.Factory.create()
|
||||
// LoginManager.getInstance().registerCallback(callbackManager,
|
||||
// object : FacebookCallback<LoginResult> {
|
||||
// override fun onSuccess(loginResult: LoginResult) {
|
||||
// val enableButtons = AccessToken.getCurrentAccessToken() != null
|
||||
// if (enableButtons) {
|
||||
// val mGraphRequest = GraphRequest.newMeRequest(
|
||||
// loginResult.accessToken
|
||||
// ) { jsonObject, response ->
|
||||
// if (response!!.error != null) {
|
||||
// toast("Facebook login exception.${response.error?.exception.toString()}")
|
||||
// loginDialog?.dismiss()
|
||||
// } else {
|
||||
// val id = jsonObject?.optString("id")
|
||||
// val name = jsonObject?.optString("name")
|
||||
// val object_pic: JSONObject? =
|
||||
// jsonObject!!.optJSONObject("picture")
|
||||
// val object_data = object_pic?.optJSONObject("data")
|
||||
// val photo = object_data?.optString("url")
|
||||
// showLoading()
|
||||
// EventBus.getDefault()
|
||||
// .post(Constants.CONSTANTS_leaveApp)
|
||||
// mViewModel.doLogin(
|
||||
// LoginReq(
|
||||
// photo.toString(),
|
||||
// "",
|
||||
// name.toString(),
|
||||
// "",
|
||||
// "facebook",
|
||||
// id.toString()
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// val parameters = Bundle()
|
||||
// parameters.putString("fields", "id,name,email,picture")
|
||||
// mGraphRequest.parameters = parameters
|
||||
// mGraphRequest.executeAsync()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun onCancel() {
|
||||
// toast("Facebook login Cancel")
|
||||
// loginDialog?.dismiss()
|
||||
// }
|
||||
//
|
||||
// override fun onError(exception: FacebookException) {
|
||||
// toast("Facebook login exception.$exception")
|
||||
// loginDialog?.dismiss()
|
||||
// }
|
||||
// })
|
||||
// loginDialog = LoginDialog(this)
|
||||
// val tv_facebook_login =
|
||||
// loginDialog?.findViewById<AppCompatTextView>(R.id.tv_facebook_login)
|
||||
// tv_facebook_login?.setOnClickListener {
|
||||
// singleClick {
|
||||
// callbackManager?.let { it1 ->
|
||||
// LoginManager.getInstance()
|
||||
// .logInWithReadPermissions(this, it1, arrayListOf("public_profile", "email"))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// loginDialog?.show()
|
||||
// loginDialog?.setOnDismissListener {
|
||||
// LoginManager.getInstance().unregisterCallback(callbackManager)
|
||||
// callbackManager = null
|
||||
// loginDialog = null
|
||||
// }
|
||||
// }
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
moveTaskToBack(true)
|
||||
return true
|
||||
}
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
// scheduler?.shutdown()
|
||||
// scheduler = null
|
||||
super.onDestroy()
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.jia.er.nebuluxe.app.main
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.jia.er.nebuluxe.app.basics.BaseActivity
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivitySplashBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.Memory
|
||||
|
||||
class SplashActivity : BaseActivity<ActivitySplashBinding>() {
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
override fun top() {
|
||||
|
||||
val toString = Memory.getMMKV()
|
||||
.getString(Constants.CONSTANTS_AuthorizationExample, "")
|
||||
.toString()
|
||||
if (toString.isEmpty()) {
|
||||
mViewModel.createUserAccount()
|
||||
} else {
|
||||
goMain()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun center() {
|
||||
mViewModel.userRegisterData.observe(this) {
|
||||
if (it != null) {
|
||||
Memory.getMMKV()
|
||||
.putString(Constants.CONSTANTS_AuthorizationExample, it.data?.token)
|
||||
goMain()
|
||||
} else {
|
||||
goMain()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun goMain() {
|
||||
binding?.root?.postDelayed({
|
||||
startActivity(
|
||||
Intent(
|
||||
this,
|
||||
MainActivity::class.java
|
||||
)
|
||||
)
|
||||
finish()
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
override fun getViewBinding(): ActivitySplashBinding {
|
||||
return ActivitySplashBinding.inflate(layoutInflater)
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.jia.er.nebuluxe.app.me
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import com.jia.er.nebuluxe.app.basics.BaseActivity
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivityAboutBinding
|
||||
import com.jia.er.nebuluxe.app.utils.PackageUtils
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
|
||||
class AboutActivity : BaseActivity<ActivityAboutBinding>() {
|
||||
override fun top() {
|
||||
binding.exampleIvBack.setOnClickListener { finish() }
|
||||
}
|
||||
|
||||
override fun center() {
|
||||
binding.tvVersion.text = "V".plus(PackageUtils.getPackageVersion(this))
|
||||
binding.tvPrivacyPolicy.setOnClickListener {
|
||||
singleClick {
|
||||
val webIntent =
|
||||
Intent(Intent.ACTION_VIEW, Uri.parse("https://www.nebuluxetv.com/private"))
|
||||
startActivity(webIntent)
|
||||
}
|
||||
}
|
||||
binding.tvUserAgreement.setOnClickListener {
|
||||
singleClick {
|
||||
val webIntent =
|
||||
Intent(Intent.ACTION_VIEW, Uri.parse("https://www.nebuluxetv.com/user_policy"))
|
||||
startActivity(webIntent)
|
||||
}
|
||||
}
|
||||
binding.tvVisitWebsite.setOnClickListener {
|
||||
singleClick {
|
||||
val webIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.nebuluxetv.com"))
|
||||
startActivity(webIntent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewBinding(): ActivityAboutBinding {
|
||||
return ActivityAboutBinding.inflate(layoutInflater)
|
||||
}
|
||||
}
|
247
app/src/main/java/com/jia/er/nebuluxe/app/me/MeFragment.kt
Normal file
247
app/src/main/java/com/jia/er/nebuluxe/app/me/MeFragment.kt
Normal file
@ -0,0 +1,247 @@
|
||||
package com.jia.er.nebuluxe.app.me
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.UnderlineSpan
|
||||
import android.view.View
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.load.resource.bitmap.CircleCrop
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseFragment
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.databinding.FragmentMeBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.Memory
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class MeFragment : BaseFragment<FragmentMeBinding>() {
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
|
||||
override fun top() {
|
||||
EventBus.getDefault().register(this)
|
||||
mViewModel.noticeNum()
|
||||
binding.srMe.setOnRefreshListener {
|
||||
mViewModel.getInfo()
|
||||
mViewModel.noticeNum()
|
||||
}
|
||||
// binding.llFeedback.setOnClickListener {
|
||||
// singleClick {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// requireActivity(),
|
||||
// FeedBackActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// binding.clTopUp.setOnClickListener {
|
||||
// singleClick {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// requireActivity(),
|
||||
// StoreActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// binding.clVip.setOnClickListener {
|
||||
// singleClick {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// requireActivity(),
|
||||
// StoreActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// binding.tvExampleAbout.setOnClickListener {
|
||||
// singleClick {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// requireActivity(),
|
||||
// AboutActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// binding.tvExampleSettings.setOnClickListener {
|
||||
// singleClick {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// requireActivity(),
|
||||
// SettingActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// binding.tvId.setOnClickListener {
|
||||
// val clipboard = context?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
// clipboard.setPrimaryClip(
|
||||
// ClipData.newPlainText(
|
||||
// "label",
|
||||
// Memory.getCustomId()
|
||||
// )
|
||||
// )
|
||||
// toast("Copied")
|
||||
// }
|
||||
// binding.wallet.setOnClickListener {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// requireActivity(),
|
||||
// MyWalletActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// setUserUI()
|
||||
// binding.tvVipStatus.applyTextSkew(-10f)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setUserUI()
|
||||
}
|
||||
|
||||
override fun center() {
|
||||
mViewModel.infoData.observe(this) {
|
||||
if (it != null) {
|
||||
it.data?.let { it1 ->
|
||||
Memory.saveUserInfo(it1)
|
||||
setUserUI()
|
||||
}
|
||||
}
|
||||
binding.srMe.finishRefresh()
|
||||
}
|
||||
// mViewModel.noticeNumData.observe(this) {
|
||||
// if (it != null) {
|
||||
// if (it.data?.feedback_notice_num != 0) {
|
||||
// binding?.tvBackNum?.visibility = View.VISIBLE
|
||||
// binding?.tvBackNum?.text = it.data?.feedback_notice_num.toString()
|
||||
// } else {
|
||||
// binding?.tvBackNum?.visibility = View.INVISIBLE
|
||||
// }
|
||||
// } else {
|
||||
// binding?.tvBackNum?.visibility = View.INVISIBLE
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
private fun setUserUI() {
|
||||
if (Memory.isTourist()) {
|
||||
binding?.ivAvatar?.let {
|
||||
Glide.with(this).load(Memory.getUserInfo()?.avator).skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.apply(RequestOptions.bitmapTransform(CircleCrop()))
|
||||
.placeholder(R.drawable.iv_avatar)
|
||||
.error(R.drawable.iv_avatar).into(it)
|
||||
}
|
||||
} else {
|
||||
binding?.tvUserName?.text =
|
||||
Memory.getUserInfo()?.family_name.plus(Memory.getUserInfo()?.giving_name)
|
||||
binding?.ivAvatar?.let {
|
||||
Glide.with(this).load(Memory.getUserInfo()?.avator).skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.apply(RequestOptions.bitmapTransform(CircleCrop()))
|
||||
.placeholder(R.drawable.iv_avatar)
|
||||
.error(R.drawable.iv_avatar).into(it)
|
||||
}
|
||||
}
|
||||
// if (Memory.isVip()) {
|
||||
// binding.clVip.background = context?.getDrawable(R.drawable.iv_me_vip_h)
|
||||
// binding.tvVipStatus.text = Memory.getUserInfo()?.vip_type
|
||||
// val content = binding.tvVipStatus.text
|
||||
// val spannableString = SpannableString(content)
|
||||
// spannableString.setSpan(
|
||||
// UnderlineSpan(),
|
||||
// 0,
|
||||
// content.length,
|
||||
// Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
// )
|
||||
// binding.tvVipStatus.text = spannableString
|
||||
// binding?.tvInfoVip?.text =
|
||||
// "Expiration Time:".plus(Memory.getUserInfo()?.vip_end_time?.toLong()
|
||||
// ?.let { transToString(it) })
|
||||
// binding?.tvInfoVip?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
// context?.getDrawable(R.drawable.iv_time),
|
||||
// null,
|
||||
// null,
|
||||
// null
|
||||
// )
|
||||
// binding?.tvVipStatus?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
// context?.getDrawable(R.drawable.iv_vip_h),
|
||||
// null,
|
||||
// context?.getDrawable(R.drawable.iv_vip_right),
|
||||
// null
|
||||
// )
|
||||
// binding.tvGo.text = "Renew"
|
||||
// binding.tvGo.background = context?.getDrawable(R.drawable.bg_vip_go_h)
|
||||
// } else {
|
||||
// binding?.tvInfoVip?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
// null,
|
||||
// null,
|
||||
// null,
|
||||
// null
|
||||
// )
|
||||
// val spannableString = SpannableString("VIP Membership")
|
||||
// spannableString.setSpan(
|
||||
// UnderlineSpan(),
|
||||
// 0,
|
||||
// spannableString.length,
|
||||
// Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
// )
|
||||
// binding.tvVipStatus.text = spannableString
|
||||
// binding?.tvVipStatus?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
// context?.getDrawable(R.drawable.iv_vip),
|
||||
// null,
|
||||
// context?.getDrawable(R.drawable.iv_vip_right),
|
||||
// null
|
||||
// )
|
||||
// binding.tvGo.text = "Go"
|
||||
// binding.tvGo.background = context?.getDrawable(R.drawable.bg_vip_go)
|
||||
// binding?.tvInfoVip?.text = "Unlock VIP Now"
|
||||
// binding.clVip.background = context?.getDrawable(R.drawable.iv_me_vip_n)
|
||||
//
|
||||
// }
|
||||
binding?.tvId?.text = "ID:".plus(Memory.getUserInfo()?.customer_id)
|
||||
// binding?.tvCoinNum?.text = Memory.getUserInfo()?.coin_left_total.toString()
|
||||
// binding?.tvDonateNum?.text = Memory.getUserInfo()?.send_coin_left_total.toString()
|
||||
}
|
||||
|
||||
|
||||
override fun onHiddenChanged(hidden: Boolean) {
|
||||
super.onHiddenChanged(hidden)
|
||||
if (!hidden) {
|
||||
mViewModel.getInfo()
|
||||
mViewModel.noticeNum()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEvent(event: String) {
|
||||
if (Constants.CONSTANTS_refresh_me == event) {
|
||||
mViewModel.getInfo()
|
||||
mViewModel.noticeNum()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewBinding(): FragmentMeBinding {
|
||||
return FragmentMeBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
}
|
131
app/src/main/java/com/jia/er/nebuluxe/app/me/SettingActivity.kt
Normal file
131
app/src/main/java/com/jia/er/nebuluxe/app/me/SettingActivity.kt
Normal file
@ -0,0 +1,131 @@
|
||||
package com.jia.er.nebuluxe.app.me
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseActivity
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivitySettingBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.utils.toast
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.io.File
|
||||
|
||||
class SettingActivity : BaseActivity<ActivitySettingBinding>() {
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
|
||||
override fun top() {
|
||||
binding.exampleIvBack.setOnClickListener { finish() }
|
||||
binding.tvClearCache.setOnClickListener {
|
||||
clearCache(this)
|
||||
toast(getString(R.string.success))
|
||||
}
|
||||
binding.exampleIvBack.setOnClickListener { finish() }
|
||||
// binding.tvExampleLogOut.setOnClickListener {
|
||||
// singleClick {
|
||||
// if (!Memory.isTourist()) {
|
||||
// startActivity(
|
||||
// Intent(
|
||||
// this,
|
||||
// AccountDeleteActivity::class.java
|
||||
// )
|
||||
// )
|
||||
// } else {
|
||||
// toast(getString(R.string.log_first))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// binding?.tvExampleQuit?.setOnClickListener {
|
||||
// singleClick {
|
||||
// if (!Memory.isTourist()) {
|
||||
// val exampleUnFavoriteDialog = NotificationDialog(this)
|
||||
// val tvThinkAgain =
|
||||
// exampleUnFavoriteDialog.findViewById<AppCompatTextView>(R.id.example_tv_think_again)
|
||||
// val tvUnfavorite =
|
||||
// exampleUnFavoriteDialog.findViewById<AppCompatTextView>(R.id.example_tv_unfavorite)
|
||||
// val tvTitle =
|
||||
// exampleUnFavoriteDialog.findViewById<AppCompatTextView>(R.id.example_tv_title)
|
||||
// val tvContent =
|
||||
// exampleUnFavoriteDialog.findViewById<AppCompatTextView>(R.id.example_tv_content)
|
||||
// tvThinkAgain.text = "Cancel"
|
||||
// tvUnfavorite.text = "Confirm"
|
||||
// tvTitle.text = "Tips"
|
||||
// tvContent.text = "Are you sure you want to log out?"
|
||||
// tvThinkAgain.setOnClickListener { exampleUnFavoriteDialog.dismiss() }
|
||||
// tvUnfavorite.setOnClickListener {
|
||||
// singleClick {
|
||||
// showLoading()
|
||||
// EventBus.getDefault()
|
||||
// .post(Constants.CONSTANTS_leaveApp)
|
||||
// mViewModel.doSignout()
|
||||
// exampleUnFavoriteDialog.dismiss()
|
||||
// }
|
||||
// }
|
||||
// exampleUnFavoriteDialog.show()
|
||||
// } else {
|
||||
// toast(getString(R.string.log_first))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// override fun onResume() {
|
||||
// super.onResume()
|
||||
// if (Constants.WebRefresh){
|
||||
// finish()
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
override fun center() {
|
||||
// mViewModel.signoutData.observe(this) {
|
||||
// if (it != null) {
|
||||
// toast(getString(R.string.success))
|
||||
// LoginManager.getInstance().logOut()
|
||||
// Memory.getMMKV()
|
||||
// .putString(Constants.CONSTANTS_AuthorizationExample, it.data?.token)
|
||||
// EventBus.getDefault()
|
||||
// .post(Constants.CONSTANTS_enterTheApp)
|
||||
// EventBus.getDefault()
|
||||
// .post(Constants.CONSTANTS_onLine)
|
||||
// EventBus.getDefault()
|
||||
// .post(Constants.CONSTANTS_refresh_me)
|
||||
// Constants.WebRefresh = true
|
||||
// finish()
|
||||
// } else {
|
||||
// toast(getString(R.string.network_error))
|
||||
// }
|
||||
// hideLoading()
|
||||
// }
|
||||
}
|
||||
|
||||
override fun getViewBinding(): ActivitySettingBinding {
|
||||
return ActivitySettingBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
|
||||
private fun clearCache(context: Context) {
|
||||
deleteFilesInDirectory(context.cacheDir)
|
||||
|
||||
context.externalCacheDir?.let {
|
||||
deleteFilesInDirectory(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteFilesInDirectory(directory: File) {
|
||||
if (directory.isDirectory) {
|
||||
val files = directory.listFiles()
|
||||
if (files != null) {
|
||||
for (file in files) {
|
||||
if (file.isDirectory) {
|
||||
deleteFilesInDirectory(file)
|
||||
} else {
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
directory.delete()
|
||||
}
|
||||
}
|
258
app/src/main/java/com/jia/er/nebuluxe/app/net/AppService.kt
Normal file
258
app/src/main/java/com/jia/er/nebuluxe/app/net/AppService.kt
Normal file
@ -0,0 +1,258 @@
|
||||
package com.jia.er.nebuluxe.app.net
|
||||
|
||||
import com.jia.er.nebuluxe.app.data.BaseRes
|
||||
import com.jia.er.nebuluxe.app.data.BuyVideoRes
|
||||
import com.jia.er.nebuluxe.app.data.CategoriesDataRes
|
||||
import com.jia.er.nebuluxe.app.data.CollectionRes
|
||||
import com.jia.er.nebuluxe.app.data.CreateOrderReq
|
||||
import com.jia.er.nebuluxe.app.data.CreateOrderRes
|
||||
import com.jia.er.nebuluxe.app.data.CustomerBuyRecordsRes
|
||||
import com.jia.er.nebuluxe.app.data.CustomerOrderRes
|
||||
import com.jia.er.nebuluxe.app.data.DetailsRecommendRes
|
||||
import com.jia.er.nebuluxe.app.data.ExampleKeywordDataRes
|
||||
import com.jia.er.nebuluxe.app.data.FbNotificationReq
|
||||
import com.jia.er.nebuluxe.app.data.FreeSeriesMoreRes
|
||||
import com.jia.er.nebuluxe.app.data.HistoryDataRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeModuleBean
|
||||
import com.jia.er.nebuluxe.app.data.HomeNewShortPlayNoPaginateRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeNewShortPlayRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeRankingRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeTopRes
|
||||
import com.jia.er.nebuluxe.app.data.LoginReq
|
||||
import com.jia.er.nebuluxe.app.data.LoginRes
|
||||
import com.jia.er.nebuluxe.app.data.NoticeNumRes
|
||||
import com.jia.er.nebuluxe.app.data.PayReq
|
||||
import com.jia.er.nebuluxe.app.data.PayRes
|
||||
import com.jia.er.nebuluxe.app.data.PaySettingRes
|
||||
import com.jia.er.nebuluxe.app.data.PlayerDetailDataRes
|
||||
import com.jia.er.nebuluxe.app.data.RecommendDataRes
|
||||
import com.jia.er.nebuluxe.app.data.RewardCoinsRes
|
||||
import com.jia.er.nebuluxe.app.data.ShortListCategoryDataInfo
|
||||
import com.jia.er.nebuluxe.app.data.UploadHistoryReq
|
||||
import com.jia.er.nebuluxe.app.data.VideoListDataRes
|
||||
import com.jia.er.nebuluxe.app.data.UserInfoRes
|
||||
import com.jia.er.nebuluxe.app.data.UserRegisterRes
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.Field
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface AppService {
|
||||
|
||||
@POST("customer/register")
|
||||
fun register(): Call<BaseRes<UserRegisterRes>>
|
||||
|
||||
@GET("customer/info")
|
||||
fun getInfo(): Call<BaseRes<UserInfoRes>>
|
||||
|
||||
|
||||
@POST("homeTop")
|
||||
fun homeTop(): Call<BaseRes<HomeTopRes>>
|
||||
|
||||
@POST("newShortPlay")
|
||||
fun newShortPlay(
|
||||
@Query("current_page") current_page: Int,
|
||||
@Query("page_size") page_size: Int = 10
|
||||
): Call<BaseRes<HomeNewShortPlayRes>>
|
||||
|
||||
@GET("myCollections")
|
||||
fun getCollections(
|
||||
@Query("current_page") current_page: Int,
|
||||
@Query("page_size") page_size: Int = 10
|
||||
): Call<BaseRes<CollectionRes>>
|
||||
|
||||
@GET("getVideoDetails")
|
||||
fun getVideoDetails(
|
||||
@Query("short_play_id") short_play_id: Int,
|
||||
@Query("video_id") video_id: Int,
|
||||
@Query("activity_id") activity_id: Int,
|
||||
@Query("revolution") revolution: String,
|
||||
@Query("no_ads") no_ads: Boolean?,
|
||||
): Call<BaseRes<PlayerDetailDataRes>>
|
||||
|
||||
@POST("newShortPlayNoPaginate")
|
||||
fun newShortPlayNoPaginate(): Call<BaseRes<HomeNewShortPlayNoPaginateRes>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("createHistory")
|
||||
fun createHistory(
|
||||
@Field("short_play_id") short_play_id: Int,
|
||||
@Field("video_id") video_id: Int,
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
@GET("getRecommands")
|
||||
fun getRecommands(
|
||||
@Query("current_page") current_page: Int,
|
||||
@Query("page_size") page_size: Int,
|
||||
@Query("revolution") revolution: String,
|
||||
): Call<BaseRes<RecommendDataRes>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("collect")
|
||||
fun collect(
|
||||
@Field("short_play_id") short_play_id: Int,
|
||||
@Field("video_id") video_id: Int
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("cancelCollect")
|
||||
fun cancelCollect(
|
||||
@Field("short_play_id") short_play_id: Int,
|
||||
@Field("video_id") video_id: Int
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
|
||||
@GET("myHistorys")
|
||||
fun myHistorys(
|
||||
@Query("current_page") current_page: Int,
|
||||
@Query("page_size") page_size: Int = 10
|
||||
): Call<BaseRes<HistoryDataRes>>
|
||||
|
||||
@GET("search")
|
||||
fun getVideoList(@Query("search") search: String): Call<BaseRes<VideoListDataRes>>
|
||||
|
||||
@GET("videoList")
|
||||
fun getVideoList(
|
||||
@Query("current_page") current_page: Int,
|
||||
@Query("category_id") category_id: Int,
|
||||
@Query("page_size") page_size: Int = 10
|
||||
): Call<BaseRes<VideoListDataRes>>
|
||||
|
||||
@POST("homeRanking")
|
||||
fun homeRanking(@Query("type") type: String): Call<BaseRes<HomeRankingRes>>
|
||||
|
||||
@POST("uploadHistorySeconds")
|
||||
fun uploadHistorySeconds(
|
||||
@Body uploadHistoryReq: UploadHistoryReq
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
@GET("freeShorPlayListNoPaginate")
|
||||
fun freeMoreVideo(): Call<BaseRes<FreeSeriesMoreRes>>
|
||||
|
||||
@GET("getDetailsRecommand")
|
||||
fun getDetailsRecommand(
|
||||
): Call<BaseRes<DetailsRecommendRes>>
|
||||
|
||||
@GET("search/hots")
|
||||
fun hots(): Call<BaseRes<ExampleKeywordDataRes>>
|
||||
|
||||
@POST("search/click")
|
||||
fun click(
|
||||
@Query("short_play_id") short_play_id: Int,
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
|
||||
@GET("search")
|
||||
fun keyword(@Query("search") search: String): Call<BaseRes<ExampleKeywordDataRes>>
|
||||
|
||||
@GET("home/all-modules")
|
||||
fun allModules(): Call<BaseRes<HomeModuleBean>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("buy_video")
|
||||
fun buyVideo(
|
||||
@Field("short_play_id") short_play_id: Int,
|
||||
@Field("video_id") video_id: Int,
|
||||
): Call<BaseRes<BuyVideoRes>>
|
||||
|
||||
@GET("getCategories")
|
||||
fun getCategories(): Call<BaseRes<CategoriesDataRes>>
|
||||
|
||||
@POST("customer/onLine")
|
||||
fun onLine(
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
@POST("customer/enterTheApp")
|
||||
fun enterTheApp(): Call<BaseRes<Any>>
|
||||
|
||||
@POST("customer/leaveApp")
|
||||
fun leaveApp(): Call<BaseRes<Any>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("customer/firebaseToken")
|
||||
fun firebaseToken(@Field("fcm_token") fcm_token: String): Call<BaseRes<Any>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("w2aSelfAttribution")
|
||||
fun w2aSelfAttribution(
|
||||
@Field("data") data: String
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
|
||||
@POST("openNotify")
|
||||
fun openNotify(
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
@POST("customer/uploadNoticeStatus")
|
||||
fun uploadNoticeStatus(
|
||||
@Body fbNotificationReq: FbNotificationReq
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("message/sendReport")
|
||||
fun sendReport(
|
||||
@Field("message_id") message_id: String, @Field("title") title: String
|
||||
): Call<BaseRes<Any>>
|
||||
|
||||
@POST("noticeNum")
|
||||
fun noticeNum(): Call<BaseRes<NoticeNumRes>>
|
||||
|
||||
@GET("getCustomerOrder")
|
||||
fun getCustomerOrder(
|
||||
@Query("current_page") current_page: Int,
|
||||
@Query("buy_type") buy_type: String,
|
||||
@Query("page_size") page_size: Int = 10
|
||||
): Call<BaseRes<CustomerOrderRes>>
|
||||
|
||||
@GET("getCustomerBuyRecords")
|
||||
fun getCustomerBuyRecords(
|
||||
@Query("current_page") current_page: Int,
|
||||
@Query("page_size") page_size: Int = 10
|
||||
): Call<BaseRes<CustomerBuyRecordsRes>>
|
||||
|
||||
@POST("sendCoinList")
|
||||
fun sendCoinList(
|
||||
@Query("current_page") current_page: Int,
|
||||
@Query("page_size") page_size: Int = 10
|
||||
): Call<BaseRes<RewardCoinsRes>>
|
||||
|
||||
@GET("paySettingsV3")
|
||||
fun getPaySetting(
|
||||
@Query("short_play_id") short_play_id: Int?,
|
||||
@Query("short_play_video_id") short_play_video_id: Int?
|
||||
): Call<BaseRes<PaySettingRes>>
|
||||
|
||||
|
||||
@POST("createOrder")
|
||||
fun createOrder(@Body createOrderReq: CreateOrderReq): Call<BaseRes<CreateOrderRes>>
|
||||
|
||||
@POST("googlePaid")
|
||||
fun googlePaid(@Body examplePayReq: PayReq?): Call<BaseRes<PayRes>>
|
||||
|
||||
@POST("event/add")
|
||||
suspend fun upError(@Body body: Map<String, @JvmSuppressWildcards Any>): Call<BaseRes<Any>>
|
||||
|
||||
@POST("customer/login")
|
||||
fun login(@Body exampleLoginReq: LoginReq): Call<BaseRes<LoginRes>>
|
||||
|
||||
@POST("customer/logoff")
|
||||
fun logoff(): Call<BaseRes<Any>>
|
||||
|
||||
@POST("customer/signout")
|
||||
fun signout(): Call<BaseRes<LoginRes>>
|
||||
|
||||
@GET("highestPaymentAndHottestVideo")
|
||||
fun homeHot(
|
||||
@Query("buy_count_num") buycount: Int,
|
||||
@Query("hottest_num") hottestnum: Int,
|
||||
): Call<BaseRes<VideoListDataRes>>
|
||||
|
||||
@GET("categoryListAppendShortPlay")
|
||||
fun userCenterRecommend(
|
||||
@Query("short_play_num") shortplaynum: Int,
|
||||
): Call<BaseRes<ShortListCategoryDataInfo>>
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.jia.er.nebuluxe.app.net
|
||||
|
||||
import com.jia.er.nebuluxe.app.net.Decryption.EN_STR_TAG
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import okhttp3.ResponseBody
|
||||
import java.io.IOException
|
||||
|
||||
|
||||
class BodyInterceptor : Interceptor {
|
||||
|
||||
@kotlin.jvm.Throws(IOException::class)
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val k_center = chain.proceed(chain.request())
|
||||
return if (k_center.body != null && k_center.body!!.contentType() != null) {
|
||||
val actiity = k_center.body!!.contentType()
|
||||
val circle = k_center.body!!.string()
|
||||
val str: String = if (!circle.startsWith(EN_STR_TAG)) {
|
||||
circle
|
||||
} else {
|
||||
Decryption.deStr(circle)
|
||||
}
|
||||
val current = ResponseBody.create(actiity, str)
|
||||
k_center.newBuilder().body(current).build()
|
||||
} else {
|
||||
k_center
|
||||
}
|
||||
}
|
||||
|
||||
}
|
66
app/src/main/java/com/jia/er/nebuluxe/app/net/Decryption.kt
Normal file
66
app/src/main/java/com/jia/er/nebuluxe/app/net/Decryption.kt
Normal file
@ -0,0 +1,66 @@
|
||||
package com.jia.er.nebuluxe.app.net
|
||||
|
||||
|
||||
object Decryption {
|
||||
const val BF_SIZE = 2048
|
||||
const val EN_STR_TAG = '$'
|
||||
|
||||
fun deStr(data: String): String {
|
||||
return String(deStrBytes(data), Charsets.UTF_8)
|
||||
}
|
||||
|
||||
// Decrypt bytes from hex string
|
||||
fun deStrBytes(data: String): ByteArray {
|
||||
if (!data.startsWith(EN_STR_TAG)) {
|
||||
throw IllegalArgumentException("Invalid encoded string")
|
||||
}
|
||||
val hexData = data.substring(1)
|
||||
val bytes = hexData.chunked(2).map { it.toInt(16).toByte() }.toByteArray()
|
||||
return desadasd(bytes)
|
||||
}
|
||||
|
||||
// Decrypt data
|
||||
fun desadasd(data: ByteArray): ByteArray {
|
||||
if (data.isEmpty()) {
|
||||
return data
|
||||
}
|
||||
val saltLen = data[0].toInt()
|
||||
val salt = data.slice(1 until 1 + saltLen).toByteArray()
|
||||
return deWithSalt(data.slice(1 + saltLen until data.size).toByteArray(), salt)
|
||||
}
|
||||
|
||||
// Decrypt data with salt
|
||||
fun deWithSalt(data: ByteArray, salt: ByteArray): ByteArray {
|
||||
val decryptedData = cxEd(data)
|
||||
return removeSalt(decryptedData, salt)
|
||||
}
|
||||
|
||||
// Encrypt/Decrypt data by flipping bits
|
||||
fun cxEd(data: ByteArray): ByteArray {
|
||||
return data.map { (it.toInt() xor 0xFF).toByte() }.toByteArray()
|
||||
}
|
||||
|
||||
// Remove salt from data
|
||||
fun removeSalt(data: ByteArray, salt: ByteArray): ByteArray {
|
||||
if (salt.isEmpty()) return data
|
||||
val ret = mutableListOf<Byte>()
|
||||
var idx = 0
|
||||
val sl = salt.size
|
||||
data.forEach {
|
||||
val s = salt[idx % sl]
|
||||
ret.add(ssadcalRemoveSalt(it, s))
|
||||
idx++
|
||||
}
|
||||
return ret.toByteArray()
|
||||
}
|
||||
|
||||
fun ssadcalRemoveSalt(v: Byte, s: Byte): Byte {
|
||||
return if (v >= s) {
|
||||
(v - s).toByte()
|
||||
} else {
|
||||
(0xFF - (s - v) + 1).toByte()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
316
app/src/main/java/com/jia/er/nebuluxe/app/net/MainRequest.kt
Normal file
316
app/src/main/java/com/jia/er/nebuluxe/app/net/MainRequest.kt
Normal file
@ -0,0 +1,316 @@
|
||||
package com.jia.er.nebuluxe.app.net
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.jia.er.nebuluxe.app.data.BaseRes
|
||||
import com.jia.er.nebuluxe.app.data.BuyVideoRes
|
||||
import com.jia.er.nebuluxe.app.data.CollectionRes
|
||||
import com.jia.er.nebuluxe.app.data.CreateOrderReq
|
||||
import com.jia.er.nebuluxe.app.data.CreateOrderRes
|
||||
import com.jia.er.nebuluxe.app.data.CustomerBuyRecordsRes
|
||||
import com.jia.er.nebuluxe.app.data.CustomerOrderRes
|
||||
import com.jia.er.nebuluxe.app.data.DetailsRecommendRes
|
||||
import com.jia.er.nebuluxe.app.data.ExampleKeywordDataRes
|
||||
import com.jia.er.nebuluxe.app.data.FbNotificationReq
|
||||
import com.jia.er.nebuluxe.app.data.FreeSeriesMoreRes
|
||||
import com.jia.er.nebuluxe.app.data.HistoryDataRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeModuleBean
|
||||
import com.jia.er.nebuluxe.app.data.HomeNewShortPlayNoPaginateRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeNewShortPlayRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeRankingRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeTopRes
|
||||
import com.jia.er.nebuluxe.app.data.NoticeNumRes
|
||||
import com.jia.er.nebuluxe.app.data.PayReq
|
||||
import com.jia.er.nebuluxe.app.data.PayRes
|
||||
import com.jia.er.nebuluxe.app.data.PaySettingRes
|
||||
import com.jia.er.nebuluxe.app.data.PlayerDetailDataRes
|
||||
import com.jia.er.nebuluxe.app.data.RecommendDataRes
|
||||
import com.jia.er.nebuluxe.app.data.RewardCoinsRes
|
||||
import com.jia.er.nebuluxe.app.data.UploadHistoryReq
|
||||
import com.jia.er.nebuluxe.app.data.VideoListDataRes
|
||||
import com.jia.er.nebuluxe.app.data.UserInfoRes
|
||||
import com.jia.er.nebuluxe.app.data.UserRegisterRes
|
||||
import com.jia.er.nebuluxe.app.net.Retrofit.handleData
|
||||
import com.jia.er.nebuluxe.app.net.Retrofit.response
|
||||
import com.jia.er.nebuluxe.app.data.CategoriesDataRes
|
||||
import com.jia.er.nebuluxe.app.data.LoginReq
|
||||
import com.jia.er.nebuluxe.app.data.LoginRes
|
||||
import com.jia.er.nebuluxe.app.data.ShortListCategoryDataInfo
|
||||
|
||||
object MainRequest {
|
||||
private val appService = Retrofit.build(AppService::class.java)
|
||||
|
||||
|
||||
fun userRegister(): LiveData<Result<BaseRes<UserRegisterRes>>> = handleData {
|
||||
appService.register().response()
|
||||
}
|
||||
|
||||
fun getInfo(): LiveData<Result<BaseRes<UserInfoRes>>> = handleData {
|
||||
appService.getInfo().response()
|
||||
}
|
||||
|
||||
|
||||
fun homeTop(): LiveData<Result<BaseRes<HomeTopRes>>> = handleData {
|
||||
appService.homeTop()
|
||||
.response()
|
||||
}
|
||||
|
||||
|
||||
fun newShortPlay(current_page: Int): LiveData<Result<BaseRes<HomeNewShortPlayRes>>> =
|
||||
handleData {
|
||||
appService.newShortPlay(current_page)
|
||||
.response()
|
||||
}
|
||||
|
||||
|
||||
fun getCollections(current_page: Int): LiveData<Result<BaseRes<CollectionRes>>> =
|
||||
handleData {
|
||||
appService.getCollections(current_page).response()
|
||||
}
|
||||
|
||||
fun getVideoDetails(
|
||||
short_play_id: Int, video_id: Int, activity_id: Int, revolution: String, no_ads: Boolean?
|
||||
): LiveData<Result<BaseRes<PlayerDetailDataRes>>> = handleData {
|
||||
appService.getVideoDetails(
|
||||
short_play_id,
|
||||
video_id,
|
||||
activity_id,
|
||||
revolution,
|
||||
no_ads
|
||||
)
|
||||
.response()
|
||||
}
|
||||
|
||||
|
||||
fun newShortPlayNoPaginate(): LiveData<Result<BaseRes<HomeNewShortPlayNoPaginateRes>>> =
|
||||
handleData {
|
||||
appService.newShortPlayNoPaginate()
|
||||
.response()
|
||||
}
|
||||
|
||||
|
||||
fun doCreateHistory(
|
||||
short_play_id: Int, video_id: Int
|
||||
): LiveData<Result<BaseRes<Any>>> = handleData {
|
||||
appService.createHistory(short_play_id, video_id).response()
|
||||
}
|
||||
|
||||
|
||||
fun getRecommands(
|
||||
current_page: Int, page_size: Int, revolution: String
|
||||
): LiveData<Result<BaseRes<RecommendDataRes>>> = handleData {
|
||||
appService.getRecommands(current_page, page_size, revolution).response()
|
||||
}
|
||||
|
||||
|
||||
private suspend fun collect(short_play_id: Int, video_id: Int) =
|
||||
appService.collect(short_play_id, video_id).response()
|
||||
|
||||
fun doCollect(
|
||||
short_play_id: Int, video_id: Int
|
||||
): LiveData<Result<BaseRes<Any>>> = handleData {
|
||||
collect(short_play_id, video_id)
|
||||
}
|
||||
|
||||
private suspend fun cancelCollect(short_play_id: Int, video_id: Int) =
|
||||
appService.cancelCollect(short_play_id, video_id).response()
|
||||
|
||||
fun doCancelCollect(
|
||||
short_play_id: Int, video_id: Int
|
||||
): LiveData<Result<BaseRes<Any>>> = handleData {
|
||||
cancelCollect(short_play_id, video_id)
|
||||
}
|
||||
|
||||
|
||||
fun myHistorys(
|
||||
current_page: Int
|
||||
): LiveData<Result<BaseRes<HistoryDataRes>>> = handleData {
|
||||
appService.myHistorys(current_page).response()
|
||||
}
|
||||
|
||||
|
||||
fun getVideoList(search: String): LiveData<Result<BaseRes<VideoListDataRes>>> =
|
||||
handleData {
|
||||
appService.getVideoList(search).response()
|
||||
}
|
||||
|
||||
fun getVideoList(
|
||||
current_page: Int,
|
||||
category_id: Int
|
||||
): LiveData<Result<BaseRes<VideoListDataRes>>> =
|
||||
handleData {
|
||||
appService.getVideoList(current_page, category_id).response()
|
||||
}
|
||||
|
||||
|
||||
fun homeRanking(type: String): LiveData<Result<BaseRes<HomeRankingRes>>> = handleData {
|
||||
appService.homeRanking(type)
|
||||
.response()
|
||||
}
|
||||
|
||||
fun freeMoreVideo(
|
||||
): LiveData<Result<BaseRes<FreeSeriesMoreRes>>> =
|
||||
handleData {
|
||||
appService.freeMoreVideo().response()
|
||||
}
|
||||
|
||||
|
||||
fun getDetailsRecommand(
|
||||
): LiveData<Result<BaseRes<DetailsRecommendRes>>> =
|
||||
handleData {
|
||||
appService.getDetailsRecommand().response()
|
||||
}
|
||||
|
||||
fun uploadHistorySeconds(
|
||||
uploadHistoryReq: UploadHistoryReq
|
||||
): LiveData<Result<BaseRes<Any>>> =
|
||||
handleData {
|
||||
appService.uploadHistorySeconds(uploadHistoryReq).response()
|
||||
}
|
||||
|
||||
|
||||
fun hots(): LiveData<Result<BaseRes<ExampleKeywordDataRes>>> =
|
||||
handleData {
|
||||
appService.hots().response()
|
||||
}
|
||||
|
||||
fun click(short_play_id: Int): LiveData<Result<BaseRes<Any>>> =
|
||||
handleData {
|
||||
appService.click(short_play_id).response()
|
||||
}
|
||||
|
||||
fun keyword(search: String): LiveData<Result<BaseRes<ExampleKeywordDataRes>>> =
|
||||
handleData {
|
||||
appService.keyword(search).response()
|
||||
}
|
||||
|
||||
|
||||
fun allModules(): LiveData<Result<BaseRes<HomeModuleBean>>> = handleData {
|
||||
appService.allModules().response()
|
||||
}
|
||||
|
||||
fun doBuyVideo(
|
||||
short_play_id: Int, video_id: Int
|
||||
): LiveData<Result<BaseRes<BuyVideoRes>>> = handleData {
|
||||
appService.buyVideo(short_play_id, video_id).response()
|
||||
}
|
||||
|
||||
fun getCategories(): LiveData<Result<BaseRes<CategoriesDataRes>>> =
|
||||
handleData {
|
||||
appService.getCategories().response()
|
||||
}
|
||||
|
||||
fun enterTheApp(): LiveData<Result<BaseRes<Any>>> = handleData {
|
||||
appService.enterTheApp().response()
|
||||
}
|
||||
|
||||
fun leaveApp(): LiveData<Result<BaseRes<Any>>> = handleData {
|
||||
appService.leaveApp().response()
|
||||
}
|
||||
|
||||
fun onLine(
|
||||
): LiveData<Result<BaseRes<Any>>> =
|
||||
handleData {
|
||||
appService.onLine().response()
|
||||
}
|
||||
|
||||
fun firebaseToken(fcm_token: String): LiveData<Result<BaseRes<Any>>> = handleData {
|
||||
appService.firebaseToken(fcm_token).response()
|
||||
}
|
||||
|
||||
fun w2aSelfAttribution(
|
||||
data: String
|
||||
): LiveData<Result<BaseRes<Any>>> =
|
||||
handleData {
|
||||
appService.w2aSelfAttribution(data).response()
|
||||
}
|
||||
|
||||
fun openNotify(
|
||||
): LiveData<Result<BaseRes<Any>>> =
|
||||
handleData {
|
||||
appService.openNotify().response()
|
||||
}
|
||||
|
||||
fun uploadNoticeStatus(fbNotificationReq: FbNotificationReq): LiveData<Result<BaseRes<Any>>> =
|
||||
handleData {
|
||||
appService.uploadNoticeStatus(fbNotificationReq)
|
||||
.response()
|
||||
}
|
||||
|
||||
fun sendReport(
|
||||
message_id: String, title: String
|
||||
): LiveData<Result<BaseRes<Any>>> =
|
||||
handleData {
|
||||
appService.sendReport(message_id, title).response()
|
||||
}
|
||||
|
||||
fun noticeNum(): LiveData<Result<BaseRes<NoticeNumRes>>> =
|
||||
handleData {
|
||||
appService.noticeNum().response()
|
||||
}
|
||||
|
||||
fun getCustomerOrder(
|
||||
current_page: Int,
|
||||
buy_type: String
|
||||
): LiveData<Result<BaseRes<CustomerOrderRes>>> = handleData {
|
||||
appService.getCustomerOrder(current_page, buy_type).response()
|
||||
}
|
||||
|
||||
fun getCustomerBuyRecords(current_page: Int): LiveData<Result<BaseRes<CustomerBuyRecordsRes>>> =
|
||||
handleData {
|
||||
appService.getCustomerBuyRecords(current_page).response()
|
||||
}
|
||||
|
||||
|
||||
fun sendCoinList(current_page: Int): LiveData<Result<BaseRes<RewardCoinsRes>>> =
|
||||
handleData {
|
||||
appService.sendCoinList(current_page).response()
|
||||
}
|
||||
|
||||
fun getPaySetting(
|
||||
short_play_id: Int?,
|
||||
video_id: Int?
|
||||
): LiveData<Result<BaseRes<PaySettingRes>>> = handleData {
|
||||
appService.getPaySetting(short_play_id, video_id).response()
|
||||
}
|
||||
|
||||
fun doGooglePaid(examplePayReq: PayReq?): LiveData<Result<BaseRes<PayRes>>> =
|
||||
handleData {
|
||||
appService.googlePaid(examplePayReq).response()
|
||||
}
|
||||
|
||||
fun doCreateOrder(createOrderReq: CreateOrderReq): LiveData<Result<BaseRes<CreateOrderRes>>> =
|
||||
handleData {
|
||||
appService.createOrder(createOrderReq).response()
|
||||
}
|
||||
|
||||
|
||||
fun upError(body: Map<String, @JvmSuppressWildcards Any>): LiveData<Result<BaseRes<Any>>> =
|
||||
handleData {
|
||||
appService.upError(body).response()
|
||||
}
|
||||
|
||||
fun doLogin(exampleLoginReq: LoginReq): LiveData<Result<BaseRes<LoginRes>>> =
|
||||
handleData {
|
||||
appService.login(exampleLoginReq).response()
|
||||
}
|
||||
|
||||
fun doLogoff(): LiveData<Result<BaseRes<Any>>> = handleData {
|
||||
appService.logoff().response()
|
||||
}
|
||||
|
||||
fun doSignout(): LiveData<Result<BaseRes<LoginRes>>> = handleData {
|
||||
appService.signout().response()
|
||||
}
|
||||
|
||||
fun homeHot(buycount: Int, hottestnum: Int): LiveData<Result<BaseRes<VideoListDataRes>>> =
|
||||
handleData {
|
||||
appService.homeHot(buycount, hottestnum)
|
||||
.response()
|
||||
}
|
||||
|
||||
fun userCenterRecommend(): LiveData<Result<BaseRes<ShortListCategoryDataInfo>>> =
|
||||
handleData {
|
||||
appService.userCenterRecommend(5)
|
||||
.response()
|
||||
}
|
||||
}
|
403
app/src/main/java/com/jia/er/nebuluxe/app/net/MainViewModel.kt
Normal file
403
app/src/main/java/com/jia/er/nebuluxe/app/net/MainViewModel.kt
Normal file
@ -0,0 +1,403 @@
|
||||
package com.jia.er.nebuluxe.app.net
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.jia.er.nebuluxe.app.data.LoginRes
|
||||
import com.jia.er.nebuluxe.app.data.BaseRes
|
||||
import com.jia.er.nebuluxe.app.data.BuyVideoRes
|
||||
import com.jia.er.nebuluxe.app.data.CategoriesDataRes
|
||||
import com.jia.er.nebuluxe.app.data.CollectionRes
|
||||
import com.jia.er.nebuluxe.app.data.CreateOrderReq
|
||||
import com.jia.er.nebuluxe.app.data.CreateOrderRes
|
||||
import com.jia.er.nebuluxe.app.data.CustomerBuyRecordsRes
|
||||
import com.jia.er.nebuluxe.app.data.CustomerOrderRes
|
||||
import com.jia.er.nebuluxe.app.data.DetailsRecommendRes
|
||||
import com.jia.er.nebuluxe.app.data.ExampleKeywordDataRes
|
||||
import com.jia.er.nebuluxe.app.data.FbNotificationReq
|
||||
import com.jia.er.nebuluxe.app.data.FreeSeriesMoreRes
|
||||
import com.jia.er.nebuluxe.app.data.HistoryDataRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeModuleBean
|
||||
import com.jia.er.nebuluxe.app.data.HomeNewShortPlayNoPaginateRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeNewShortPlayRes
|
||||
import com.jia.er.nebuluxe.app.data.HomeRankingRes
|
||||
import com.jia.er.nebuluxe.app.data.LoginReq
|
||||
import com.jia.er.nebuluxe.app.data.NoticeNumRes
|
||||
import com.jia.er.nebuluxe.app.data.PayReq
|
||||
import com.jia.er.nebuluxe.app.data.PayRes
|
||||
import com.jia.er.nebuluxe.app.data.PaySettingRes
|
||||
import com.jia.er.nebuluxe.app.data.PlayerDetailDataRes
|
||||
import com.jia.er.nebuluxe.app.data.RecommendDataRes
|
||||
import com.jia.er.nebuluxe.app.data.RewardCoinsRes
|
||||
import com.jia.er.nebuluxe.app.data.ShortListCategoryDataInfo
|
||||
import com.jia.er.nebuluxe.app.data.UploadHistoryReq
|
||||
import com.jia.er.nebuluxe.app.data.UserInfoRes
|
||||
import com.jia.er.nebuluxe.app.data.UserRegisterRes
|
||||
import com.jia.er.nebuluxe.app.data.VideoListDataRes
|
||||
import com.jia.er.nebuluxe.app.net.MainRequest
|
||||
|
||||
class MainViewModel : ViewModel() {
|
||||
private val userRegisterLiveData = MutableLiveData<BaseRes<UserRegisterRes>>()
|
||||
val userRegisterData: MutableLiveData<BaseRes<UserRegisterRes>> get() = userRegisterLiveData
|
||||
fun createUserAccount(
|
||||
) {
|
||||
MainRequest.userRegister().observeForever { result ->
|
||||
userRegisterLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val infoLiveData = MutableLiveData<BaseRes<UserInfoRes>>()
|
||||
val infoData: MutableLiveData<BaseRes<UserInfoRes>> get() = infoLiveData
|
||||
fun getInfo() {
|
||||
MainRequest.getInfo().observeForever { result ->
|
||||
infoLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val newShortPlayLiveData = MutableLiveData<BaseRes<HomeNewShortPlayRes>>()
|
||||
val newShortPlayData: MutableLiveData<BaseRes<HomeNewShortPlayRes>> get() = newShortPlayLiveData
|
||||
fun newShortPlay(current_page: Int) {
|
||||
MainRequest.newShortPlay(current_page)
|
||||
.observeForever {
|
||||
newShortPlayLiveData.value = it.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val videoDetailsLiveData = MutableLiveData<BaseRes<PlayerDetailDataRes>>()
|
||||
val videoDetailsData: MutableLiveData<BaseRes<PlayerDetailDataRes>> get() = videoDetailsLiveData
|
||||
fun getVideoDetails(
|
||||
short_play_id: Int,
|
||||
video_id: Int,
|
||||
activity_id: Int,
|
||||
revolution: String,
|
||||
no_ads: Boolean?
|
||||
) {
|
||||
MainRequest.getVideoDetails(
|
||||
short_play_id,
|
||||
video_id,
|
||||
activity_id,
|
||||
revolution,
|
||||
no_ads
|
||||
)
|
||||
.observeForever { result ->
|
||||
videoDetailsLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val homeNewLiveData = MutableLiveData<BaseRes<HomeNewShortPlayNoPaginateRes>>()
|
||||
val homeNewData: MutableLiveData<BaseRes<HomeNewShortPlayNoPaginateRes>> get() = homeNewLiveData
|
||||
fun newShortPlayNoPaginate() {
|
||||
MainRequest.newShortPlayNoPaginate()
|
||||
.observeForever {
|
||||
homeNewLiveData.value = it.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun doCreateHistory(short_play_id: Int, video_id: Int) {
|
||||
MainRequest.doCreateHistory(short_play_id, video_id).observeForever {}
|
||||
}
|
||||
|
||||
private val searchLiveData = MutableLiveData<BaseRes<VideoListDataRes>>()
|
||||
val searchData: MutableLiveData<BaseRes<VideoListDataRes>> get() = searchLiveData
|
||||
fun getVideoList(search: String) {
|
||||
MainRequest.getVideoList(search).observeForever { result ->
|
||||
searchLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val videoListLiveData = MutableLiveData<BaseRes<VideoListDataRes>>()
|
||||
val videoListData: MutableLiveData<BaseRes<VideoListDataRes>> get() = videoListLiveData
|
||||
fun getVideoList(current_page: Int, category_id: Int) {
|
||||
MainRequest.getVideoList(current_page, category_id).observeForever { result ->
|
||||
videoListLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val homeRankingLiveData = MutableLiveData<BaseRes<HomeRankingRes>>()
|
||||
val homeRankingData: MutableLiveData<BaseRes<HomeRankingRes>> get() = homeRankingLiveData
|
||||
fun homeRanking(type: String) {
|
||||
MainRequest.homeRanking(type)
|
||||
.observeForever {
|
||||
homeRankingLiveData.value = it.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val freeMoreLiveData = MutableLiveData<BaseRes<FreeSeriesMoreRes>>()
|
||||
val freeMoreData: MutableLiveData<BaseRes<FreeSeriesMoreRes>> get() = freeMoreLiveData
|
||||
|
||||
fun freeMoreVideo() {
|
||||
MainRequest.freeMoreVideo().observeForever { result ->
|
||||
freeMoreLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val recommendLiveData = MutableLiveData<BaseRes<RecommendDataRes>>()
|
||||
val recommendData: MutableLiveData<BaseRes<RecommendDataRes>> get() = recommendLiveData
|
||||
fun getRecommands(current_page: Int, page_size: Int, revolution: String) {
|
||||
MainRequest.getRecommands(current_page, page_size, revolution)
|
||||
.observeForever { result ->
|
||||
recommendLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val collectLiveData = MutableLiveData<BaseRes<Any>>()
|
||||
val collectData: MutableLiveData<BaseRes<Any>> get() = collectLiveData
|
||||
fun doCollect(short_play_id: Int, video_id: Int) {
|
||||
MainRequest.doCollect(short_play_id, video_id).observeForever { result ->
|
||||
collectLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val cancelCollectLiveData = MutableLiveData<BaseRes<Any>>()
|
||||
val cancelCollectData: MutableLiveData<BaseRes<Any>> get() = cancelCollectLiveData
|
||||
fun doCancelCollect(short_play_id: Int, video_id: Int) {
|
||||
MainRequest.doCancelCollect(short_play_id, video_id).observeForever { result ->
|
||||
cancelCollectLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val collectionsLiveData = MutableLiveData<BaseRes<CollectionRes>>()
|
||||
val collectionsData: MutableLiveData<BaseRes<CollectionRes>> get() = collectionsLiveData
|
||||
fun getCollections(current_page: Int) {
|
||||
MainRequest.getCollections(current_page).observeForever { result ->
|
||||
collectionsLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val historysLiveData = MutableLiveData<BaseRes<HistoryDataRes>>()
|
||||
val historysData: MutableLiveData<BaseRes<HistoryDataRes>> get() = historysLiveData
|
||||
fun myHistorys(
|
||||
current_page: Int
|
||||
) {
|
||||
MainRequest.myHistorys(current_page).observeForever { result ->
|
||||
historysLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val getDetailsRecommandLiveData = MutableLiveData<BaseRes<DetailsRecommendRes>>()
|
||||
val getDetailsRecommandData: MutableLiveData<BaseRes<DetailsRecommendRes>> get() = getDetailsRecommandLiveData
|
||||
|
||||
fun getDetailsRecommand() {
|
||||
MainRequest.getDetailsRecommand().observeForever { result ->
|
||||
getDetailsRecommandLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun uploadHistorySeconds(uploadHistoryReq: UploadHistoryReq) {
|
||||
MainRequest.uploadHistorySeconds(uploadHistoryReq).observeForever {}
|
||||
}
|
||||
|
||||
|
||||
private val hotsLiveData = MutableLiveData<BaseRes<ExampleKeywordDataRes>>()
|
||||
val hotsData: MutableLiveData<BaseRes<ExampleKeywordDataRes>> get() = hotsLiveData
|
||||
fun hots() {
|
||||
MainRequest.hots().observeForever { result ->
|
||||
hotsLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun click(short_play_id: Int) {
|
||||
MainRequest.click(short_play_id).observeForever {}
|
||||
}
|
||||
|
||||
private val keywordLiveData = MutableLiveData<BaseRes<ExampleKeywordDataRes>>()
|
||||
val keywordData: MutableLiveData<BaseRes<ExampleKeywordDataRes>> get() = keywordLiveData
|
||||
fun keyword(search: String) {
|
||||
MainRequest.keyword(search).observeForever { result ->
|
||||
keywordLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val allModulesLiveData = MutableLiveData<BaseRes<HomeModuleBean>>()
|
||||
val allModulesData: MutableLiveData<BaseRes<HomeModuleBean>> get() = allModulesLiveData
|
||||
fun allModules() {
|
||||
MainRequest.allModules().observeForever { result ->
|
||||
allModulesLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val buy_videoLiveData = MutableLiveData<BaseRes<BuyVideoRes>>()
|
||||
val buy_videoData: MutableLiveData<BaseRes<BuyVideoRes>> get() = buy_videoLiveData
|
||||
fun doBuyVideo(short_play_id: Int, video_id: Int) {
|
||||
MainRequest.doBuyVideo(short_play_id, video_id).observeForever { result ->
|
||||
buy_videoLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val categoriesLiveData = MutableLiveData<BaseRes<CategoriesDataRes>>()
|
||||
val categoriesData: MutableLiveData<BaseRes<CategoriesDataRes>> get() = categoriesLiveData
|
||||
fun getCategories() {
|
||||
MainRequest.getCategories().observeForever { result ->
|
||||
categoriesLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun enterTheApp() {
|
||||
MainRequest.enterTheApp().observeForever {}
|
||||
}
|
||||
|
||||
fun leaveApp() {
|
||||
MainRequest.leaveApp().observeForever {}
|
||||
}
|
||||
|
||||
fun onLine() {
|
||||
MainRequest.onLine().observeForever {}
|
||||
}
|
||||
|
||||
fun firebaseToken(
|
||||
fcm_token: String
|
||||
) {
|
||||
MainRequest.firebaseToken(fcm_token).observeForever {}
|
||||
}
|
||||
|
||||
private val w2aSelfAttributionLiveData =
|
||||
MutableLiveData<BaseRes<Any>>()
|
||||
|
||||
fun w2aSelfAttribution(data: String) {
|
||||
MainRequest.w2aSelfAttribution(data).observeForever { result ->
|
||||
w2aSelfAttributionLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val openNotifyLiveData = MutableLiveData<BaseRes<Any>>()
|
||||
val openNotifyData: MutableLiveData<BaseRes<Any>> get() = openNotifyLiveData
|
||||
|
||||
fun openNotify() {
|
||||
MainRequest.openNotify().observeForever { result ->
|
||||
openNotifyLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val notificationLiveData = MutableLiveData<BaseRes<Any>>()
|
||||
fun uploadNoticeStatus(fbNotificationReq: FbNotificationReq) {
|
||||
MainRequest.uploadNoticeStatus(fbNotificationReq)
|
||||
.observeForever {
|
||||
notificationLiveData.value = it.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun sendReport(message_id: String, title: String) {
|
||||
MainRequest.sendReport(message_id, title).observeForever {}
|
||||
}
|
||||
|
||||
private val noticeNumLiveData =
|
||||
MutableLiveData<BaseRes<NoticeNumRes>>()
|
||||
val noticeNumData: MutableLiveData<BaseRes<NoticeNumRes>> get() = noticeNumLiveData
|
||||
fun noticeNum() {
|
||||
MainRequest.noticeNum().observeForever { result ->
|
||||
noticeNumLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val getPaySettingLiveData = MutableLiveData<BaseRes<PaySettingRes>>()
|
||||
val getPaySettingData: MutableLiveData<BaseRes<PaySettingRes>> get() = getPaySettingLiveData
|
||||
fun getPaySetting(
|
||||
short_play_id: Int?,
|
||||
video_id: Int?
|
||||
) {
|
||||
MainRequest.getPaySetting(short_play_id, video_id).observeForever { result ->
|
||||
getPaySettingLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val restorePaidLiveData = MutableLiveData<BaseRes<PayRes>>()
|
||||
val restorePaidData: MutableLiveData<BaseRes<PayRes>> get() = restorePaidLiveData
|
||||
fun restorePaid(examplePayReq: PayReq?) {
|
||||
MainRequest.doGooglePaid(examplePayReq).observeForever { result ->
|
||||
restorePaidLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val createOrderLiveData = MutableLiveData<BaseRes<CreateOrderRes>>()
|
||||
val createOrderData: MutableLiveData<BaseRes<CreateOrderRes>> get() = createOrderLiveData
|
||||
fun createOrder(createOrderReq: CreateOrderReq) {
|
||||
MainRequest.doCreateOrder(createOrderReq).observeForever { result ->
|
||||
createOrderLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val googlePaidLiveData = MutableLiveData<BaseRes<PayRes>>()
|
||||
val googlePaidData: MutableLiveData<BaseRes<PayRes>> get() = googlePaidLiveData
|
||||
fun googlePaid(examplePayReq: PayReq?) {
|
||||
MainRequest.doGooglePaid(examplePayReq).observeForever { result ->
|
||||
googlePaidLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val customerOrderLiveData = MutableLiveData<BaseRes<CustomerOrderRes>>()
|
||||
val customerOrderData: MutableLiveData<BaseRes<CustomerOrderRes>> get() = customerOrderLiveData
|
||||
fun getCustomerOrder(current_page: Int, buy_type: String) {
|
||||
MainRequest.getCustomerOrder(current_page, buy_type).observeForever { result ->
|
||||
customerOrderLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val customerBuyRecordsLiveData =
|
||||
MutableLiveData<BaseRes<CustomerBuyRecordsRes>>()
|
||||
val customerBuyRecordsData: MutableLiveData<BaseRes<CustomerBuyRecordsRes>> get() = customerBuyRecordsLiveData
|
||||
fun getCustomerBuyRecords(current_page: Int) {
|
||||
MainRequest.getCustomerBuyRecords(current_page).observeForever { result ->
|
||||
customerBuyRecordsLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val sendCoinListLiveData =
|
||||
MutableLiveData<BaseRes<RewardCoinsRes>>()
|
||||
val sendCoinListData: MutableLiveData<BaseRes<RewardCoinsRes>> get() = sendCoinListLiveData
|
||||
fun sendCoinList(current_page: Int) {
|
||||
MainRequest.sendCoinList(current_page).observeForever { result ->
|
||||
sendCoinListLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun upError(body: Map<String, @JvmSuppressWildcards Any>) {
|
||||
MainRequest.upError(body).observeForever {}
|
||||
}
|
||||
|
||||
private val loginLiveData = MutableLiveData<BaseRes<LoginRes>>()
|
||||
val loginData: MutableLiveData<BaseRes<LoginRes>> get() = loginLiveData
|
||||
fun doLogin(exampleLoginReq: LoginReq) {
|
||||
MainRequest.doLogin(exampleLoginReq).observeForever { result ->
|
||||
loginLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val logoffLiveData = MutableLiveData<BaseRes<Any>>()
|
||||
val logoffData: MutableLiveData<BaseRes<Any>> get() = logoffLiveData
|
||||
fun doLogoff() {
|
||||
MainRequest.doLogoff().observeForever { result ->
|
||||
logoffLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val signoutLiveData = MutableLiveData<BaseRes<LoginRes>>()
|
||||
val signoutData: MutableLiveData<BaseRes<LoginRes>> get() = signoutLiveData
|
||||
fun doSignout() {
|
||||
MainRequest.doSignout().observeForever { result ->
|
||||
signoutLiveData.value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val homeHotLiveData = MutableLiveData<BaseRes<VideoListDataRes>?>()
|
||||
val homeHotData: MutableLiveData<BaseRes<VideoListDataRes>?> get() = homeHotLiveData
|
||||
fun homeHot(buycount: Int, hottestnum: Int) {
|
||||
MainRequest.homeHot(buycount, hottestnum)
|
||||
.observeForever {
|
||||
homeHotLiveData.value = it.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private val userCenterRecommendLiveData = MutableLiveData<BaseRes<ShortListCategoryDataInfo>?>()
|
||||
val userCenterRecommendData: MutableLiveData<BaseRes<ShortListCategoryDataInfo>?> get() = userCenterRecommendLiveData
|
||||
fun userCenterRecommend(){
|
||||
MainRequest.userCenterRecommend()
|
||||
.observeForever {
|
||||
userCenterRecommendLiveData.value = it.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
221
app/src/main/java/com/jia/er/nebuluxe/app/net/Retrofit.kt
Normal file
221
app/src/main/java/com/jia/er/nebuluxe/app/net/Retrofit.kt
Normal file
@ -0,0 +1,221 @@
|
||||
package com.jia.er.nebuluxe.app.net
|
||||
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.liveData
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.basics.MyApplication.Companion.context
|
||||
import com.jia.er.nebuluxe.app.data.BaseRes
|
||||
import com.jia.er.nebuluxe.app.utils.Memory
|
||||
import com.jia.er.nebuluxe.app.utils.PackageUtils
|
||||
import com.jia.er.nebuluxe.app.utils.getAdvertisingIdInfo
|
||||
import com.jia.er.nebuluxe.app.utils.getUserAgent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import java.util.TimeZone
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
|
||||
object Retrofit {
|
||||
private val retrofit: Retrofit
|
||||
fun <P> build(serviceClass: Class<P>): P = retrofit.create(serviceClass)
|
||||
private val httpLoggingInterceptor = HttpLoggingInterceptor()
|
||||
private const val DELAY_TIME_MILLIS = 2000L
|
||||
private var lastPostTime: Long = 0L
|
||||
private val lock = Any()
|
||||
private val lock1 = Any()
|
||||
|
||||
init {
|
||||
httpLoggingInterceptor.level =
|
||||
if (Constants.isUat) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
|
||||
val okHttpClient = OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS)
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.addInterceptor(BodyInterceptor())
|
||||
.addInterceptor { chain ->
|
||||
val request =
|
||||
chain.request().newBuilder().header("Content-Type", "application/json")
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_AuthorizationExample,
|
||||
Memory.getMMKV()
|
||||
.getString(Constants.CONSTANTS_AuthorizationExample, "")
|
||||
.toString()
|
||||
)
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_device_id,
|
||||
Settings.Secure.getString(
|
||||
context.contentResolver,
|
||||
Settings.Secure.ANDROID_ID
|
||||
)
|
||||
).addHeader("User-Agent", getUserAgent())
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_device_gaid,
|
||||
getAdvertisingIdInfo(context)
|
||||
)
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_app_name,
|
||||
context.getString(R.string.app_name)
|
||||
).addHeader(
|
||||
Constants.CONSTANTS_app_version,
|
||||
PackageUtils.getPackageVersion(context)
|
||||
)
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_system_type,
|
||||
"android"
|
||||
)
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_lang_key,
|
||||
Memory.getMMKV()
|
||||
.getString(Constants.CONSTANTS_lang_key, "en").toString()
|
||||
)
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_time_zone,
|
||||
getCurrentTimeZone()
|
||||
)
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_model,
|
||||
Build.MODEL
|
||||
)
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_brand,
|
||||
Build.BRAND
|
||||
)
|
||||
.addHeader(
|
||||
Constants.CONSTANTS_system_version,
|
||||
Build.VERSION.RELEASE
|
||||
)
|
||||
.build()
|
||||
if (Constants.isUat) {
|
||||
for (headerName in request.headers.names()) {
|
||||
println(headerName + ": " + request.header(headerName))
|
||||
}
|
||||
}
|
||||
chain.proceed(request)
|
||||
}
|
||||
.build()
|
||||
retrofit =
|
||||
Retrofit.Builder()
|
||||
.baseUrl(Constants.Constants_BASE_URL_RES)
|
||||
.addConverterFactory(
|
||||
GsonConverterFactory.create()
|
||||
)
|
||||
.client(okHttpClient)
|
||||
.build()
|
||||
}
|
||||
|
||||
suspend fun <T> Call<T>.response(): T {
|
||||
return suspendCoroutine { continuation ->
|
||||
enqueue(object : Callback<T> {
|
||||
override fun onFailure(call: Call<T>, t: Throwable) {
|
||||
continuation.resumeWithException(t)
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call<T>, response: Response<T>) {
|
||||
val body = response.body()
|
||||
if (response.raw().code == 401) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
handle401Response()
|
||||
}
|
||||
}
|
||||
if (response.raw().code == 402) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
handle402Response()
|
||||
}
|
||||
}
|
||||
if (body != null) continuation.resume(body)
|
||||
else continuation.resumeWithException(RuntimeException("response body is null"))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private suspend fun handle402Response() = withContext(Dispatchers.Main) {
|
||||
synchronized(lock) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (currentTime - lastPostTime >= DELAY_TIME_MILLIS) {
|
||||
EventBus.getDefault()
|
||||
.post(Constants.CONSTANTS_auth_refresh)
|
||||
lastPostTime = currentTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handle401Response() = withContext(Dispatchers.Main) {
|
||||
synchronized(lock1) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (currentTime - lastPostTime >= DELAY_TIME_MILLIS) {
|
||||
EventBus.getDefault()
|
||||
.post(Constants.CONSTANTS_auth_refresh)
|
||||
lastPostTime = currentTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun <T> handleData(apiCall: suspend () -> BaseRes<T>): LiveData<Result<BaseRes<T>>> {
|
||||
return liveData(Dispatchers.IO) {
|
||||
val result = try {
|
||||
val response = apiCall.invoke()
|
||||
if (response.code == 200) {
|
||||
Result.success(response)
|
||||
} else {
|
||||
Memory.getMMKV().putString("errorMsg", response.msg)
|
||||
Result.failure(RuntimeException("Result failure"))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
emit(result)
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentTimeZone(): String {
|
||||
return createGmtOffsetString(true, true, TimeZone.getDefault().rawOffset)
|
||||
}
|
||||
|
||||
private fun createGmtOffsetString(
|
||||
includeGmt: Boolean, includeMinuteSeparator: Boolean, offsetMillis: Int
|
||||
): String {
|
||||
var offsetMinutes = offsetMillis / 60000
|
||||
var sign = '+'
|
||||
if (offsetMinutes < 0) {
|
||||
sign = '-'
|
||||
offsetMinutes = -offsetMinutes
|
||||
}
|
||||
val builder: StringBuilder = StringBuilder(9)
|
||||
if (includeGmt) {
|
||||
builder.append("GMT")
|
||||
}
|
||||
builder.append(sign)
|
||||
appendNumber(builder, 2, offsetMinutes / 60)
|
||||
if (includeMinuteSeparator) {
|
||||
builder.append(':')
|
||||
}
|
||||
appendNumber(builder, 2, offsetMinutes % 60)
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private fun appendNumber(builder: StringBuilder, count: Int, value: Int) {
|
||||
val string = value.toString()
|
||||
for (i in 0 until count - string.length) {
|
||||
builder.append('0')
|
||||
}
|
||||
builder.append(string);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import android.graphics.*
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||
import java.security.MessageDigest
|
||||
|
||||
class CustomRoundedCorners(
|
||||
private val topLeft: Float = 0f,
|
||||
private val topRight: Float = 0f,
|
||||
private val bottomRight: Float = 0f,
|
||||
private val bottomLeft: Float = 0f
|
||||
) : BitmapTransformation() {
|
||||
|
||||
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
|
||||
messageDigest.update("$topLeft-$topRight-$bottomRight-$bottomLeft".toByteArray())
|
||||
}
|
||||
|
||||
override fun transform(
|
||||
pool: BitmapPool,
|
||||
toTransform: Bitmap,
|
||||
outWidth: Int,
|
||||
outHeight: Int
|
||||
): Bitmap {
|
||||
return roundCrop(pool, toTransform)
|
||||
}
|
||||
|
||||
private fun roundCrop(pool: BitmapPool, source: Bitmap?): Bitmap {
|
||||
if (source == null) return Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
|
||||
|
||||
val result = pool.get(source.width, source.height, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(result)
|
||||
|
||||
val paint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
shader = BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
|
||||
}
|
||||
|
||||
val path = Path()
|
||||
val radii = floatArrayOf(
|
||||
topLeft, topLeft,
|
||||
topRight, topRight,
|
||||
bottomRight, bottomRight,
|
||||
bottomLeft, bottomLeft
|
||||
)
|
||||
path.addRoundRect(
|
||||
RectF(0f, 0f, source.width.toFloat(), source.height.toFloat()),
|
||||
radii,
|
||||
Path.Direction.CW
|
||||
)
|
||||
|
||||
canvas.drawPath(path, paint)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import androidx.media3.decoder.ffmpeg.FfmpegAudioRenderer
|
||||
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||
import androidx.media3.exoplayer.Renderer
|
||||
import androidx.media3.exoplayer.audio.AudioRendererEventListener
|
||||
import androidx.media3.exoplayer.audio.AudioSink
|
||||
import androidx.media3.exoplayer.mediacodec.MediaCodecSelector
|
||||
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
internal class FfmpegRenderersFactory(context: Context?) : DefaultRenderersFactory(
|
||||
context!!
|
||||
) {
|
||||
init {
|
||||
setExtensionRendererMode(EXTENSION_RENDERER_MODE_ON)
|
||||
}
|
||||
|
||||
override fun buildAudioRenderers(
|
||||
context: Context,
|
||||
extensionRendererMode: Int,
|
||||
mediaCodecSelector: MediaCodecSelector,
|
||||
enableDecoderFallback: Boolean,
|
||||
audioSink: AudioSink,
|
||||
eventHandler: Handler,
|
||||
eventListener: AudioRendererEventListener,
|
||||
out: ArrayList<Renderer>
|
||||
) {
|
||||
out.add(FfmpegAudioRenderer())
|
||||
super.buildAudioRenderers(
|
||||
context,
|
||||
extensionRendererMode,
|
||||
mediaCodecSelector,
|
||||
enableDecoderFallback,
|
||||
audioSink,
|
||||
eventHandler,
|
||||
eventListener,
|
||||
out
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
interface ListItemsVisibilityCalculator {
|
||||
fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int)
|
||||
fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int)
|
||||
fun detachToSnapHelper()
|
||||
}
|
59
app/src/main/java/com/jia/er/nebuluxe/app/ui/LoadingLine.kt
Normal file
59
app/src/main/java/com/jia/er/nebuluxe/app/ui/LoadingLine.kt
Normal file
@ -0,0 +1,59 @@
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.AnimationSet
|
||||
import android.view.animation.ScaleAnimation
|
||||
import android.widget.FrameLayout
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
|
||||
|
||||
class LoadingLine : FrameLayout {
|
||||
private var loadView: View? = null
|
||||
|
||||
constructor(context: Context) : super(context) {
|
||||
initView(context)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
|
||||
initView(context)
|
||||
}
|
||||
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int
|
||||
) : super(context, attrs, defStyleAttr) {
|
||||
initView(context)
|
||||
}
|
||||
|
||||
private fun initView(mContext: Context) {
|
||||
val view: View = LayoutInflater.from(mContext).inflate(R.layout.line_layout, null)
|
||||
loadView = view.findViewById<View>(R.id.loadingView)
|
||||
this.addView(view)
|
||||
}
|
||||
|
||||
fun startAnimation() {
|
||||
val scale = ScaleAnimation(
|
||||
0.3f, 1f, 1f, 1f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f
|
||||
)
|
||||
val alpha = AlphaAnimation(1f, 0.2f)
|
||||
scale.repeatCount = -1
|
||||
alpha.repeatCount = -1
|
||||
val set = AnimationSet(true)
|
||||
set.addAnimation(scale)
|
||||
set.addAnimation(alpha)
|
||||
set.duration = 500
|
||||
loadView!!.startAnimation(set)
|
||||
}
|
||||
|
||||
fun endAnimation(){
|
||||
loadView!!.clearAnimation()
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import android.view.View
|
||||
|
||||
interface OnSnapHelperCurrentListener {
|
||||
|
||||
fun setActive(currentView: View?, position: Int, previousView: View?, previousPosition: Int)
|
||||
|
||||
fun disActive(detachedView: View?, detachedPosition: Int)
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.CustomTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
|
||||
/**
|
||||
* 海报风格图片视图 - 简化版
|
||||
* 使用顶部略倾斜的大圆角路径,贴合上传海报的形状
|
||||
*/
|
||||
class PosterStyleImageView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : View(context, attrs, defStyleAttr) {
|
||||
|
||||
// 画笔
|
||||
private val imagePaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
|
||||
// 路径
|
||||
private val imagePath = Path()
|
||||
|
||||
// 图片相关
|
||||
private var imageBitmap: Bitmap? = null
|
||||
private var imageMatrix = Matrix()
|
||||
private var imageShader: BitmapShader? = null
|
||||
|
||||
// 尺寸和位置
|
||||
private var imageRect = RectF()
|
||||
|
||||
// 圆角(像素)——默认左上更短,其余正常
|
||||
private var cornerRadiusTopLeft = dpToPx(12f)
|
||||
private var cornerRadiusTopRight = dpToPx(18f)
|
||||
private var cornerRadiusBottomRight = dpToPx(18f)
|
||||
private var cornerRadiusBottomLeft = dpToPx(18f)
|
||||
|
||||
// 顶边倾斜偏移(像素):左上相对右上向下偏移,正值代表左侧更低
|
||||
private var topSlantOffset = dpToPx(10f)
|
||||
|
||||
init {
|
||||
setupPaint()
|
||||
}
|
||||
|
||||
private fun setupPaint() {
|
||||
imagePaint.style = Paint.Style.FILL
|
||||
}
|
||||
|
||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||
super.onSizeChanged(w, h, oldw, oldh)
|
||||
|
||||
imageRect.set(
|
||||
paddingLeft.toFloat(),
|
||||
paddingTop.toFloat(),
|
||||
(w - paddingRight).toFloat(),
|
||||
(h - paddingBottom).toFloat()
|
||||
)
|
||||
|
||||
createImagePath()
|
||||
}
|
||||
|
||||
private fun createImagePath() {
|
||||
imagePath.reset()
|
||||
|
||||
// 四个角的半径,限定不要超过边长的一半
|
||||
val rTL = cornerRadiusTopLeft.coerceAtMost(minOf(imageRect.width(), imageRect.height()) / 2f)
|
||||
val rTR = cornerRadiusTopRight.coerceAtMost(minOf(imageRect.width(), imageRect.height()) / 2f)
|
||||
val rBR = cornerRadiusBottomRight.coerceAtMost(minOf(imageRect.width(), imageRect.height()) / 2f)
|
||||
val rBL = cornerRadiusBottomLeft.coerceAtMost(minOf(imageRect.width(), imageRect.height()) / 2f)
|
||||
|
||||
// 顶部两点,形成倾斜
|
||||
val left = imageRect.left
|
||||
val right = imageRect.right
|
||||
val topLeftY = imageRect.top + topSlantOffset
|
||||
val topRightY = imageRect.top
|
||||
val bottom = imageRect.bottom
|
||||
|
||||
// 起点:左上边内切圆起始点(顺时针)
|
||||
imagePath.moveTo(left + rTL, topLeftY)
|
||||
|
||||
// 顶边(倾斜)到右上角前
|
||||
imagePath.lineTo(right - rTR, topRightY)
|
||||
// 右上角圆弧(用二阶贝塞尔逼近)
|
||||
imagePath.quadTo(right, topRightY, right, topRightY + rTR)
|
||||
|
||||
// 右边到右下角前
|
||||
imagePath.lineTo(right, bottom - rBR)
|
||||
// 右下角
|
||||
imagePath.quadTo(right, bottom, right - rBR, bottom)
|
||||
|
||||
// 底边到左下角前
|
||||
imagePath.lineTo(left + rBL, bottom)
|
||||
// 左下角
|
||||
imagePath.quadTo(left, bottom, left, bottom - rBL)
|
||||
|
||||
// 左边到左上角前(注意顶边是倾斜的,终点是 topLeftY)
|
||||
imagePath.lineTo(left, topLeftY + rTL)
|
||||
// 左上角(小圆角)
|
||||
imagePath.quadTo(left, topLeftY, left + rTL, topLeftY)
|
||||
|
||||
imagePath.close()
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
drawImage(canvas)
|
||||
}
|
||||
|
||||
private fun drawImage(canvas: Canvas) {
|
||||
imageBitmap?.let { bitmap ->
|
||||
if (imageShader == null) {
|
||||
imageShader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
|
||||
}
|
||||
|
||||
val bitmapWidth = bitmap.width.toFloat()
|
||||
val bitmapHeight = bitmap.height.toFloat()
|
||||
val scaleX = imageRect.width() / bitmapWidth
|
||||
val scaleY = imageRect.height() / bitmapHeight
|
||||
val scale = maxOf(scaleX, scaleY)
|
||||
|
||||
imageMatrix.reset()
|
||||
imageMatrix.setScale(scale, scale)
|
||||
imageMatrix.postTranslate(
|
||||
imageRect.left + (imageRect.width() - bitmapWidth * scale) / 2,
|
||||
imageRect.top + (imageRect.height() - bitmapHeight * scale) / 2
|
||||
)
|
||||
|
||||
imageShader?.setLocalMatrix(imageMatrix)
|
||||
imagePaint.shader = imageShader
|
||||
canvas.drawPath(imagePath, imagePaint)
|
||||
}
|
||||
}
|
||||
|
||||
fun setImage(bitmap: Bitmap) {
|
||||
imageBitmap = bitmap
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun setImageResource(resId: Int) {
|
||||
ContextCompat.getDrawable(context, resId)?.let { drawable ->
|
||||
setImage(drawable.toBitmap())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 Glide 从网络加载图片
|
||||
*/
|
||||
fun loadImage(url: String, placeholderRes: Int? = null, errorRes: Int? = null) {
|
||||
val requestOptions = RequestOptions()
|
||||
placeholderRes?.let { requestOptions.placeholder(it) }
|
||||
errorRes?.let { requestOptions.error(it) }
|
||||
|
||||
Glide.with(this)
|
||||
.asBitmap()
|
||||
.load(url)
|
||||
.apply(requestOptions)
|
||||
.into(object : CustomTarget<Bitmap>() {
|
||||
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
|
||||
setImage(resource)
|
||||
}
|
||||
override fun onLoadCleared(placeholder: Drawable?) {
|
||||
placeholder?.toBitmap()?.let { setImage(it) }
|
||||
}
|
||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||
super.onLoadFailed(errorDrawable)
|
||||
errorDrawable?.toBitmap()?.let { setImage(it) }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 统一设置四角圆角(像素)
|
||||
fun setCornerRadius(radiusPx: Float) {
|
||||
cornerRadiusTopLeft = radiusPx
|
||||
cornerRadiusTopRight = radiusPx
|
||||
cornerRadiusBottomRight = radiusPx
|
||||
cornerRadiusBottomLeft = radiusPx
|
||||
createImagePath()
|
||||
invalidate()
|
||||
}
|
||||
|
||||
// 分别设置四角圆角(像素)
|
||||
fun setCornerRadii(
|
||||
topLeftPx: Float,
|
||||
topRightPx: Float,
|
||||
bottomRightPx: Float,
|
||||
bottomLeftPx: Float
|
||||
) {
|
||||
cornerRadiusTopLeft = topLeftPx
|
||||
cornerRadiusTopRight = topRightPx
|
||||
cornerRadiusBottomRight = bottomRightPx
|
||||
cornerRadiusBottomLeft = bottomLeftPx
|
||||
createImagePath()
|
||||
invalidate()
|
||||
}
|
||||
|
||||
// 统一设置四角圆角(dp)
|
||||
fun setCornerRadiusDp(radiusDp: Float) {
|
||||
setCornerRadius(dpToPx(radiusDp))
|
||||
}
|
||||
|
||||
// 分别设置四角圆角(dp)
|
||||
fun setCornerRadiiDp(
|
||||
topLeftDp: Float,
|
||||
topRightDp: Float,
|
||||
bottomRightDp: Float,
|
||||
bottomLeftDp: Float
|
||||
) {
|
||||
setCornerRadii(
|
||||
dpToPx(topLeftDp),
|
||||
dpToPx(topRightDp),
|
||||
dpToPx(bottomRightDp),
|
||||
dpToPx(bottomLeftDp)
|
||||
)
|
||||
}
|
||||
|
||||
// 便捷方法:左上短、其他正常(传入dp)
|
||||
fun setTopLeftShortStyle(topLeftDp: Float = 12f, otherDp: Float = 18f) {
|
||||
setCornerRadiiDp(topLeftDp, otherDp, otherDp, otherDp)
|
||||
}
|
||||
|
||||
// 设置顶边倾斜偏移
|
||||
fun setTopSlantOffsetPx(offsetPx: Float) {
|
||||
topSlantOffset = offsetPx
|
||||
createImagePath()
|
||||
invalidate()
|
||||
}
|
||||
fun setTopSlantOffsetDp(offsetDp: Float) {
|
||||
setTopSlantOffsetPx(dpToPx(offsetDp))
|
||||
}
|
||||
|
||||
fun getCornerRadius(): Float = cornerRadiusTopLeft
|
||||
|
||||
private fun dpToPx(dp: Float): Float {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics)
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener
|
||||
import androidx.recyclerview.widget.SnapHelper
|
||||
|
||||
class RecyclerViewScrollerDetection : ListItemsVisibilityCalculator {
|
||||
|
||||
private var mSnapHelper: SnapHelper? = null
|
||||
private var mCurrentListener: OnSnapHelperCurrentListener? = null
|
||||
var position = RecyclerView.NO_POSITION
|
||||
private var previousPosition = RecyclerView.NO_POSITION
|
||||
var isFirstAttached = false
|
||||
private var recyclerView: RecyclerView? = null
|
||||
val mSnapScrollListener = SnapScrollListener()
|
||||
var mSnapChildAttachStateListener: SnapChildAttachStateChangeListener? = null
|
||||
|
||||
var isFirstActive = true
|
||||
private var currentItemView: View? = null
|
||||
private var previousView: View? = null
|
||||
|
||||
|
||||
fun attachToSnapHelper(snapHelper: SnapHelper) {
|
||||
mSnapHelper = snapHelper
|
||||
}
|
||||
|
||||
fun addOnScrollListener(recyclerView: RecyclerView) {
|
||||
this.recyclerView = recyclerView
|
||||
recyclerView.addOnScrollListener(mSnapScrollListener)
|
||||
mSnapChildAttachStateListener = SnapChildAttachStateChangeListener(recyclerView)
|
||||
mSnapChildAttachStateListener?.run {
|
||||
recyclerView.addOnChildAttachStateChangeListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
inner class SnapScrollListener : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
super.onScrollStateChanged(recyclerView, newState)
|
||||
this@RecyclerViewScrollerDetection.onScrollStateChanged(recyclerView, newState)
|
||||
}
|
||||
}
|
||||
|
||||
inner class SnapChildAttachStateChangeListener(var recyclerView: RecyclerView) :
|
||||
OnChildAttachStateChangeListener {
|
||||
override fun onChildViewAttachedToWindow(view: View) {
|
||||
if (!isFirstActive || isFirstAttached) return
|
||||
position = recyclerView.getChildAdapterPosition(view)
|
||||
currentItemView = view
|
||||
mCurrentListener?.setActive(view, position, null, previousPosition)
|
||||
previousPosition = position
|
||||
previousView = view
|
||||
isFirstAttached = true
|
||||
}
|
||||
|
||||
override fun onChildViewDetachedFromWindow(view: View) {
|
||||
val previousPosition = recyclerView.getChildAdapterPosition(view)
|
||||
currentItemView?.run {
|
||||
val position = recyclerView.getChildAdapterPosition(
|
||||
this
|
||||
)
|
||||
mCurrentListener?.let {
|
||||
if (position == previousPosition) {
|
||||
it.disActive(view, previousPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setCurrentListener(mCurrentListener: OnSnapHelperCurrentListener?) {
|
||||
this.mCurrentListener = mCurrentListener
|
||||
}
|
||||
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
try {
|
||||
when (newState) {
|
||||
RecyclerView.SCROLL_STATE_IDLE -> {
|
||||
val layoutManager = recyclerView.layoutManager
|
||||
currentItemView = mSnapHelper?.findSnapView(layoutManager)
|
||||
if (null == currentItemView) return
|
||||
val currentPosition = recyclerView.getChildAdapterPosition(currentItemView!!)
|
||||
if (previousPosition == currentPosition || null == mCurrentListener) return
|
||||
position = recyclerView.getChildAdapterPosition(currentItemView!!)
|
||||
val mPreviousView = previousView
|
||||
val mPreviousPosition = previousPosition
|
||||
mCurrentListener?.setActive(
|
||||
currentItemView,
|
||||
position,
|
||||
mPreviousView,
|
||||
mPreviousPosition
|
||||
)
|
||||
previousPosition = currentPosition
|
||||
previousView = currentItemView
|
||||
}
|
||||
|
||||
RecyclerView.SCROLL_STATE_DRAGGING -> {
|
||||
}
|
||||
|
||||
RecyclerView.SCROLL_STATE_SETTLING -> {
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun detachToSnapHelper() {
|
||||
recyclerView?.removeOnScrollListener(mSnapScrollListener)
|
||||
mSnapChildAttachStateListener?.run {
|
||||
recyclerView?.removeOnChildAttachStateChangeListener(
|
||||
this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import android.view.View
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
|
||||
|
||||
class RotateDownPageTransformer(
|
||||
private val maxRotate: Float = DEFAULT_MAX_ROTATE,
|
||||
private val sideMargin: Float = 0f, // Positive value creates visible gap
|
||||
private val scaleFactor: Float = 0.95f
|
||||
) : ViewPager2.PageTransformer {
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_MAX_ROTATE = 15.0f
|
||||
private const val DEFAULT_CENTER = 0.5f
|
||||
}
|
||||
|
||||
override fun transformPage(view: View, position: Float) {
|
||||
val scale = if (abs(position) <= 1) {
|
||||
(1 - abs(position)) * (1 - scaleFactor) + scaleFactor
|
||||
} else {
|
||||
scaleFactor
|
||||
}
|
||||
|
||||
when {
|
||||
position < -1 -> {
|
||||
// [-Infinity,-1)
|
||||
view.rotation = maxRotate * -1
|
||||
view.pivotX = view.width.toFloat()
|
||||
view.pivotY = view.height.toFloat()
|
||||
view.scaleX = scaleFactor
|
||||
view.scaleY = scaleFactor
|
||||
view.translationX = -sideMargin * 2
|
||||
}
|
||||
position <= 1 -> { // [-1,1]
|
||||
// Calculate direction (left or right)
|
||||
val direction = if (position < 0) -1f else 1f
|
||||
|
||||
view.pivotX = if (position < 0) {
|
||||
view.width * (DEFAULT_CENTER + DEFAULT_CENTER * -position)
|
||||
} else {
|
||||
view.width * DEFAULT_CENTER * (1 - position)
|
||||
}
|
||||
|
||||
view.pivotY = view.height.toFloat()
|
||||
view.rotation = maxRotate * position
|
||||
view.scaleX = scale
|
||||
view.scaleY = scale
|
||||
view.translationX = (sideMargin * position) + (sideMargin * direction)
|
||||
}
|
||||
else -> {
|
||||
// (1,+Infinity]
|
||||
view.rotation = maxRotate
|
||||
view.pivotX = 0f
|
||||
view.pivotY = view.height.toFloat()
|
||||
view.scaleX = scaleFactor
|
||||
view.scaleY = scaleFactor
|
||||
view.translationX = sideMargin * 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun abs(value: Float): Float {
|
||||
return if (value < 0) -value else value
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
|
||||
|
||||
class ScrollTextView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : AppCompatTextView(context, attrs, defStyleAttr) {
|
||||
|
||||
private var animator: ObjectAnimator? = null
|
||||
private var currentIndex = 0
|
||||
private var dataList: MutableList<String> = mutableListOf()
|
||||
|
||||
fun setData(data: MutableList<String>) {
|
||||
dataList.clear()
|
||||
dataList = data
|
||||
currentIndex = 0
|
||||
animator?.cancel()
|
||||
animator?.removeAllListeners()
|
||||
if (dataList.isNotEmpty()) {
|
||||
animateText(dataList[currentIndex])
|
||||
startSwitchAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startSwitchAnimation() {
|
||||
animator = ObjectAnimator.ofFloat(this, "alpha", 1f, 0f)
|
||||
animator?.duration = 500
|
||||
animator?.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
super.onAnimationEnd(animation)
|
||||
if (dataList.size != 0) {
|
||||
currentIndex = (currentIndex + 1) % dataList.size
|
||||
text = dataList[currentIndex]
|
||||
animateText(dataList[currentIndex])
|
||||
animate().alpha(1f).start()
|
||||
startSwitchAnimation()
|
||||
}
|
||||
}
|
||||
})
|
||||
animator?.startDelay = 4500
|
||||
animator?.start()
|
||||
}
|
||||
|
||||
private fun animateText(text: String) {
|
||||
animate().cancel()
|
||||
alpha = 0f
|
||||
this.text = text
|
||||
animate().alpha(1f).setDuration(500).start()
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
animator?.cancel()
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.jia.er.nebuluxe.app.ui
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.Gravity
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
|
||||
class UnFavoriteDialog(context: Context) : Dialog(context) {
|
||||
|
||||
init {
|
||||
init()
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
setContentView(R.layout.dialog_un_collection)
|
||||
|
||||
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
window?.setLayout(
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
window?.setGravity(Gravity.CENTER)
|
||||
setCancelable(true)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.jia.er.nebuluxe.app.utils
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.ui.UnFavoriteDialog
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
|
||||
|
||||
object DialogUtils {
|
||||
|
||||
|
||||
fun unFavoriteDialog(
|
||||
context: Context,
|
||||
short_play_id: Int,
|
||||
video_id: Int,
|
||||
genresViewModel: MainViewModel
|
||||
) {
|
||||
val exampleUnFavoriteDialog = UnFavoriteDialog(context)
|
||||
val tvThinkAgain =
|
||||
exampleUnFavoriteDialog.findViewById<AppCompatTextView>(R.id.example_tv_think_again)
|
||||
val iv_close_notification =
|
||||
exampleUnFavoriteDialog.findViewById<AppCompatImageView>(R.id.iv_close_notification)
|
||||
iv_close_notification.setOnClickListener { exampleUnFavoriteDialog.dismiss() }
|
||||
tvThinkAgain.setOnClickListener {
|
||||
singleClick {
|
||||
genresViewModel.doCancelCollect(short_play_id, video_id)
|
||||
}
|
||||
exampleUnFavoriteDialog.dismiss()
|
||||
}
|
||||
exampleUnFavoriteDialog.show()
|
||||
}
|
||||
}
|
104
app/src/main/java/com/jia/er/nebuluxe/app/utils/Memory.kt
Normal file
104
app/src/main/java/com/jia/er/nebuluxe/app/utils/Memory.kt
Normal file
@ -0,0 +1,104 @@
|
||||
package com.jia.er.nebuluxe.app.utils
|
||||
|
||||
import com.jia.er.nebuluxe.app.data.PayReq
|
||||
import com.jia.er.nebuluxe.app.data.UserInfoRes
|
||||
import com.google.gson.Gson
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.basics.Constants.CONSTANTS_SEARCH_STRINGExample
|
||||
import com.tencent.mmkv.MMKV
|
||||
|
||||
|
||||
object Memory {
|
||||
|
||||
private var mmkv: MMKV? = null
|
||||
|
||||
|
||||
fun getMMKV(): MMKV {
|
||||
if (mmkv == null) {
|
||||
mmkv = MMKV.mmkvWithID("nebuluxe")
|
||||
}
|
||||
return mmkv!!
|
||||
}
|
||||
|
||||
fun saveUserInfo(infoRes: UserInfoRes?) {
|
||||
val toJson = Gson().toJson(infoRes)
|
||||
getMMKV()
|
||||
.putString(Constants.CONSTANTS_User_STRING, toJson)
|
||||
}
|
||||
|
||||
fun getUserInfo(): UserInfoRes? {
|
||||
val string = getMMKV().getString(Constants.CONSTANTS_User_STRING, "{}")
|
||||
if ("{}" == string) {
|
||||
return UserInfoRes.createWithDefaults()
|
||||
}
|
||||
return Gson().fromJson(string, UserInfoRes::class.java)
|
||||
}
|
||||
|
||||
fun saveSearchString(search: String) {
|
||||
val strings = getSearch()
|
||||
if (!strings.contains(search)) {
|
||||
strings.add(0, search)
|
||||
}
|
||||
val toJson = Gson().toJson(strings)
|
||||
getMMKV().putString(CONSTANTS_SEARCH_STRINGExample, toJson)
|
||||
}
|
||||
|
||||
fun getSearch(): MutableList<String> {
|
||||
val string = getMMKV().getString(CONSTANTS_SEARCH_STRINGExample, "[]")
|
||||
return Gson().fromJson(string, Array<String>::class.java).toMutableList()
|
||||
}
|
||||
|
||||
fun isTourist(): Boolean {
|
||||
return getUserInfo()?.is_tourist == true
|
||||
}
|
||||
|
||||
fun getCustomId(): String {
|
||||
return getUserInfo()?.customer_id.toString()
|
||||
}
|
||||
|
||||
fun getAllCoin(): Int {
|
||||
if (getUserInfo() == null) {
|
||||
return 0
|
||||
}
|
||||
return getUserInfo()?.coin_left_total!! + getUserInfo()?.send_coin_left_total!!
|
||||
}
|
||||
|
||||
fun isVip(): Boolean {
|
||||
return getUserInfo()?.is_vip == true
|
||||
}
|
||||
|
||||
fun saveOrder(payReq: PayReq) {
|
||||
val list = getOrder()
|
||||
if (!list.contains(payReq)) {
|
||||
list.add(payReq)
|
||||
}
|
||||
val toJson = Gson().toJson(list)
|
||||
getMMKV().putString(Constants.CONSTANTS_examplePayReq, toJson)
|
||||
}
|
||||
|
||||
fun removeOrderString(order: String) {
|
||||
val updatedList = getOrder().filterNot { it.order_code == order }
|
||||
getMMKV().putString(
|
||||
Constants.CONSTANTS_examplePayReq,
|
||||
Gson().toJson(updatedList)
|
||||
)
|
||||
}
|
||||
|
||||
fun getOrder(): MutableList<PayReq> {
|
||||
try {
|
||||
val string = getMMKV().getString(Constants.CONSTANTS_examplePayReq, "[]")
|
||||
if (null != string && "[]" != string) {
|
||||
return Gson().fromJson(string, Array<PayReq>::class.java).toMutableList()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
getMMKV().putString(
|
||||
Constants.CONSTANTS_examplePayReq,
|
||||
"[]"
|
||||
)
|
||||
}
|
||||
return mutableListOf()
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.jia.er.nebuluxe.app.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import com.jia.er.nebuluxe.app.basics.MyApplication
|
||||
|
||||
object PackageUtils {
|
||||
|
||||
fun getPackageName(): String {
|
||||
var packageName = ""
|
||||
try {
|
||||
packageName = MyApplication.context.packageName
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return packageName
|
||||
}
|
||||
|
||||
fun getPackageVersion(context: Context): String {
|
||||
var packageVersion = ""
|
||||
try {
|
||||
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
||||
packageVersion = packageInfo.versionName.toString()
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return packageVersion
|
||||
}
|
||||
|
||||
fun getPackageVersionCode(context: Context): Int {
|
||||
var versionCode = 0
|
||||
try {
|
||||
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
||||
versionCode = packageInfo.versionCode
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return versionCode
|
||||
}
|
||||
}
|
183
app/src/main/java/com/jia/er/nebuluxe/app/utils/Toast.kt
Normal file
183
app/src/main/java/com/jia/er/nebuluxe/app/utils/Toast.kt
Normal file
@ -0,0 +1,183 @@
|
||||
package com.jia.er.nebuluxe.app.utils
|
||||
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.LinearGradient
|
||||
import android.graphics.Shader
|
||||
import android.graphics.Typeface
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import com.google.android.gms.ads.identifier.AdvertisingIdClient
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.basics.Constants.ONE_DAY_IN_MILLIS
|
||||
import com.jia.er.nebuluxe.app.basics.MyApplication
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import kotlin.math.tan
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
fun toast(text: String) {
|
||||
handler.post {
|
||||
Toast.makeText(MyApplication.context, text, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun formatNumber(num: Int): String {
|
||||
return when {
|
||||
num >= 1000000 -> "${(num / 1000000.0).format(1)}M"
|
||||
num >= 1000 -> "${(num / 1000.0).format(1)}K"
|
||||
else -> num.toString()
|
||||
}
|
||||
}
|
||||
|
||||
fun formatNumberByLong(num: Long): String {
|
||||
return when {
|
||||
num >= 1000000 -> "${(num / 1000000.0).format(1)}M"
|
||||
num >= 1000 -> "${(num / 1000.0).format(1)}K"
|
||||
else -> num.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun Double.format(digits: Int) = "%.${digits}f".format(this)
|
||||
|
||||
|
||||
var lastClickTime = 0L
|
||||
fun singleClick(during: Long = 500L, callBack: () -> Unit) {
|
||||
val now = Date().time
|
||||
if (now - lastClickTime > during) {
|
||||
callBack()
|
||||
}
|
||||
lastClickTime = now
|
||||
}
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
fun transToString(time: Long): String {
|
||||
val date = Date(time * 1000)
|
||||
return SimpleDateFormat("yyyy-MM-dd").format(date)
|
||||
}
|
||||
|
||||
fun getUserAgent(): String {
|
||||
return System.getProperty("http.agent") ?: ""
|
||||
}
|
||||
|
||||
fun formatTimestamp(timestampInSeconds: Long): String {
|
||||
val minutes = timestampInSeconds / 60
|
||||
val seconds = timestampInSeconds % 60
|
||||
return String.format("%02d:%02d", minutes, seconds)
|
||||
}
|
||||
|
||||
|
||||
fun SpannableStringBuilder.appendWithStyle(
|
||||
text: String,
|
||||
color: Int = Color.BLACK,
|
||||
isBold: Boolean = false
|
||||
): SpannableStringBuilder {
|
||||
val start = this.length
|
||||
append(text)
|
||||
val end = this.length
|
||||
setSpan(ForegroundColorSpan(color), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
setSpan(
|
||||
StyleSpan(if (isBold) Typeface.BOLD else Typeface.NORMAL),
|
||||
start,
|
||||
end,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
||||
fun shouldShowNotification(): Boolean {
|
||||
val lastPopupTime =
|
||||
Memory.getMMKV().getLong(Constants.CONSTANTS_PREF_LAST_POPUP_TIME_Notification, 0)
|
||||
val currentTime = System.currentTimeMillis()
|
||||
|
||||
return currentTime - lastPopupTime > ONE_DAY_IN_MILLIS
|
||||
}
|
||||
|
||||
fun getAdvertisingIdInfo(context: Context): String {
|
||||
try {
|
||||
return AdvertisingIdClient.getAdvertisingIdInfo(context).id.toString()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
fun AppCompatTextView.applyTextSkew(angle: Float) {
|
||||
val skewX = tan(Math.toRadians(angle.toDouble())).toFloat()
|
||||
paint.textSkewX = skewX
|
||||
post {
|
||||
val extraWidth = (height * skewX).toInt()
|
||||
layoutParams.width = measuredWidth + extraWidth + paddingEnd
|
||||
requestLayout()
|
||||
}
|
||||
}
|
||||
|
||||
fun dpToPx(dp: Int, context: Context): Int {
|
||||
return (dp * context.resources.displayMetrics.density).toInt()
|
||||
}
|
||||
fun dpToPxByFloat(dp: Int, context: Context): Float {
|
||||
return (dp * context.resources.displayMetrics.density)
|
||||
}
|
||||
|
||||
fun upError(
|
||||
event_name: String,
|
||||
viewModel: MainViewModel,
|
||||
error_msg: String,
|
||||
event_key: String,
|
||||
type: String? = "",
|
||||
pay_data: String? = "",
|
||||
short_play_id: Int,
|
||||
short_play_video_id: Int
|
||||
) {
|
||||
val map = HashMap<String, Any>()
|
||||
map.put("error_msg", error_msg)
|
||||
map.put("userId", Memory.getCustomId())
|
||||
map.put("event_name", event_name)
|
||||
map.put("event_key", event_key)
|
||||
if (pay_data?.isNotEmpty() == true) {
|
||||
map.put("pay_data", pay_data)
|
||||
}
|
||||
if (type?.isNotEmpty() == true) {
|
||||
map.put("type", type)
|
||||
}
|
||||
map.put("short_play_id", short_play_id)
|
||||
map.put("short_play_video_id", short_play_video_id)
|
||||
viewModel.upError(map)
|
||||
}
|
||||
|
||||
fun setLeftRightGradient(textView: TextView, colors: IntArray) {
|
||||
textView.paint.shader = LinearGradient(
|
||||
0f, 0f,
|
||||
textView.textSize * textView.text.length, 0f,
|
||||
colors,
|
||||
null,
|
||||
Shader.TileMode.CLAMP
|
||||
)
|
||||
textView.invalidate()
|
||||
}
|
||||
|
||||
fun setUpDownGradient(textView: TextView, colors: IntArray) {
|
||||
textView.paint.shader = LinearGradient(
|
||||
0f, 0f,
|
||||
0f, textView.textSize,
|
||||
colors,
|
||||
null,
|
||||
Shader.TileMode.CLAMP
|
||||
)
|
||||
textView.invalidate()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,158 @@
|
||||
package com.jia.er.nebuluxe.app.video
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.LoadControl
|
||||
import androidx.media3.ui.PlayerView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.DetailsRecommendRes
|
||||
import com.youth.banner.adapter.BannerAdapter
|
||||
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
class NewRecommendBannerAdapter(items: List<DetailsRecommendRes.Item?>?, context: Context) :
|
||||
BannerAdapter<DetailsRecommendRes.Item?, NewRecommendBannerAdapter.BannerViewHolder?>(items) {
|
||||
var currentPlayingPosition = -1
|
||||
private var context: Context? = null
|
||||
val playerMap = mutableMapOf<Int, ExoPlayer>()
|
||||
val imageMap = mutableMapOf<Int, AppCompatImageView>()
|
||||
|
||||
init {
|
||||
this.context = context
|
||||
}
|
||||
|
||||
override fun onCreateHolder(parent: ViewGroup, viewType: Int): BannerViewHolder {
|
||||
val view: View = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.new_detail_player_banner_view, parent, false)
|
||||
view.layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
return BannerViewHolder(view)
|
||||
}
|
||||
|
||||
|
||||
override fun onBindView(
|
||||
holder: BannerViewHolder?,
|
||||
data: DetailsRecommendRes.Item?,
|
||||
position: Int,
|
||||
size: Int
|
||||
) {
|
||||
val playerView = holder?.view?.findViewById<PlayerView>(R.id.player_view)
|
||||
val imageView = holder?.view?.findViewById<AppCompatImageView>(R.id.iv_cover)
|
||||
if (null != imageView) {
|
||||
Glide.with(context!!)
|
||||
.load(data?.image_url)
|
||||
.placeholder(R.drawable.iv_placeholder_v)
|
||||
.into(imageView)
|
||||
}
|
||||
imageView?.visibility = View.VISIBLE
|
||||
imageView?.let { imageMap[position] = it }
|
||||
var exoPlayer = playerMap[position]
|
||||
if (exoPlayer == null) {
|
||||
val mediaItem = MediaItem.fromUri(Uri.parse(data?.video_url))
|
||||
exoPlayer = ExoPlayer.Builder(context!!)
|
||||
.setRenderersFactory(
|
||||
DefaultRenderersFactory(context!!).setEnableDecoderFallback(
|
||||
true
|
||||
)
|
||||
)
|
||||
.setLoadControl(getLoadControl())
|
||||
.build().apply {
|
||||
setMediaItem(mediaItem)
|
||||
prepare()
|
||||
}
|
||||
playerMap[position] = exoPlayer
|
||||
}
|
||||
playerView?.player = exoPlayer
|
||||
exoPlayer.let { player ->
|
||||
|
||||
player.addListener(object : Player.Listener {
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
super.onPlaybackStateChanged(playbackState)
|
||||
when (playbackState) {
|
||||
Player.STATE_READY -> {
|
||||
if (position == currentPlayingPosition) {
|
||||
player.play()
|
||||
imageView?.visibility = View.INVISIBLE
|
||||
} else {
|
||||
player.playWhenReady = false
|
||||
player.pause()
|
||||
}
|
||||
}
|
||||
|
||||
Player.STATE_ENDED -> {
|
||||
player.seekTo(0)
|
||||
player.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
super.onPlayerError(error)
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
imageView?.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLoadControl(): LoadControl {
|
||||
return androidx.media3.exoplayer.DefaultLoadControl.Builder()
|
||||
.setBufferDurationsMs(
|
||||
2500, 15000, 1500, 2000
|
||||
)
|
||||
.setTargetBufferBytes(50 * 1024 * 1024)
|
||||
.setPrioritizeTimeOverSizeThresholds(false)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
inner class BannerViewHolder(var view: View) : RecyclerView.ViewHolder(
|
||||
view
|
||||
)
|
||||
|
||||
|
||||
fun resumeCurrentPlayer() {
|
||||
playerMap[currentPlayingPosition]?.let { player ->
|
||||
if (player.playbackState != Player.STATE_ENDED) {
|
||||
player.play()
|
||||
imageMap[currentPlayingPosition]?.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun pauseAllPlayers() {
|
||||
playerMap.values.forEach { player ->
|
||||
if (player.isPlaying) {
|
||||
player.pause()
|
||||
}
|
||||
}
|
||||
imageMap[currentPlayingPosition]?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun releaseAllPlayers() {
|
||||
playerMap.values.forEach { player ->
|
||||
player.stop()
|
||||
player.release()
|
||||
}
|
||||
playerMap.clear()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,820 @@
|
||||
package com.jia.er.nebuluxe.app.video
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.SeekBar
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.AppCompatSeekBar
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.datasource.DataSource
|
||||
import androidx.media3.datasource.DefaultDataSourceFactory
|
||||
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.hls.HlsMediaSource
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.exoplayer.source.ProgressiveMediaSource
|
||||
import androidx.media3.ui.PlayerView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.PagerSnapHelper
|
||||
import com.blankj.utilcode.util.ViewUtils
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.gson.Gson
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.BaseActivity
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.data.DetailsRecommendRes
|
||||
import com.jia.er.nebuluxe.app.data.MainDataHis
|
||||
import com.jia.er.nebuluxe.app.data.PlayerDetailDataRes
|
||||
import com.jia.er.nebuluxe.app.data.UploadHistoryReq
|
||||
import com.jia.er.nebuluxe.app.databinding.ActivityPlayDetailBinding
|
||||
import com.jia.er.nebuluxe.app.net.MainViewModel
|
||||
import com.jia.er.nebuluxe.app.ui.FfmpegRenderersFactory
|
||||
import com.jia.er.nebuluxe.app.ui.LoadingLine
|
||||
import com.jia.er.nebuluxe.app.ui.OnSnapHelperCurrentListener
|
||||
import com.jia.er.nebuluxe.app.ui.RecyclerViewScrollerDetection
|
||||
import com.jia.er.nebuluxe.app.utils.DialogUtils
|
||||
import com.jia.er.nebuluxe.app.utils.Memory
|
||||
import com.jia.er.nebuluxe.app.utils.appendWithStyle
|
||||
import com.jia.er.nebuluxe.app.utils.formatTimestamp
|
||||
import com.jia.er.nebuluxe.app.utils.singleClick
|
||||
import com.jia.er.nebuluxe.app.utils.toast
|
||||
import com.youth.banner.listener.OnPageChangeListener
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
class PlayerDetailActivity : BaseActivity<ActivityPlayDetailBinding>(),
|
||||
OnSnapHelperCurrentListener, SeriesDialogFragment.SeriesCallBack {
|
||||
private var builder: ExoPlayer.Builder? = null
|
||||
private var player: ExoPlayer? = null
|
||||
private val pagerSnapHelper = PagerSnapHelper()
|
||||
private val recyclerViewScrollerDetection = RecyclerViewScrollerDetection()
|
||||
private var playerDetailAdapter: PlayerDetailAdapter? = null
|
||||
private var playerView: PlayerView? = null
|
||||
private var currentView: View? = null
|
||||
private var loadingLine: LoadingLine? = null
|
||||
private var tvName: AppCompatTextView? = null
|
||||
private var tvTime: AppCompatTextView? = null
|
||||
private var tvEpTotal: AppCompatTextView? = null
|
||||
private var tvCollectionNum: AppCompatTextView? = null
|
||||
private var play: AppCompatImageView? = null
|
||||
private var collection: AppCompatImageView? = null
|
||||
private var ivIconPlayer: AppCompatImageView? = null
|
||||
private var ivCover: AppCompatImageView? = null
|
||||
private var ivBackController: AppCompatImageView? = null
|
||||
private var exampleSeekbarPlayerController: AppCompatSeekBar? = null
|
||||
private var exampleProgressJob: Job? = null
|
||||
private var isDragging = false
|
||||
private var isPlaying = false
|
||||
private var shortVideoId: Int = 0
|
||||
private var dataRes: PlayerDetailDataRes.Episode? = null
|
||||
private var currentPosition = 0
|
||||
private val mViewModel by lazy { ViewModelProvider(this)[MainViewModel::class.java] }
|
||||
private var activityId: Int = 0
|
||||
private var progress: Long = 0L
|
||||
private var seek = true
|
||||
private var needRestart: Boolean = false
|
||||
private var startTime: Long = 0
|
||||
private var recommendBannerAdapter: NewRecommendBannerAdapter? = null
|
||||
private var revolution = ""
|
||||
private var needRefresh: Boolean = false
|
||||
private var payPosition = 0
|
||||
private var isCanPlay = false
|
||||
// private var isLock = false
|
||||
private var exampleSeriesDialogFragment: SeriesDialogFragment? = null
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
override fun top() {
|
||||
EventBus.getDefault().register(this)
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
showLoading()
|
||||
startTime = System.currentTimeMillis()
|
||||
shortVideoId = intent.getIntExtra(Constants.CONSTANTS_short_play_id, 0)
|
||||
activityId = intent.getIntExtra(Constants.CONSTANTS_activity_id, 0)
|
||||
builder = ExoPlayer.Builder(this, FfmpegRenderersFactory(this))
|
||||
.setRenderersFactory(
|
||||
DefaultRenderersFactory(this).setEnableDecoderFallback(
|
||||
true
|
||||
)
|
||||
)
|
||||
player = builder?.build()
|
||||
playerView = ViewUtils.layoutId2View(R.layout.include_detail_player_view) as PlayerView
|
||||
playerView?.player = player
|
||||
loadingLine = playerView?.findViewById(R.id.load_line)
|
||||
tvName = playerView?.findViewById(R.id.example_tv_title_player_controller)
|
||||
tvTime = playerView?.findViewById(R.id.tv_player_seek_time)
|
||||
tvEpTotal = playerView?.findViewById(R.id.tv_ep_total)
|
||||
tvCollectionNum = playerView?.findViewById(R.id.example_tv_collection_num_controller)
|
||||
collection = playerView?.findViewById(R.id.example_iv_collection_controller)
|
||||
play = playerView?.findViewById(R.id.example_iv_play_player_controller)
|
||||
ivIconPlayer = playerView?.findViewById(R.id.iv_icon_player)
|
||||
ivBackController = playerView?.findViewById(R.id.iv_back_controller)
|
||||
exampleSeekbarPlayerController =
|
||||
playerView?.findViewById(R.id.example_seekBar_player_controller)
|
||||
play?.setOnClickListener {
|
||||
singleClick {
|
||||
if (isPlaying) {
|
||||
pause()
|
||||
} else {
|
||||
play()
|
||||
}
|
||||
}
|
||||
}
|
||||
ivBackController?.setOnClickListener {
|
||||
singleClick {
|
||||
handleCustomLogic()
|
||||
}
|
||||
}
|
||||
player?.addListener(object : Player.Listener {
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
super.onPlaybackStateChanged(playbackState)
|
||||
when (playbackState) {
|
||||
Player.STATE_BUFFERING -> {
|
||||
loadingLine?.visibility = View.VISIBLE
|
||||
loadingLine?.startAnimation()
|
||||
ivIconPlayer?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
Player.STATE_READY -> {
|
||||
// if (!isLock) {
|
||||
if (isCanPlay) {
|
||||
if (seek && progress > 0) {
|
||||
player?.seekTo(progress)
|
||||
seek = false
|
||||
}
|
||||
canPlay()
|
||||
}
|
||||
// } else {
|
||||
// loadingLine?.endAnimation()
|
||||
// loadingLine?.visibility = View.INVISIBLE
|
||||
// ivCover = currentView?.findViewById(R.id.iv_icon)
|
||||
// ivCover?.visibility = View.INVISIBLE
|
||||
// ivIconPlayer?.visibility = View.INVISIBLE
|
||||
// pause()
|
||||
// }
|
||||
}
|
||||
|
||||
Player.STATE_ENDED -> {
|
||||
needRestart = true
|
||||
uploadSeconds()
|
||||
val plus = currentPosition.plus(1)
|
||||
recyclerViewScrollerDetection.isFirstAttached = false
|
||||
binding.rvDetail.scrollToPosition(plus)
|
||||
}
|
||||
|
||||
Player.STATE_IDLE -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
super.onPlayerError(error)
|
||||
ivIconPlayer?.visibility = View.VISIBLE
|
||||
toast(getString(R.string.network_error))
|
||||
}
|
||||
})
|
||||
collection?.setOnClickListener {
|
||||
singleClick {
|
||||
doCollect()
|
||||
}
|
||||
}
|
||||
tvEpTotal?.setOnClickListener {
|
||||
singleClick {
|
||||
exampleSeriesDialogFragment = SeriesDialogFragment()
|
||||
val bundle = Bundle()
|
||||
dataRes?.episode?.let { it1 ->
|
||||
bundle.putInt(
|
||||
Constants.Constants_Episodes_Series_Data_currentPositionExample,
|
||||
it1
|
||||
)
|
||||
}
|
||||
bundle.putParcelable(
|
||||
Constants.Constants_Episodes_Series_DataExample,
|
||||
dataRes?.shortPlayInfo
|
||||
)
|
||||
bundle.putParcelableArrayList(
|
||||
Constants.Constants_Episodes_Series_Data_ListExample,
|
||||
playerDetailAdapter?.items?.let { it1 -> ArrayList(it1) }
|
||||
)
|
||||
exampleSeriesDialogFragment?.seriesCallBack = this
|
||||
exampleSeriesDialogFragment?.arguments = bundle
|
||||
exampleSeriesDialogFragment?.show(
|
||||
supportFragmentManager,
|
||||
"SeriesDialogFragment"
|
||||
)
|
||||
}
|
||||
}
|
||||
mViewModel.getVideoDetails(
|
||||
shortVideoId,
|
||||
0,
|
||||
activityId,
|
||||
revolution,
|
||||
null
|
||||
)
|
||||
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
if (handleCustomLogic()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
// binding.tvLockEpisode.setOnClickListener {
|
||||
// singleClick {
|
||||
// if (currentPosition > 0) {
|
||||
// val beforeItem =
|
||||
// playerDetailAdapter?.getItem(currentPosition - 1) as PlayerDetailDataRes.Episode
|
||||
// if (beforeItem.is_lock && !Memory.isVip()) {
|
||||
// toast(getString(R.string.prequel_before))
|
||||
// return@singleClick
|
||||
// }
|
||||
// }
|
||||
// val allCoin = Memory.getAllCoin()
|
||||
// val coins = dataRes?.coins!!
|
||||
// if (allCoin >= coins) {
|
||||
// showLoading()
|
||||
// dataRes?.short_play_id?.let { it1 ->
|
||||
// dataRes?.short_play_video_id?.let { it2 ->
|
||||
// mViewModel.doBuyVideo(
|
||||
// it1,
|
||||
// it2
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// rechargeDialog(dataRes)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
binding?.viewVideoRecommend?.ivCloseRecommend?.setOnClickListener { finish() }
|
||||
binding?.viewVideoRecommend?.tvWatchNowRecommend?.setOnClickListener {
|
||||
singleClick {
|
||||
val data = recommendBannerAdapter?.getData(recommendBannerPosition)
|
||||
watchNow(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doCollect() {
|
||||
if (dataRes?.shortPlayInfo?.is_collect == true) {
|
||||
dataRes?.short_play_id?.let { it1 ->
|
||||
dataRes?.short_play_video_id?.let { it2 ->
|
||||
DialogUtils.unFavoriteDialog(
|
||||
this,
|
||||
it1,
|
||||
it2,
|
||||
mViewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dataRes?.short_play_id?.let {
|
||||
dataRes?.short_play_video_id.let { it1 ->
|
||||
if (it1 != null) {
|
||||
mViewModel.doCollect(
|
||||
it, it1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun canPlay() {
|
||||
loadingLine?.endAnimation()
|
||||
loadingLine?.visibility = View.INVISIBLE
|
||||
ivCover = currentView?.findViewById(R.id.iv_icon)
|
||||
play()
|
||||
setProgress()
|
||||
ivCover?.visibility = View.INVISIBLE
|
||||
ivIconPlayer?.visibility = View.INVISIBLE
|
||||
}
|
||||
// private var storeDialogFragment: StoreDialogFragment? = null
|
||||
// private fun rechargeDialog(dataRes: PlayerDetailDataRes.Episode?) {
|
||||
// try {
|
||||
// storeDialogFragment =
|
||||
// StoreDialogFragment()
|
||||
// val bundle = Bundle()
|
||||
// bundle.putParcelable(Constants.CONSTANTS_Episode, dataRes)
|
||||
// storeDialogFragment?.setStyle(DialogFragment.STYLE_NO_FRAME, 0)
|
||||
// storeDialogFragment?.arguments = bundle
|
||||
// storeDialogFragment?.show(
|
||||
// supportFragmentManager,
|
||||
// "StoreDialogFragment"
|
||||
// )
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun watchNow(
|
||||
data: DetailsRecommendRes.Item?
|
||||
) {
|
||||
binding?.viewVideoRecommend?.exampleBannerRecommend?.postDelayed({
|
||||
if (data?.short_play_id != null) {
|
||||
shortVideoId = data.short_play_id
|
||||
recommendBannerAdapter?.releaseAllPlayers()
|
||||
detailRefresh()
|
||||
}
|
||||
}, 300)
|
||||
binding?.viewVideoRecommend?.root?.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
private fun handleCustomLogic(): Boolean {
|
||||
if (binding?.viewVideoRecommend?.root?.visibility == View.INVISIBLE) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
val duration = currentTime - startTime
|
||||
if (duration > 3000) {
|
||||
mViewModel.getDetailsRecommand()
|
||||
binding.root.postDelayed({
|
||||
pause()
|
||||
player?.stop()
|
||||
}, 500)
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private var recommendBannerPosition = 0
|
||||
|
||||
override fun center() {
|
||||
mViewModel.getDetailsRecommandData.observe(this) {
|
||||
if (it != null) {
|
||||
if (it.data?.list?.isNotEmpty() == true) {
|
||||
binding.viewVideoRecommend.root.visibility = View.VISIBLE
|
||||
binding.viewVideoRecommend.bottom.setOnClickListener { }
|
||||
recommendBannerAdapter =
|
||||
NewRecommendBannerAdapter(it.data.list, this)
|
||||
binding?.viewVideoRecommend?.exampleBannerRecommend?.setBannerGalleryEffect(
|
||||
52,
|
||||
12
|
||||
)
|
||||
binding?.viewVideoRecommend?.exampleBannerRecommend?.setAdapter(
|
||||
recommendBannerAdapter
|
||||
)
|
||||
val i = it.data.list.size / 2
|
||||
binding?.viewVideoRecommend?.exampleBannerRecommend?.setCurrentItem(
|
||||
i,
|
||||
false
|
||||
)
|
||||
recommendBannerAdapter?.currentPlayingPosition = i
|
||||
recommendBannerPosition = i
|
||||
recommendBannerAdapter?.resumeCurrentPlayer()
|
||||
binding?.viewVideoRecommend?.exampleBannerRecommend?.addOnPageChangeListener(
|
||||
object :
|
||||
OnPageChangeListener {
|
||||
override fun onPageScrolled(
|
||||
position: Int,
|
||||
positionOffset: Float,
|
||||
positionOffsetPixels: Int
|
||||
) {
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
override fun onPageSelected(position: Int) {
|
||||
recommendBannerPosition = position
|
||||
recommendBannerAdapter?.pauseAllPlayers()
|
||||
recommendBannerAdapter?.currentPlayingPosition = position
|
||||
recommendBannerAdapter?.playerMap?.get(position)?.let { newPlayer ->
|
||||
recommendBannerAdapter?.resumeCurrentPlayer()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
mViewModel.infoData.observe(this) {
|
||||
if (it != null) {
|
||||
it.data?.let { it1 ->
|
||||
Memory.saveUserInfo(it1)
|
||||
if (needRefresh) {
|
||||
detailRefresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// mViewModel.buy_videoData.observe(this) {
|
||||
// if (it != null) {
|
||||
// when (it.data?.status) {
|
||||
// "not_enough" -> {
|
||||
// rechargeDialog(dataRes)
|
||||
// hideLoading()
|
||||
// }
|
||||
//
|
||||
// "success" -> {
|
||||
// needRefresh = false
|
||||
// mViewModel.getInfo()
|
||||
// toast(getString(R.string.success))
|
||||
// val get = playerDetailAdapter?.items?.get(currentPosition)
|
||||
// get?.is_lock = false
|
||||
// collection?.isEnabled = true
|
||||
// tvEpTotal?.isEnabled = true
|
||||
// play?.isEnabled = true
|
||||
// binding.tvLockEpisode.postDelayed({
|
||||
// binding.tvLockEpisode.visibility = View.INVISIBLE
|
||||
// binding.clLock.visibility = View.INVISIBLE
|
||||
// canPlay()
|
||||
// hideLoading()
|
||||
// }, 1000)
|
||||
// }
|
||||
//
|
||||
// else -> {
|
||||
// hideLoading()
|
||||
// toast(it.data?.status.toString())
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// hideLoading()
|
||||
// toast(getString(R.string.network_error))
|
||||
// }
|
||||
// }
|
||||
mViewModel.videoDetailsData.observe(this) { it ->
|
||||
if (it != null) {
|
||||
playerDetailAdapter = PlayerDetailAdapter()
|
||||
val layoutManager =
|
||||
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
binding?.rvDetail?.layoutManager = layoutManager
|
||||
binding?.rvDetail?.adapter = playerDetailAdapter
|
||||
binding?.rvDetail?.isNestedScrollingEnabled = false
|
||||
pagerSnapHelper.attachToRecyclerView(binding?.rvDetail)
|
||||
recyclerViewScrollerDetection.setCurrentListener(this)
|
||||
recyclerViewScrollerDetection.attachToSnapHelper(pagerSnapHelper)
|
||||
binding?.rvDetail?.let { it1 ->
|
||||
recyclerViewScrollerDetection.addOnScrollListener(
|
||||
it1
|
||||
)
|
||||
}
|
||||
it.data?.episodeList?.forEach { it1 ->
|
||||
it1.shortPlayInfo = it.data.shortPlayInfo
|
||||
}
|
||||
ivIconPlayer?.let { it1 ->
|
||||
Glide.with(this).load(it.data?.shortPlayInfo?.image_url)
|
||||
.into(it1)
|
||||
}
|
||||
playerDetailAdapter?.submitList(it.data?.episodeList)
|
||||
if (needRefresh) {
|
||||
recyclerViewScrollerDetection.isFirstAttached = false
|
||||
binding.rvDetail.scrollToPosition(payPosition)
|
||||
needRefresh = false
|
||||
} else {
|
||||
if (it.data?.video_info != null) {
|
||||
if (it.data.video_info.episode > 1) {
|
||||
it.data.video_info.episode.minus(1)
|
||||
.let { it1 ->
|
||||
recyclerViewScrollerDetection.isFirstAttached = false
|
||||
binding.rvDetail.scrollToPosition(it1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hideLoading()
|
||||
} else {
|
||||
showNoDrama()
|
||||
toast(getString(R.string.network_error))
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
mViewModel.collectData.observe(this) {
|
||||
if (it != null) {
|
||||
collection?.setImageResource(R.drawable.iv_example_collection_h)
|
||||
dataRes?.shortPlayInfo?.collect_total =
|
||||
dataRes?.shortPlayInfo?.collect_total?.plus(1)!!
|
||||
tvCollectionNum?.text = dataRes?.shortPlayInfo?.collect_total.toString()
|
||||
dataRes?.shortPlayInfo?.is_collect = true
|
||||
EventBus.getDefault().post(Constants.CONSTANTS_collect_refresh)
|
||||
toast(getString(R.string.success))
|
||||
} else {
|
||||
toast(getString(R.string.network_error))
|
||||
}
|
||||
}
|
||||
mViewModel.cancelCollectData.observe(this) {
|
||||
if (it != null) {
|
||||
collection?.setImageResource(R.drawable.iv_example_collection_n)
|
||||
dataRes?.shortPlayInfo?.collect_total =
|
||||
dataRes?.shortPlayInfo?.collect_total?.minus(1)!!
|
||||
tvCollectionNum?.text = dataRes?.shortPlayInfo?.collect_total.toString()
|
||||
dataRes?.shortPlayInfo?.is_collect = false
|
||||
toast(getString(R.string.success))
|
||||
EventBus.getDefault().post(Constants.CONSTANTS_collect_refresh)
|
||||
} else {
|
||||
toast(getString(R.string.network_error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
private fun buildMediaSource(videoPath: String): MediaSource {
|
||||
val dataSourceFactory: DataSource.Factory =
|
||||
DefaultDataSourceFactory(this, "reelcrush")
|
||||
|
||||
return if (videoPath.endsWith(".m3u8")) {
|
||||
HlsMediaSource.Factory(dataSourceFactory)
|
||||
.createMediaSource(MediaItem.fromUri(Uri.parse(videoPath)))
|
||||
} else {
|
||||
ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||
.createMediaSource(MediaItem.fromUri(Uri.parse(videoPath)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
isCanPlay = false
|
||||
binding.root.postDelayed({ player?.pause() }, 300)
|
||||
recommendBannerAdapter?.pauseAllPlayers()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// if (!isLock && player?.isPlaying == false) {
|
||||
isCanPlay = true
|
||||
binding.root.postDelayed({ canPlay() }, 300)
|
||||
// }
|
||||
recommendBannerAdapter?.resumeCurrentPlayer()
|
||||
}
|
||||
|
||||
private fun setProgress() {
|
||||
exampleProgressJob?.cancel()
|
||||
val duration = player!!.duration
|
||||
exampleSeekbarPlayerController?.max = duration.toInt()
|
||||
exampleSeekbarPlayerController?.progress = player!!.currentPosition.toInt()
|
||||
exampleSeekbarPlayerController?.setOnSeekBarChangeListener(null)
|
||||
exampleProgressJob = lifecycleScope.launch {
|
||||
while (isActive) {
|
||||
if (!isDragging) {
|
||||
withContext(Dispatchers.Main) {
|
||||
exampleSeekbarPlayerController?.progress = player!!.currentPosition.toInt()
|
||||
}
|
||||
}
|
||||
delay(1000)
|
||||
}
|
||||
}
|
||||
|
||||
exampleSeekbarPlayerController?.setOnSeekBarChangeListener(object :
|
||||
SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
seekTo(progress)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar?) {
|
||||
tvTime?.visibility = FrameLayout.VISIBLE
|
||||
isDragging = true
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar?) {
|
||||
isDragging = false
|
||||
tvTime?.visibility = FrameLayout.INVISIBLE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun play() {
|
||||
player?.play()
|
||||
play?.setImageResource(R.drawable.iv_example_stop)
|
||||
isPlaying = true
|
||||
isDragging = false
|
||||
}
|
||||
|
||||
fun pause() {
|
||||
player?.pause()
|
||||
play?.setImageResource(R.drawable.iv_example_play)
|
||||
isPlaying = false
|
||||
isDragging = true
|
||||
}
|
||||
|
||||
private fun seekTo(progress: Int) {
|
||||
player?.seekTo(progress.toLong())
|
||||
seekTime()
|
||||
}
|
||||
|
||||
private fun seekTime() {
|
||||
val currentPosition = player!!.currentPosition
|
||||
val currentTime = formatTimestamp(currentPosition / 1000)
|
||||
val totalDuration = player!!.duration
|
||||
val totalTime = formatTimestamp(totalDuration / 1000)
|
||||
tvTime?.text = "$currentTime/$totalTime"
|
||||
}
|
||||
|
||||
override fun getViewBinding(): ActivityPlayDetailBinding {
|
||||
return ActivityPlayDetailBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
isCanPlay = false
|
||||
player?.stop()
|
||||
player?.release()
|
||||
// storeDialogFragment?.storeCallBack = null
|
||||
exampleSeriesDialogFragment?.seriesCallBack = null
|
||||
recommendBannerAdapter?.releaseAllPlayers()
|
||||
super.onDestroy()
|
||||
recyclerViewScrollerDetection.detachToSnapHelper()
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
EventBus.getDefault().unregister(this)
|
||||
System.gc()
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
override fun setActive(
|
||||
currentView: View?,
|
||||
position: Int,
|
||||
previousView: View?,
|
||||
previousPosition: Int
|
||||
) {
|
||||
seek = true
|
||||
isCanPlay = true
|
||||
this.currentView = currentView
|
||||
currentPosition = position
|
||||
val frameLayout = currentView?.findViewById<FrameLayout>(R.id.video)
|
||||
(playerView?.parent as FrameLayout?)?.removeView(playerView)
|
||||
frameLayout?.removeAllViews()
|
||||
frameLayout?.addView(playerView)
|
||||
playerView?.showController()
|
||||
dataRes = playerDetailAdapter?.getItem(position)
|
||||
progress = if (dataRes?.play_seconds?.isNotEmpty() == true) {
|
||||
dataRes?.play_seconds!!.toLong()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
// isLock = (dataRes?.is_lock == true && !Memory.isVip())
|
||||
// collection?.isEnabled = !isLock
|
||||
// tvEpTotal?.isEnabled = !isLock
|
||||
// play?.isEnabled = !isLock
|
||||
// binding.tvLockEpisode.visibility = if (isLock) View.VISIBLE else View.INVISIBLE
|
||||
// binding.clLock.visibility = if (isLock) View.VISIBLE else View.INVISIBLE
|
||||
// if (currentPosition > 0) {
|
||||
// playerDetailAdapter?.items?.get(currentPosition - 1)
|
||||
// ?.let { it2 ->
|
||||
// if (!it2.is_lock) {
|
||||
// binding.tvLockEpisode.text =
|
||||
// "Unlocking costs ".plus(dataRes?.coins).plus(" coins")
|
||||
// } else {
|
||||
// binding.tvLockEpisode.text = "Prev. locked"
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// binding.tvLockEpisode.text = "Unlocking costs ".plus(dataRes?.coins).plus(" coins")
|
||||
// }
|
||||
dataRes?.video_url?.let { buildMediaSource(it) }?.let { player?.setMediaSource(it) }
|
||||
player?.prepare()
|
||||
tvName?.text = dataRes?.shortPlayInfo?.name
|
||||
tvCollectionNum?.text = dataRes?.shortPlayInfo?.collect_total.toString()
|
||||
val builder = SpannableStringBuilder()
|
||||
builder.appendWithStyle(
|
||||
"Ep.".plus(dataRes?.episode),
|
||||
Color.parseColor("#FFDAA4"),
|
||||
isBold = true
|
||||
)
|
||||
.appendWithStyle(
|
||||
"/Ep.".plus(dataRes?.shortPlayInfo?.episode_total),
|
||||
Color.parseColor("#FFFFFF"),
|
||||
isBold = false
|
||||
)
|
||||
tvEpTotal?.text = builder
|
||||
if (dataRes?.is_lock == false || Memory.isVip()) {
|
||||
dataRes?.short_play_video_id?.let {
|
||||
mViewModel.doCreateHistory(
|
||||
shortVideoId,
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
collection?.setImageResource(if (dataRes?.shortPlayInfo?.is_collect == true) R.drawable.iv_example_collection_h else R.drawable.iv_example_collection_n)
|
||||
}
|
||||
|
||||
|
||||
override fun disActive(detachedView: View?, detachedPosition: Int) {
|
||||
if (null == detachedView) return
|
||||
ivCover = detachedView.findViewById(R.id.iv_icon)
|
||||
ivCover?.visibility = View.VISIBLE
|
||||
if (player?.isPlaying == true) {
|
||||
pause()
|
||||
}
|
||||
exampleSeekbarPlayerController?.progress = 0
|
||||
uploadSeconds()
|
||||
}
|
||||
|
||||
private fun uploadSeconds() {
|
||||
if (dataRes?.is_lock == false) {
|
||||
playerDetailAdapter?.getItem(currentPosition)?.play_seconds =
|
||||
if (needRestart) "0" else lastProgress()
|
||||
.toString()
|
||||
mViewModel.uploadHistorySeconds(
|
||||
UploadHistoryReq(
|
||||
if (needRestart) 0 else lastProgress(),
|
||||
shortVideoId,
|
||||
dataRes?.short_play_video_id
|
||||
)
|
||||
)
|
||||
needRestart = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun chooseSeries(episode: PlayerDetailDataRes.Episode) {
|
||||
// isLock = episode.is_lock
|
||||
uploadSeconds()
|
||||
val index = playerDetailAdapter?.items?.withIndex()?.firstOrNull {
|
||||
(episode.episode == it.value.episode) && (episode.shortPlayInfo?.name == it.value.shortPlayInfo?.name
|
||||
)
|
||||
}?.index
|
||||
recyclerViewScrollerDetection.isFirstAttached = false
|
||||
index?.let { binding.rvDetail.scrollToPosition(it) }
|
||||
}
|
||||
|
||||
override fun collection() {
|
||||
doCollect()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
if (dataRes?.is_lock == false || Memory.isVip()) {
|
||||
dataRes?.short_play_id?.let {
|
||||
UploadHistoryReq(
|
||||
lastProgress(),
|
||||
it,
|
||||
dataRes?.short_play_video_id
|
||||
)
|
||||
}?.let {
|
||||
mViewModel.uploadHistorySeconds(
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
if (dataRes?.shortPlayInfo?.image_url?.isNotEmpty() == true) {
|
||||
val toJson = Gson().toJson(
|
||||
dataRes?.short_play_id?.let {
|
||||
MainDataHis(
|
||||
dataRes?.shortPlayInfo?.episode_total.toString(),
|
||||
it,
|
||||
dataRes?.episode.toString(),
|
||||
dataRes?.shortPlayInfo?.image_url.toString()
|
||||
)
|
||||
}
|
||||
)
|
||||
Memory.getMMKV()
|
||||
.putString(Constants.Constants_Main_Video_info, toJson)
|
||||
Memory.getMMKV()
|
||||
.putBoolean(Constants.Constants_Main_Video_status, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun lastProgress(): Long {
|
||||
return player?.currentPosition ?: 0
|
||||
}
|
||||
|
||||
private fun detailRefresh() {
|
||||
recyclerViewScrollerDetection.isFirstAttached = false
|
||||
player?.pause()
|
||||
player?.stop()
|
||||
mViewModel.getVideoDetails(
|
||||
shortVideoId,
|
||||
0,
|
||||
activityId,
|
||||
revolution,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEvent(event: String) {
|
||||
if (Constants.CONSTANTS_pay_refresh == event) {
|
||||
payPosition = dataRes?.episode?.minus(1)!!
|
||||
needRefresh = true
|
||||
mViewModel.getInfo()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReturn() {
|
||||
super.onReturn()
|
||||
finish()
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.jia.er.nebuluxe.app.video
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.Glide
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.PlayerDetailDataRes
|
||||
|
||||
class PlayerDetailAdapter :
|
||||
BaseQuickAdapter<PlayerDetailDataRes.Episode, QuickViewHolder>() {
|
||||
override fun onBindViewHolder(
|
||||
holder: QuickViewHolder,
|
||||
position: Int,
|
||||
item: PlayerDetailDataRes.Episode?
|
||||
) {
|
||||
Glide.with(context).load(item?.shortPlayInfo?.image_url).placeholder(R.drawable.iv_placeholder_v)
|
||||
.into(holder.getView(R.id.iv_icon))
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
context: Context,
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuickViewHolder {
|
||||
return QuickViewHolder(R.layout.item_home_for_you, parent)
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.jia.er.nebuluxe.app.video
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.data.PlayerDetailDataRes
|
||||
|
||||
class SeriesDataAdapter :
|
||||
BaseQuickAdapter<PlayerDetailDataRes.Episode, QuickViewHolder>() {
|
||||
var currentPosition = -1
|
||||
override fun onBindViewHolder(
|
||||
holder: QuickViewHolder,
|
||||
position: Int,
|
||||
item: PlayerDetailDataRes.Episode?
|
||||
) {
|
||||
val view = holder.getView<AppCompatTextView>(R.id.example_tv_num_data)
|
||||
view.text = item?.episode.toString()
|
||||
if (currentPosition == view.text.toString().toInt()) {
|
||||
holder.setBackgroundResource(R.id.example_tv_num_data, R.drawable.bg_example_num_h)
|
||||
holder.setTextColor(
|
||||
R.id.example_tv_num_data,
|
||||
context.getColor(R.color.black)
|
||||
)
|
||||
} else {
|
||||
holder.setBackgroundResource(R.id.example_tv_num_data, R.drawable.bg_example_num_n)
|
||||
holder.setTextColor(
|
||||
R.id.example_tv_num_data,
|
||||
context.getColor(R.color.white)
|
||||
)
|
||||
}
|
||||
// if (item?.is_lock == true && !Memory.isVip()) {
|
||||
// holder.setVisible(R.id.iv_example_lock, true)
|
||||
// } else {
|
||||
// holder.setVisible(R.id.iv_example_lock, false)
|
||||
// }
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
context: Context,
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuickViewHolder {
|
||||
return QuickViewHolder(R.layout.item_num_data, parent)
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package com.jia.er.nebuluxe.app.video
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.jia.er.nebuluxe.app.R
|
||||
import com.jia.er.nebuluxe.app.basics.Constants
|
||||
import com.jia.er.nebuluxe.app.basics.Constants.Constants_Episodes_Series_DataExample
|
||||
import com.jia.er.nebuluxe.app.basics.Constants.Constants_Episodes_Series_Data_ListExample
|
||||
import com.jia.er.nebuluxe.app.basics.Constants.Constants_Episodes_Series_Data_currentPositionExample
|
||||
import com.jia.er.nebuluxe.app.data.PlayerDetailDataRes
|
||||
import com.jia.er.nebuluxe.app.databinding.DialogSeriesBinding
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class SeriesDialogFragment : DialogFragment() {
|
||||
var seriesCallBack: SeriesCallBack? = null
|
||||
var is_collect = false
|
||||
var exampleDialogSeriesBinding: DialogSeriesBinding? = null
|
||||
|
||||
interface SeriesCallBack {
|
||||
fun chooseSeries(episode: PlayerDetailDataRes.Episode)
|
||||
fun collection()
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
EventBus.getDefault().register(this)
|
||||
val builder = AlertDialog.Builder(requireActivity())
|
||||
val inflater = requireActivity().layoutInflater
|
||||
val view = inflater.inflate(R.layout.dialog_series, null)
|
||||
exampleDialogSeriesBinding = DialogSeriesBinding.bind(view)
|
||||
val episodeList: List<PlayerDetailDataRes.Episode>? =
|
||||
arguments?.getParcelableArrayList(Constants_Episodes_Series_Data_ListExample)
|
||||
val data: PlayerDetailDataRes.ShortPlayInfo? =
|
||||
arguments?.getParcelable(Constants_Episodes_Series_DataExample)
|
||||
val currentPosition =
|
||||
arguments?.getInt(Constants_Episodes_Series_Data_currentPositionExample, 0)
|
||||
val exampleSeriesDataAdapter = SeriesDataAdapter()
|
||||
val spanCount = 6
|
||||
val layoutManager = GridLayoutManager(context, spanCount)
|
||||
exampleDialogSeriesBinding?.rvDataDialogSeries?.layoutManager = layoutManager
|
||||
exampleDialogSeriesBinding?.rvDataDialogSeries?.adapter = exampleSeriesDataAdapter
|
||||
exampleSeriesDataAdapter.submitList(episodeList)
|
||||
if (currentPosition != null) {
|
||||
exampleSeriesDataAdapter.currentPosition = currentPosition
|
||||
}
|
||||
exampleDialogSeriesBinding?.tvDesDialogSeries?.text = data?.description
|
||||
if (data?.category?.isNotEmpty() == true) {
|
||||
exampleDialogSeriesBinding?.tvTag?.visibility = View.VISIBLE
|
||||
exampleDialogSeriesBinding?.tvTag?.text = data?.category?.get(0)
|
||||
} else {
|
||||
exampleDialogSeriesBinding?.tvTag?.visibility = View.GONE
|
||||
}
|
||||
is_collect = data?.is_collect == true
|
||||
exampleDialogSeriesBinding?.ivCollect?.setImageResource(if (data?.is_collect == true) R.drawable.iv_example_collection_h else R.drawable.iv_example_collection_n)
|
||||
exampleDialogSeriesBinding?.ivCollect?.setOnClickListener {
|
||||
seriesCallBack?.collection()
|
||||
}
|
||||
exampleSeriesDataAdapter.setOnItemClickListener { adapter, view, position ->
|
||||
val item = adapter.getItem(position) as PlayerDetailDataRes.Episode
|
||||
// if (position > 0) {
|
||||
// val beforeItem = adapter.getItem(position - 1) as PlayerDetailDataRes.Episode
|
||||
// if (beforeItem.is_lock && !Memory.isVip()) {
|
||||
// toast(getString(R.string.prequel_before))
|
||||
// dismiss()
|
||||
// return@setOnItemClickListener
|
||||
// }
|
||||
// }
|
||||
seriesCallBack?.chooseSeries(item)
|
||||
dismiss()
|
||||
}
|
||||
isCancelable = true
|
||||
exampleDialogSeriesBinding?.tvContentDialogSeries?.text = data?.name
|
||||
builder.setView(exampleDialogSeriesBinding?.root)
|
||||
val dialog = builder.create()
|
||||
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
|
||||
val window = dialog.window
|
||||
window?.decorView?.setPadding(0, 0, 0, 0)
|
||||
window?.setGravity(Gravity.BOTTOM)
|
||||
val layoutParams = window?.attributes
|
||||
layoutParams?.width = WindowManager.LayoutParams.MATCH_PARENT
|
||||
layoutParams?.height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||
window?.attributes = layoutParams
|
||||
return dialog
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEvent(event: String) {
|
||||
if (Constants.CONSTANTS_collect_refresh == event) {
|
||||
is_collect = !is_collect
|
||||
exampleDialogSeriesBinding?.ivCollect?.setImageResource(if (is_collect == true) R.drawable.iv_example_collection_h else R.drawable.iv_example_collection_n)
|
||||
}
|
||||
}
|
||||
}
|
BIN
app/src/main/res/drawable-xxhdpi/bg_rank_1.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/bg_rank_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
app/src/main/res/drawable-xxhdpi/bg_rank_2.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/bg_rank_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
BIN
app/src/main/res/drawable-xxhdpi/bg_rank_3.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/bg_rank_3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user