first commit

This commit is contained in:
yuyl 2025-04-16 15:37:20 +08:00
commit fc428a8e09
557 changed files with 42392 additions and 0 deletions

16
Android_Mireo/.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
/app/release

Binary file not shown.

View File

@ -0,0 +1,155 @@
apply plugin: 'com.android.application'
apply plugin: 'android-aspectjx'
apply plugin: 'kotlin-kapt'
apply from: '../common.gradle'
android {
defaultConfig {
applicationId 'com.localee.mireo.app'
resConfigs 'zh'
resConfigs 'xxhdpi'
proguardFiles 'proguard-sdk.pro', 'proguard-app.pro'
buildConfigField('boolean', 'LOG_ENABLE', '' + LOG_ENABLE + '')
buildConfigField('String', 'HOST_URL', '"' + HOST_URL + '"')
}
signingConfigs {
config {
storeFile file(StoreFile)
storePassword StorePassword
keyAlias KeyAlias
keyPassword KeyPassword
}
}
buildFeatures {
viewBinding = true
dataBinding = true
buildConfig = true
}
buildTypes {
debug {
applicationIdSuffix '.debug'
debuggable true
jniDebuggable true
zipAlignEnabled false
shrinkResources false
minifyEnabled false
signingConfig signingConfigs.config
addManifestPlaceholders([
'app_name': 'Mireo Debug'
])
}
preview.initWith(debug)
preview {
debuggable false
jniDebuggable false
zipAlignEnabled true
shrinkResources false
minifyEnabled false
signingConfig signingConfigs.config
addManifestPlaceholders([
'app_name': '@string/app_name'
])
}
release {
debuggable false
jniDebuggable false
zipAlignEnabled false
shrinkResources true
minifyEnabled true
signingConfig signingConfigs.config
addManifestPlaceholders([
'app_name': '@string/app_name'
])
}
}
packagingOptions {
exclude 'META-INF/*******'
}
aspectjx {
include android.defaultConfig.applicationId
}
applicationVariants.all { variant ->
variant.outputs.all { output ->
outputFileName = rootProject.getName() + '_v' + variant.versionName + '_' + variant.buildType.name
if (variant.buildType.name == buildTypes.release.getName()) {
outputFileName += '_' + new Date().format('MMdd')
}
outputFileName += '.apk'
}
}
}
dependencies {
implementation project(':library:base')
implementation project(':library:widget')
implementation 'com.github.getActivity:XXPermissions:12.3'
implementation 'com.github.getActivity:TitleBar:9.2'
implementation 'com.github.getActivity:ToastUtils:9.5'
implementation 'com.github.getActivity:EasyHttp:13.0'
implementation 'com.squareup.okhttp3:okhttp:3.14.9'
implementation 'com.google.code.gson:gson:2.8.8'
implementation 'com.github.getActivity:GsonFactory:5.2'
implementation 'com.github.getActivity:ShapeView:9.0'
implementation 'org.aspectj:aspectjrt:1.9.6'
implementation 'com.github.bumptech.glide:glide:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.12.0'
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
implementation 'com.github.Baseflow:PhotoView:2.3.0'
implementation 'com.tencent.bugly:crashreport:3.4.4'
implementation 'com.tencent.bugly:nativecrashreport:3.9.2'
implementation 'com.airbnb.android:lottie:4.1.0'
implementation 'com.scwang.smart:refresh-layout-kernel:2.0.3'
implementation 'com.scwang.smart:refresh-header-material:2.0.3'
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'me.relex:circleindicator:2.1.6'
implementation 'com.tencent:mmkv-static:1.2.10'
// banner
implementation 'io.github.youth5201314:banner:2.2.3'
implementation "io.github.cymchad:BaseRecyclerViewAdapterHelper4:4.1.4"
implementation "com.afollestad.material-dialogs:core:3.1.1"
implementation "com.afollestad.material-dialogs:lifecycle:3.1.1"
implementation "androidx.media3:media3-ui:1.4.0"
implementation "androidx.media3:media3-exoplayer:1.4.0"
implementation "androidx.media3:media3-exoplayer-dash:1.4.0"
implementation "androidx.media3:media3-exoplayer-hls:1.4.0"
implementation(files("libs/lib-decoder-ffmpeg-release.aar"))
implementation "org.greenrobot:eventbus:3.3.1"
implementation("com.blankj:utilcodex:1.31.1")
implementation("com.github.li-xiaojun:XPopup:2.10.0")
}

View File

@ -0,0 +1,4 @@
StoreFile = AppMireo.jks
StorePassword = appmireo
KeyAlias = appmireo
KeyPassword = appmireo

View File

@ -0,0 +1,36 @@
#-ignorewarning
-libraryjars libs/lib-decoder-ffmpeg-release.aar
-keep class com.localee.mireo.app.http.api.** {
<fields>;
}
-keep class com.localee.mireo.app.http.response.** {
<fields>;
}
-keep class com.localee.mireo.app.http.model.** {
<fields>;
}
-keep class com.localee.mireo.app.http.exception.** {
<fields>;
}
-keepclassmembernames class ** {
@com.localee.mireo.app.aop.Log <methods>;
}
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * {
public void *(android.view.View);
}

View File

@ -0,0 +1,45 @@
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep class * extends com.bumptech.glide.module.AppGlideModule {
<init>(...);
}
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
*** rewind();
}
# for DexGuard only
#-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
# Bugly
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# AOP
-adaptclassstrings
-keepattributes InnerClasses, EnclosingMethod, Signature, *Annotation*
-keepnames @org.aspectj.lang.annotation.Aspect class * {
public <methods>;
}
# OkHttp3
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn org.conscrypt.**
-keep class com.gyf.immersionbar.* {*;}
-dontwarn com.gyf.immersionbar.**
# com.hjq
-keep class com.hjq.permissions.** {*;}
-keep class com.hjq.bar.** {*;}
-keep class com.hjq.toast.** {*;}
-keep class com.hjq.shape.** {*;}

View File

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.localee.mireo.app">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:name=".app.AppApplication"
android:allowBackup="false"
android:icon="@mipmap/ic_app_logo"
android:label="${app_name}"
android:networkSecurityConfig="@xml/network_security_config"
android:requestLegacyExternalStorage="true"
android:resizeableActivity="true"
android:roundIcon="@mipmap/ic_app_logo"
android:supportsRtl="false"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:ignore="AllowBackup,LockedOrientationActivity"
tools:replace="android:allowBackup,android:supportsRtl"
tools:targetApi="31">
<meta-data
android:name="ScopedStorage"
android:value="true" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<activity
android:name=".ui.activity.SplashActivity"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@style/Theme.Splash"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.activity.HomeActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan" />
<activity
android:name=".ui.activity.SettingActivity"
android:label="@string/setting_title"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.AboutActivity"
android:label="@string/about_title"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.BrowserActivity"
android:label="@string/web_title"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.VideoPlayActivity"
android:launchMode="singleTop"
android:theme="@style/FullScreenTheme" />
<activity
android:name=".ui.activity.SearchActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
</application>
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
</intent>
<intent>
<action android:name="android.intent.action.GET_CONTENT" />
</intent>
</queries>
</manifest>

View File

@ -0,0 +1,74 @@
package com.localee.mireo.app.action
import android.graphics.drawable.Drawable
import android.net.ConnectivityManager
import android.net.NetworkInfo
import androidx.annotation.DrawableRes
import androidx.annotation.RawRes
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import com.localee.mireo.app.R
import com.localee.mireo.app.widget.StatusLayout
import com.localee.mireo.app.widget.StatusLayout.OnRetryListener
interface StatusAction {
fun getStatusLayout(): StatusLayout?
fun showLoading(@RawRes id: Int = R.raw.loading) {
getStatusLayout()?.let {
it.show()
it.setAnimResource(id)
it.setHint("")
it.setOnRetryListener(null)
}
}
fun showComplete() {
getStatusLayout()?.let {
if (!it.isShow()) {
return
}
it.hide()
}
}
fun showEmpty() {
showLayout(R.drawable.status_empty_ic, R.string.status_layout_no_data, null)
}
fun showError(listener: OnRetryListener?) {
getStatusLayout()?.let {
val manager: ConnectivityManager? = ContextCompat.getSystemService(it.context, ConnectivityManager::class.java)
if (manager != null) {
val info: NetworkInfo? = manager.activeNetworkInfo
if (info == null || !info.isConnected) {
showLayout(R.drawable.status_network_ic, R.string.status_layout_error_network, listener)
return
}
}
showLayout(R.drawable.status_error_ic, R.string.status_layout_error_request, listener)
}
}
fun showLayout(@DrawableRes drawableId: Int, @StringRes stringId: Int, listener: OnRetryListener?) {
getStatusLayout()?.let {
showLayout(ContextCompat.getDrawable(it.context, drawableId), it.context.getString(stringId), listener)
}
}
fun showLayout(drawable: Drawable?, hint: CharSequence?, listener: OnRetryListener?) {
getStatusLayout()?.let {
it.show()
it.setIcon(drawable)
it.setHint(hint)
it.setOnRetryListener(listener)
}
}
}

View File

@ -0,0 +1,94 @@
package com.localee.mireo.app.action
import android.graphics.drawable.Drawable
import android.view.View
import android.view.ViewGroup
import androidx.annotation.StringRes
import com.hjq.bar.OnTitleBarListener
import com.hjq.bar.TitleBar
interface TitleBarAction : OnTitleBarListener {
fun getTitleBar(): TitleBar?
override fun onLeftClick(view: View) {}
override fun onTitleClick(view: View) {}
override fun onRightClick(view: View) {}
fun setTitle(@StringRes id: Int) {
getTitleBar()?.setTitle(id)
}
fun setTitle(title: CharSequence?) {
getTitleBar()?.title = title
}
fun setLeftTitle(id: Int) {
getTitleBar()?.setLeftTitle(id)
}
fun setLeftTitle(text: CharSequence?) {
getTitleBar()?.leftTitle = text
}
fun getLeftTitle(): CharSequence? {
return getTitleBar()?.leftTitle
}
fun setRightTitle(id: Int) {
getTitleBar()?.setRightTitle(id)
}
fun setRightTitle(text: CharSequence?) {
getTitleBar()?.rightTitle = text
}
fun getRightTitle(): CharSequence? {
return getTitleBar()?.rightTitle
}
fun setLeftIcon(id: Int) {
getTitleBar()?.setLeftIcon(id)
}
fun setLeftIcon(drawable: Drawable?) {
getTitleBar()?.leftIcon = drawable
}
fun getLeftIcon(): Drawable? {
return getTitleBar()?.leftIcon
}
fun setRightIcon(id: Int) {
getTitleBar()?.setRightIcon(id)
}
fun setRightIcon(drawable: Drawable?) {
getTitleBar()?.rightIcon = drawable
}
fun getRightIcon(): Drawable? {
return getTitleBar()?.rightIcon
}
fun obtainTitleBar(group: ViewGroup?): TitleBar? {
if (group == null) {
return null
}
for (i in 0 until group.childCount) {
val view = group.getChildAt(i)
if (view is TitleBar) {
return view
}
if (view is ViewGroup) {
val titleBar = obtainTitleBar(view)
if (titleBar != null) {
return titleBar
}
}
}
return null
}
}

View File

@ -0,0 +1,19 @@
package com.localee.mireo.app.action
import androidx.annotation.StringRes
import com.hjq.toast.ToastUtils
interface ToastAction {
fun toast(text: CharSequence?) {
ToastUtils.show(text)
}
fun toast(@StringRes id: Int) {
ToastUtils.show(id)
}
fun toast(`object`: Any?) {
ToastUtils.show(`object`)
}
}

View File

@ -0,0 +1,7 @@
package com.localee.mireo.app.aop
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER)
annotation class CheckNet

View File

@ -0,0 +1,36 @@
package com.localee.mireo.app.aop
import android.app.*
import android.net.ConnectivityManager
import android.net.NetworkInfo
import androidx.core.content.ContextCompat
import com.localee.mireo.app.R
import com.localee.mireo.app.manager.ActivityManager
import com.hjq.toast.ToastUtils
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
@Suppress("unused")
@Aspect
class CheckNetAspect {
@Pointcut("execution(@com.localee.mireo.app.aop.CheckNet * *(..))")
fun method() {}
@Around("method() && @annotation(checkNet)")
@Throws(Throwable::class)
fun aroundJoinPoint(joinPoint: ProceedingJoinPoint, checkNet: CheckNet) {
val application: Application = ActivityManager.getInstance().getApplication()
val manager: ConnectivityManager? = ContextCompat.getSystemService(application, ConnectivityManager::class.java)
if (manager != null) {
val info: NetworkInfo? = manager.activeNetworkInfo
if (info == null || !info.isConnected) {
ToastUtils.show(R.string.common_network_hint)
return
}
}
joinPoint.proceed()
}
}

View File

@ -0,0 +1,8 @@
package com.localee.mireo.app.aop
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.CONSTRUCTOR)
annotation class Log constructor(val value: String = "AppLog")

View File

@ -0,0 +1,96 @@
package com.localee.mireo.app.aop
import android.os.Looper
import android.os.Trace
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.Signature
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.aspectj.lang.reflect.CodeSignature
import org.aspectj.lang.reflect.MethodSignature
import timber.log.Timber
import java.util.concurrent.TimeUnit
@Suppress("unused")
@Aspect
class LogAspect {
@Pointcut("execution(@com.localee.mireo.app.aop.Log *.new(..))")
fun constructor() {}
@Pointcut("execution(@com.localee.mireo.app.aop.Log * *(..))")
fun method() {}
@Around("(method() || constructor()) && @annotation(log)")
@Throws(Throwable::class)
fun aroundJoinPoint(joinPoint: ProceedingJoinPoint, log: Log): Any? {
enterMethod(joinPoint, log)
val startNanos: Long = System.nanoTime()
val result: Any? = joinPoint.proceed()
val stopNanos: Long = System.nanoTime()
exitMethod(joinPoint, log, result, TimeUnit.NANOSECONDS.toMillis(stopNanos - startNanos))
return result
}
private fun enterMethod(joinPoint: ProceedingJoinPoint, log: Log) {
val codeSignature: CodeSignature = joinPoint.signature as CodeSignature
val className: String = codeSignature.declaringType.name
val methodName: String = codeSignature.name
val parameterNames: Array<String?> = codeSignature.parameterNames
val parameterValues: Array<Any?> = joinPoint.args
val builder: StringBuilder =
getMethodLogInfo(className, methodName, parameterNames, parameterValues)
log(log.value, builder.toString())
val section: String = builder.substring(2)
Trace.beginSection(section)
}
private fun getMethodLogInfo(className: String, methodName: String, parameterNames: Array<String?>, parameterValues: Array<Any?>): StringBuilder {
val builder: StringBuilder = StringBuilder("\u21E2 ")
builder.append(className)
.append(".")
.append(methodName)
.append('(')
for (i in parameterValues.indices) {
if (i > 0) {
builder.append(", ")
}
builder.append(parameterNames[i]).append('=')
builder.append(parameterValues[i].toString())
}
builder.append(')')
if (Looper.myLooper() != Looper.getMainLooper()) {
builder.append(" [Thread:\"").append(Thread.currentThread().name).append("\"]")
}
return builder
}
private fun exitMethod(joinPoint: ProceedingJoinPoint, log: Log, result: Any?, lengthMillis: Long) {
Trace.endSection()
val signature: Signature = joinPoint.signature
val className: String? = signature.declaringType.name
val methodName: String? = signature.name
val builder: StringBuilder = StringBuilder("\u21E0 ")
.append(className)
.append(".")
.append(methodName)
.append(" [")
.append(lengthMillis)
.append("ms]")
// 判断方法是否有返回值
if (signature is MethodSignature && signature.returnType != Void.TYPE) {
builder.append(" = ")
builder.append(result.toString())
}
log(log.value, builder.toString())
}
private fun log(tag: String?, msg: String?) {
Timber.tag(tag)
Timber.d(msg)
}
}

View File

@ -0,0 +1,9 @@
package com.localee.mireo.app.aop
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER)
annotation class Permissions constructor(
vararg val value: String
)

View File

@ -0,0 +1,58 @@
package com.localee.mireo.app.aop
import android.app.Activity
import com.localee.mireo.app.other.PermissionCallback
import com.hjq.permissions.XXPermissions
import com.localee.mireo.app.manager.ActivityManager
import com.tencent.bugly.crashreport.CrashReport
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import timber.log.Timber
@Suppress("unused")
@Aspect
class PermissionsAspect {
@Pointcut("execution(@com.localee.mireo.app.aop.Permissions * *(..))")
fun method() {}
@Around("method() && @annotation(permissions)")
fun aroundJoinPoint(joinPoint: ProceedingJoinPoint, permissions: Permissions) {
var activity: Activity? = null
val parameterValues: Array<Any?> = joinPoint.args
for (arg: Any? in parameterValues) {
if (arg !is Activity) {
continue
}
activity = arg
break
}
if ((activity == null) || activity.isFinishing || activity.isDestroyed) {
activity = ActivityManager.getInstance().getTopActivity()
}
if ((activity == null) || activity.isFinishing || activity.isDestroyed) {
Timber.e("The activity has been destroyed and permission requests cannot be made")
return
}
requestPermissions(joinPoint, activity, permissions.value)
}
private fun requestPermissions(joinPoint: ProceedingJoinPoint, activity: Activity, permissions: Array<out String>) {
XXPermissions.with(activity)
.permission(*permissions)
.request(object : PermissionCallback() {
override fun onGranted(permissions: MutableList<String?>?, all: Boolean) {
if (all) {
try {
// 获得权限,执行原方法
joinPoint.proceed()
} catch (e: Throwable) {
CrashReport.postCatchedException(e)
}
}
}
})
}
}

View File

@ -0,0 +1,9 @@
package com.localee.mireo.app.aop
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER)
annotation class SingleClick constructor(
val value: Long = 1000
)

View File

@ -0,0 +1,51 @@
package com.localee.mireo.app.aop
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.aspectj.lang.reflect.CodeSignature
import timber.log.Timber
@Suppress("unused")
@Aspect
class SingleClickAspect {
private var lastTime: Long = 0
private var lastTag: String? = null
@Pointcut("execution(@com.localee.mireo.app.aop.SingleClick * *(..))")
fun method() {}
@Around("method() && @annotation(singleClick)")
@Throws(Throwable::class)
fun aroundJoinPoint(joinPoint: ProceedingJoinPoint, singleClick: SingleClick) {
val codeSignature: CodeSignature = joinPoint.signature as CodeSignature
val className: String = codeSignature.declaringType.name
val methodName: String = codeSignature.name
val builder: StringBuilder = StringBuilder("$className.$methodName")
builder.append("(")
val parameterValues: Array<Any?> = joinPoint.args
for (i in parameterValues.indices) {
val arg: Any? = parameterValues[i]
if (i == 0) {
builder.append(arg)
} else {
builder.append(", ")
.append(arg)
}
}
builder.append(")")
val tag: String = builder.toString()
val currentTimeMillis: Long = System.currentTimeMillis()
if (currentTimeMillis - lastTime < singleClick.value && (tag == lastTag)) {
Timber.tag("SingleClick")
Timber.i("Within %s milliseconds, there was a rapid click%s", singleClick.value, tag)
return
}
lastTime = currentTimeMillis
lastTag = tag
joinPoint.proceed()
}
}

View File

@ -0,0 +1,161 @@
package com.localee.mireo.app.app
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.annotation.StringRes
import com.gyf.immersionbar.ImmersionBar
import com.hjq.bar.TitleBar
import com.hjq.base.BaseActivity
import com.hjq.base.BaseDialog
import com.localee.mireo.app.R
import com.localee.mireo.app.action.TitleBarAction
import com.localee.mireo.app.action.ToastAction
import com.localee.mireo.app.http.model.HttpData
import com.localee.mireo.app.ui.dialog.WaitDialog
import com.hjq.http.config.IRequestApi
import com.hjq.http.listener.OnHttpListener
import com.hjq.toast.ToastUtils
abstract class AppActivity : BaseActivity(),
ToastAction, TitleBarAction, OnHttpListener<Any> {
private var titleBar: TitleBar? = null
private var immersionBar: ImmersionBar? = null
private var dialog: BaseDialog? = null
private var dialogCount: Int = 0
open fun isShowDialog(): Boolean {
return dialog != null && dialog!!.isShowing
}
open fun showDialog() {
if (isFinishing || isDestroyed) {
return
}
dialogCount++
postDelayed(Runnable {
if ((dialogCount <= 0) || isFinishing || isDestroyed) {
return@Runnable
}
if (dialog == null) {
dialog = WaitDialog.Builder(this)
.setCancelable(false)
.create()
}
if (!dialog!!.isShowing) {
dialog!!.show()
}
}, 300)
}
open fun hideDialog() {
if (isFinishing || isDestroyed) {
return
}
if (dialogCount > 0) {
dialogCount--
}
if ((dialogCount != 0) || (dialog == null) || !dialog!!.isShowing) {
return
}
dialog?.dismiss()
}
override fun initLayout() {
super.initLayout()
val titleBar = getTitleBar()
titleBar?.setOnTitleBarListener(this)
if (isStatusBarEnabled()) {
getStatusBarConfig().init()
if (titleBar != null) {
ImmersionBar.setTitleBar(this, titleBar)
}
}
}
protected open fun isStatusBarEnabled(): Boolean {
return true
}
open fun isStatusBarDarkFont(): Boolean {
return true
}
open fun getStatusBarConfig(): ImmersionBar {
if (immersionBar == null) {
immersionBar = createStatusBarConfig()
}
return immersionBar!!
}
protected open fun createStatusBarConfig(): ImmersionBar {
return ImmersionBar.with(this) // 默认状态栏字体颜色为黑色
.statusBarDarkFont(false) // 指定导航栏背景颜色
.navigationBarColor(R.color.black) // 状态栏字体和导航栏内容自动变色,必须指定状态栏颜色和导航栏颜色才可以自动变色
.autoDarkModeEnable(true, 0.2f)
}
override fun setTitle(@StringRes id: Int) {
title = getString(id)
}
override fun setTitle(title: CharSequence?) {
super<BaseActivity>.setTitle(title)
getTitleBar()?.title = title
}
override fun getTitleBar(): TitleBar? {
if (titleBar == null) {
titleBar = obtainTitleBar(getContentView())
}
return titleBar
}
override fun onLeftClick(view: View) {
onBackPressed()
}
override fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?) {
super.startActivityForResult(intent, requestCode, options)
overridePendingTransition(R.anim.right_in_activity, R.anim.right_out_activity)
}
override fun finish() {
super.finish()
overridePendingTransition(R.anim.left_in_activity, R.anim.left_out_activity)
}
override fun onHttpStart(api: IRequestApi) {
showDialog()
}
override fun onHttpSuccess(result: Any) {
if (result is HttpData<*>) {
toast(result.getMessage())
}
}
override fun onHttpFail(throwable: Throwable) {
ToastUtils.show(throwable.message)
}
override fun onHttpEnd(api: IRequestApi) {
hideDialog()
}
override fun onDestroy() {
super.onDestroy()
if (isShowDialog()) {
hideDialog()
}
dialog = null
}
}

View File

@ -0,0 +1,140 @@
package com.localee.mireo.app.app
import android.content.Context
import android.view.View
import androidx.annotation.IntRange
import androidx.annotation.LayoutRes
import com.hjq.base.BaseAdapter
import java.util.*
abstract class AppAdapter<T> constructor(context: Context) :
BaseAdapter<AppAdapter<T>.AppViewHolder>(context) {
private var dataSet: MutableList<T> = ArrayList()
private var pageNumber = 1
private var lastPage = false
private var tag: Any? = null
override fun getItemCount(): Int {
return getCount()
}
open fun getCount(): Int {
return dataSet.size
}
open fun setData(data: MutableList<T>?) {
if (data == null) {
dataSet.clear()
} else {
dataSet = data
}
notifyDataSetChanged()
}
open fun getData(): MutableList<T> {
return dataSet
}
open fun addData(data: MutableList<T>?) {
if (data == null || data.isEmpty()) {
return
}
dataSet.addAll(data)
notifyItemRangeInserted(dataSet.size - data.size, data.size)
}
open fun clearData() {
dataSet.clear()
notifyDataSetChanged()
}
open fun containsItem(@IntRange(from = 0) position: Int): Boolean {
return containsItem(getItem(position))
}
open fun containsItem(item: T?): Boolean {
return if (item == null) {
false
} else dataSet.contains(item)
}
open fun getItem(@IntRange(from = 0) position: Int): T {
return dataSet[position]
}
open fun setItem(@IntRange(from = 0) position: Int, item: T) {
dataSet[position] = item
notifyItemChanged(position)
}
open fun addItem(item: T) {
addItem(dataSet.size, item)
}
open fun addItem(@IntRange(from = 0) position: Int, item: T) {
var finalPosition = position
if (finalPosition < dataSet.size) {
dataSet.add(finalPosition, item)
} else {
dataSet.add(item)
finalPosition = dataSet.size - 1
}
notifyItemInserted(finalPosition)
}
open fun removeItem(item: T) {
val index = dataSet.indexOf(item)
if (index != -1) {
removeItem(index)
}
}
open fun removeItem(@IntRange(from = 0) position: Int) {
dataSet.removeAt(position)
notifyItemRemoved(position)
}
open fun getPageNumber(): Int {
return pageNumber
}
open fun setPageNumber(@IntRange(from = 0) number: Int) {
pageNumber = number
}
open fun isLastPage(): Boolean {
return lastPage
}
open fun setLastPage(last: Boolean) {
lastPage = last
}
open fun getTag(): Any? {
return tag
}
open fun setTag(tag: Any) {
this.tag = tag
}
abstract inner class AppViewHolder : BaseViewHolder {
constructor(@LayoutRes id: Int) : super(id)
constructor(itemView: View) : super(itemView)
}
inner class SimpleViewHolder : AppViewHolder {
constructor(@LayoutRes id: Int) : super(id)
constructor(itemView: View) : super(itemView)
override fun onBindView(position: Int) {}
}
}

View File

@ -0,0 +1,171 @@
package com.localee.mireo.app.app
import android.app.Activity
import android.app.Application
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.os.Build
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonToken
import com.hjq.bar.TitleBar
import com.hjq.gson.factory.GsonFactory
import com.hjq.http.EasyConfig
import com.hjq.http.config.IRequestInterceptor
import com.hjq.http.model.HttpHeaders
import com.hjq.http.model.HttpParams
import com.hjq.http.request.HttpRequest
import com.hjq.toast.ToastUtils
import com.localee.mireo.app.R
import com.localee.mireo.app.aop.Log
import com.localee.mireo.app.http.exception.HttpBodyInterceptor
import com.localee.mireo.app.http.model.RequestHandler
import com.localee.mireo.app.http.model.RequestServer
import com.localee.mireo.app.manager.ActivityManager
import com.localee.mireo.app.other.AppConfig
import com.localee.mireo.app.other.CrashHandler
import com.localee.mireo.app.other.DebugLoggerTree
import com.localee.mireo.app.other.MaterialHeader
import com.localee.mireo.app.other.SmartBallPulseFooter
import com.localee.mireo.app.other.TitleBarStyle
import com.localee.mireo.app.other.ToastStyle
import com.localee.mireo.app.utils.MsMMKVUtils
import com.localee.mireo.app.utils.MsSystemUtlis
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.scwang.smart.refresh.layout.api.RefreshLayout
import com.tencent.bugly.crashreport.CrashReport
import com.tencent.mmkv.MMKV
import okhttp3.OkHttpClient
import timber.log.Timber
class AppApplication : Application() {
@Log("启动耗时")
override fun onCreate() {
super.onCreate()
instance = this;
initSdk(this)
}
override fun onLowMemory() {
super.onLowMemory()
}
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
}
companion object {
lateinit var instance: Application;
var isCurrentPage: Boolean = true
fun initSdk(application: Application) {
TitleBar.setDefaultStyle(TitleBarStyle())
SmartRefreshLayout.setDefaultRefreshHeaderCreator { context: Context, layout: RefreshLayout ->
MaterialHeader(context).setColorSchemeColors(
ContextCompat.getColor(
context,
R.color.common_accent_color
)
)
}
SmartRefreshLayout.setDefaultRefreshFooterCreator { context: Context, layout: RefreshLayout ->
SmartBallPulseFooter(context)
}
SmartRefreshLayout.setDefaultRefreshInitializer { context: Context, layout: RefreshLayout ->
layout.setEnableHeaderTranslationContent(true)
.setEnableFooterTranslationContent(true)
.setEnableFooterFollowWhenNoMoreData(true)
.setEnableLoadMoreWhenContentNotFull(false)
.setEnableOverScrollDrag(false)
}
ToastUtils.init(application, ToastStyle())
ToastUtils.setDebugMode(AppConfig.isDebug())
CrashHandler.register(application)
ActivityManager.getInstance().init(application)
MMKV.initialize(application)
val okHttpClient: OkHttpClient = OkHttpClient.Builder()
.addInterceptor(HttpBodyInterceptor())
.build()
EasyConfig.with(okHttpClient)
.setLogEnabled(AppConfig.isLogEnable())
.setServer(RequestServer())
.setHandler(RequestHandler(application))
.setRetryCount(1)
.setInterceptor(object : IRequestInterceptor {
override fun interceptArguments(
httpRequest: HttpRequest<*>,
params: HttpParams,
headers: HttpHeaders
) {
headers.put("Content-Type", "application/json; charset=utf-8")
headers.put("Content-Type", "text/plain; charset=utf-8")
headers.put("Authorization", MsMMKVUtils.getToken())
headers.put(
"device-id",
MsSystemUtlis.getDeviceId(instance).toString()
)
headers.put(
"lang-key",
"en"
)
headers.put("system-type", "android")
headers.put("app_id", "nice_short")
headers.put("system_version", "12")
headers.put("model", Build.MODEL)
headers.put("brand", Build.MANUFACTURER + "-" + Build.PRODUCT)
headers.put(
"app_version",
MsSystemUtlis.getVerNameInfo(instance)
)
// headers.put("security","true")
}
})
.into()
GsonFactory.setJsonCallback { typeToken: TypeToken<*>, fieldName: String?, jsonToken: JsonToken ->
CrashReport.postCatchedException(IllegalArgumentException("Type parsing exception$typeToken#$fieldNamethe type returned by the background is$jsonToken"))
}
if (AppConfig.isLogEnable()) {
Timber.plant(DebugLoggerTree())
}
val connectivityManager: ConnectivityManager? =
ContextCompat.getSystemService(application, ConnectivityManager::class.java)
if (connectivityManager != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.registerDefaultNetworkCallback(object :
ConnectivityManager.NetworkCallback() {
override fun onLost(network: Network) {
val topActivity: Activity? = ActivityManager.getInstance().getTopActivity()
if (topActivity !is LifecycleOwner) {
return
}
val lifecycleOwner: LifecycleOwner = topActivity
if (lifecycleOwner.lifecycle.currentState != Lifecycle.State.RESUMED) {
return
}
ToastUtils.show(R.string.common_network_error)
}
})
}
}
}
}

View File

@ -0,0 +1,46 @@
package com.localee.mireo.app.app
import com.hjq.base.BaseFragment
import com.localee.mireo.app.action.ToastAction
import com.localee.mireo.app.http.model.HttpData
import com.hjq.http.config.IRequestApi
import com.hjq.http.listener.OnHttpListener
import com.hjq.toast.ToastUtils
abstract class AppFragment<A : AppActivity> : BaseFragment<A>(),
ToastAction, OnHttpListener<Any> {
open fun isShowDialog(): Boolean {
val activity: A = getAttachActivity() ?: return false
return activity.isShowDialog()
}
open fun showDialog() {
getAttachActivity()?.showDialog()
}
open fun hideDialog() {
getAttachActivity()?.hideDialog()
}
override fun onHttpStart(api: IRequestApi) {
showDialog()
}
override fun onHttpSuccess(result: Any) {
if (result !is HttpData<*>) {
return
}
toast(result.getMessage())
}
override fun onHttpFail(throwable: Throwable) {
ToastUtils.show(throwable.message)
}
override fun onHttpEnd(api: IRequestApi) {
hideDialog()
}
}

View File

@ -0,0 +1,4 @@
package com.localee.mireo.app.app
data class BaseEventBus<T>(val code: String, val data: T)

View File

@ -0,0 +1,69 @@
package com.localee.mireo.app.app
import android.os.Bundle
import android.view.*
import com.gyf.immersionbar.ImmersionBar
import com.hjq.bar.TitleBar
import com.localee.mireo.app.R
import com.localee.mireo.app.action.TitleBarAction
abstract class TitleBarFragment<A : AppActivity> : AppFragment<A>(), TitleBarAction {
private var titleBar: TitleBar? = null
private var immersionBar: ImmersionBar? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val titleBar = getTitleBar()
titleBar?.setOnTitleBarListener(this)
if (isStatusBarEnabled()) {
getStatusBarConfig().init()
if (titleBar != null) {
ImmersionBar.setTitleBar(this, titleBar)
}
}
}
override fun onResume() {
super.onResume()
if (isStatusBarEnabled()) {
getStatusBarConfig().init()
}
}
open fun isStatusBarEnabled(): Boolean {
return false
}
protected fun getStatusBarConfig(): ImmersionBar {
if (immersionBar == null) {
immersionBar = createStatusBarConfig()
}
return immersionBar!!
}
protected fun createStatusBarConfig(): ImmersionBar {
return ImmersionBar.with(this)
.statusBarDarkFont(false)
.navigationBarColor(R.color.black)
.autoDarkModeEnable(true, 0.2f)
}
protected open fun isStatusBarDarkFont(): Boolean {
return getAttachActivity()!!.isStatusBarDarkFont()
}
override fun getTitleBar(): TitleBar? {
if (titleBar == null || !isLoading()) {
titleBar = obtainTitleBar(view as ViewGroup)
}
return titleBar
}
}

View File

@ -0,0 +1,17 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
class CancelCollectApi : IRequestApi {
override fun getApi(): String {
return "cancelCollect"
}
var short_play_id: Int? = null
var video_id: Int? = null
}

View File

@ -0,0 +1,18 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
class CreateHistoryApi : IRequestApi {
override fun getApi(): String {
return "createHistory"
}
var short_play_id: Int? = null
var video_id: Int? = null
}

View File

@ -0,0 +1,19 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
import java.io.Serializable
class CustomerRegisterApi : IRequestApi {
override fun getApi(): String {
return "customer/register"
}
class Bean : Serializable{
var token: String? = null
var customer_id: Int? = null
var auto_login: Boolean = false
}
}

View File

@ -0,0 +1,29 @@
package com.localee.mireo.app.http.api
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
)
}

View File

@ -0,0 +1,25 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
class DoCollectApi : IRequestApi {
override fun getApi(): String {
return "collect"
}
private var short_play_id: String? = null
private var video_id: String? = null
fun setShortPlayId(short_play_id: String?): com.localee.mireo.app.http.api.DoCollectApi = apply {
this.short_play_id = short_play_id
}
fun setVideoId(video_id: String?): com.localee.mireo.app.http.api.DoCollectApi = apply {
this.video_id = video_id
}
}

View File

@ -0,0 +1,39 @@
package com.localee.mireo.app.http.api
data class ExampleRecommendDataRes(
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
)
}

View File

@ -0,0 +1,33 @@
package com.localee.mireo.app.http.api
class HistoryBean (
val list: List<Data>,
val pagination: Pagination
) {
data class Data(
val name: String,
val short_play_video_id: Int,
var description: String,
val short_play_id: Int,
val image_url: String,
val episode_total: Int,
val current_episode: String,
var is_collect: Boolean,
var is_check: Boolean,
val categoryList: List<categoryBean>
)
data class Pagination(
val current_page: Int,
val page_size: Int,
val page_total: Int,
val total_size: Int
)
data class categoryBean(
val id: String,
val name: String
)
}

View File

@ -0,0 +1,31 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
import java.io.Serializable
class HomeBannerApi : IRequestApi {
override fun getApi(): String {
return "getBanners"
}
class Bean : Serializable{
var id: Int? = null
var short_id: Int? = null
var short_play_id: Int? = null
var name: String? = null
var description: String? = null
var process: Int? = null
var image_url: String? = null
var horizontally_img: String? = null
var buy_type: Int? = null
var tag_type: String? = null
var all_coins: Int? = null
var collect_total: Int? = null
var watch_total: Int? = null
var episode_total: Int? = null
var search_click_total: Int? = null
}
}

View File

@ -0,0 +1,22 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
class HomeCategoriesApi : IRequestApi {
override fun getApi(): String {
return "getCategories"
}
class Bean(
val list: List<Data>,
) {
data class Data(
val id: Int,
val name: String
)
}
}

View File

@ -0,0 +1,18 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
import java.io.Serializable
class HomeDayMaxRechargeShortPlayRankApi : IRequestApi {
override fun getApi(): String {
return "homeRanking"
}
class Bean {
var list: List<RecommendBean>? = null
}
}

View File

@ -0,0 +1,32 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
import java.io.Serializable
class HomeModuleApi : IRequestApi {
override fun getApi(): String {
return "homeModuleData"
}
class Bean : Serializable {
var bannerData: List<RecommendBean>? = null
var recommandData: RecommandDataBean? = null
var manualNewestRecommand: RecommandDataBean? = null
var hotData: List<RecommendBean>? = null
var newTopThree: List<RecommendBean>? = null
var highestPayment: List<RecommendBean>? = null
var hottestPist: List<RecommendBean>? = null
}
class RecommandDataBean {
var title: String? = null
var list: List<RecommendBean>? = null
}
}

View File

@ -0,0 +1,19 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
import java.io.Serializable
class HomeRecommendApi : IRequestApi {
override fun getApi(): String {
return "getRecommands"
}
var current_page: Int? = null
var page_size: Int? = null
var revolution: String? = null
}

View File

@ -0,0 +1,33 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
import java.io.Serializable
class HomeVideoListApi : IRequestApi {
override fun getApi(): String {
return "videoList"
}
var category_id : Int? = null
var current_page : Int? = null
var page_size : Int? = null
class Bean (
val list: List<RecommendBean>,
val pagination: Pagination
) {
data class Pagination(
val current_page: Int,
val page_size: Int,
val page_total: Int,
val total_size: Int
)
}
}

View File

@ -0,0 +1,16 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
class MyCollectionsApi : IRequestApi {
override fun getApi(): String {
return "myCollections"
}
var current_page: Int? = null
var page_size: Int? = null
}

View File

@ -0,0 +1,16 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
class MyHistoryApi : IRequestApi {
override fun getApi(): String {
return "myHistorys"
}
var current_page: Int? = null
var page_size: Int? = null
}

View File

@ -0,0 +1,26 @@
package com.localee.mireo.app.http.api
class RecommendBean(
var id: Int,
var short_id: Int,
var short_play_id: Int,
var name: String,
var description: String,
var process: Int,
var image_url: String,
var horizontally_img: String,
var buy_type: String,
var tag_type: String,
var all_coins: String,
var collect_total: String,
var watch_total: Int,
var episode_total: String,
var search_click_total: String,
val category: List<String>,
val categoryList: List<categoryBean>
) {
data class categoryBean(
val id: String, val name: String
)
}

View File

@ -0,0 +1,41 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
class SearchHotApi : IRequestApi {
override fun getApi(): String {
return "search/hots"
}
class Bean(
val list: List<com.localee.mireo.app.http.api.SearchHotApi.Bean.Data>,
) {
data class Data(
val id: String,
val short_id: Int,
var short_play_id: Int,
val name: String,
val description: String,
val process: Int,
val image_url: String,
var horizontally_img: String,
var buy_type: Int,
var tag_type: String,
var all_coins: Int,
var collect_total: String,
var watch_total: String,
var episode_total: String,
var search_click_total: Boolean,
val categoryList: List<com.localee.mireo.app.http.api.SearchHotApi.Bean.categoryBean>
)
data class categoryBean(
val id: String,
val name: String
)
}
}

View File

@ -0,0 +1,43 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
class SearchSearchApi : IRequestApi {
override fun getApi(): String {
return "search"
}
var search : String? = null
class Bean(
val list: List<com.localee.mireo.app.http.api.SearchSearchApi.Bean.Data>,
) {
data class Data(
val id: String,
val short_id: Int,
var short_play_id: Int,
val name: String,
val description: String,
val process: Int,
val image_url: String,
var horizontally_img: String,
var buy_type: Int,
var tag_type: String,
var all_coins: Int,
var collect_total: String,
var watch_total: String,
var episode_total: String,
var search_click_total: Boolean,
val categoryList: List<com.localee.mireo.app.http.api.SearchSearchApi.Bean.categoryBean>
)
data class categoryBean(
val id: String,
val name: String
)
}
}

View File

@ -0,0 +1,14 @@
package com.localee.mireo.app.http.api
import com.hjq.http.config.IRequestApi
class UserInfoApi : IRequestApi {
override fun getApi(): String {
return "customer/info"
}
var short_video_id : Int? = null
}

View File

@ -0,0 +1,30 @@
package com.localee.mireo.app.http.api
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()
}
}
}

View File

@ -0,0 +1,165 @@
package com.localee.mireo.app.http.api
import android.os.Parcel
import android.os.Parcelable
import com.hjq.http.config.IRequestApi
import java.io.Serializable
class VideoDetailsApi : IRequestApi {
override fun getApi(): String {
return "getVideoDetails"
}
var short_play_id: Int? = null
var video_id: Int? = null
data class Bean(
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 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 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().toString(),
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.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 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.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.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
)
}
}

View File

@ -0,0 +1,85 @@
package com.localee.mireo.app.http.exception
import okhttp3.Interceptor
import okhttp3.Response
import okhttp3.ResponseBody
import java.io.IOException
class HttpBodyInterceptor : Interceptor {
val EN_STR_TAG = '$'
@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 = deStr(circle)
val current = ResponseBody.create(actiity, str)
k_center.newBuilder().body(current).build()
} else {
k_center
}
}
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 de(bytes)
}
// Decrypt data
fun de(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(calRemoveSalt(it, s))
idx++
}
return ret.toByteArray()
}
fun calRemoveSalt(v: Byte, s: Byte): Byte {
return if (v >= s) {
(v - s).toByte()
} else {
(0xFF - (s - v) + 1).toByte()
}
}
}

View File

@ -0,0 +1,27 @@
package com.localee.mireo.app.http.exception;
import androidx.annotation.NonNull;
import com.localee.mireo.app.http.model.HttpData;
import com.hjq.http.exception.HttpException;
public final class ResultException extends HttpException {
private final HttpData<?> mData;
public ResultException(String message, HttpData<?> data) {
super(message);
mData = data;
}
public ResultException(String message, Throwable cause, HttpData<?> data) {
super(message, cause);
mData = data;
}
@NonNull
public HttpData<?> getHttpData() {
return mData;
}
}

View File

@ -0,0 +1,15 @@
package com.localee.mireo.app.http.exception;
import com.hjq.http.exception.HttpException;
public final class TokenException extends HttpException {
public TokenException(String message) {
super(message);
}
public TokenException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,22 @@
package com.localee.mireo.app.http.model
import okhttp3.Interceptor
import okhttp3.Response
class CharsetInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val response = chain.proceed(request)
val contentType = response.header("Content-Type")
val newContentType = if (contentType?.contains("charset=") == true) {
contentType
} else {
"$contentType; charset=utf-8"
}
return response.newBuilder()
.header("Content-Type", newContentType)
.build()
}
}

View File

@ -0,0 +1,64 @@
package com.localee.mireo.app.http.model;
import androidx.annotation.NonNull;
import com.hjq.gson.factory.GsonFactory;
import com.hjq.http.config.IRequestApi;
import com.hjq.http.request.HttpRequest;
import com.tencent.mmkv.MMKV;
public final class HttpCacheManager {
private static final MMKV HTTP_CACHE_CONTENT = MMKV.mmkvWithID("http_cache_content");;
private static final MMKV HTTP_CACHE_TIME = MMKV.mmkvWithID("http_cache_time");
@NonNull
public static String generateCacheKey(@NonNull HttpRequest<?> httpRequest) {
IRequestApi requestApi = httpRequest.getRequestApi();
return "请替换成当前的用户 id" + "\n" + requestApi.getApi() + "\n" + GsonFactory.getSingletonGson().toJson(requestApi);
}
public static String readHttpCache(@NonNull String cacheKey) {
String cacheValue = HTTP_CACHE_CONTENT.getString(cacheKey, null);
if (cacheValue == null || cacheValue.isEmpty() || "{}".equals(cacheValue)) {
return null;
}
return cacheValue;
}
public static boolean writeHttpCache(String cacheKey, String cacheValue) {
return HTTP_CACHE_CONTENT.putString(cacheKey, cacheValue).commit();
}
public static boolean deleteHttpCache(String cacheKey) {
return HTTP_CACHE_CONTENT.remove(cacheKey).commit();
}
public static void clearCache() {
HTTP_CACHE_CONTENT.clearMemoryCache();
HTTP_CACHE_CONTENT.clearAll();
HTTP_CACHE_TIME.clearMemoryCache();
HTTP_CACHE_TIME.clearAll();
}
public static long getHttpCacheTime(String cacheKey) {
return HTTP_CACHE_TIME.getLong(cacheKey, 0);
}
public static boolean setHttpCacheTime(String cacheKey, long cacheTime) {
return HTTP_CACHE_TIME.putLong(cacheKey, cacheTime).commit();
}
public static boolean isCacheInvalidate(String cacheKey, long maxCacheTime) {
if (maxCacheTime == Long.MAX_VALUE) {
return false;
}
long httpCacheTime = getHttpCacheTime(cacheKey);
if (httpCacheTime == 0) {
return true;
}
return httpCacheTime + maxCacheTime < System.currentTimeMillis();
}
}

View File

@ -0,0 +1,30 @@
package com.localee.mireo.app.http.model
open class HttpData<T> {
private val code: Int = 0
private val msg: String? = null
private val data: T? = null
fun getCode(): Int {
return code
}
fun getMessage(): String? {
return msg
}
fun getData(): T? {
return data
}
fun isRequestSucceed(): Boolean {
return code == 200
}
fun isTokenFailure(): Boolean {
return code == 1001
}
}

View File

@ -0,0 +1,38 @@
package com.localee.mireo.app.http.model
import com.localee.mireo.app.http.model.HttpListData.ListBean
import kotlin.math.ceil
class HttpListData<T> : HttpData<ListBean<T?>?>() {
class ListBean<T> {
private val pageIndex: Int = 0
private val pageSize: Int = 0
private val totalNumber: Int = 0
private val items: MutableList<T?>? = null
fun isLastPage(): Boolean {
return ceil((totalNumber.toFloat() / pageSize.toFloat())) <= pageIndex
}
fun getTotalNumber(): Int {
return totalNumber
}
fun getPageIndex(): Int {
return pageIndex
}
fun getPageSize(): Int {
return pageSize
}
fun getItems(): MutableList<T?>? {
return items
}
}
}

View File

@ -0,0 +1,238 @@
package com.localee.mireo.app.http.model
import android.app.Application
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.ConnectivityManager
import com.google.gson.JsonSyntaxException
import com.hjq.gson.factory.GsonFactory
import com.hjq.http.EasyLog
import com.hjq.http.config.IRequestHandler
import com.hjq.http.exception.CancelException
import com.hjq.http.exception.DataException
import com.hjq.http.exception.HttpException
import com.hjq.http.exception.NetworkException
import com.hjq.http.exception.NullBodyException
import com.hjq.http.exception.ResponseException
import com.hjq.http.exception.ServerException
import com.hjq.http.exception.TimeoutException
import com.hjq.http.request.HttpRequest
import com.localee.mireo.app.http.exception.ResultException
import com.localee.mireo.app.R
import com.localee.mireo.app.http.exception.TokenException
import com.tencent.mmkv.MMKV
import okhttp3.Headers
import okhttp3.Response
import okhttp3.ResponseBody
import java.io.IOException
import java.io.InputStream
import java.lang.reflect.GenericArrayType
import java.lang.reflect.Type
import java.net.SocketTimeoutException
import java.net.UnknownHostException
class RequestHandler constructor(private val mApplication: Application) : IRequestHandler {
override fun requestSuccess(httpRequest: HttpRequest<*>, response: Response, type: Type): Any {
if (Response::class.java == type) {
return response
}
if (!response.isSuccessful) {
throw ResponseException(
String.format(
mApplication.getString(R.string.http_response_error),
response.code(), response.message()
), response
)
}
if (Headers::class.java == type) {
return response.headers()
}
val body = response.body()
?: throw NullBodyException(mApplication.getString(R.string.http_response_null_body))
if (ResponseBody::class.java == type) {
return body
}
// val decryptedString = response.body()?.string()?.let { decrypt(it) }
//
// body = ResponseBody.create(response.body()!!.contentType(), decryptedString)
// 如果是用数组接收,判断一下是不是用 byte[] 类型进行接收的
if (type is GenericArrayType) {
val genericComponentType = type.genericComponentType
if (Byte::class.javaPrimitiveType == genericComponentType) {
return body.bytes()
}
}
if (InputStream::class.java == type) {
return body.byteStream()
}
if (Bitmap::class.java == type) {
return BitmapFactory.decodeStream(body.byteStream())
}
val text: String
try {
text = body.string()
} catch (e: IOException) {
throw DataException(mApplication.getString(R.string.http_data_explain_error), e)
}
EasyLog.printJson(httpRequest, text)
if (String::class.java == type) {
return text
}
val result: Any
try {
result = GsonFactory.getSingletonGson().fromJson(text, type)
} catch (e: JsonSyntaxException) {
throw DataException(mApplication.getString(R.string.http_data_explain_error), e)
}
if (result is HttpData<*>) {
val model = result
val headers = response.headers()
val headersSize = headers.size()
val headersMap: MutableMap<String, String> = HashMap(headersSize)
for (i in 0 until headersSize) {
headersMap[headers.name(i)] = headers.value(i)
}
if (model.isRequestSucceed()) {
return result
}
if (model.isTokenFailure()) {
throw TokenException(
mApplication.getString(R.string.http_token_error)
)
}
throw ResultException(model.getMessage(), model)
}
return result
}
override fun requestFail(httpRequest: HttpRequest<*>, throwable: Throwable): Throwable {
if (throwable is HttpException) {
if (throwable is TokenException) {
}
return throwable
}
if (throwable is SocketTimeoutException) {
return TimeoutException(
mApplication.getString(R.string.http_server_out_time),
throwable
)
}
if (throwable is UnknownHostException) {
val info =
(mApplication.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo
if (info != null && info.isConnected) {
return ServerException(
mApplication.getString(R.string.http_server_error),
throwable
)
}
return NetworkException(mApplication.getString(R.string.http_network_error), throwable)
}
if (throwable is IOException) {
return CancelException(mApplication.getString(R.string.http_request_cancel), throwable)
}
return HttpException(throwable.message, throwable)
}
override fun readCache(httpRequest: HttpRequest<*>, type: Type, cacheTime: Long): Any? {
val cacheKey: String =
HttpCacheManager.generateCacheKey(
httpRequest
)
val cacheValue: String =
HttpCacheManager.readHttpCache(
cacheKey
)
if (cacheValue == null || cacheValue.isEmpty() || "{}" == cacheValue) {
return null
}
EasyLog.printLog(httpRequest, "----- read cache key -----")
EasyLog.printJson(httpRequest, cacheKey)
EasyLog.printLog(httpRequest, "----- read cache value -----")
EasyLog.printJson(httpRequest, cacheValue)
EasyLog.printLog(httpRequest, "cacheTime = $cacheTime")
val cacheInvalidate: Boolean =
HttpCacheManager.isCacheInvalidate(
cacheKey,
cacheTime
)
EasyLog.printLog(httpRequest, "cacheInvalidate = $cacheInvalidate")
if (cacheInvalidate) {
return null
}
return GsonFactory.getSingletonGson().fromJson(cacheValue, type)
}
override fun writeCache(httpRequest: HttpRequest<*>, response: Response, result: Any): Boolean {
val cacheKey =
HttpCacheManager.generateCacheKey(
httpRequest
)
val cacheValue = GsonFactory.getSingletonGson().toJson(result)
if (cacheValue == null || cacheValue.isEmpty() || "{}" == cacheValue) {
return false
}
EasyLog.printLog(httpRequest, "----- write cache key -----")
EasyLog.printJson(httpRequest, cacheKey)
EasyLog.printLog(httpRequest, "----- write cache value -----")
EasyLog.printJson(httpRequest, cacheValue)
val writeHttpCacheResult =
HttpCacheManager.writeHttpCache(
cacheKey,
cacheValue
)
EasyLog.printLog(httpRequest, "writeHttpCacheResult = $writeHttpCacheResult")
val refreshHttpCacheTimeResult =
HttpCacheManager.setHttpCacheTime(
cacheKey,
System.currentTimeMillis()
)
EasyLog.printLog(httpRequest, "refreshHttpCacheTimeResult = $refreshHttpCacheTimeResult")
return writeHttpCacheResult && refreshHttpCacheTimeResult
}
override fun deleteCache(httpRequest: HttpRequest<*>): Boolean {
val cacheKey =
HttpCacheManager.generateCacheKey(
httpRequest
)
EasyLog.printLog(httpRequest, "----- delete cache key -----")
EasyLog.printJson(httpRequest, cacheKey)
val deleteHttpCacheResult =
HttpCacheManager.deleteHttpCache(
cacheKey
)
EasyLog.printLog(httpRequest, "deleteHttpCacheResult = $deleteHttpCacheResult")
return deleteHttpCacheResult
}
override fun clearCache() {
HttpCacheManager.clearCache()
}
}

View File

@ -0,0 +1,12 @@
package com.localee.mireo.app.http.model
import com.localee.mireo.app.other.AppConfig
import com.hjq.http.config.IRequestServer
class RequestServer : IRequestServer {
override fun getHost(): String {
return AppConfig.getHostUrl()
}
}

View File

@ -0,0 +1,183 @@
package com.localee.mireo.app.manager
import android.app.Activity
import android.app.Application
import android.app.Application.ActivityLifecycleCallbacks
import android.os.Bundle
import androidx.collection.ArrayMap
import timber.log.Timber
import java.util.*
class ActivityManager private constructor() : ActivityLifecycleCallbacks {
companion object {
@Suppress("StaticFieldLeak")
private val activityManager: ActivityManager by lazy { ActivityManager() }
fun getInstance(): ActivityManager {
return activityManager
}
private fun getObjectTag(`object`: Any): String {
return `object`.javaClass.name + Integer.toHexString(`object`.hashCode())
}
}
private val activitySet: ArrayMap<String?, Activity?> = ArrayMap()
private val lifecycleCallbacks: ArrayList<ApplicationLifecycleCallback> = ArrayList()
private lateinit var application: Application
private var topActivity: Activity? = null
private var resumedActivity: Activity? = null
fun init(application: Application) {
this.application = application
this.application.registerActivityLifecycleCallbacks(this)
}
fun getApplication(): Application {
return application
}
fun getTopActivity(): Activity? {
return topActivity
}
fun getResumedActivity(): Activity? {
return resumedActivity
}
fun isForeground(): Boolean {
return getResumedActivity() != null
}
fun registerApplicationLifecycleCallback(callback: ApplicationLifecycleCallback) {
lifecycleCallbacks.add(callback)
}
fun unregisterApplicationLifecycleCallback(callback: ApplicationLifecycleCallback) {
lifecycleCallbacks.remove(callback)
}
fun finishActivity(clazz: Class<out Activity?>?) {
if (clazz == null) {
return
}
val keys: Array<String?> = activitySet.keys.toTypedArray()
for (key: String? in keys) {
val activity: Activity? = activitySet[key]
if (activity == null || activity.isFinishing) {
continue
}
if ((activity.javaClass == clazz)) {
activity.finish()
activitySet.remove(key)
break
}
}
}
fun finishAllActivities() {
finishAllActivities(null as Class<out Activity?>?)
}
@SafeVarargs
fun finishAllActivities(vararg classArray: Class<out Activity>?) {
val keys: Array<String?> = activitySet.keys.toTypedArray()
for (key: String? in keys) {
val activity: Activity? = activitySet[key]
if (activity == null || activity.isFinishing) {
continue
}
var whiteClazz = false
for (clazz: Class<out Activity?>? in classArray) {
if ((activity.javaClass == clazz)) {
whiteClazz = true
}
}
if (whiteClazz) {
continue
}
activity.finish()
activitySet.remove(key)
}
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
Timber.i("%s - onCreate", activity.javaClass.simpleName)
if (activitySet.size == 0) {
for (callback: ApplicationLifecycleCallback? in lifecycleCallbacks) {
callback?.onApplicationCreate(activity)
}
Timber.i("%s - onApplicationCreate", activity.javaClass.simpleName)
}
activitySet[getObjectTag(activity)] = activity
topActivity = activity
}
override fun onActivityStarted(activity: Activity) {
Timber.i("%s - onStart", activity.javaClass.simpleName)
}
override fun onActivityResumed(activity: Activity) {
Timber.i("%s - onResume", activity.javaClass.simpleName)
if (topActivity === activity && resumedActivity == null) {
for (callback: ApplicationLifecycleCallback in lifecycleCallbacks) {
callback.onApplicationForeground(activity)
}
Timber.i("%s - onApplicationForeground", activity.javaClass.simpleName)
}
topActivity = activity
resumedActivity = activity
}
override fun onActivityPaused(activity: Activity) {
Timber.i("%s - onPause", activity.javaClass.simpleName)
}
override fun onActivityStopped(activity: Activity) {
Timber.i("%s - onStop", activity.javaClass.simpleName)
if (resumedActivity === activity) {
resumedActivity = null
}
if (resumedActivity == null) {
for (callback: ApplicationLifecycleCallback in lifecycleCallbacks) {
callback.onApplicationBackground(activity)
}
Timber.i("%s - onApplicationBackground", activity.javaClass.simpleName)
}
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
Timber.i("%s - onSaveInstanceState", activity.javaClass.simpleName)
}
override fun onActivityDestroyed(activity: Activity) {
Timber.i("%s - onDestroy", activity.javaClass.simpleName)
activitySet.remove(getObjectTag(activity))
if (topActivity === activity) {
topActivity = null
}
if (activitySet.size == 0) {
for (callback: ApplicationLifecycleCallback in lifecycleCallbacks) {
callback.onApplicationDestroy(activity)
}
Timber.i("%s - onApplicationDestroy", activity.javaClass.simpleName)
}
}
interface ApplicationLifecycleCallback {
fun onApplicationCreate(activity: Activity)
fun onApplicationDestroy(activity: Activity)
fun onApplicationBackground(activity: Activity)
fun onApplicationForeground(activity: Activity)
}
}

View File

@ -0,0 +1,77 @@
package com.localee.mireo.app.manager
import android.content.Context
import android.os.Environment
import com.tencent.bugly.crashreport.CrashReport
import java.io.File
import java.math.BigDecimal
object CacheDataManager {
fun getTotalCacheSize(context: Context): String {
var cacheSize: Long = getFolderSize(context.cacheDir)
if ((Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED)) {
cacheSize += getFolderSize(context.externalCacheDir!!)
}
return getFormatSize(cacheSize.toDouble())
}
fun clearAllCache(context: Context) {
deleteDir(context.cacheDir)
if ((Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED)) {
deleteDir(context.externalCacheDir)
}
}
private fun deleteDir(dir: File?): Boolean {
if (dir == null) {
return false
}
if (!dir.isDirectory) {
return dir.delete()
}
val children: Array<out String> = dir.list() ?: return false
for (child: String in children) {
deleteDir(File(dir, child))
}
return false
}
private fun getFolderSize(file: File): Long {
var size: Long = 0
try {
val list: Array<out File> = file.listFiles() ?: return 0
for (temp: File in list) {
size += if (temp.isDirectory) {
getFolderSize(temp)
} else {
temp.length()
}
}
} catch (e: Exception) {
CrashReport.postCatchedException(e)
}
return size
}
fun getFormatSize(size: Double): String {
val kiloByte: Double = size / 1024
if (kiloByte < 1) {
// return size + "Byte";
return "0K"
}
val megaByte: Double = kiloByte / 1024
if (megaByte < 1) {
return BigDecimal(kiloByte).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "K"
}
val gigaByte: Double = megaByte / 1024
if (gigaByte < 1) {
return BigDecimal(megaByte).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "M"
}
val teraBytes: Double = gigaByte / 1024
if (teraBytes < 1) {
return BigDecimal(gigaByte).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB"
}
return BigDecimal(teraBytes).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB"
}
}

View File

@ -0,0 +1,186 @@
package com.localee.mireo.app.manager
import android.content.Context
import android.view.View
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Recycler
import kotlin.math.abs
import kotlin.math.min
class PickerLayoutManager private constructor(
context: Context, orientation: Int, reverseLayout: Boolean, maxItem: Int, scale: Float, alpha: Boolean) :
LinearLayoutManager(context, orientation, reverseLayout) {
private val linearSnapHelper: LinearSnapHelper = LinearSnapHelper()
private val maxItem: Int
private val scale: Float
private val alpha: Boolean
private var recyclerView: RecyclerView? = null
private var listener: OnPickerListener? = null
init {
this.maxItem = maxItem
this.alpha = alpha
this.scale = scale
}
override fun onAttachedToWindow(recyclerView: RecyclerView) {
super.onAttachedToWindow(recyclerView)
this.recyclerView = recyclerView
this.recyclerView!!.clipToPadding = false
// 添加 LinearSnapHelper
linearSnapHelper.attachToRecyclerView(this.recyclerView)
}
override fun onDetachedFromWindow(recyclerView: RecyclerView?, recycler: Recycler?) {
super.onDetachedFromWindow(recyclerView, recycler)
this.recyclerView = null
}
override fun isAutoMeasureEnabled(): Boolean {
return maxItem == 0
}
override fun onMeasure(recycler: Recycler, state: RecyclerView.State, widthSpec: Int, heightSpec: Int) {
var width: Int = chooseSize(widthSpec, paddingLeft + paddingRight, ViewCompat.getMinimumWidth(recyclerView!!))
var height: Int = chooseSize(heightSpec, paddingTop + paddingBottom, ViewCompat.getMinimumHeight(recyclerView!!))
if (state.itemCount != 0 && maxItem != 0) {
val itemView: View = recycler.getViewForPosition(0)
measureChildWithMargins(itemView, widthSpec, heightSpec)
if (orientation == HORIZONTAL) {
val measuredWidth: Int = itemView.measuredWidth
val paddingHorizontal: Int = (maxItem - 1) / 2 * measuredWidth
recyclerView!!.setPadding(paddingHorizontal, 0, paddingHorizontal, 0)
width = measuredWidth * maxItem
} else if (orientation == VERTICAL) {
val measuredHeight: Int = itemView.measuredHeight
val paddingVertical: Int = (maxItem - 1) / 2 * measuredHeight
recyclerView!!.setPadding(0, paddingVertical, 0, paddingVertical)
height = measuredHeight * maxItem
}
}
setMeasuredDimension(width, height)
}
override fun onScrollStateChanged(state: Int) {
super.onScrollStateChanged(state)
if (state != RecyclerView.SCROLL_STATE_IDLE) {
return
}
recyclerView?.let {
listener?.onPicked(it, getPickedPosition())
}
}
override fun onLayoutChildren(recycler: Recycler, state: RecyclerView.State) {
super.onLayoutChildren(recycler, state)
if (itemCount < 0 || state.isPreLayout) {
return
}
if (orientation == HORIZONTAL) {
scaleHorizontalChildView()
} else if (orientation == VERTICAL) {
scaleVerticalChildView()
}
}
override fun scrollHorizontallyBy(dx: Int, recycler: Recycler?, state: RecyclerView.State?): Int {
scaleHorizontalChildView()
return super.scrollHorizontallyBy(dx, recycler, state)
}
override fun scrollVerticallyBy(dy: Int, recycler: Recycler?, state: RecyclerView.State?): Int {
scaleVerticalChildView()
return super.scrollVerticallyBy(dy, recycler, state)
}
private fun scaleHorizontalChildView() {
val mid: Float = width / 2.0f
for (i in 0 until childCount) {
val childView: View = getChildAt(i) ?: continue
val childMid: Float =
(getDecoratedLeft(childView) + getDecoratedRight(childView)) / 2.0f
val scale: Float = 1.0f + (-1 * (1 - scale)) * min(mid, abs(mid - childMid)) / mid
childView.scaleX = scale
childView.scaleY = scale
if (alpha) {
childView.alpha = scale
}
}
}
private fun scaleVerticalChildView() {
val mid: Float = height / 2.0f
for (i in 0 until childCount) {
val childView: View = getChildAt(i) ?: continue
val childMid: Float = (getDecoratedTop(childView) + getDecoratedBottom(childView)) / 2.0f
val scale: Float = 1.0f + (-1 * (1 - scale)) * (min(mid, abs(mid - childMid))) / mid
childView.scaleX = scale
childView.scaleY = scale
if (alpha) {
childView.alpha = scale
}
}
}
fun getPickedPosition(): Int {
val itemView: View = linearSnapHelper.findSnapView(this) ?: return 0
return getPosition(itemView)
}
fun setOnPickerListener(listener: OnPickerListener?) {
this.listener = listener
}
interface OnPickerListener {
fun onPicked(recyclerView: RecyclerView, position: Int)
}
class Builder constructor(private val context: Context) {
private var orientation: Int = VERTICAL
private var reverseLayout: Boolean = false
private var listener: OnPickerListener? = null
private var maxItem: Int = 3
private var scale: Float = 0.6f
private var alpha: Boolean = true
fun setOrientation(@RecyclerView.Orientation orientation: Int): Builder = apply {
this.orientation = orientation
}
fun setReverseLayout(reverseLayout: Boolean): Builder = apply {
this.reverseLayout = reverseLayout
}
fun setMaxItem(maxItem: Int): Builder = apply {
this.maxItem = maxItem
}
fun setScale(scale: Float): Builder = apply {
this.scale = scale
}
fun setAlpha(alpha: Boolean): Builder = apply {
this.alpha = alpha
}
fun setOnPickerListener(listener: OnPickerListener?): Builder = apply {
this.listener = listener
}
fun build(): PickerLayoutManager {
val layoutManager = PickerLayoutManager(context, orientation, reverseLayout, maxItem, scale, alpha)
layoutManager.setOnPickerListener(listener)
return layoutManager
}
fun into(recyclerView: RecyclerView) {
recyclerView.layoutManager = build()
}
}
}

View File

@ -0,0 +1,34 @@
package com.localee.mireo.app.other
import com.localee.mireo.app.BuildConfig
object AppConfig {
fun isDebug(): Boolean {
return BuildConfig.DEBUG
}
fun getBuildType(): String {
return BuildConfig.BUILD_TYPE
}
fun isLogEnable(): Boolean {
return BuildConfig.LOG_ENABLE
}
fun getPackageName(): String {
return BuildConfig.APPLICATION_ID
}
fun getVersionName(): String {
return BuildConfig.VERSION_NAME
}
fun getVersionCode(): Int {
return BuildConfig.VERSION_CODE
}
fun getHostUrl(): String {
return BuildConfig.HOST_URL
}
}

View File

@ -0,0 +1,56 @@
package com.localee.mireo.app.other
import android.app.*
import android.content.*
import android.os.Process
class CrashHandler private constructor(private val application: Application) :
Thread.UncaughtExceptionHandler {
companion object {
private const val CRASH_FILE_NAME: String = "crash_file"
private const val KEY_CRASH_TIME: String = "key_crash_time"
fun register(application: Application) {
Thread.setDefaultUncaughtExceptionHandler(CrashHandler(application))
}
}
private val nextHandler: Thread.UncaughtExceptionHandler? = Thread.getDefaultUncaughtExceptionHandler()
init {
if ((javaClass.name == nextHandler?.javaClass?.name)) {
throw IllegalStateException("are you ok?")
}
}
@Suppress("ApplySharedPref")
override fun uncaughtException(thread: Thread, throwable: Throwable) {
val sharedPreferences: SharedPreferences = application.getSharedPreferences(
CRASH_FILE_NAME, Context.MODE_PRIVATE)
val currentCrashTime: Long = System.currentTimeMillis()
val lastCrashTime: Long = sharedPreferences.getLong(KEY_CRASH_TIME, 0)
sharedPreferences.edit().putLong(KEY_CRASH_TIME, currentCrashTime).commit()
val deadlyCrash: Boolean = currentCrashTime - lastCrashTime < 1000 * 60 * 5
// if (AppConfig.isDebug()) {
// CrashActivity.start(application, throwable)
// } else {
// if (!deadlyCrash) {
// // 如果不是致命的异常就自动重启应用
// RestartActivity.start(application)
// }
// }
// 不去触发系统的崩溃处理com.android.internal.os.RuntimeInit$KillApplicationHandler
if (nextHandler != null && !nextHandler.javaClass.name
.startsWith("com.android.internal.os")) {
nextHandler.uncaughtException(thread, throwable)
}
Process.killProcess(Process.myPid())
System.exit(10)
}
}

View File

@ -0,0 +1,19 @@
package com.localee.mireo.app.other
import android.os.Build
import timber.log.Timber.DebugTree
class DebugLoggerTree : DebugTree() {
companion object {
private const val MAX_TAG_LENGTH: Int = 23
}
override fun createStackElementTag(element: StackTraceElement): String {
val tag: String = "(" + element.fileName + ":" + element.lineNumber + ")"
if (tag.length <= MAX_TAG_LENGTH || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return tag
}
return tag.substring(0, MAX_TAG_LENGTH)
}
}

View File

@ -0,0 +1,239 @@
package com.localee.mireo.app.other
import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.util.AttributeSet
import android.widget.ImageView
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import com.localee.mireo.app.R
import com.scwang.smart.refresh.header.material.CircleImageView
import com.scwang.smart.refresh.header.material.MaterialProgressDrawable
import com.scwang.smart.refresh.layout.api.RefreshHeader
import com.scwang.smart.refresh.layout.api.RefreshKernel
import com.scwang.smart.refresh.layout.api.RefreshLayout
import com.scwang.smart.refresh.layout.constant.RefreshState
import com.scwang.smart.refresh.layout.constant.SpinnerStyle
import com.scwang.smart.refresh.layout.simple.SimpleComponent
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
class MaterialHeader @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
SimpleComponent(context, attrs, 0), RefreshHeader {
companion object {
const val BALL_STYLE_LARGE: Int = 0
const val BALL_STYLE_DEFAULT: Int = 1
private val CIRCLE_BG_LIGHT: Int = Color.parseColor("#FAFAFA")
private const val MAX_PROGRESS_ANGLE: Float = 0.8f
}
private var finished: Boolean = false
private var circleDiameter: Int
private var circleView: ImageView
private var progressDrawable: MaterialProgressDrawable
private var waveHeight: Int = 0
private var headHeight: Int = 0
private var bezierPath: Path
private var bezierPaint: Paint
private var refreshState: RefreshState? = null
private var showBezierWave: Boolean = false
private var scrollableWhenRefreshing: Boolean = true
init {
mSpinnerStyle = SpinnerStyle.MatchLayout
minimumHeight = resources.getDimension(R.dimen.dp_100).toInt()
progressDrawable = MaterialProgressDrawable(this)
progressDrawable.setColorSchemeColors(
Color.parseColor("#0099CC"),
Color.parseColor("#FF4444"),
Color.parseColor("#669900"),
Color.parseColor("#AA66CC"),
Color.parseColor("#FF8800"))
circleView = CircleImageView(context, CIRCLE_BG_LIGHT)
circleView.setImageDrawable(progressDrawable)
circleView.alpha = 0f
addView(circleView)
circleDiameter = resources.getDimension(R.dimen.dp_40).toInt()
bezierPath = Path()
bezierPaint = Paint()
bezierPaint.isAntiAlias = true
bezierPaint.style = Paint.Style.FILL
val typedArray: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.MaterialHeader)
showBezierWave = typedArray.getBoolean(R.styleable.MaterialHeader_srlShowBezierWave, showBezierWave)
scrollableWhenRefreshing = typedArray.getBoolean(R.styleable.MaterialHeader_srlScrollableWhenRefreshing, scrollableWhenRefreshing)
bezierPaint.color = typedArray.getColor(R.styleable.MaterialHeader_srlPrimaryColor, Color.parseColor("#11BBFF"))
if (typedArray.hasValue(R.styleable.MaterialHeader_srlShadowRadius)) {
val radius: Int = typedArray.getDimensionPixelOffset(R.styleable.MaterialHeader_srlShadowRadius, 0)
val color: Int = typedArray.getColor(R.styleable.MaterialHeader_mhShadowColor, Color.parseColor("#000000"))
bezierPaint.setShadowLayer(radius.toFloat(), 0f, 0f, color)
setLayerType(LAYER_TYPE_SOFTWARE, null)
}
showBezierWave = typedArray.getBoolean(R.styleable.MaterialHeader_mhShowBezierWave, showBezierWave)
scrollableWhenRefreshing = typedArray.getBoolean(R.styleable.MaterialHeader_mhScrollableWhenRefreshing, scrollableWhenRefreshing)
if (typedArray.hasValue(R.styleable.MaterialHeader_mhPrimaryColor)) {
bezierPaint.color = typedArray.getColor(R.styleable.MaterialHeader_mhPrimaryColor, Color.parseColor("#11BBFF"))
}
if (typedArray.hasValue(R.styleable.MaterialHeader_mhShadowRadius)) {
val radius: Int = typedArray.getDimensionPixelOffset(R.styleable.MaterialHeader_mhShadowRadius, 0)
val color: Int = typedArray.getColor(R.styleable.MaterialHeader_mhShadowColor, Color.parseColor("#000000"))
bezierPaint.setShadowLayer(radius.toFloat(), 0f, 0f, color)
setLayerType(LAYER_TYPE_SOFTWARE, null)
}
typedArray.recycle()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec))
circleView.measure(MeasureSpec.makeMeasureSpec(circleDiameter, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(circleDiameter, MeasureSpec.EXACTLY))
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
if (childCount == 0) {
return
}
val width: Int = measuredWidth
val circleWidth: Int = circleView.measuredWidth
val circleHeight: Int = circleView.measuredHeight
if (isInEditMode && headHeight > 0) {
val circleTop: Int = headHeight - circleHeight / 2
circleView.layout((width / 2 - circleWidth / 2), circleTop,
(width / 2 + circleWidth / 2), circleTop + circleHeight)
progressDrawable.showArrow(true)
progressDrawable.setStartEndTrim(0f, MAX_PROGRESS_ANGLE)
progressDrawable.setArrowScale(1f)
circleView.alpha = 1f
circleView.visibility = VISIBLE
} else {
circleView.layout((width / 2 - circleWidth / 2), -circleHeight, (width / 2 + circleWidth / 2), 0)
}
}
override fun dispatchDraw(canvas: Canvas) {
if (showBezierWave) {
// 重置画笔
bezierPath.reset()
bezierPath.lineTo(0f, headHeight.toFloat())
// 绘制贝塞尔曲线
bezierPath.quadTo(measuredWidth / 2f, headHeight + waveHeight * 1.9f, measuredWidth.toFloat(), headHeight.toFloat())
bezierPath.lineTo(measuredWidth.toFloat(), 0f)
canvas.drawPath(bezierPath, bezierPaint)
}
super.dispatchDraw(canvas)
}
override fun onInitialized(kernel: RefreshKernel, height: Int, maxDragHeight: Int) {
if (!showBezierWave) {
kernel.requestDefaultTranslationContentFor(this, false)
}
if (isInEditMode) {
headHeight = height / 2
waveHeight = headHeight
}
}
override fun onMoving(dragging: Boolean, percent: Float, offset: Int, height: Int, maxDragHeight: Int) {
if (refreshState == RefreshState.Refreshing) {
return
}
if (showBezierWave) {
headHeight = min(offset, height)
waveHeight = max(0, offset - height)
postInvalidate()
}
if (dragging || (!progressDrawable.isRunning && !finished)) {
if (refreshState != RefreshState.Refreshing) {
val originalDragPercent: Float = 1f * offset / height
val dragPercent: Float = min(1f, abs(originalDragPercent))
val adjustedPercent: Float = max(dragPercent - .4, 0.0).toFloat() * 5 / 3
val extraOs: Float = (abs(offset) - height).toFloat()
val tensionSlingshotPercent: Float = max(0f, (min(extraOs, height.toFloat() * 2) / height.toFloat()))
val tensionPercent: Float = ((tensionSlingshotPercent / 4) - (tensionSlingshotPercent / 4).toDouble().pow(2.0)).toFloat() * 2f
val strokeStart: Float = adjustedPercent * .8f
progressDrawable.showArrow(true)
progressDrawable.setStartEndTrim(0f, min(MAX_PROGRESS_ANGLE, strokeStart))
progressDrawable.setArrowScale(min(1f, adjustedPercent))
val rotation: Float = (-0.25f + (.4f * adjustedPercent) + (tensionPercent * 2)) * .5f
progressDrawable.setProgressRotation(rotation)
}
val targetY: Float = offset / 2f + circleDiameter / 2f
circleView.translationY = min(offset.toFloat(), targetY)
circleView.alpha = min(1f, 4f * offset / circleDiameter)
}
}
override fun onReleased(layout: RefreshLayout, height: Int, maxDragHeight: Int) {
progressDrawable.start()
}
override fun onStateChanged(refreshLayout: RefreshLayout, oldState: RefreshState, newState: RefreshState) {
refreshState = newState
if (newState == RefreshState.PullDownToRefresh) {
finished = false
circleView.visibility = VISIBLE
circleView.translationY = 0f
circleView.scaleX = 1f
circleView.scaleY = 1f
}
}
override fun onFinish(layout: RefreshLayout, success: Boolean): Int {
progressDrawable.stop()
circleView.animate().scaleX(0f).scaleY(0f)
finished = true
return 0
}
fun setProgressBackgroundResource(@ColorRes id: Int): MaterialHeader = apply {
setProgressBackgroundColor(ContextCompat.getColor(context, id))
}
fun setProgressBackgroundColor(@ColorInt color: Int): MaterialHeader = apply {
circleView.setBackgroundColor(color)
}
fun setColorSchemeColors(@ColorInt vararg colors: Int): MaterialHeader = apply {
progressDrawable.setColorSchemeColors(*colors)
}
fun setColorSchemeResources(@ColorRes vararg ids: Int): MaterialHeader = apply {
val colors = IntArray(ids.size)
for (i in ids.indices) {
colors[i] = ContextCompat.getColor(context, ids[i])
}
setColorSchemeColors(*colors)
}
fun setBallStyle(style: Int): MaterialHeader = apply {
if (style != BALL_STYLE_LARGE && style != BALL_STYLE_DEFAULT) {
return@apply
}
circleDiameter = if (style == BALL_STYLE_LARGE) resources.getDimension(R.dimen.dp_56).toInt() else resources.getDimension(R.dimen.dp_40).toInt()
// force the bounds of the progress circle inside the circle view to
// update by setting it to null before updating its size and then
// re-setting it
circleView.setImageDrawable(null)
progressDrawable.updateSizes(style)
circleView.setImageDrawable(progressDrawable)
}
fun setShowBezierWave(show: Boolean): MaterialHeader = apply {
showBezierWave = show
}
fun setScrollableWhenRefreshing(scrollable: Boolean): MaterialHeader = apply {
scrollableWhenRefreshing = scrollable
}
}

View File

@ -0,0 +1,65 @@
package com.localee.mireo.app.other
object MsConstants {
const val ACCESS_TOKEN = "access_token"
const val APP_LANG = "app_langs"
const val CONSTANTS_User_STRING = "CONSTANTS_User_STRING"
const val Constants_web = "https://www.mireotv.com/"
const val Constants_user_agreement = "https://www.mireotv.com/user_policy"
const val Constants_privacy_policy = "https://www.mireotv.com/private"
const val EVENT_VIDEO_CLOSE = "event_video_close"
const val EVENT_VIDEO_NEXT = "event_video_next"
const val EVENT_VIDEO_HOME_NEXT = "event_video_home_next"
const val EVENT_VIDEO_PLAY = "event_video_play"
const val EVENT_VIDEO_UPDATE = "event_video_update"
const val EVENT_SELECT_COLLECT = "event_select_collect"
const val EVENT_SELECT_HOME_COLLECT = "event_select_home_collect"
const val EVENT_CLICK_COLLECTION = "event_click_Collection"
const val EVENT_TO_LOGIN = "event_to_login"
const val EVENT_SHOW_AD = "event_show_ad"
const val EVENT_ADD_IN = "event_add_in"
const val EVENT_TO_HOME = "event_to_home"
const val EVENT_DELE_ACC = "event_dele_acc"
const val EVENT_UPDATE_MAIN = "event_update_main"
const val EVENT_UPDATE_USER = "event_update_user_info"
const val EVENT_MAIN_UPDATE_USER_INFO = "event_update_user_info"
const val CLOSE_VIDEO = "close_video"
const val EVENT_SHOW_ADS = "event_show_ads"
const val EVENT_UPDATE_COLLECTION = "event_update_Collection"
var ExampleIsCurrentPage: Boolean = true
var Exampleplaying: Boolean = false
var ExampleDetailPlaying: Boolean = false
var Exampleready: Boolean = false
var ExampleDetailCanPlay: Boolean = true
var CanNotification: Boolean = false
var WebRefresh: Boolean = false
var isBannerScrolling: Boolean = true
var seek = true
const val Constants_RecommendPlayerView_PLAYER_STATUS_FINISHExample =
"Constants_RecommendPlayerView_PLAYER_STATUS_FINISHExample"
const val Constants_DetailPlayerView_PLAYER_STATUS_FINISHExample =
"Constants_DetailPlayerView_PLAYER_STATUS_FINISHE"
const val Constants_RecommendPlayerView_CLOSEExample =
"Constants_RecommendPlayerView_CLOSEExample"
const val Constants_RecommendPlayerView_DramaSeriesExample =
"Constants_RecommendPlayerView_DramaSeriesExample"
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_Translates_STRING = "CONSTANTS_Translates_STRING"
const val CONSTANTS_quality_refresh = "CONSTANTS_quality_refresh"
const val CONSTANTS_quality = "CONSTANTS_quality"
const val Constants_Episodes_Series_DataExample = "Constants_Episodes_Series_DataExample"
const val CONSTANTS_short_play_id = "CONSTANTS_short_play_id"
const val CONSTANTS_activity_id = "CONSTANTS_activity_id"
const val CONSTANTS_stop_play = "CONSTANTS_stop_play"
}

View File

@ -0,0 +1,188 @@
package com.localee.mireo.app.other
import android.app.Activity
import android.content.*
import android.os.*
import com.hjq.base.BaseDialog
import com.localee.mireo.app.manager.*
import com.localee.mireo.app.ui.dialog.MessageDialog
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.hjq.toast.ToastUtils
import com.localee.mireo.app.manager.ActivityManager
import java.util.*
import com.localee.mireo.app.R
abstract class PermissionCallback : OnPermissionCallback {
override fun onDenied(permissions: MutableList<String>, never: Boolean) {
if (never) {
showPermissionDialog(permissions)
return
}
if (permissions.size == 1 && (Permission.ACCESS_BACKGROUND_LOCATION == permissions[0])) {
ToastUtils.show(R.string.common_permission_fail_4)
return
}
ToastUtils.show(R.string.common_permission_fail_1)
}
protected fun showPermissionDialog(permissions: MutableList<String>) {
val activity: Activity? = ActivityManager.getInstance().getTopActivity()
if ((activity == null) || activity.isFinishing || activity.isDestroyed) {
return
}
MessageDialog.Builder(activity)
.setTitle(R.string.common_permission_alert)
.setMessage(getPermissionHint(activity, permissions))
.setConfirm(R.string.common_permission_goto)
.setCancel(null)
.setCancelable(false)
.setListener(object : MessageDialog.OnListener {
override fun onConfirm(dialog: BaseDialog?) {
XXPermissions.startPermissionActivity(activity, permissions)
}
})
.show()
}
protected fun getPermissionHint(context: Context, permissions: MutableList<String>): String {
if (permissions.isEmpty()) {
return context.getString(R.string.common_permission_fail_2)
}
val hints: MutableList<String> = ArrayList()
for (permission: String? in permissions) {
when (permission) {
Permission.READ_EXTERNAL_STORAGE,
Permission.WRITE_EXTERNAL_STORAGE,
Permission.MANAGE_EXTERNAL_STORAGE -> {
val hint: String = context.getString(R.string.common_permission_storage)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.CAMERA -> {
val hint: String = context.getString(R.string.common_permission_camera)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.RECORD_AUDIO -> {
val hint: String = context.getString(R.string.common_permission_microphone)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.ACCESS_FINE_LOCATION,
Permission.ACCESS_COARSE_LOCATION,
Permission.ACCESS_BACKGROUND_LOCATION -> {
val hint: String = if (!permissions.contains(Permission.ACCESS_FINE_LOCATION) &&
!permissions.contains(Permission.ACCESS_COARSE_LOCATION)) {
context.getString(R.string.common_permission_location_background)
} else {
context.getString(R.string.common_permission_location)
}
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.READ_PHONE_STATE,
Permission.CALL_PHONE,
Permission.ADD_VOICEMAIL,
Permission.USE_SIP,
Permission.READ_PHONE_NUMBERS,
Permission.ANSWER_PHONE_CALLS -> {
val hint: String = context.getString(R.string.common_permission_phone)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.GET_ACCOUNTS,
Permission.READ_CONTACTS,
Permission.WRITE_CONTACTS -> {
val hint: String = context.getString(R.string.common_permission_contacts)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.READ_CALENDAR,
Permission.WRITE_CALENDAR -> {
val hint: String = context.getString(R.string.common_permission_calendar)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.READ_CALL_LOG,
Permission.WRITE_CALL_LOG,
Permission.PROCESS_OUTGOING_CALLS -> {
val hint: String = context.getString(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) R.string.common_permission_call_log else R.string.common_permission_phone)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.BODY_SENSORS -> {
val hint: String = context.getString(R.string.common_permission_sensors)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.ACTIVITY_RECOGNITION -> {
val hint: String = context.getString(R.string.common_permission_activity_recognition)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.SEND_SMS,
Permission.RECEIVE_SMS,
Permission.READ_SMS,
Permission.RECEIVE_WAP_PUSH,
Permission.RECEIVE_MMS -> {
val hint: String = context.getString(R.string.common_permission_sms)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.REQUEST_INSTALL_PACKAGES -> {
val hint: String = context.getString(R.string.common_permission_install)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.NOTIFICATION_SERVICE -> {
val hint: String = context.getString(R.string.common_permission_notification)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.SYSTEM_ALERT_WINDOW -> {
val hint: String = context.getString(R.string.common_permission_window)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
Permission.WRITE_SETTINGS -> {
val hint: String = context.getString(R.string.common_permission_setting)
if (!hints.contains(hint)) {
hints.add(hint)
}
}
}
}
if (hints.isNotEmpty()) {
val builder: StringBuilder = StringBuilder()
for (text: String? in hints) {
if (builder.isEmpty()) {
builder.append(text)
} else {
builder.append("")
.append(text)
}
}
builder.append(" ")
return context.getString(R.string.common_permission_fail_3, builder.toString())
}
return context.getString(R.string.common_permission_fail_2)
}
}

View File

@ -0,0 +1,149 @@
package com.localee.mireo.app.other
import android.animation.TimeInterpolator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.view.animation.AccelerateDecelerateInterpolator
import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils
import com.localee.mireo.app.R
import com.scwang.smart.refresh.layout.api.RefreshFooter
import com.scwang.smart.refresh.layout.api.RefreshLayout
import com.scwang.smart.refresh.layout.constant.SpinnerStyle
import com.scwang.smart.refresh.layout.simple.SimpleComponent
import kotlin.math.min
class SmartBallPulseFooter @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) :
SimpleComponent(context, attrs, 0), RefreshFooter {
private val interpolator: TimeInterpolator = AccelerateDecelerateInterpolator()
private var noMoreData: Boolean = false
private var manualNormalColor: Boolean = false
private var manualAnimationColor: Boolean = false
private val paint: Paint = Paint()
private var normalColor: Int = Color.parseColor("#EEEEEE")
private var animatingColor: IntArray = intArrayOf(
Color.parseColor("#30B399"),
Color.parseColor("#FF4600"),
Color.parseColor("#142DCC")
)
private val circleSpacing: Float
private var startTime: Long = 0
private var started: Boolean = false
private val textWidth: Float
init {
minimumHeight = resources.getDimension(R.dimen.dp_60).toInt()
paint.color = Color.WHITE
paint.style = Paint.Style.FILL
paint.isAntiAlias = true
mSpinnerStyle = SpinnerStyle.Translate
circleSpacing = resources.getDimension(R.dimen.dp_2)
paint.textSize = resources.getDimension(R.dimen.sp_14)
textWidth = paint.measureText(getContext().getString(R.string.common_no_more_data))
}
override fun dispatchDraw(canvas: Canvas) {
val width: Int = width
val height: Int = height
if (noMoreData) {
paint.color = Color.parseColor("#898989")
canvas.drawText(
context.getString(R.string.common_no_more_data),
(width - textWidth) / 2, (height - paint.textSize) / 2, paint
)
} else {
val radius: Float = (min(width, height) - circleSpacing * 2) / 7
val x: Float = width / 2f - (radius * 2 + circleSpacing)
val y: Float = height / 2f
val now: Long = System.currentTimeMillis()
for (i in 0..2) {
val time: Long = now - startTime - (120 * (i + 1))
var percent: Float = if (time > 0) ((time % 750) / 750f) else 0f
percent = interpolator.getInterpolation(percent)
canvas.save()
val translateX: Float = x + ((radius * 2) * i) + (circleSpacing * i)
if (percent < 0.5) {
val scale: Float = 1 - percent * 2 * 0.7f
val translateY: Float = y - scale * 10
canvas.translate(translateX, translateY)
} else {
val scale: Float = percent * 2 * 0.7f - 0.4f
val translateY: Float = y + scale * 10
canvas.translate(translateX, translateY)
}
paint.color = animatingColor[i % animatingColor.size]
canvas.drawCircle(0f, 0f, radius / 3, paint)
canvas.restore()
}
}
if (started) {
postInvalidate()
}
}
override fun onStartAnimator(layout: RefreshLayout, height: Int, maxDragHeight: Int) {
if (started) {
return
}
invalidate()
started = true
startTime = System.currentTimeMillis()
}
override fun onFinish(layout: RefreshLayout, success: Boolean): Int {
started = false
startTime = 0
paint.color = normalColor
return 0
}
override fun setPrimaryColors(@ColorInt vararg colors: Int) {
if (!manualAnimationColor && colors.size > 1) {
setAnimatingColor(colors[0])
manualAnimationColor = false
}
if (!manualNormalColor) {
if (colors.size > 1) {
setNormalColor(colors[1])
} else if (colors.isNotEmpty()) {
setNormalColor(ColorUtils.compositeColors(Color.parseColor("#99FFFFFF"), colors[0]))
}
manualNormalColor = false
}
}
override fun setNoMoreData(noMoreData: Boolean): Boolean {
this.noMoreData = noMoreData
return true
}
fun setSpinnerStyle(style: SpinnerStyle?): SmartBallPulseFooter = apply {
mSpinnerStyle = style
}
fun setNormalColor(@ColorInt color: Int): SmartBallPulseFooter = apply {
normalColor = color
manualNormalColor = true
if (!started) {
paint.color = color
}
}
fun setAnimatingColor(@ColorInt color: Int): SmartBallPulseFooter = apply {
animatingColor = intArrayOf(color)
manualAnimationColor = true
if (started) {
paint.color = color
}
}
}

View File

@ -0,0 +1,74 @@
package com.localee.mireo.app.other
import android.content.*
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.widget.TextView
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.ContextCompat
import com.hjq.bar.style.LightBarStyle
import com.localee.mireo.app.R
import com.hjq.widget.view.PressAlphaTextView
class TitleBarStyle : LightBarStyle() {
override fun newTitleView(context: Context): TextView {
return AppCompatTextView(context)
}
override fun newLeftView(context: Context): TextView {
return PressAlphaTextView(context)
}
override fun newRightView(context: Context): TextView {
return PressAlphaTextView(context)
}
override fun getTitleBarBackground(context: Context): Drawable {
return ColorDrawable(ContextCompat.getColor(context, R.color.common_primary_color))
}
override fun getBackButtonDrawable(context: Context): Drawable? {
return ContextCompat.getDrawable(context, R.drawable.arrows_left_ic)
}
override fun getLeftTitleBackground(context: Context): Drawable? {
return null
}
override fun getRightTitleBackground(context: Context): Drawable? {
return null
}
override fun getChildHorizontalPadding(context: Context): Int {
return context.resources.getDimension(R.dimen.dp_12).toInt()
}
override fun getChildVerticalPadding(context: Context): Int {
return context.resources.getDimension(R.dimen.dp_14).toInt()
}
override fun getTitleSize(context: Context): Float {
return context.resources.getDimension(R.dimen.sp_15)
}
override fun getLeftTitleSize(context: Context): Float {
return context.resources.getDimension(R.dimen.sp_13)
}
override fun getRightTitleSize(context: Context): Float {
return context.resources.getDimension(R.dimen.sp_13)
}
override fun getTitleIconPadding(context: Context): Int {
return context.resources.getDimension(R.dimen.dp_2).toInt()
}
override fun getLeftIconPadding(context: Context): Int {
return context.resources.getDimension(R.dimen.dp_2).toInt()
}
override fun getRightIconPadding(context: Context): Int {
return context.resources.getDimension(R.dimen.dp_2).toInt()
}
}

View File

@ -0,0 +1,29 @@
package com.localee.mireo.app.other
import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import com.localee.mireo.app.R
import com.hjq.toast.style.BlackToastStyle
class ToastStyle : BlackToastStyle() {
override fun getBackgroundDrawable(context: Context): Drawable {
val drawable = GradientDrawable()
drawable.setColor(-0x78000000)
drawable.cornerRadius = context.resources.getDimension(R.dimen.button_circle_size)
return drawable
}
override fun getTextSize(context: Context): Float {
return context.resources.getDimension(R.dimen.sp_14)
}
override fun getHorizontalPadding(context: Context): Int {
return context.resources.getDimension(R.dimen.sp_24).toInt()
}
override fun getVerticalPadding(context: Context): Int {
return context.resources.getDimension(R.dimen.sp_16).toInt()
}
}

View File

@ -0,0 +1,45 @@
package com.localee.mireo.app.ui.activity
import android.content.Intent
import android.net.Uri
import android.view.View
import com.localee.mireo.app.R
import com.localee.mireo.app.aop.SingleClick
import com.localee.mireo.app.app.AppActivity
import com.localee.mireo.app.other.MsConstants
class AboutActivity : AppActivity() {
override fun getLayoutId(): Int {
return R.layout.about_activity
}
override fun initView() {
setOnClickListener(R.id.sb_about_web, R.id.sb_about_privacy, R.id.sb_about_agreement)
}
override fun initData() {
}
@SingleClick
override fun onClick(view: View) {
when (view.id) {
R.id.sb_about_web -> {
val webIntent = Intent(Intent.ACTION_VIEW, Uri.parse(MsConstants.Constants_web))
startActivity(webIntent)
}
R.id.sb_about_privacy -> {
BrowserActivity.start(this, MsConstants.Constants_privacy_policy)
}
R.id.sb_about_agreement -> {
BrowserActivity.start(this, MsConstants.Constants_user_agreement)
}
}
}
}

View File

@ -0,0 +1,143 @@
package com.localee.mireo.app.ui.activity
import android.app.Activity
import android.content.*
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.text.TextUtils
import android.view.*
import android.webkit.WebView
import android.widget.ProgressBar
import com.localee.mireo.app.R
import com.localee.mireo.app.action.StatusAction
import com.localee.mireo.app.aop.CheckNet
import com.localee.mireo.app.aop.Log
import com.localee.mireo.app.app.AppActivity
import com.localee.mireo.app.widget.BrowserView
import com.localee.mireo.app.widget.BrowserView.BrowserChromeClient
import com.localee.mireo.app.widget.BrowserView.BrowserViewClient
import com.localee.mireo.app.widget.StatusLayout
import com.localee.mireo.app.widget.StatusLayout.OnRetryListener
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.scwang.smart.refresh.layout.api.RefreshLayout
import com.scwang.smart.refresh.layout.listener.OnRefreshListener
class BrowserActivity : AppActivity(), StatusAction, OnRefreshListener {
companion object {
const val INTENT_KEY_IN_URL: String = "url"
@CheckNet
@Log
fun start(context: Context, url: String) {
if (TextUtils.isEmpty(url)) {
return
}
val intent = Intent(context, BrowserActivity::class.java)
intent.putExtra(INTENT_KEY_IN_URL, url)
if (context !is Activity) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
}
}
private val hintLayout: StatusLayout? by lazy { findViewById(R.id.hl_browser_hint) }
private val progressBar: ProgressBar? by lazy { findViewById(R.id.pb_browser_progress) }
private val refreshLayout: SmartRefreshLayout? by lazy { findViewById(R.id.sl_browser_refresh) }
private val browserView: BrowserView? by lazy { findViewById(R.id.wv_browser_view) }
override fun getLayoutId(): Int {
return R.layout.browser_activity
}
override fun initView() {
browserView?.setLifecycleOwner(this)
refreshLayout?.setOnRefreshListener(this)
}
override fun initData() {
showLoading()
browserView?.apply {
setBrowserViewClient(AppBrowserViewClient())
setBrowserChromeClient(AppBrowserChromeClient(this))
loadUrl(getString(INTENT_KEY_IN_URL)!!)
}
}
override fun getStatusLayout(): StatusLayout? {
return hintLayout
}
override fun onLeftClick(view: View) {
finish()
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
browserView?.apply {
if (keyCode == KeyEvent.KEYCODE_BACK && canGoBack()) {
// 后退网页并且拦截该事件
goBack()
return true
}
}
return super.onKeyDown(keyCode, event)
}
@CheckNet
private fun reload() {
browserView?.reload()
}
/**
* [OnRefreshListener]
*/
override fun onRefresh(refreshLayout: RefreshLayout) {
reload()
}
private inner class AppBrowserViewClient : BrowserViewClient() {
override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) {
post {
showError(object : OnRetryListener {
override fun onRetry(layout: StatusLayout) {
reload()
}
})
}
}
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
progressBar?.visibility = View.VISIBLE
}
override fun onPageFinished(view: WebView, url: String) {
progressBar?.visibility = View.GONE
refreshLayout?.finishRefresh()
showComplete()
}
}
private inner class AppBrowserChromeClient constructor(view: BrowserView) : BrowserChromeClient(view) {
override fun onReceivedTitle(view: WebView, title: String?) {
if (title == null) {
return
}
setTitle(title)
}
override fun onReceivedIcon(view: WebView, icon: Bitmap?) {
if (icon == null) {
return
}
setRightIcon(BitmapDrawable(resources, icon))
}
override fun onProgressChanged(view: WebView, newProgress: Int) {
progressBar?.progress = newProgress
}
}
}

View File

@ -0,0 +1,171 @@
package com.localee.mireo.app.ui.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import com.localee.mireo.app.utils.MsMMKVUtils
import com.gyf.immersionbar.ImmersionBar
import com.hjq.base.FragmentPagerAdapter
import com.hjq.http.EasyHttp
import com.hjq.http.listener.HttpCallbackProxy
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppActivity
import com.localee.mireo.app.app.AppFragment
import com.localee.mireo.app.http.api.UserInfoApi
import com.localee.mireo.app.http.api.UserInfoRes
import com.localee.mireo.app.http.model.HttpData
import com.localee.mireo.app.ui.adapter.NavigationAdapter
import com.localee.mireo.app.ui.fragment.ExploreFragment
import com.localee.mireo.app.ui.fragment.HomeFragment
import com.localee.mireo.app.ui.fragment.MessageFragment
import com.localee.mireo.app.ui.fragment.MineFragment
import com.localee.mireo.app.ui.fragment.SharedViewModel
class HomeActivity : AppActivity(), NavigationAdapter.OnNavigationListener {
companion object {
private const val INTENT_KEY_IN_FRAGMENT_INDEX: String = "fragmentIndex"
private const val INTENT_KEY_IN_FRAGMENT_CLASS: String = "fragmentClass"
@JvmOverloads
fun start(
context: Context,
fragmentClass: Class<out AppFragment<*>?>? = HomeFragment::class.java
) {
val intent = Intent(context, HomeActivity::class.java)
intent.putExtra(INTENT_KEY_IN_FRAGMENT_CLASS, fragmentClass)
if (context !is Activity) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
}
}
private val viewPager: ViewPager? by lazy { findViewById(R.id.vp_home_pager) }
private val navigationView: RecyclerView? by lazy { findViewById(R.id.rv_home_navigation) }
private var navigationAdapter: NavigationAdapter? = null
private var pagerAdapter: FragmentPagerAdapter<AppFragment<*>>? = null
private val viewModel: SharedViewModel by viewModels()
override fun getLayoutId(): Int {
return R.layout.home_activity
}
override fun initView() {
navigationAdapter = NavigationAdapter(this).apply {
addItem(
NavigationAdapter.MenuItem(
getString(R.string.home_nav_index),
ContextCompat.getDrawable(this@HomeActivity, R.drawable.home_home_selector)
)
)
addItem(
NavigationAdapter.MenuItem(
getString(R.string.home_nav_explore),
ContextCompat.getDrawable(this@HomeActivity, R.drawable.home_explore_selector)
)
)
addItem(
NavigationAdapter.MenuItem(
getString(R.string.home_nav_my_list),
ContextCompat.getDrawable(this@HomeActivity, R.drawable.home_my_list_selector)
)
)
addItem(
NavigationAdapter.MenuItem(
getString(R.string.home_nav_me),
ContextCompat.getDrawable(this@HomeActivity, R.drawable.home_me_selector)
)
)
setOnNavigationListener(this@HomeActivity)
navigationView?.adapter = this
}
}
override fun initData() {
// getCustomerUser()
pagerAdapter = FragmentPagerAdapter<AppFragment<*>>(this).apply {
addFragment(HomeFragment.newInstance())
addFragment(ExploreFragment.newInstance())
addFragment(MessageFragment.newInstance())
addFragment(MineFragment.newInstance())
viewPager?.adapter = this
}
onNewIntent(intent)
viewModel.action.observe(this) { data ->
switchFragment(data);
}
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
pagerAdapter?.let {
switchFragment(it.getFragmentIndex(getSerializable(INTENT_KEY_IN_FRAGMENT_CLASS)))
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
viewPager?.let {
outState.putInt(INTENT_KEY_IN_FRAGMENT_INDEX, it.currentItem)
}
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
switchFragment(savedInstanceState.getInt(INTENT_KEY_IN_FRAGMENT_INDEX))
}
private fun switchFragment(fragmentIndex: Int) {
if (fragmentIndex == -1) {
return
}
when (fragmentIndex) {
0, 1, 2, 3 -> {
viewPager?.currentItem = fragmentIndex
navigationAdapter?.setSelectedPosition(fragmentIndex)
}
}
}
/**
* [NavigationAdapter.OnNavigationListener]
*/
override fun onNavigationItemSelected(position: Int): Boolean {
return when (position) {
0, 1, 2, 3 -> {
viewPager?.currentItem = position
true
}
else -> false
}
}
override fun createStatusBarConfig(): ImmersionBar {
return super.createStatusBarConfig()
.navigationBarColor(R.color.white)
}
override fun onBackPressed() {
moveTaskToBack(false)
}
override fun onDestroy() {
super.onDestroy()
viewPager?.adapter = null
navigationView?.adapter = null
navigationAdapter?.setOnNavigationListener(null)
}
}

View File

@ -0,0 +1,160 @@
package com.localee.mireo.app.ui.activity
import android.content.Intent
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.widget.EditText
import android.widget.ImageView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.localee.mireo.app.R
import com.localee.mireo.app.action.StatusAction
import com.localee.mireo.app.app.AppActivity
import com.localee.mireo.app.http.api.SearchHotApi
import com.localee.mireo.app.http.api.SearchSearchApi
import com.localee.mireo.app.http.model.HttpData
import com.localee.mireo.app.other.MsConstants.CONSTANTS_short_play_id
import com.localee.mireo.app.ui.adapter.SearchHotAdapter
import com.localee.mireo.app.ui.adapter.SearchSearchAdapter
import com.localee.mireo.app.widget.StatusLayout
import com.hjq.http.EasyHttp
import com.hjq.http.config.IRequestApi
import com.hjq.http.listener.HttpCallbackProxy
class SearchActivity : AppActivity(), StatusAction {
private val hintLayout: StatusLayout? by lazy { findViewById(R.id.hl_status_hint) }
private val ivClose: ImageView? by lazy { findViewById(R.id.iv_close) }
private val etSearch: EditText? by lazy { findViewById(R.id.et_search) }
private val recycler: RecyclerView? by lazy { findViewById(R.id.recycler) }
private var mAdapter: SearchHotAdapter? = null
private var mKeyAdapter: SearchSearchAdapter? = null
override fun getLayoutId(): Int {
return R.layout.status_activity
}
override fun initView() {
recycler?.layoutManager =
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
mAdapter = SearchHotAdapter()
mKeyAdapter = SearchSearchAdapter()
recycler?.adapter = mAdapter
getSearchHot()
}
override fun initData() {
ivClose?.setOnClickListener {
finish()
}
etSearch?.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
if (!TextUtils.isEmpty(charSequence.toString())) {
recycler?.adapter = mKeyAdapter
getSearchSearch(charSequence.toString())
} else {
recycler?.adapter = mAdapter
}
}
override fun afterTextChanged(editable: Editable) {
}
})
mAdapter?.setOnItemClickListener { adapter, view, position ->
val searchHot: com.localee.mireo.app.http.api.SearchHotApi.Bean.Data = adapter.items.get(position)
startActivity(
Intent(
this,
VideoPlayActivity::class.java
).apply {
searchHot.short_play_id.let {
putExtra(CONSTANTS_short_play_id, it)
}
})
}
mKeyAdapter?.setOnItemClickListener { adapter, view, position ->
val search: com.localee.mireo.app.http.api.SearchSearchApi.Bean.Data = adapter.items.get(position)
startActivity(
Intent(
this,
VideoPlayActivity::class.java
).apply {
search.short_play_id.let {
putExtra(CONSTANTS_short_play_id, it)
}
})
}
}
fun getSearchHot() {
EasyHttp.get(this)
.api(com.localee.mireo.app.http.api.SearchHotApi().apply {
})
.request(object : HttpCallbackProxy<HttpData<SearchHotApi.Bean>>(this) {
override fun onHttpSuccess(result: HttpData<SearchHotApi.Bean>) {
result.getData()?.let {
if (it.list.isEmpty()) {
hintLayout?.show()
} else {
hintLayout?.hide()
}
mAdapter?.submitList(it.list)
}
}
override fun onHttpFail(throwable: Throwable) {
super.onHttpFail(throwable)
hintLayout?.show()
}
})
}
fun getSearchSearch(searchKey: String) {
EasyHttp.get(this)
.api(com.localee.mireo.app.http.api.SearchSearchApi().apply {
search = searchKey
})
.request(object : HttpCallbackProxy<HttpData<SearchSearchApi.Bean>>(this) {
override fun onHttpStart(api: IRequestApi) {
}
override fun onHttpSuccess(result: HttpData<SearchSearchApi.Bean>) {
result.getData()?.let {
if (it.list.isEmpty()) {
hintLayout?.show()
} else {
hintLayout?.hide()
}
mKeyAdapter?.submitList(it.list)
}
}
override fun onHttpFail(throwable: Throwable) {
super.onHttpFail(throwable)
hintLayout?.show()
}
})
}
override fun getStatusLayout(): StatusLayout? {
return hintLayout
}
}

View File

@ -0,0 +1,47 @@
package com.localee.mireo.app.ui.activity
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.hjq.widget.layout.SettingBar
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppActivity
import com.localee.mireo.app.manager.CacheDataManager
import com.localee.mireo.app.utils.singleClick
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class SettingActivity : AppActivity(){
private val cleanCacheView: SettingBar? by lazy { findViewById(R.id.sb_setting_cache) }
override fun getLayoutId(): Int {
return R.layout.setting_activity
}
override fun initView() {
cleanCacheView?.setOnClickListener {
singleClick {
// 清除内存缓存(必须在主线程)
Glide.get(this@SettingActivity).clearMemory()
lifecycleScope.launch(Dispatchers.IO) {
CacheDataManager.clearAllCache(this@SettingActivity)
// 清除本地缓存(必须在子线程)
Glide.get(this@SettingActivity).clearDiskCache()
withContext(Dispatchers.Main) {
// 重新获取应用缓存大小
cleanCacheView?.setRightText(CacheDataManager.getTotalCacheSize(this@SettingActivity))
}
}
}
}
}
override fun initData() {
// 获取应用缓存大小
cleanCacheView?.setRightText(CacheDataManager.getTotalCacheSize(this))
}
}

View File

@ -0,0 +1,31 @@
package com.localee.mireo.app.ui.activity
import com.gyf.immersionbar.BarHide
import com.gyf.immersionbar.ImmersionBar
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppActivity
class SplashActivity : AppActivity() {
override fun getLayoutId(): Int {
return R.layout.splash_activity
}
override fun initView() {
postDelayed(Runnable {
HomeActivity.start(this@SplashActivity)
finish()
}, 300)
}
override fun initData() {
}
override fun createStatusBarConfig(): ImmersionBar {
return super.createStatusBarConfig()
.hideBar(BarHide.FLAG_HIDE_BAR)
}
}

View File

@ -0,0 +1,635 @@
package com.localee.mireo.app.ui.activity
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.blankj.utilcode.util.NetworkUtils
import com.localee.mireo.app.utils.MsMMKVUtils
import com.hjq.http.EasyHttp
import com.hjq.http.config.IRequestApi
import com.hjq.http.listener.HttpCallbackProxy
import com.hjq.toast.ToastUtils
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppActivity
import com.localee.mireo.app.app.BaseEventBus
import com.localee.mireo.app.http.api.CreateHistoryApi
import com.localee.mireo.app.http.api.VideoDetailsApi
import com.localee.mireo.app.http.model.HttpData
import com.localee.mireo.app.other.MsConstants
import com.localee.mireo.app.other.MsConstants.CONSTANTS_activity_id
import com.localee.mireo.app.other.MsConstants.CONSTANTS_quality
import com.localee.mireo.app.other.MsConstants.CONSTANTS_quality_refresh
import com.localee.mireo.app.other.MsConstants.CONSTANTS_short_play_id
import com.localee.mireo.app.other.MsConstants.Constants_Episodes_Series_Data_currentPositionExample
import com.localee.mireo.app.ui.videoPaly.ExamplePlayerDetailDataRes
import com.localee.mireo.app.ui.videoPaly.ExampleSeriesDialogFragment
import com.localee.mireo.app.ui.videoPaly.ExampleUnFavoriteDialog
import com.localee.mireo.app.ui.videoPaly.VideoPlayAdapter
import com.localee.mireo.app.ui.videoPaly.VideoPlayerView
import com.localee.mireo.app.utils.DHStringUtils.getPublicRequest
import com.localee.mireo.app.utils.TranslatesUtils
import com.localee.mireo.app.utils.formatNumber
import com.localee.mireo.app.utils.singleClick
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
open class VideoPlayActivity : AppActivity(), VideoPlayAdapter.PlayerDetailCollection,
ExampleSeriesDialogFragment.SeriesCallBack {
companion object {
const val INTENT_KEY_PARAMETERS: String = "parameters"
}
private var first: Boolean = true
private var play: Boolean = true
private var qualityRefresh: Boolean = false
// private val exampleRecommendViewModel by lazy { ViewModelProvider(this)[ExampleRecommendViewModel::class.java] }
private var currentPage = 1
private val currentSize = 10
private var currentPosition = 0
private var exampleRecommendAdapter: VideoPlayAdapter? = null
private var data: com.localee.mireo.app.http.api.ExampleRecommendDataRes.Data? = null
private var revolution =
MsMMKVUtils.getMMKV().getInt(MsConstants.CONSTANTS_quality, 0).toString()
private val srRecommend: SmartRefreshLayout? by lazy { findViewById(R.id.sr_recommend) }
private val viewPagerExampleRecommend: ViewPager2? by lazy { findViewById(R.id.viewPager_example_recommend) }
private val exampleNetwork: ViewGroup? by lazy { findViewById(R.id.example_network) }
private val exampleTvNoNetwork: TextView? by lazy { exampleNetwork?.findViewById(R.id.example_tv_no_network) }
private val tvExampleRetry: TextView? by lazy { exampleNetwork?.findViewById(R.id.tv_example_retry) }
private val exampleEmpty: ViewGroup? by lazy { findViewById(R.id.example_empty) }
private val exampleTvEmpty: TextView? by lazy { exampleEmpty?.findViewById(R.id.example_tv_empty) }
// private val avi: LoadingAnimationView? by lazy { findViewById(R.id.avi) }
private var shortVideoId: Int? = null
private var activityId: Int? = null
private var shortVideo: VideoDetailsApi.Bean.ShortPlayInfo? = null
override fun getLayoutId(): Int {
return R.layout.video_play_activity
}
override fun initView() {
shortVideoId = intent.getIntExtra(CONSTANTS_short_play_id, 0)
activityId = intent.getIntExtra(CONSTANTS_activity_id, 0)
EventBus.getDefault().register(this)
this.window?.setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
)
this.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
exampleTvNoNetwork?.text =
TranslatesUtils.translates()?.no_network
tvExampleRetry?.text = TranslatesUtils.translates()?.retry
exampleTvEmpty?.text = TranslatesUtils.translates()?.s_no_content
}
override fun initData() {
initialization()
MsConstants.ExampleIsCurrentPage = true
if (!play) {
qualityLogic()
} else {
play = false
}
}
fun initialization() {
if (NetworkUtils.isConnected()) {
// avi?.start()
getVideoDetails()
} else {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_network.toString())
} else {
ToastUtils.show(getString(R.string.example_no_network))
}
exampleNetwork?.visibility = View.VISIBLE
}
srRecommend?.setOnRefreshListener {
if (NetworkUtils.isConnected()) {
// avi?.start()
currentPage = 1
viewPagerExampleRecommend?.post {
detailPlayerView()?.stop()
detailPlayerView()?.release()
}
getVideoDetails()
} else {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_network.toString())
} else {
ToastUtils.show(getString(R.string.example_no_network))
}
}
}
viewPagerExampleRecommend?.registerOnPageChangeCallback(object :
ViewPager2.OnPageChangeCallback() {
@SuppressLint("NotifyDataSetChanged")
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
currentPosition = position
val previousPosition = exampleRecommendAdapter?.currentPlayingPosition
if (previousPosition != position) {
exampleRecommendAdapter?.recyclerView?.post { exampleRecommendAdapter?.notifyDataSetChanged() }
}
exampleRecommendAdapter?.currentPlayingPosition = position
previousPosition?.let {
val recyclerView =
viewPagerExampleRecommend?.getChildAt(0) as RecyclerView
val exampleDetailPlayerView =
recyclerView.layoutManager?.findViewByPosition(it) as VideoPlayerView?
if (null != exampleDetailPlayerView) {
val episode1 =
exampleRecommendAdapter?.items?.get(it)
episode1?.short_play_id?.let { it1 ->
episode1?.short_play_video_id?.let { it2 ->
createHistory(
it1,
it2
)
}
}
}
}
}
override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)
when (state) {
ViewPager2.SCROLL_STATE_IDLE -> {
if (viewPagerExampleRecommend?.currentItem == viewPagerExampleRecommend?.adapter?.itemCount?.minus(
1
)
) {
if (!first) {
getVideoDetails()
} else {
first = false
}
}
}
ViewPager2.SCROLL_STATE_DRAGGING -> {
}
ViewPager2.SCROLL_STATE_SETTLING -> {
}
}
}
})
exampleTvEmpty?.setOnClickListener {
singleClick {
if (!NetworkUtils.isConnected()) {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_network.toString())
} else {
ToastUtils.show(getString(R.string.example_no_network))
}
return@singleClick
}
// avi?.start()
currentPage = 1
getVideoDetails()
}
}
tvExampleRetry?.setOnClickListener {
singleClick {
if (!NetworkUtils.isConnected()) {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_network.toString())
} else {
ToastUtils.show(getString(R.string.example_no_network))
}
return@singleClick
}
// avi?.start()
currentPage = 1
getVideoDetails()
}
}
}
// override fun onHiddenChanged(hidden: Boolean) {
// super.onHiddenChanged(hidden)
// if (!hidden) {
// activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
// MsConstants.ExampleIsCurrentPage = true
// qualityLogic()
// } else {
// activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
// MsConstants.ExampleIsCurrentPage = false
// srRecommend?.postDelayed({ detailPlayerView()?.pause() }, 300)
// }
// }
override fun onResume() {
super.onResume()
if (!play) {
detailPlayerView()?.play()
} else {
play = false
}
}
private fun qualityLogic() {
if (qualityRefresh) {
viewPagerExampleRecommend?.post {
detailPlayerView()?.stop()
detailPlayerView()?.release()
}
getVideoDetails()
qualityRefresh = false
} else {
detailPlayerView()?.play()
}
}
override fun onPause() {
super.onPause()
MsConstants.ExampleIsCurrentPage = false
srRecommend?.postDelayed({ detailPlayerView()?.pause() }, 300)
}
fun getVideoDetails() {
EasyHttp.get(this)
.api(VideoDetailsApi().apply {
if (activityId!! != 0) {
video_id = activityId;
}
short_play_id = shortVideoId;
})
.request(object : HttpCallbackProxy<HttpData<VideoDetailsApi.Bean>>(this) {
override fun onHttpSuccess(result: HttpData<VideoDetailsApi.Bean>) {
result.getData()?.let {
if (it.episodeList.isNotEmpty()) {
shortVideo = it.shortPlayInfo
exampleRecommendAdapter = VideoPlayAdapter()
exampleRecommendAdapter?.shortVideo = it.shortPlayInfo
viewPagerExampleRecommend?.adapter = exampleRecommendAdapter
exampleRecommendAdapter?.submitList(it.episodeList)
exampleRecommendAdapter?.playerDetailCollection =
this@VideoPlayActivity
createHistory(
it.episodeList[0].short_play_id,
it.episodeList[0].short_play_video_id
);
exampleNetwork?.visibility = View.INVISIBLE
exampleEmpty?.visibility = View.INVISIBLE
} else {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_more_data.toString())
} else {
ToastUtils.show(getString(R.string.example_there_s_no_more_data))
}
if (currentPage == 1) {
exampleEmpty?.visibility = View.VISIBLE
}
}
// avi?.stop()
srRecommend?.finishRefresh()
}
}
})
// ExampleRecommendRequest.getVideoDetails(current_page, page_size, revolution)
// .observeForever { result ->
// recommendLiveData.value = result.getOrNull()
// }
}
fun createHistory(videoId: Int, shortPlayId: Int) {
val sMap: MutableMap<String, String?> = LinkedHashMap()
// StringMap = getSortMap(StringMap);
sMap.put("short_play_id", videoId.toString())
sMap.put("video_id", shortPlayId.toString())
EasyHttp.post(this)
.api(CreateHistoryApi())
.body(getPublicRequest(sMap))
.request(object : HttpCallbackProxy<HttpData<Any>>(this) {
override fun onHttpStart(api: IRequestApi) {
}
override fun onHttpSuccess(result: HttpData<Any>) {
}
})
}
fun doCollect(shortPlayId: Int, videoId: Int) {
val sMap: MutableMap<String, String?> = LinkedHashMap()
// StringMap = getSortMap(StringMap);
sMap.put("short_play_id", shortPlayId.toString())
sMap.put("video_id", videoId.toString())
EasyHttp.post(this)
.api(com.localee.mireo.app.http.api.DoCollectApi())
.body(getPublicRequest(sMap))
.request(object : HttpCallbackProxy<HttpData<Any>>(this) {
override fun onHttpSuccess(result: HttpData<Any>) {
result.getData()?.let {
if (it != null) {
val imageView =
detailPlayerView()?.findViewById<AppCompatImageView>(R.id.example_iv_collection_controller)
val textview =
detailPlayerView()?.findViewById<AppCompatTextView>(R.id.example_tv_collection_num_controller)
imageView?.setImageResource(R.mipmap.iv_example_collection_h)
shortVideo?.collect_total = shortVideo?.collect_total?.plus(1)!!
shortVideo?.is_collect = true
textview?.text = formatNumber(shortVideo?.collect_total!!)
textview?.setTextColor(resources.getColor(R.color.example_color_F56490))
exampleRecommendAdapter?.shortVideo = shortVideo
EventBus.getDefault().post(
BaseEventBus(
MsConstants.Constants_Episodes_Series_DataExample,
shortVideo
)
)
if (TranslatesUtils.translates() != null) {
toast(TranslatesUtils.translates()?.success.toString())
}
} else {
if (TranslatesUtils.translates() != null) {
toast(TranslatesUtils.translates()?.network_error.toString())
} else {
toast(getString(R.string.example_service_exception_please_try_again))
}
}
}
}
})
}
fun doCancelCollect(shortPlayId: Int, videoId: Int) {
val sMap: MutableMap<String, String?> = LinkedHashMap()
// StringMap = getSortMap(StringMap);
sMap.put("short_play_id", shortPlayId.toString())
sMap.put("video_id", videoId.toString())
EasyHttp.post(this)
.api(com.localee.mireo.app.http.api.CancelCollectApi())
.body(getPublicRequest(sMap))
.request(object : HttpCallbackProxy<HttpData<Any>>(this) {
override fun onHttpSuccess(result: HttpData<Any>) {
result.getData()?.let {
if (it != null) {
val imageView =
detailPlayerView()?.findViewById<AppCompatImageView>(R.id.example_iv_collection_controller)
val textview =
detailPlayerView()?.findViewById<AppCompatTextView>(R.id.example_tv_collection_num_controller)
imageView?.setImageResource(R.mipmap.iv_example_collection_n)
shortVideo?.collect_total = shortVideo?.collect_total?.minus(1)!!
shortVideo?.is_collect = false
textview?.text = formatNumber(shortVideo?.collect_total!!)
textview?.setTextColor(resources.getColor(R.color.white))
exampleRecommendAdapter?.shortVideo = shortVideo
EventBus.getDefault().post(
BaseEventBus(
MsConstants.Constants_Episodes_Series_DataExample,
shortVideo
)
)
if (TranslatesUtils.translates() != null) {
toast(TranslatesUtils.translates()?.success.toString())
}
} else {
if (TranslatesUtils.translates() != null) {
toast(TranslatesUtils.translates()?.network_error.toString())
} else {
toast(getString(R.string.example_service_exception_please_try_again))
}
}
}
}
})
}
private fun detailPlayerView(): VideoPlayerView? {
try {
val recyclerView = viewPagerExampleRecommend?.getChildAt(0) as RecyclerView
return recyclerView.layoutManager?.findViewByPosition(currentPosition) as VideoPlayerView?
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
override fun onDestroy() {
viewPagerExampleRecommend?.post {
detailPlayerView()?.stop()
detailPlayerView()?.release()
}
super.onDestroy()
EventBus.getDefault().unregister(this)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(event: String) {
if (MsConstants.Constants_RecommendPlayerView_DramaSeriesExample == event) {
if (exampleRecommendAdapter?.items?.isNotEmpty() == true) {
val exampleSeriesDialogFragment = ExampleSeriesDialogFragment()
val bundle = Bundle()
bundle.putInt(
Constants_Episodes_Series_Data_currentPositionExample,
currentPosition
)
bundle.putParcelable(
MsConstants.Constants_Episodes_Series_DataExample,
shortVideo
)
bundle.putParcelableArrayList(
MsConstants.Constants_Episodes_Series_Data_ListExample,
exampleRecommendAdapter?.items?.let { ArrayList(it) }
)
exampleSeriesDialogFragment.seriesCallBack = this
exampleSeriesDialogFragment.arguments = bundle
exampleSeriesDialogFragment.show(
supportFragmentManager,
"ExampleSeriesDialogFragment"
)
}
}
if (MsConstants.Constants_DetailPlayerView_PLAYER_STATUS_FINISHExample == event) {
if (viewPagerExampleRecommend?.currentItem == exampleRecommendAdapter?.items?.size?.minus(
1
)
) {
// exampleHomeViewModel.getDetailsRecommand()
viewPagerExampleRecommend?.post {
detailPlayerView()?.pause()
detailPlayerView()?.release()
viewPagerExampleRecommend?.visibility = View.GONE
}
}
currentPosition.plus(1)
.let {
exampleRecommendAdapter?.items?.get(it)?.let { it1 ->
if (it1.coins > 0) {
if (MsMMKVUtils.getMMKV().getString(
CONSTANTS_short_play_id,
""
) == shortVideoId.toString()
) {
}
}
}
detailPlayerView()?.stop()
viewPagerExampleRecommend?.currentItem = it
}
}
if (CONSTANTS_quality_refresh == event) {
revolution =
MsMMKVUtils.getMMKV().getInt(MsConstants.CONSTANTS_quality, 0)
.toString()
qualityRefresh = true
}
if (MsConstants.Constants_RecommendPlayerView_CLOSEExample == event) {
finish()
}
if (CONSTANTS_quality == event) {
startActivity(SearchActivity::class.java)
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(event: BaseEventBus<ExamplePlayerDetailDataRes.ShortPlayInfo>) {
// if (MsConstants.Constants_Episodes_Series_DataExample == event.code) {
// if (exampleRecommendAdapter?.items?.get(currentPosition)?.name == event.data.name) {
// val imageView =
// detailPlayerView()?.findViewById<AppCompatImageView>(R.id.example_iv_collection_controller)
// val textview =
// detailPlayerView()?.findViewById<AppCompatTextView>(R.id.example_tv_collection_num_controller)
// imageView?.setImageResource(if (event.data.is_collect) R.mipmap.iv_example_collection_h else R.mipmap.iv_example_collection_n)
// exampleRecommendAdapter?.items?.get(currentPosition)?.collect_total =
// event.data.collect_total
// exampleRecommendAdapter?.items?.get(currentPosition)?.is_collect =
// event.data.is_collect
// textview?.text = formatNumber(event.data.collect_total)
// }
// }
}
// override fun collection(dataRes: ExampleRecommendDataRes.Data) {
// singleClick {
// data = dataRes
// if (dataRes.is_collect) {
// val exampleUnFavoriteDialog = ExampleUnFavoriteDialog(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)
// if (TranslatesUtils.translates() != null) {
// tvThinkAgain.text = TranslatesUtils.translates()?.try_again
// tvUnfavorite.text = TranslatesUtils.translates()?.collection
// tvTitle.text = TranslatesUtils.translates()?.collection
// tvContent.text = TranslatesUtils.translates()?.not_collect_warning
// }
// tvThinkAgain.setOnClickListener { exampleUnFavoriteDialog.dismiss() }
// tvUnfavorite.setOnClickListener {
// dataRes.video_info?.short_play_id?.let {
// dataRes.video_info.short_play_video_id.let { it1 ->
// doCancelCollect(
// it, it1
// )
// }
// }
// exampleUnFavoriteDialog.dismiss()
// }
// exampleUnFavoriteDialog.show()
// } else {
// dataRes.video_info?.short_play_id?.let {
// dataRes.video_info.short_play_video_id.let { it1 ->
// doCollect(
// it, it1
// )
// }
// }
// }
// }
// }
override fun collection(episode: VideoDetailsApi.Bean.Episode) {
singleClick {
if (!episode.is_lock) {
if (shortVideo?.is_collect == true) {
val exampleUnFavoriteDialog = ExampleUnFavoriteDialog(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)
if (TranslatesUtils.translates() != null) {
tvThinkAgain.text = TranslatesUtils.translates()?.try_again
tvUnfavorite.text = TranslatesUtils.translates()?.collection
tvTitle.text = TranslatesUtils.translates()?.collection
tvContent.text = TranslatesUtils.translates()?.not_collect_warning
}
tvThinkAgain.setOnClickListener { exampleUnFavoriteDialog.dismiss() }
tvUnfavorite.setOnClickListener {
episode.short_play_id.let {
episode.short_play_video_id.let { it1 ->
doCancelCollect(
it, it1
)
}
}
exampleUnFavoriteDialog.dismiss()
}
exampleUnFavoriteDialog.show()
} else {
episode.short_play_id.let {
episode.short_play_video_id.let { it1 ->
doCollect(
it, it1
)
}
}
}
}
}
}
override fun chooseSeries(episode: VideoDetailsApi.Bean.Episode) {
postDelayed({ detailPlayerView()?.pause() }, 300)
episode.episode.minus(1)
.let {
viewPagerExampleRecommend?.currentItem = it
}
}
}

View File

@ -0,0 +1,62 @@
package com.localee.mireo.app.ui.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppApplication
import com.localee.mireo.app.http.api.RecommendBean
import com.youth.banner.adapter.BannerAdapter
class HomeBannerAdapter(mDatas: List<RecommendBean>) :
BannerAdapter<RecommendBean, HomeBannerAdapter.BannerViewHolder>(mDatas) {
override fun onCreateHolder(parent: ViewGroup, viewType: Int): BannerViewHolder {
val view: View =
LayoutInflater.from(parent.context).inflate(R.layout.home_banner_item, parent, false)
return BannerViewHolder(view)
}
override fun onBindView(
holder: BannerViewHolder,
data: RecommendBean,
position: Int,
size: Int
) {
Glide.with(AppApplication.instance)
.load(data.image_url)
.into(holder.imageView)
holder.tvName.setText(data.name)
holder.tvDescription.setText(data.description)
holder.tvAdd.setOnClickListener {
data.let { it1 -> homeBannerOnClick?.bannerAdd(it1) }
}
holder.tvPlay.setOnClickListener {
data.let { it1 -> homeBannerOnClick?.bannerPlay(it1) }
}
}
inner class BannerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val imageView: ImageView = view.findViewById(R.id.iv_img)
val tvName: TextView = view.findViewById(R.id.tv_name)
val tvDescription: TextView = view.findViewById(R.id.tv_description)
val tvAdd: TextView = view.findViewById(R.id.tv_add)
val tvPlay: TextView = view.findViewById(R.id.tv_play)
}
var homeBannerOnClick: HomeBannerOnClick? = null
interface HomeBannerOnClick {
fun bannerAdd(dataRes: RecommendBean)
fun bannerPlay(dataRes: RecommendBean)
}
}

View File

@ -0,0 +1,36 @@
package com.localee.mireo.app.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.chad.library.adapter4.BaseQuickAdapter
import com.localee.mireo.app.app.AppApplication
import com.localee.mireo.app.databinding.ItemListTabBinding
import com.localee.mireo.app.http.api.RecommendBean
class HomeCategoriesTabAdapter : BaseQuickAdapter<RecommendBean, HomeCategoriesTabAdapter.VH>() {
class VH(
parent: ViewGroup,
val binding: ItemListTabBinding = ItemListTabBinding.inflate(
LayoutInflater.from(parent.context), parent, false
),
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
return VH(parent)
}
override fun onBindViewHolder(holder: VH, position: Int, item: RecommendBean?) {
if (null != item) {
holder.binding.tvName.text = item.name
Glide.with(AppApplication.instance)
.load(item.image_url)
.into(holder.binding.ivContent)
}
}
}

View File

@ -0,0 +1,52 @@
package com.localee.mireo.app.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.chad.library.adapter4.BaseQuickAdapter
import com.localee.mireo.app.app.AppApplication
import com.localee.mireo.app.databinding.ItemHomeCriticallyBinding
import com.localee.mireo.app.http.api.RecommendBean
import com.localee.mireo.app.utils.formatNumber
class HomeCriticallyAdapter :
BaseQuickAdapter<RecommendBean, HomeCriticallyAdapter.VH>() {
class VH(
parent: ViewGroup,
val binding: ItemHomeCriticallyBinding = ItemHomeCriticallyBinding.inflate(
LayoutInflater.from(parent.context), parent, false
),
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
return VH(parent)
}
override fun onBindViewHolder(
holder: VH,
position: Int,
item: RecommendBean?
) {
if (null != item) {
holder.binding.tvName.text = item.name
holder.binding.tvDescription.text = item.description
holder.binding.tvScore.text = item.all_coins
holder.binding.tvGood.text = item.watch_total?.let { formatNumber(it) }
if (item.category.isEmpty()) {
holder.binding.tvFavor.visibility = View.GONE
} else {
holder.binding.tvFavor.visibility = View.VISIBLE
holder.binding.tvFavor.text = item.category[0]
}
Glide.with(AppApplication.instance)
.load(item.image_url)
.into(holder.binding.ivContent)
}
}
}

View File

@ -0,0 +1,42 @@
package com.localee.mireo.app.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter
import com.hjq.shape.view.ShapeTextView
import com.localee.mireo.app.databinding.ItemHomeGenresBinding
class HomeGenresAdapter(var id: Int) : BaseQuickAdapter<String, HomeGenresAdapter.VH>() {
class VH(
parent: ViewGroup,
val binding: ItemHomeGenresBinding = ItemHomeGenresBinding.inflate(
LayoutInflater.from(parent.context), parent, false
),
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
return VH(parent)
}
override fun onBindViewHolder(holder: VH, position: Int, item: String?) {
if (null != item) {
holder.binding.tvType.text = item
val text: ShapeTextView = holder.binding.tvType
if (position == id) {
text.getShapeDrawableBuilder().setSolidColor(0xFFF8726D.toInt())
.setShadowColor(0xFFF8726D.toInt())
.intoBackground();
} else {
text.getShapeDrawableBuilder().setSolidColor(0x00000000.toInt())
.setShadowColor(0xFFF8726D.toInt())
.intoBackground();
}
}
}
}

View File

@ -0,0 +1,37 @@
package com.localee.mireo.app.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.chad.library.adapter4.BaseQuickAdapter
import com.localee.mireo.app.app.AppApplication
import com.localee.mireo.app.databinding.ItemHomeShortBinding
import com.localee.mireo.app.http.api.RecommendBean
class HomeShortAdapter : BaseQuickAdapter<RecommendBean, HomeShortAdapter.VH>() {
class VH(
parent: ViewGroup,
val binding: ItemHomeShortBinding = ItemHomeShortBinding.inflate(
LayoutInflater.from(parent.context), parent, false
),
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
return VH(parent)
}
override fun onBindViewHolder(holder: VH, position: Int, item: RecommendBean?) {
if (null != item) {
holder.binding.tvName.text = item.name
holder.binding.tvDescription.text = item.description
Glide.with(AppApplication.instance)
.load(item.image_url)
.into(holder.binding.ivContent)
}
}
}

View File

@ -0,0 +1,54 @@
package com.localee.mireo.app.ui.adapter
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.hjq.shape.view.ShapeTextView
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppApplication
import com.localee.mireo.app.http.api.RecommendBean
class HomeTopAdapter(var type: Int) :
BaseQuickAdapter<RecommendBean, QuickViewHolder>() {
override fun onCreateViewHolder(
context: Context,
parent: ViewGroup,
viewType: Int
): QuickViewHolder {
return QuickViewHolder(R.layout.item_home_top, parent)
}
override fun onBindViewHolder(
holder: QuickViewHolder,
position: Int,
item: RecommendBean?
) {
Glide.with(AppApplication.instance)
.load(item?.image_url)
.into(holder.getView(R.id.iv_content))
val text: ShapeTextView = holder.getView(R.id.tv_hot)
when (type) {
1 -> {
text.setText("HOT")
text.getShapeDrawableBuilder().setSolidColor(0xFFFF1E63.toInt())
.intoBackground();
}
2 -> {
text.setText("NEW")
text.getShapeDrawableBuilder().setSolidColor(0xFF564FC0.toInt())
.intoBackground();
}
3 -> {
}
}
}
}

View File

@ -0,0 +1,95 @@
package com.localee.mireo.app.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.chad.library.adapter4.BaseQuickAdapter
import com.localee.mireo.app.app.AppApplication
import com.localee.mireo.app.databinding.ItemListTabBinding
import com.localee.mireo.app.http.api.HistoryBean
class LostTabAdapter(var tabPosition: Int) :
BaseQuickAdapter<HistoryBean.Data, LostTabAdapter.VH>() {
var type = 0
var selectEdit = false
class VH(
parent: ViewGroup,
val binding: ItemListTabBinding = ItemListTabBinding.inflate(
LayoutInflater.from(parent.context), parent, false
),
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
return VH(parent)
}
override fun onBindViewHolder(holder: VH, position: Int, item: HistoryBean.Data?) {
if (null != item) {
holder.binding.tvName.text = item.name
Glide.with(AppApplication.instance)
.load(item.image_url)
.into(holder.binding.ivContent)
holder.binding.tvName2.text = item.name
Glide.with(AppApplication.instance)
.load(item.image_url)
.into(holder.binding.ivContent2)
if (type == 0) {
holder.binding.clOne.visibility = View.VISIBLE
holder.binding.rlTwo.visibility = View.GONE
} else {
holder.binding.clOne.visibility = View.GONE
holder.binding.rlTwo.visibility = View.VISIBLE
}
if (selectEdit) {
holder.binding.cbOne.visibility = View.VISIBLE
holder.binding.cbTwo.visibility = View.VISIBLE
} else {
holder.binding.cbOne.visibility = View.GONE
holder.binding.cbTwo.visibility = View.GONE
}
if (item.is_check) {
holder.binding.cbOne.isChecked = true
holder.binding.cbTwo.isChecked = true
} else {
holder.binding.cbOne.isChecked = false
holder.binding.cbTwo.isChecked = false
}
when (tabPosition) {
0 -> {
if (item.categoryList?.isNotEmpty() == true) {
holder.binding.tvFavor.text = item.categoryList.get(0).name
holder.binding.tvFavor.visibility = View.VISIBLE
if (item.categoryList.size > 1) {
holder.binding.tvLove.text = item.categoryList.get(1).name
holder.binding.tvLove.visibility = View.VISIBLE
} else {
holder.binding.tvLove.visibility = View.GONE
}
} else {
holder.binding.tvFavor.visibility = View.GONE
}
}
1 -> {
holder.binding.tvFavor.text =
"EP" + item.current_episode + " / EP" + item.episode_total
holder.binding.tvFavor.visibility = View.VISIBLE
holder.binding.tvLove.visibility = View.GONE
}
}
}
}
}

View File

@ -0,0 +1,38 @@
package com.localee.mireo.app.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.chad.library.adapter4.BaseQuickAdapter
import com.localee.mireo.app.app.AppApplication
import com.localee.mireo.app.databinding.ItemMeHistoryBinding
import com.localee.mireo.app.http.api.HistoryBean
class MeHistoryAdapter() :
BaseQuickAdapter<HistoryBean.Data, MeHistoryAdapter.VH>() {
var type = 0
var selectEdit = false
class VH(
parent: ViewGroup,
val binding: ItemMeHistoryBinding = ItemMeHistoryBinding.inflate(
LayoutInflater.from(parent.context), parent, false
),
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
return VH(parent)
}
override fun onBindViewHolder(holder: VH, position: Int, item: HistoryBean.Data?) {
if (null != item) {
Glide.with(AppApplication.instance)
.load(item.image_url)
.into(holder.binding.ivContent)
}
}
}

View File

@ -0,0 +1,89 @@
package com.localee.mireo.app.ui.adapter
import android.content.*
import android.graphics.drawable.Drawable
import android.view.*
import android.widget.*
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.hjq.base.BaseAdapter
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppAdapter
class NavigationAdapter constructor(context: Context) :
AppAdapter<NavigationAdapter.MenuItem>(context), BaseAdapter.OnItemClickListener {
private var selectedPosition: Int = 0
private var listener: OnNavigationListener? = null
init {
setOnItemClickListener(this)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder()
}
override fun generateDefaultLayoutManager(context: Context): RecyclerView.LayoutManager {
return GridLayoutManager(context, getCount(), RecyclerView.VERTICAL, false)
}
fun getSelectedPosition(): Int {
return selectedPosition
}
fun setSelectedPosition(position: Int) {
selectedPosition = position
notifyDataSetChanged()
}
fun setOnNavigationListener(listener: OnNavigationListener?) {
this.listener = listener
}
override fun onItemClick(recyclerView: RecyclerView?, itemView: View?, position: Int) {
if (selectedPosition == position) {
return
}
if (listener == null) {
selectedPosition = position
notifyDataSetChanged()
return
}
if (listener!!.onNavigationItemSelected(position)) {
selectedPosition = position
notifyDataSetChanged()
}
}
inner class ViewHolder : AppViewHolder(R.layout.home_navigation_item) {
private val iconView: ImageView? by lazy { findViewById(R.id.iv_home_navigation_icon) }
private val titleView: TextView? by lazy { findViewById(R.id.tv_home_navigation_title) }
override fun onBindView(position: Int) {
getItem(position).apply {
iconView?.setImageDrawable(getDrawable())
titleView?.text = getText()
iconView?.isSelected = (selectedPosition == position)
titleView?.isSelected = (selectedPosition == position)
}
}
}
class MenuItem constructor(private val text: String?, private val drawable: Drawable?) {
fun getText(): String? {
return text
}
fun getDrawable(): Drawable? {
return drawable
}
}
interface OnNavigationListener {
fun onNavigationItemSelected(position: Int): Boolean
}
}

View File

@ -0,0 +1,51 @@
package com.localee.mireo.app.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.chad.library.adapter4.BaseQuickAdapter
import com.localee.mireo.app.app.AppApplication
import com.localee.mireo.app.databinding.ItemSearchHotBinding
import com.localee.mireo.app.http.api.SearchHotApi
class SearchHotAdapter : BaseQuickAdapter<SearchHotApi.Bean.Data, SearchHotAdapter.VH>() {
class VH(
parent: ViewGroup,
val binding: ItemSearchHotBinding = ItemSearchHotBinding.inflate(
LayoutInflater.from(parent.context), parent, false
),
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
return VH(parent)
}
override fun onBindViewHolder(holder: VH, position: Int, item: SearchHotApi.Bean.Data?) {
if (null != item) {
holder.binding.tvName.text = item.name
holder.binding.tvDescription.text = item.description
// 设置item数据
Glide.with(AppApplication.instance)
.load(item.image_url)
.into(holder.binding.ivContent)
if (item.categoryList?.isNotEmpty() == true) {
holder.binding.tvFavor.text = item.categoryList.get(0).name
holder.binding.tvFavor.visibility = View.VISIBLE
if (item.categoryList.size > 1) {
holder.binding.tvLove.text = item.categoryList.get(1).name
holder.binding.tvLove.visibility = View.VISIBLE
} else {
holder.binding.tvLove.visibility = View.GONE
}
} else {
holder.binding.tvFavor.visibility = View.GONE
}
}
}
}

View File

@ -0,0 +1,31 @@
package com.localee.mireo.app.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter
import com.localee.mireo.app.databinding.ItemSearchSearchBinding
import com.localee.mireo.app.http.api.SearchSearchApi
class SearchSearchAdapter : BaseQuickAdapter<SearchSearchApi.Bean.Data, SearchSearchAdapter.VH>() {
class VH(
parent: ViewGroup,
val binding: ItemSearchSearchBinding = ItemSearchSearchBinding.inflate(
LayoutInflater.from(parent.context), parent, false
),
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
return VH(parent)
}
override fun onBindViewHolder(holder: VH, position: Int, item: SearchSearchApi.Bean.Data?) {
if (null != item) {
holder.binding.tvKey.text = item.name
}
}
}

View File

@ -0,0 +1,223 @@
package com.localee.mireo.app.ui.adapter
import android.animation.ValueAnimator
import android.animation.ValueAnimator.AnimatorUpdateListener
import android.content.Context
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
import com.hjq.base.BaseAdapter
import com.hjq.shape.view.ShapeTextView
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppAdapter
class TabAdapter @JvmOverloads constructor(
context: Context,
private val tabMode: Int = TAB_MODE_DESIGN,
private val fixed: Boolean = true
) : AppAdapter<String?>(context), BaseAdapter.OnItemClickListener {
companion object {
const val TAB_MODE_DESIGN: Int = 1
const val TAB_MODE_SLIDING: Int = 2
}
private var selectedPosition: Int = 0
private var listener: OnTabListener? = null
init {
setOnItemClickListener(this)
registerAdapterDataObserver(TabAdapterDataObserver())
}
override fun getItemViewType(position: Int): Int {
return tabMode
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder {
return when (viewType) {
TAB_MODE_DESIGN -> DesignViewHolder()
TAB_MODE_SLIDING -> SlidingViewHolder()
else -> throw IllegalArgumentException("are you ok?")
}
}
override fun generateDefaultLayoutManager(context: Context): RecyclerView.LayoutManager {
return if (fixed) {
var count: Int = getCount()
if (count < 1) {
count = 1
}
GridLayoutManager(context, count, RecyclerView.VERTICAL, false)
} else {
LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
}
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
recyclerView.itemAnimator = null
}
fun getSelectedPosition(): Int {
return selectedPosition
}
fun setSelectedPosition(position: Int) {
if (selectedPosition == position) {
return
}
notifyItemChanged(selectedPosition)
selectedPosition = position
notifyItemChanged(position)
}
fun setOnTabListener(listener: OnTabListener?) {
this.listener = listener
}
override fun onItemClick(recyclerView: RecyclerView?, itemView: View?, position: Int) {
if (selectedPosition == position) {
return
}
if (listener == null) {
selectedPosition = position
notifyDataSetChanged()
return
}
if (listener!!.onTabSelected(recyclerView, position)) {
selectedPosition = position
notifyDataSetChanged()
}
}
inner class DesignViewHolder : AppViewHolder(R.layout.tab_item_design) {
private val titleView: TextView? by lazy { findViewById(R.id.tv_tab_design_title) }
private val lineView: View? by lazy { findViewById(R.id.v_tab_design_line) }
init {
if (fixed) {
val itemView: View = getItemView()
val layoutParams: ViewGroup.LayoutParams = itemView.layoutParams
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
itemView.layoutParams = layoutParams
}
}
override fun onBindView(position: Int) {
titleView?.text = getItem(position)
titleView?.isSelected = (selectedPosition == position)
lineView?.visibility =
if (selectedPosition == position) View.VISIBLE else View.INVISIBLE
}
}
inner class SlidingViewHolder : AppViewHolder(R.layout.tab_item_sliding),
AnimatorUpdateListener {
private val titleView: ShapeTextView? by lazy { findViewById(R.id.tv_tab_sliding_title) }
private val mDefaultTextSize: Int by lazy {
getResources().getDimension(R.dimen.sp_12).toInt()
}
private val mSelectedTextSize: Int by lazy {
getResources().getDimension(R.dimen.sp_12).toInt()
}
init {
titleView?.setTextSize(TypedValue.COMPLEX_UNIT_PX, mDefaultTextSize.toFloat())
if (fixed) {
val itemView: View = getItemView()
val layoutParams: ViewGroup.LayoutParams = itemView.layoutParams
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
itemView.layoutParams = layoutParams
}
}
override fun onBindView(position: Int) {
titleView?.let {
it.text = getItem(position)
it.isSelected = (selectedPosition == position)
val textSize: Int = it.textSize.toInt()
if (selectedPosition == position) {
it.shapeDrawableBuilder.setSolidGradientColors(
0xFFF24C92.toInt(),
0xFFF8726D.toInt()
).setStrokeSize(0)
.intoBackground();
if (textSize != mSelectedTextSize) {
startAnimator(mDefaultTextSize, mSelectedTextSize)
}
return
} else {
it.shapeDrawableBuilder.setSolidGradientColors(
0x00000000.toInt(),
0x00000000.toInt()
).setStrokeSize(getResources().getDimension(R.dimen.dp_1).toInt())
.setStrokeColor(0xFFF56490.toInt())
.intoBackground();
}
if (textSize != mDefaultTextSize) {
startAnimator(mSelectedTextSize, mDefaultTextSize)
}
}
}
private fun startAnimator(start: Int, end: Int) {
val valueAnimator: ValueAnimator = ValueAnimator.ofInt(start, end)
valueAnimator.addUpdateListener(this)
valueAnimator.duration = 100
valueAnimator.start()
}
override fun onAnimationUpdate(animation: ValueAnimator) {
titleView?.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
(animation.animatedValue as Int).toFloat()
)
}
}
private inner class TabAdapterDataObserver : AdapterDataObserver() {
override fun onChanged() {
refreshLayoutManager()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
refreshLayoutManager()
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
refreshLayoutManager()
if (getSelectedPosition() > positionStart - itemCount) {
setSelectedPosition(positionStart - itemCount)
}
}
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {}
private fun refreshLayoutManager() {
if (!fixed) {
return
}
getRecyclerView()?.layoutManager = generateDefaultLayoutManager(getContext())
}
}
interface OnTabListener {
fun onTabSelected(recyclerView: RecyclerView?, position: Int): Boolean
}
}

View File

@ -0,0 +1,80 @@
package com.localee.mireo.app.ui.dialog
import android.content.*
import android.view.*
import android.widget.TextView
import androidx.annotation.LayoutRes
import androidx.annotation.StringRes
import com.hjq.base.BaseDialog
import com.hjq.base.action.AnimAction
import com.localee.mireo.app.R
class CommonDialog {
@Suppress("UNCHECKED_CAST", "LeakingThis")
open class Builder<B : Builder<B>>(context: Context) : BaseDialog.Builder<B>(context) {
private var autoDismiss = true
private val containerLayout: ViewGroup? by lazy { findViewById(R.id.ll_ui_container) }
private val titleView: TextView? by lazy { findViewById(R.id.tv_ui_title) }
private val cancelView: TextView? by lazy { findViewById(R.id.tv_ui_cancel) }
private val lineView: View? by lazy { findViewById(R.id.v_ui_line) }
private val confirmView: TextView? by lazy { findViewById(R.id.tv_ui_confirm) }
init {
setContentView(R.layout.ui_dialog)
setAnimStyle(AnimAction.ANIM_IOS)
setGravity(Gravity.CENTER)
setOnClickListener(cancelView, confirmView)
}
fun setCustomView(@LayoutRes id: Int): B {
return setCustomView(LayoutInflater.from(getContext()).inflate(id, containerLayout, false))
}
fun setCustomView(view: View?): B {
containerLayout?.addView(view, 1)
return this as B
}
fun setTitle(@StringRes id: Int): B {
return setTitle(getString(id))
}
fun setTitle(text: CharSequence?): B {
titleView?.text = text
return this as B
}
fun setCancel(@StringRes id: Int): B {
return setCancel(getString(id))
}
fun setCancel(text: CharSequence?): B {
cancelView?.text = text
lineView?.visibility = if (text == null || "" == text.toString()) View.GONE else View.VISIBLE
return this as B
}
fun setConfirm(@StringRes id: Int): B {
return setConfirm(getString(id))
}
fun setConfirm(text: CharSequence?): B {
confirmView?.text = text
return this as B
}
fun setAutoDismiss(dismiss: Boolean): B {
autoDismiss = dismiss
return this as B
}
fun autoDismiss() {
if (autoDismiss) {
dismiss()
}
}
}
}

View File

@ -0,0 +1,101 @@
package com.localee.mireo.app.ui.dialog
import android.content.Context
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import android.widget.TextView.OnEditorActionListener
import androidx.annotation.StringRes
import com.hjq.base.BaseDialog
import com.localee.mireo.app.R
import com.localee.mireo.app.aop.SingleClick
import com.hjq.widget.view.RegexEditText
class InputDialog {
class Builder(context: Context) : CommonDialog.Builder<Builder>(context),
BaseDialog.OnShowListener, OnEditorActionListener {
private val inputView: RegexEditText? by lazy { findViewById(R.id.tv_input_message) }
private var listener: OnListener? = null
init {
setCustomView(R.layout.input_dialog)
inputView?.setOnEditorActionListener(this)
addOnShowListener(this)
}
fun setHint(@StringRes id: Int): Builder = apply {
setHint(getString(id))
}
fun setHint(text: CharSequence?): Builder = apply {
inputView?.hint = text
}
fun setContent(@StringRes id: Int): Builder = apply {
setContent(getString(id))
}
fun setContent(text: CharSequence?): Builder = apply {
inputView?.setText(text)
val editable = inputView?.text ?: return@apply
val index = editable.length
if (index <= 0) {
return@apply
}
inputView?.requestFocus()
inputView?.setSelection(index)
}
fun setInputRegex(regex: String?): Builder = apply {
inputView?.setInputRegex(regex)
}
fun setListener(listener: OnListener?): Builder = apply {
this.listener = listener
}
/**
* [BaseDialog.OnShowListener]
*/
override fun onShow(dialog: BaseDialog?) {
postDelayed({ showKeyboard(inputView) }, 500)
}
@SingleClick
override fun onClick(view: View) {
when (view.id) {
R.id.tv_ui_confirm -> {
autoDismiss()
listener?.onConfirm(getDialog(), inputView?.text?.toString() ?: "")
}
R.id.tv_ui_cancel -> {
autoDismiss()
listener?.onCancel(getDialog())
}
}
}
/**
* [TextView.OnEditorActionListener]
*/
override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
if (actionId == EditorInfo.IME_ACTION_DONE) {
findViewById<View>(R.id.tv_ui_confirm)?.let {
// 模拟点击确认按钮
onClick(it)
}
return true
}
return false
}
}
interface OnListener {
fun onConfirm(dialog: BaseDialog?, content: String)
fun onCancel(dialog: BaseDialog?) {}
}
}

View File

@ -0,0 +1,63 @@
package com.localee.mireo.app.ui.dialog
import android.content.Context
import android.view.View
import android.widget.TextView
import androidx.annotation.StringRes
import com.hjq.base.BaseDialog
import com.localee.mireo.app.R
import com.localee.mireo.app.aop.SingleClick
class MessageDialog {
class Builder constructor(context: Context) : CommonDialog.Builder<Builder>(context) {
private val messageView: TextView? by lazy { findViewById(R.id.tv_message_message) }
private var listener: OnListener? = null
init {
setCustomView(R.layout.message_dialog)
}
fun setMessage(@StringRes id: Int): Builder = apply {
setMessage(getString(id))
}
fun setMessage(text: CharSequence?): Builder = apply {
messageView?.text = text
}
fun setListener(listener: OnListener?): Builder = apply {
this.listener = listener
}
override fun create(): BaseDialog {
if (("" == messageView?.text.toString())) {
throw IllegalArgumentException("Dialog message not null")
}
return super.create()
}
@SingleClick
override fun onClick(view: View) {
when (view.id) {
R.id.tv_ui_confirm -> {
autoDismiss()
listener?.onConfirm(getDialog())
}
R.id.tv_ui_cancel -> {
autoDismiss()
listener?.onCancel(getDialog())
}
}
}
}
interface OnListener {
fun onConfirm(dialog: BaseDialog?)
fun onCancel(dialog: BaseDialog?) {}
}
}

View File

@ -0,0 +1,70 @@
package com.localee.mireo.app.ui.dialog
import android.content.Context
import android.text.TextUtils
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.hjq.base.BaseDialog
import com.hjq.base.action.AnimAction
import com.localee.mireo.app.R
class TipsDialog {
companion object {
const val ICON_FINISH: Int = R.drawable.tips_finish_ic
const val ICON_ERROR: Int = R.drawable.tips_error_ic
const val ICON_WARNING: Int = R.drawable.tips_warning_ic
}
class Builder(context: Context) : BaseDialog.Builder<Builder>(context),
Runnable, BaseDialog.OnShowListener {
private val messageView: TextView? by lazy { findViewById(R.id.tv_tips_message) }
private val iconView: ImageView? by lazy { findViewById(R.id.iv_tips_icon) }
private var duration = 2000
init {
setContentView(R.layout.tips_dialog)
setAnimStyle(AnimAction.ANIM_TOAST)
setBackgroundDimEnabled(false)
setCancelable(false)
addOnShowListener(this)
}
fun setIcon(@DrawableRes id: Int): Builder = apply {
iconView?.setImageResource(id)
}
fun setDuration(duration: Int): Builder = apply {
this.duration = duration
}
fun setMessage(@StringRes id: Int): Builder = apply {
setMessage(getString(id))
}
fun setMessage(text: CharSequence?): Builder = apply {
messageView?.text = text
}
override fun create(): BaseDialog {
requireNotNull(iconView?.drawable) { "The display type must be specified" }
require(!TextUtils.isEmpty(messageView?.text.toString())) { "Dialog message not null" }
return super.create()
}
override fun onShow(dialog: BaseDialog?) {
postDelayed(this, duration.toLong())
}
override fun run() {
if (!isShowing()) {
return
}
dismiss()
}
}
}

View File

@ -0,0 +1,33 @@
package com.localee.mireo.app.ui.dialog
import android.content.*
import android.view.*
import android.widget.TextView
import androidx.annotation.StringRes
import com.hjq.base.BaseDialog
import com.hjq.base.action.AnimAction
import com.localee.mireo.app.R
class WaitDialog {
class Builder(context: Context) : BaseDialog.Builder<Builder>(context) {
private val messageView: TextView? by lazy { findViewById(R.id.tv_wait_message) }
init {
setContentView(R.layout.wait_dialog)
setAnimStyle(AnimAction.ANIM_TOAST)
setBackgroundDimEnabled(false)
setCancelable(false)
}
fun setMessage(@StringRes id: Int): Builder = apply {
setMessage(getString(id))
}
fun setMessage(text: CharSequence?): Builder = apply {
messageView?.text = text
messageView?.visibility = if (text == null) View.GONE else View.VISIBLE
}
}
}

View File

@ -0,0 +1,104 @@
package com.localee.mireo.app.ui.fragment
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.webkit.WebView
import com.localee.mireo.app.R
import com.localee.mireo.app.action.StatusAction
import com.localee.mireo.app.aop.CheckNet
import com.localee.mireo.app.aop.Log
import com.localee.mireo.app.app.AppActivity
import com.localee.mireo.app.app.AppFragment
import com.localee.mireo.app.ui.activity.BrowserActivity
import com.localee.mireo.app.widget.BrowserView
import com.localee.mireo.app.widget.BrowserView.BrowserChromeClient
import com.localee.mireo.app.widget.BrowserView.BrowserViewClient
import com.localee.mireo.app.widget.StatusLayout
import com.localee.mireo.app.widget.StatusLayout.OnRetryListener
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.scwang.smart.refresh.layout.api.RefreshLayout
import com.scwang.smart.refresh.layout.listener.OnRefreshListener
import java.util.*
class BrowserFragment : AppFragment<AppActivity>(), StatusAction, OnRefreshListener {
companion object {
private const val INTENT_KEY_IN_URL: String = "url"
@Log
fun newInstance(url: String): BrowserFragment {
val fragment = BrowserFragment()
val bundle = Bundle()
bundle.putString(INTENT_KEY_IN_URL, url)
fragment.arguments = bundle
return fragment
}
}
private val hintLayout: StatusLayout? by lazy { findViewById(R.id.hl_browser_hint) }
private val refreshLayout: SmartRefreshLayout? by lazy { findViewById(R.id.sl_browser_refresh) }
private val browserView: BrowserView? by lazy { findViewById(R.id.wv_browser_view) }
override fun getLayoutId(): Int {
return R.layout.browser_fragment
}
override fun initView() {
browserView?.setLifecycleOwner(this)
refreshLayout?.setOnRefreshListener(this)
}
override fun initData() {
browserView?.apply {
setBrowserViewClient(AppBrowserViewClient())
setBrowserChromeClient(BrowserChromeClient(this))
loadUrl(getString(INTENT_KEY_IN_URL)!!)
}
showLoading()
}
override fun getStatusLayout(): StatusLayout {
return hintLayout!!
}
@CheckNet
private fun reload() {
browserView?.reload()
}
/**
* [OnRefreshListener]
*/
override fun onRefresh(refreshLayout: RefreshLayout) {
reload()
}
private inner class AppBrowserViewClient : BrowserViewClient() {
override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) {
post {
showError(object : OnRetryListener {
override fun onRetry(layout: StatusLayout) {
reload()
}
})
}
}
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {}
override fun onPageFinished(view: WebView, url: String) {
refreshLayout?.finishRefresh()
showComplete()
}
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
val scheme: String = Uri.parse(url).scheme ?: return true
when (scheme.lowercase(Locale.getDefault())) {
"http", "https" -> BrowserActivity.start(getAttachActivity()!!, url)
}
return true
}
}
}

View File

@ -0,0 +1,502 @@
package com.localee.mireo.app.ui.fragment
import android.annotation.SuppressLint
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.blankj.utilcode.util.NetworkUtils
import com.localee.mireo.app.utils.MsMMKVUtils
import com.localee.mireo.app.R
import com.localee.mireo.app.app.BaseEventBus
import com.localee.mireo.app.app.TitleBarFragment
import com.localee.mireo.app.http.api.ExampleRecommendDataRes
import com.localee.mireo.app.http.api.HomeRecommendApi
import com.localee.mireo.app.http.model.HttpData
import com.localee.mireo.app.other.MsConstants
import com.localee.mireo.app.other.MsConstants.CONSTANTS_quality_refresh
import com.localee.mireo.app.ui.activity.HomeActivity
import com.localee.mireo.app.ui.videoPaly.ExamplePlayerDetailDataRes
import com.localee.mireo.app.ui.videoPaly.ExampleRecommendAdapter
import com.localee.mireo.app.ui.videoPaly.ExampleRecommendPlayerView
import com.localee.mireo.app.ui.videoPaly.ExampleUnFavoriteDialog
import com.localee.mireo.app.utils.DHStringUtils.getPublicRequest
import com.localee.mireo.app.utils.TranslatesUtils
import com.localee.mireo.app.utils.formatNumber
import com.localee.mireo.app.utils.singleClick
import com.hjq.http.EasyHttp
import com.hjq.http.listener.HttpCallbackProxy
import com.hjq.toast.ToastUtils
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class ExploreFragment : TitleBarFragment<HomeActivity>(),
ExampleRecommendAdapter.ExampleRecommendCollection {
companion object {
fun newInstance(): ExploreFragment {
return ExploreFragment()
}
}
private var first: Boolean = true
private var play: Boolean = true
private var qualityRefresh: Boolean = false
// private val exampleRecommendViewModel by lazy { ViewModelProvider(this)[ExampleRecommendViewModel::class.java] }
private var currentPage = 1
private val currentSize = 10
private var currentPosition = 0
private var exampleRecommendAdapter: ExampleRecommendAdapter? = null
private var data: com.localee.mireo.app.http.api.ExampleRecommendDataRes.Data? = null
private var revolution =
MsMMKVUtils.getMMKV().getInt(MsConstants.CONSTANTS_quality, 0).toString()
private val srRecommend: SmartRefreshLayout? by lazy { findViewById(R.id.sr_recommend) }
private val viewPagerExampleRecommend: ViewPager2? by lazy { findViewById(R.id.viewPager_example_recommend) }
private val exampleNetwork: ViewGroup? by lazy { findViewById(R.id.example_network) }
private val exampleTvNoNetwork: TextView? by lazy { exampleNetwork?.findViewById(R.id.example_tv_no_network) }
private val tvExampleRetry: TextView? by lazy { exampleNetwork?.findViewById(R.id.tv_example_retry) }
private val exampleEmpty: ViewGroup? by lazy { findViewById(R.id.example_empty) }
private val exampleTvEmpty: TextView? by lazy { exampleEmpty?.findViewById(R.id.example_tv_empty) }
// private val avi: LoadingAnimationView? by lazy { findViewById(R.id.avi) }
override fun getLayoutId(): Int {
return R.layout.find_fragment
}
override fun initView() {
EventBus.getDefault().register(this)
activity?.window?.setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
)
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
exampleTvNoNetwork?.text =
TranslatesUtils.translates()?.no_network
tvExampleRetry?.text = TranslatesUtils.translates()?.retry
exampleTvEmpty?.text = TranslatesUtils.translates()?.s_no_content
}
override fun initData() {
}
fun initialization() {
if (NetworkUtils.isConnected()) {
// avi?.start()
getRecommands(currentPage, currentSize, revolution)
} else {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_network.toString())
} else {
ToastUtils.show(getString(R.string.example_no_network))
}
exampleNetwork?.visibility = View.VISIBLE
}
srRecommend?.setOnRefreshListener {
if (NetworkUtils.isConnected()) {
// avi?.start()
currentPage = 1
viewPagerExampleRecommend?.post {
recommendPlayerView()?.stop()
recommendPlayerView()?.release()
}
getRecommands(
currentPage,
currentSize, revolution
)
} else {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_network.toString())
} else {
ToastUtils.show(getString(R.string.example_no_network))
}
}
}
viewPagerExampleRecommend?.registerOnPageChangeCallback(object :
ViewPager2.OnPageChangeCallback() {
@SuppressLint("NotifyDataSetChanged")
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
currentPosition = position
val previousPosition = exampleRecommendAdapter?.currentPlayingPosition
if (previousPosition != position) {
exampleRecommendAdapter?.recyclerView?.post { exampleRecommendAdapter?.notifyDataSetChanged() }
}
exampleRecommendAdapter?.currentPlayingPosition = position
}
override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)
when (state) {
ViewPager2.SCROLL_STATE_IDLE -> {
if (viewPagerExampleRecommend?.currentItem == viewPagerExampleRecommend?.adapter?.itemCount?.minus(
1
)
) {
if (!first) {
currentPage++
getRecommands(
currentPage,
currentSize,
revolution
)
} else {
first = false
}
}
}
ViewPager2.SCROLL_STATE_DRAGGING -> {
}
ViewPager2.SCROLL_STATE_SETTLING -> {
}
}
}
})
exampleTvEmpty?.setOnClickListener {
singleClick {
if (!NetworkUtils.isConnected()) {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_network.toString())
} else {
ToastUtils.show(getString(R.string.example_no_network))
}
return@singleClick
}
// avi?.start()
currentPage = 1
getRecommands(
currentPage,
currentSize, revolution
)
}
}
tvExampleRetry?.setOnClickListener {
singleClick {
if (!NetworkUtils.isConnected()) {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_network.toString())
} else {
ToastUtils.show(getString(R.string.example_no_network))
}
return@singleClick
}
// avi?.start()
currentPage = 1
getRecommands(
currentPage,
currentSize, revolution
)
}
}
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
if (!hidden) {
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
MsConstants.ExampleIsCurrentPage = true
qualityLogic()
} else {
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
MsConstants.ExampleIsCurrentPage = false
srRecommend?.postDelayed({ recommendPlayerView()?.pause() }, 300)
}
}
private var isDataLoaded = false
override fun onResume() {
super.onResume()
if (isVisible && !isDataLoaded) { // 检查是否对用户可见
initialization()
isDataLoaded = true
}
MsConstants.ExampleIsCurrentPage = true
if (isVisible) {
if (!play) {
qualityLogic()
} else {
play = false
}
}
}
private fun qualityLogic() {
if (qualityRefresh) {
viewPagerExampleRecommend?.post {
recommendPlayerView()?.stop()
recommendPlayerView()?.release()
}
getRecommands(
currentPage,
currentSize, revolution
)
qualityRefresh = false
} else {
recommendPlayerView()?.play()
}
}
override fun onPause() {
super.onPause()
MsConstants.ExampleIsCurrentPage = false
srRecommend?.postDelayed({ recommendPlayerView()?.pause() }, 300)
}
fun getRecommands(currentPage: Int, pageSize: Int, revolutionS: String) {
EasyHttp.get(this)
.api(HomeRecommendApi().apply {
current_page = currentPage;
page_size = pageSize;
revolution = revolutionS;
})
.request(object : HttpCallbackProxy<HttpData<ExampleRecommendDataRes>>(this) {
override fun onHttpSuccess(result: HttpData<ExampleRecommendDataRes>) {
result.getData()?.let {
if (it != null) {
if (it.list?.isNotEmpty() == true) {
if (currentPage == 1) {
exampleRecommendAdapter = ExampleRecommendAdapter()
viewPagerExampleRecommend?.adapter = exampleRecommendAdapter
exampleRecommendAdapter?.submitList(it.list)
exampleRecommendAdapter?.recommendCollection =
this@ExploreFragment
} else {
exampleRecommendAdapter?.addAll(it.list)
}
exampleNetwork?.visibility = View.INVISIBLE
exampleEmpty?.visibility = View.INVISIBLE
} else {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.no_more_data.toString())
} else {
ToastUtils.show(getString(R.string.example_there_s_no_more_data))
}
if (currentPage == 1) {
exampleEmpty?.visibility = View.VISIBLE
}
}
} else {
if (currentPage == 1) {
recommendPlayerView()?.release()
exampleEmpty?.visibility = View.VISIBLE
}
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.network_error.toString())
} else {
ToastUtils.show(getString(R.string.example_service_exception_please_try_again))
}
}
// avi?.stop()
srRecommend?.finishRefresh()
}
}
})
// ExampleRecommendRequest.getRecommands(current_page, page_size, revolution)
// .observeForever { result ->
// recommendLiveData.value = result.getOrNull()
// }
}
fun doCollect(videoId: Int, shortPlayId: Int) {
val sMap: MutableMap<String, String?> = LinkedHashMap()
// StringMap = getSortMap(StringMap);
sMap.put("short_play_id", videoId.toString())
sMap.put("video_id", shortPlayId.toString())
EasyHttp.post(this)
.api(com.localee.mireo.app.http.api.DoCollectApi())
.body(getPublicRequest(sMap))
.request(object : HttpCallbackProxy<HttpData<Any>>(this) {
override fun onHttpSuccess(result: HttpData<Any>) {
result.getData()?.let {
if (it != null) {
val imageView =
recommendPlayerView()?.findViewById<AppCompatImageView>(R.id.example_iv_collection_controller)
val textview =
recommendPlayerView()?.findViewById<AppCompatTextView>(R.id.example_tv_collection_num_controller)
imageView?.setImageResource(R.mipmap.iv_example_collection_h)
data?.collect_total = data?.collect_total?.plus(1)
exampleRecommendAdapter?.items?.get(currentPosition)?.collect_total =
data?.collect_total
exampleRecommendAdapter?.items?.get(currentPosition)?.is_collect = true
textview?.text = data?.collect_total?.let { it1 -> formatNumber(it1) }
textview?.setTextColor(resources.getColor(R.color.example_color_F56490))
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.success.toString())
}
} else {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.network_error.toString())
} else {
ToastUtils.show(getString(R.string.example_service_exception_please_try_again))
}
}
}
}
})
}
fun doCancelCollect(videoId: Int, shortPlayId: Int) {
val sMap: MutableMap<String, String?> = LinkedHashMap()
// StringMap = getSortMap(StringMap);
sMap.put("short_play_id", videoId.toString())
sMap.put("video_id", shortPlayId.toString())
EasyHttp.post(this)
.api(com.localee.mireo.app.http.api.CancelCollectApi())
.body(getPublicRequest(sMap))
.request(object : HttpCallbackProxy<HttpData<Any>>(this) {
override fun onHttpSuccess(result: HttpData<Any>) {
result.getData()?.let {
if (it != null) {
val imageView =
recommendPlayerView()?.findViewById<AppCompatImageView>(R.id.example_iv_collection_controller)
val textview =
recommendPlayerView()?.findViewById<AppCompatTextView>(R.id.example_tv_collection_num_controller)
imageView?.setImageResource(R.mipmap.iv_example_collection_n)
data?.collect_total = data?.collect_total?.minus(1)
exampleRecommendAdapter?.items?.get(currentPosition)?.collect_total =
data?.collect_total
exampleRecommendAdapter?.items?.get(currentPosition)?.is_collect = false
textview?.text = data?.collect_total?.let { it1 -> formatNumber(it1) }
textview?.setTextColor(resources.getColor(R.color.white))
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.success.toString())
}
} else {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.network_error.toString())
} else {
ToastUtils.show(getString(R.string.example_service_exception_please_try_again))
}
}
}
}
})
}
private fun recommendPlayerView(): ExampleRecommendPlayerView? {
val recyclerView = viewPagerExampleRecommend?.getChildAt(0) as RecyclerView
return recyclerView.layoutManager?.findViewByPosition(currentPosition) as ExampleRecommendPlayerView?
}
override fun onDestroy() {
viewPagerExampleRecommend?.post {
recommendPlayerView()?.stop()
recommendPlayerView()?.release()
}
super.onDestroy()
EventBus.getDefault().unregister(this)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(event: String) {
if (MsConstants.Constants_RecommendPlayerView_PLAYER_STATUS_FINISHExample == event) {
if (viewPagerExampleRecommend?.currentItem == viewPagerExampleRecommend?.adapter?.itemCount?.minus(
1
)
) {
viewPagerExampleRecommend?.currentItem = 0
} else {
currentPosition.plus(1)
.let {
viewPagerExampleRecommend?.currentItem = it
}
}
}
if (CONSTANTS_quality_refresh == event) {
revolution =
MsMMKVUtils.getMMKV().getInt(MsConstants.CONSTANTS_quality, 0)
.toString()
qualityRefresh = true
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(event: BaseEventBus<ExamplePlayerDetailDataRes.ShortPlayInfo>) {
if (MsConstants.Constants_Episodes_Series_DataExample == event.code) {
if (exampleRecommendAdapter?.items?.get(currentPosition)?.name == event.data.name) {
val imageView =
recommendPlayerView()?.findViewById<AppCompatImageView>(R.id.example_iv_collection_controller)
val textview =
recommendPlayerView()?.findViewById<AppCompatTextView>(R.id.example_tv_collection_num_controller)
imageView?.setImageResource(if (event.data.is_collect) R.mipmap.iv_example_collection_h else R.mipmap.iv_example_collection_n)
exampleRecommendAdapter?.items?.get(currentPosition)?.collect_total =
event.data.collect_total
exampleRecommendAdapter?.items?.get(currentPosition)?.is_collect =
event.data.is_collect
textview?.text = formatNumber(event.data.collect_total)
textview?.setTextColor(if (event.data.is_collect) resources.getColor(R.color.example_color_F56490) else resources.getColor(R.color.white))
}
}
}
override fun collection(dataRes: com.localee.mireo.app.http.api.ExampleRecommendDataRes.Data) {
singleClick {
data = dataRes
if (dataRes.is_collect) {
val exampleUnFavoriteDialog = ExampleUnFavoriteDialog(requireContext())
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)
if (TranslatesUtils.translates() != null) {
tvThinkAgain.text = TranslatesUtils.translates()?.try_again
tvUnfavorite.text = TranslatesUtils.translates()?.collection
tvTitle.text = TranslatesUtils.translates()?.collection
tvContent.text = TranslatesUtils.translates()?.not_collect_warning
}
tvThinkAgain.setOnClickListener { exampleUnFavoriteDialog.dismiss() }
tvUnfavorite.setOnClickListener {
dataRes.video_info?.short_play_id?.let {
dataRes.video_info.short_play_video_id.let { it1 ->
doCancelCollect(
it, it1
)
}
}
exampleUnFavoriteDialog.dismiss()
}
exampleUnFavoriteDialog.show()
} else {
dataRes.video_info?.short_play_id?.let {
dataRes.video_info.short_play_video_id.let { it1 ->
doCollect(
it, it1
)
}
}
}
}
}
}

View File

@ -0,0 +1,183 @@
package com.localee.mireo.app.ui.fragment
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.hjq.http.EasyHttp
import com.hjq.http.config.IRequestApi
import com.hjq.http.listener.HttpCallbackProxy
import com.localee.mireo.app.R
import com.localee.mireo.app.action.StatusAction
import com.localee.mireo.app.app.TitleBarFragment
import com.localee.mireo.app.http.api.HomeVideoListApi
import com.localee.mireo.app.http.api.RecommendBean
import com.localee.mireo.app.http.model.HttpData
import com.localee.mireo.app.other.MsConstants.CONSTANTS_short_play_id
import com.localee.mireo.app.ui.activity.HomeActivity
import com.localee.mireo.app.ui.activity.VideoPlayActivity
import com.localee.mireo.app.ui.adapter.HomeCategoriesTabAdapter
import com.localee.mireo.app.widget.StatusLayout
import com.scwang.smart.refresh.layout.api.RefreshLayout
import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener
class HomeCategoriesTabFragment : TitleBarFragment<HomeActivity>(), OnRefreshLoadMoreListener,
StatusAction {
companion object {
fun newInstance(tabName: String, tabId: Int): HomeCategoriesTabFragment {
return HomeCategoriesTabFragment().apply {
arguments = Bundle().apply {
putString("TAB_NAME", tabName)
putInt("TAB_ID", tabId)
}
}
}
}
private var tabName: String? = null
private var tabId: Int? = null
private val hintLayout: StatusLayout? by lazy { findViewById(R.id.hl_status_hint) }
private val recyclerView: RecyclerView? by lazy { findViewById(R.id.recyclerView) }
private var mAdapter: HomeCategoriesTabAdapter? = null
private var pageIndex = 1
private var pageTotal = 1
val detailList: MutableList<RecommendBean> = java.util.ArrayList()
override fun getLayoutId(): Int {
return R.layout.fragment_categories_tab
}
@SuppressLint("NotifyDataSetChanged")
override fun initView() {
tabName = arguments?.getString("TAB_NAME")
tabId = arguments?.getInt("TAB_ID")
mAdapter = HomeCategoriesTabAdapter()
val layoutManager = GridLayoutManager(context, 3)
// 设置给 RecyclerView
recyclerView?.layoutManager = layoutManager
recyclerView?.isNestedScrollingEnabled = false // 关键代码
recyclerView?.setHasFixedSize(true) // 优化性能
recyclerView?.adapter = mAdapter
recyclerView?.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
outRect.right = 10
outRect.left = 10
}
})
mAdapter?.setOnItemClickListener { adapter, view, position ->
val historyBean: RecommendBean = adapter.items.get(position)
startActivity(
Intent(
context,
VideoPlayActivity::class.java
).apply {
historyBean.short_play_id.let {
putExtra(CONSTANTS_short_play_id, it)
}
})
}
recyclerView?.addOnLayoutChangeListener { _, _, _, _, bottom, _, _, _, oldBottom ->
if (bottom != oldBottom) {
recyclerView?.layoutParams?.height = bottom
}
}
}
override fun initData() {
}
private var isDataLoaded = false
override fun onResume() {
super.onResume()
if (isVisible && !isDataLoaded) { // 检查是否对用户可见
loadData()
isDataLoaded = true
}
}
private fun loadData() {
getHomeVideoListApi(pageIndex, 10)
}
private fun getHomeVideoListApi(currentPage: Int, pageSize: Int) {
EasyHttp.get(this)
.api(HomeVideoListApi().apply {
category_id = tabId
current_page = currentPage
page_size = pageSize
})
.request(object : HttpCallbackProxy<HttpData<HomeVideoListApi.Bean>>(this) {
override fun onHttpSuccess(result: HttpData<HomeVideoListApi.Bean>) {
result.getData()?.let {
if (pageIndex == 1) {
if (it.list.isEmpty()) {
hintLayout?.show()
} else {
hintLayout?.hide()
}
mAdapter?.submitList(it.list)
pageTotal = it.pagination.page_total
} else {
mAdapter?.addAll(it.list)
}
}
}
override fun onHttpFail(throwable: Throwable) {
super.onHttpFail(throwable)
if (pageIndex == 1) {
hintLayout?.show()
}
}
override fun onHttpEnd(api: IRequestApi) {
super.onHttpEnd(api)
// if (pageIndex == 1) {
// rlStatusRefresh?.finishRefresh(200)
// } else {
// rlStatusRefresh?.finishLoadMore(200)
// }
}
})
}
override fun onRefresh(refreshLayout: RefreshLayout) {
pageIndex = 1
loadData()
}
override fun onLoadMore(refreshLayout: RefreshLayout) {
if (pageIndex == pageTotal) {
// rlStatusRefresh?.finishLoadMore(1000)
} else {
pageIndex++
loadData()
}
}
override fun getStatusLayout(): StatusLayout? {
return hintLayout
}
}

View File

@ -0,0 +1,434 @@
package com.localee.mireo.app.ui.fragment
import android.content.Intent
import android.graphics.Rect
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.widget.NestedScrollView
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import com.hjq.base.FragmentPagerAdapter
import com.hjq.http.EasyHttp
import com.hjq.http.config.IRequestApi
import com.hjq.http.listener.HttpCallbackProxy
import com.hjq.toast.ToastUtils
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppFragment
import com.localee.mireo.app.app.TitleBarFragment
import com.localee.mireo.app.http.api.CustomerRegisterApi
import com.localee.mireo.app.http.api.HomeCategoriesApi
import com.localee.mireo.app.http.api.HomeDayMaxRechargeShortPlayRankApi
import com.localee.mireo.app.http.api.HomeModuleApi
import com.localee.mireo.app.http.api.RecommendBean
import com.localee.mireo.app.http.api.UserInfoApi
import com.localee.mireo.app.http.api.UserInfoRes
import com.localee.mireo.app.http.model.HttpData
import com.localee.mireo.app.other.MsConstants.CONSTANTS_short_play_id
import com.localee.mireo.app.ui.activity.HomeActivity
import com.localee.mireo.app.ui.activity.SearchActivity
import com.localee.mireo.app.ui.activity.VideoPlayActivity
import com.localee.mireo.app.ui.adapter.HomeBannerAdapter
import com.localee.mireo.app.ui.adapter.HomeCriticallyAdapter
import com.localee.mireo.app.ui.adapter.HomeGenresAdapter
import com.localee.mireo.app.ui.adapter.HomeShortAdapter
import com.localee.mireo.app.ui.adapter.HomeTopAdapter
import com.localee.mireo.app.ui.adapter.TabAdapter
import com.localee.mireo.app.ui.adapter.TabAdapter.Companion.TAB_MODE_SLIDING
import com.localee.mireo.app.utils.DHStringUtils.getPublicRequest
import com.localee.mireo.app.utils.MsMMKVUtils
import com.localee.mireo.app.utils.TranslatesUtils
import com.youth.banner.Banner
import com.youth.banner.listener.OnBannerListener
class HomeFragment : TitleBarFragment<HomeActivity>(), HomeBannerAdapter.HomeBannerOnClick,
TabAdapter.OnTabListener,
ViewPager.OnPageChangeListener {
companion object {
fun newInstance(): HomeFragment {
return HomeFragment()
}
}
private val searchView: AppCompatImageView? by lazy { findViewById(R.id.iv_home_search) }
private val banner: Banner<RecommendBean, HomeBannerAdapter>? by lazy {
findViewById(
R.id.banner
)
}
private val layoutTop: ViewGroup? by lazy { findViewById(R.id.layout_top) }
private val tvTopOne: TextView? by lazy { layoutTop?.findViewById(R.id.tv_name) }
private val ivTop: ImageView? by lazy { layoutTop?.findViewById(R.id.iv_img) }
private val recyclerOne: RecyclerView? by lazy { layoutTop?.findViewById(R.id.recyclerView) }
private val layoutNew: ViewGroup? by lazy { findViewById(R.id.layout_new) }
private val tvTopNew: TextView? by lazy { layoutNew?.findViewById(R.id.tv_name) }
private val recyclerNew: RecyclerView? by lazy { layoutNew?.findViewById(R.id.recyclerView) }
private val layoutShort: ViewGroup? by lazy { findViewById(R.id.layout_short) }
private val tvTopShort: TextView? by lazy { layoutShort?.findViewById(R.id.tv_name) }
private val recyclerShort: RecyclerView? by lazy { layoutShort?.findViewById(R.id.recyclerView) }
private val layoutCritically: ViewGroup? by lazy { findViewById(R.id.layout_critically) }
private val tvTopCritically: TextView? by lazy { layoutCritically?.findViewById(R.id.tv_name) }
private val recyclerCritically: RecyclerView? by lazy { layoutCritically?.findViewById(R.id.recyclerView) }
private val layoutGenres: ViewGroup? by lazy { findViewById(R.id.layout_genres) }
private val tvTopGenres: TextView? by lazy { layoutGenres?.findViewById(R.id.tv_name) }
private val recyclerGenres: RecyclerView? by lazy { layoutGenres?.findViewById(R.id.recyclerView) }
private var bannerAdapter: HomeBannerAdapter? = null
private var topAdapter: HomeTopAdapter? = null
private var newAdapter: HomeTopAdapter? = null
private var shortAdapter: HomeShortAdapter? = null
private var criticallyAdapter: HomeCriticallyAdapter? = null
private val nestedScrollView: NestedScrollView? by lazy { findViewById(R.id.nestedScrollView) }
private val viewPager: ViewPager? by lazy { findViewById(R.id.viewPager) }
private var tabAdapter: TabAdapter? = null
private var pagerAdapter: FragmentPagerAdapter<AppFragment<*>>? = null
private var genresAdapter: HomeGenresAdapter? = null
private var category: List<HomeCategoriesApi.Bean.Data>? = null
override fun getLayoutId(): Int {
return R.layout.home_fragment
}
override fun initView() {
recyclerOne?.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
recyclerNew?.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
recyclerShort?.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
val layoutManager: GridLayoutManager = GridLayoutManager(
context, 3, RecyclerView.HORIZONTAL, false
)
recyclerCritically?.layoutManager = layoutManager
recyclerGenres?.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
topAdapter = HomeTopAdapter(1)
recyclerOne?.adapter = topAdapter
newAdapter = HomeTopAdapter(2)
recyclerNew?.adapter = newAdapter
shortAdapter = HomeShortAdapter()
recyclerShort?.adapter = shortAdapter
criticallyAdapter = HomeCriticallyAdapter()
recyclerCritically?.adapter = criticallyAdapter
genresAdapter = HomeGenresAdapter(0)
recyclerGenres?.adapter = genresAdapter
recyclerCritically?.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
outRect.right = 8
outRect.bottom = 28
}
})
ivTop?.visibility = View.VISIBLE
tvTopOne?.setText("Top 10 Skits This Week")
tvTopNew?.setText("New Releases")
tvTopShort?.setText("Shorts for You")
tvTopCritically?.setText("Critically Acclaimed")
tvTopGenres?.setText("Genres to Explore")
// genresAdapter?.submitList(genersList)
searchView?.setOnClickListener {
startActivity(SearchActivity::class.java)
}
pagerAdapter = FragmentPagerAdapter(this)
tabAdapter = TabAdapter(getAttachActivity()!!, TAB_MODE_SLIDING, false)
recyclerGenres?.adapter = tabAdapter
tabAdapter?.addItem("All")
pagerAdapter?.addFragment(HomeCategoriesTabFragment.newInstance("All", 0), "")
tabAdapter?.setOnTabListener(this)
viewPager?.adapter = pagerAdapter
viewPager?.addOnPageChangeListener(this@HomeFragment)
}
override fun initData() {
getCustomerRegister()
topAdapter?.setOnItemClickListener { adapter, view, position ->
val data: RecommendBean = adapter.items.get(position)
startActivity(
Intent(
context,
VideoPlayActivity::class.java
).apply {
data.short_play_id.let {
putExtra(CONSTANTS_short_play_id, it)
}
})
}
newAdapter?.setOnItemClickListener { adapter, view, position ->
val data: RecommendBean = adapter.items.get(position)
startActivity(
Intent(
context,
VideoPlayActivity::class.java
).apply {
data.short_play_id.let {
putExtra(CONSTANTS_short_play_id, it)
}
})
}
shortAdapter?.setOnItemClickListener { adapter, view, position ->
val data: RecommendBean = adapter.items.get(position)
startActivity(
Intent(
context,
VideoPlayActivity::class.java
).apply {
data.short_play_id.let {
putExtra(CONSTANTS_short_play_id, it)
}
})
}
criticallyAdapter?.setOnItemClickListener { adapter, view, position ->
val data: RecommendBean = adapter.items.get(position)
startActivity(
Intent(
context,
VideoPlayActivity::class.java
).apply {
data.short_play_id.let {
putExtra(CONSTANTS_short_play_id, it)
}
})
}
}
override fun isStatusBarEnabled(): Boolean {
return !super.isStatusBarEnabled()
}
fun getCustomerRegister() {
EasyHttp.post(this)
.api(CustomerRegisterApi().apply {
})
.request(object : HttpCallbackProxy<HttpData<CustomerRegisterApi.Bean>>(this) {
override fun onHttpSuccess(result: HttpData<CustomerRegisterApi.Bean>) {
result.getData()?.token?.let {
MsMMKVUtils.saveToken(it)
getCustomerUser()
getHomeModuleData()
// getCategories()
getDayMaxRechargeShortPlayRank();
}
}
})
}
fun getHomeModuleData() {
EasyHttp.get(this)
.api(HomeModuleApi().apply {
})
.request(object : HttpCallbackProxy<HttpData<HomeModuleApi.Bean>>(this) {
override fun onHttpSuccess(result: HttpData<HomeModuleApi.Bean>) {
result.getData()?.let {
bannerAdapter = it.bannerData?.let { it1 -> HomeBannerAdapter(it1) }
bannerAdapter?.homeBannerOnClick =
this@HomeFragment
banner?.addBannerLifecycleObserver(getAttachActivity())
?.setAdapter(bannerAdapter)
?.setOnBannerListener(OnBannerListener<Any?> { data, position ->
val recommendBean: RecommendBean = it.bannerData!![position]
startActivity(
Intent(
context,
VideoPlayActivity::class.java
).apply {
putExtra(
CONSTANTS_short_play_id,
recommendBean.short_play_id
)
})
})
if (it.hotData == null) {
layoutTop?.visibility = View.GONE
} else {
layoutTop?.visibility = View.VISIBLE
topAdapter?.submitList(it.hotData)
}
if (it.manualNewestRecommand == null) {
layoutNew?.visibility = View.GONE
} else {
layoutNew?.visibility = View.VISIBLE
newAdapter?.submitList(it.manualNewestRecommand?.list)
}
if (it.recommandData == null || it.recommandData?.list == null) {
layoutShort?.visibility = View.GONE
} else {
layoutShort?.visibility = View.VISIBLE
shortAdapter?.submitList(it.recommandData?.list)
}
// criticallyAdapter?.submitList(it.newTopThree)
}
}
})
}
fun getDayMaxRechargeShortPlayRank() {
val sMap: MutableMap<String, String?> = LinkedHashMap()
// StringMap = getSortMap(StringMap);
sMap.put("type", "top_searched")
EasyHttp.post(this)
.api(HomeDayMaxRechargeShortPlayRankApi().apply {
})
.body(getPublicRequest(sMap))
.request(object :
HttpCallbackProxy<HttpData<HomeDayMaxRechargeShortPlayRankApi.Bean>>(this) {
override fun onHttpStart(api: IRequestApi) {
}
override fun onHttpSuccess(result: HttpData<HomeDayMaxRechargeShortPlayRankApi.Bean>) {
if (result.getData() == null) {
layoutShort?.visibility = View.GONE
} else {
result.getData()?.let {
layoutShort?.visibility = View.VISIBLE
criticallyAdapter?.submitList(it.list)
}
}
}
})
}
fun getCategories() {
EasyHttp.get(this)
.api(HomeCategoriesApi().apply {
})
.request(object : HttpCallbackProxy<HttpData<HomeCategoriesApi.Bean>>(this) {
override fun onHttpSuccess(result: HttpData<HomeCategoriesApi.Bean>) {
result.getData()?.let {
category = it.list
for (cate in it.list) {
tabAdapter?.addItem(cate.name)
pagerAdapter?.addFragment(
HomeCategoriesTabFragment.newInstance(
cate.name,
cate.id
), ""
)
}
pagerAdapter?.notifyDataSetChanged()
}
}
})
}
fun getCustomerUser() {
EasyHttp.get(this)
.api(UserInfoApi().apply {
})
.request(object : HttpCallbackProxy<HttpData<UserInfoRes>>(this) {
override fun onHttpSuccess(result: HttpData<UserInfoRes>) {
result.getData()?.let {
MsMMKVUtils.saveUserInfo(it)
}
}
})
}
override fun onDestroy() {
super.onDestroy()
}
override fun bannerAdd(dataRes: RecommendBean) {
dataRes.short_play_id?.let { doCollect(it) };
}
override fun bannerPlay(dataRes: RecommendBean) {
startActivity(
Intent(
context,
VideoPlayActivity::class.java
).apply {
dataRes.short_play_id.let {
putExtra(CONSTANTS_short_play_id, it)
}
})
}
fun doCollect(shortPlayId: Int) {
val sMap: MutableMap<String, String?> = LinkedHashMap()
// StringMap = getSortMap(StringMap);
sMap["short_play_id"] = shortPlayId.toString()
EasyHttp.post(this)
.api(com.localee.mireo.app.http.api.DoCollectApi())
.body(getPublicRequest(sMap))
.request(object : HttpCallbackProxy<HttpData<Any>>(this) {
override fun onHttpSuccess(result: HttpData<Any>) {
result.getData()?.let {
if (it != null) {
viewModel.triggerAction(2)
viewModel.meToHistoryAction(0)
} else {
if (TranslatesUtils.translates() != null) {
ToastUtils.show(TranslatesUtils.translates()?.network_error.toString())
} else {
ToastUtils.show(getString(R.string.example_service_exception_please_try_again))
}
}
}
}
})
}
private val viewModel: SharedViewModel by activityViewModels()
override fun onTabSelected(recyclerView: RecyclerView?, position: Int): Boolean {
viewPager?.currentItem = position
return true
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
tabAdapter?.setSelectedPosition(position)
}
override fun onPageScrollStateChanged(state: Int) {
}
}

View File

@ -0,0 +1,385 @@
package com.localee.mireo.app.ui.fragment
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.hjq.http.EasyHttp
import com.hjq.http.config.IRequestApi
import com.hjq.http.listener.HttpCallbackProxy
import com.hjq.shape.layout.ShapeLinearLayout
import com.localee.mireo.app.R
import com.localee.mireo.app.action.StatusAction
import com.localee.mireo.app.app.TitleBarFragment
import com.localee.mireo.app.http.api.HistoryBean
import com.localee.mireo.app.http.api.MyCollectionsApi
import com.localee.mireo.app.http.api.MyHistoryApi
import com.localee.mireo.app.http.model.HttpData
import com.localee.mireo.app.other.MsConstants.CONSTANTS_activity_id
import com.localee.mireo.app.other.MsConstants.CONSTANTS_short_play_id
import com.localee.mireo.app.ui.activity.HomeActivity
import com.localee.mireo.app.ui.activity.VideoPlayActivity
import com.localee.mireo.app.ui.adapter.LostTabAdapter
import com.localee.mireo.app.utils.DHStringUtils.getPublicRequest
import com.localee.mireo.app.widget.StatusLayout
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.scwang.smart.refresh.layout.api.RefreshLayout
import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener
class ListTabFragment : TitleBarFragment<HomeActivity>(), OnRefreshLoadMoreListener,
StatusAction {
companion object {
fun newInstance(tabName: Int): ListTabFragment {
return ListTabFragment().apply {
arguments = Bundle().apply {
putInt("TAB_NAME", tabName)
}
}
}
}
private var tabName: Int? = null
private val hintLayout: StatusLayout? by lazy { findViewById(R.id.hl_status_hint) }
private val recyclerView: RecyclerView? by lazy { findViewById(R.id.recyclerView) }
private val rlStatusRefresh: SmartRefreshLayout? by lazy { findViewById(R.id.rl_status_refresh) }
private val llDelete: ShapeLinearLayout? by lazy { findViewById(R.id.ll_delete) }
private val ivDelete: ImageView? by lazy { findViewById(R.id.iv_delete) }
private val tvDelete: TextView? by lazy { findViewById(R.id.tv_delete) }
private var mAdapter: LostTabAdapter? = null
private var pageIndex = 1
private var pageTotal = 1
private var type = 0
private var detailPosition = 0
val detailList: MutableList<HistoryBean.Data> = java.util.ArrayList()
override fun getLayoutId(): Int {
return R.layout.fragment_list_tab
}
@SuppressLint("NotifyDataSetChanged")
override fun initView() {
tabName = arguments?.getInt("TAB_NAME")
mAdapter = tabName?.let { LostTabAdapter(it) }
val layoutManager = GridLayoutManager(context, 3)
// 设置给 RecyclerView
recyclerView!!.layoutManager = layoutManager
recyclerView?.adapter = mAdapter
recyclerView?.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
outRect.right = 10
outRect.left = 10
}
})
mAdapter?.setOnItemClickListener { adapter, view, position ->
val historyBean: HistoryBean.Data = adapter.items.get(position)
if (!mAdapter?.selectEdit!!) {
startActivity(
Intent(
context,
VideoPlayActivity::class.java
).apply {
historyBean.short_play_id.let {
historyBean.short_play_video_id.let { it1 ->
putExtra(CONSTANTS_activity_id, it1)
putExtra(CONSTANTS_short_play_id, it)
}
}
})
} else {
if (historyBean.is_check) {
adapter.items.get(position).is_check = false
for (i in detailList.indices) {
if (detailList[i].short_play_id == historyBean.short_play_id) {
detailList.removeAt(i)
}
}
} else {
adapter.items.get(position).is_check = true
detailList.add(historyBean)
}
if (detailList.size == 0) {
llDelete?.shapeDrawableBuilder?.setStrokeColor(0xFF9D9D9D.toInt())
?.intoBackground();
context?.resources?.getColor(R.color.example_color_d9d9d9)
?.let { tvDelete?.setTextColor(it) }
tvDelete?.text = "Delete (0)"
ivDelete?.setImageResource(R.mipmap.ic_list_detele_n)
} else {
llDelete?.shapeDrawableBuilder?.setStrokeColor(0xFFF56490.toInt())
?.intoBackground();
context?.resources?.getColor(R.color.example_color_F56490)
?.let { tvDelete?.setTextColor(it) }
tvDelete?.text = "Delete (" + detailList.size + ")"
ivDelete?.setImageResource(R.mipmap.ic_list_detele_y)
}
mAdapter?.notifyDataSetChanged()
}
}
rlStatusRefresh?.setOnRefreshLoadMoreListener(this)
llDelete?.setOnClickListener {
if (detailList.size != 0) {
for (i in detailList.indices) {
doCancelCollect(detailList[i].short_play_id, detailList[i].short_play_video_id)
}
}
}
}
override fun initData() {
}
fun setMode() {
when (type) {
0 -> {
val layoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
// 设置给 RecyclerView
recyclerView!!.layoutManager = layoutManager
recyclerView?.adapter = mAdapter
type = 1
mAdapter?.type = type
mAdapter?.notifyDataSetChanged()
}
1 -> {
// 创建一个 GridLayoutManager指定列数例如 3 列)
val layoutManager = GridLayoutManager(context, 3)
// 设置给 RecyclerView
recyclerView!!.layoutManager = layoutManager
recyclerView?.adapter = mAdapter
type = 0
mAdapter?.type = type
mAdapter?.notifyDataSetChanged()
}
}
}
fun setEdit() {
mAdapter?.selectEdit = !mAdapter?.selectEdit!!
mAdapter?.notifyDataSetChanged()
if (llDelete?.visibility == View.VISIBLE)
llDelete?.visibility = View.GONE
else
llDelete?.visibility = View.VISIBLE
}
fun setAllSelect(isSelect: Boolean) {
val allData: List<HistoryBean.Data>? = mAdapter?.items
if (isSelect) {
for (i in allData?.indices!!) {
allData[i].is_check = true
}
allData.let { detailList.addAll(it) }
} else {
for (i in allData?.indices!!) {
allData[i].is_check = false
}
detailList.clear()
}
if (detailList.size == 0) {
llDelete?.shapeDrawableBuilder?.setStrokeColor(0xFF9D9D9D.toInt())
?.intoBackground();
context?.resources?.getColor(R.color.example_color_d9d9d9)
?.let { tvDelete?.setTextColor(it) }
tvDelete?.text = "Delete (0)"
ivDelete?.setImageResource(R.mipmap.ic_list_detele_n)
} else {
llDelete?.shapeDrawableBuilder?.setStrokeColor(0xFFF56490.toInt())
?.intoBackground();
context?.resources?.getColor(R.color.example_color_F56490)
?.let { tvDelete?.setTextColor(it) }
tvDelete?.text = "Delete (" + detailList.size + ")"
ivDelete?.setImageResource(R.mipmap.ic_list_detele_y)
}
mAdapter?.notifyDataSetChanged()
}
private var isDataLoaded = false
override fun onResume() {
super.onResume()
if (isVisible && !isDataLoaded) { // 检查是否对用户可见
loadData()
isDataLoaded = true
}
}
private fun loadData() {
when (tabName) {
0 -> {
myCollections(pageIndex, 15)
}
1 -> {
getMyHistory(pageIndex, 15)
}
}
}
private fun getMyHistory(currentPage: Int, pageSize: Int) {
EasyHttp.get(this)
.api(MyHistoryApi().apply {
current_page = currentPage
page_size = pageSize
})
.request(object : HttpCallbackProxy<HttpData<HistoryBean>>(this) {
override fun onHttpSuccess(result: HttpData<HistoryBean>) {
result.getData()?.let {
if (pageIndex == 1) {
if (it.list.isEmpty()) {
hintLayout?.show()
} else {
hintLayout?.hide()
}
mAdapter?.submitList(it.list)
pageTotal = it.pagination.page_total
} else {
mAdapter?.addAll(it.list)
}
}
}
override fun onHttpFail(throwable: Throwable) {
super.onHttpFail(throwable)
if (pageIndex == 1) {
hintLayout?.show()
}
}
override fun onHttpEnd(api: IRequestApi) {
super.onHttpEnd(api)
if (pageIndex == 1) {
rlStatusRefresh?.finishRefresh(200)
} else {
rlStatusRefresh?.finishLoadMore(200)
}
}
})
}
private fun myCollections(currentPage: Int, pageSize: Int) {
EasyHttp.get(this)
.api(MyCollectionsApi().apply {
current_page = currentPage
page_size = pageSize
})
.request(object : HttpCallbackProxy<HttpData<HistoryBean>>(this) {
override fun onHttpSuccess(result: HttpData<HistoryBean>) {
result.getData()?.let {
if (pageIndex == 1) {
if (it.list.isEmpty()) {
hintLayout?.show()
} else {
hintLayout?.hide()
}
mAdapter?.submitList(it.list)
pageTotal = it.pagination.page_total
} else {
mAdapter?.addAll(it.list)
}
}
}
override fun onHttpFail(throwable: Throwable) {
super.onHttpFail(throwable)
if (pageIndex == 1) {
hintLayout?.show()
}
}
override fun onHttpEnd(api: IRequestApi) {
super.onHttpEnd(api)
if (pageIndex == 1) {
rlStatusRefresh?.finishRefresh(200)
} else {
rlStatusRefresh?.finishLoadMore(200)
}
}
})
}
fun doCancelCollect(shortPlayId: Int, videoId: Int) {
val sMap: MutableMap<String, String?> = LinkedHashMap()
// StringMap = getSortMap(StringMap);
sMap.put("short_play_id", shortPlayId.toString())
sMap.put("video_id", videoId.toString())
EasyHttp.post(this)
.api(com.localee.mireo.app.http.api.CancelCollectApi())
.body(getPublicRequest(sMap))
.request(object : HttpCallbackProxy<HttpData<Any>>(this) {
override fun onHttpSuccess(result: HttpData<Any>) {
result.getData()?.let {
viewModel.listTabAction(0)
}
}
override fun onHttpEnd(api: IRequestApi) {
super.onHttpEnd(api)
detailPosition++
if (detailPosition == detailList.size) {
pageIndex = 1
mAdapter?.selectEdit = false
loadData()
llDelete?.visibility = View.GONE
detailList.clear()
}
}
})
}
private val viewModel: SharedViewModel by activityViewModels()
fun onRefreshData() {
if (isDataLoaded) {
pageIndex = 1
loadData()
}
}
override fun onRefresh(refreshLayout: RefreshLayout) {
pageIndex = 1
loadData()
}
override fun onLoadMore(refreshLayout: RefreshLayout) {
if (pageIndex == pageTotal) {
rlStatusRefresh?.finishLoadMore(1000)
} else {
pageIndex++
loadData()
}
}
override fun getStatusLayout(): StatusLayout? {
return hintLayout
}
}

View File

@ -0,0 +1,203 @@
package com.localee.mireo.app.ui.fragment
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.widget.AppCompatCheckBox
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import com.hjq.base.FragmentPagerAdapter
import com.lxj.xpopup.XPopup
import com.localee.mireo.app.R
import com.localee.mireo.app.app.AppFragment
import com.localee.mireo.app.app.TitleBarFragment
import com.localee.mireo.app.ui.activity.HomeActivity
import com.localee.mireo.app.ui.adapter.TabAdapter
import com.localee.mireo.app.ui.popup.CustomBubbleAttachPopup
import com.localee.mireo.app.ui.popup.CustomBubbleAttachPopup.CustomPopupOnclick
class MessageFragment : TitleBarFragment<HomeActivity>(), TabAdapter.OnTabListener,
ViewPager.OnPageChangeListener {
companion object {
fun newInstance(): MessageFragment {
return MessageFragment()
}
}
private val ivMore: ImageView? by lazy { findViewById(R.id.iv_more) }
private val tabView: RecyclerView? by lazy { findViewById(R.id.rv_list_tab) }
private val viewPager: ViewPager? by lazy { findViewById(R.id.viewPager) }
private val tvCancel: TextView? by lazy { findViewById(R.id.tv_cancel) }
private val cbSelectCheck: AppCompatCheckBox? by lazy { findViewById(R.id.cb_select_check) }
private var tabAdapter: TabAdapter? = null
private var pagerAdapter: FragmentPagerAdapter<AppFragment<*>>? = null
override fun getLayoutId(): Int {
return R.layout.message_fragment
}
private val viewModel: SharedViewModel by activityViewModels()
var modeOne: Int = 0
var modeTwo: Int = 0
var mode: Int = 0
override fun initView() {
ivMore?.setOnClickListener {
XPopup.Builder(context)
.hasShadowBg(false)
.isTouchThrough(true)
.atView(ivMore)
.hasShadowBg(false)
.hasNavigationBar(false)
.asCustom(context?.let { it1 ->
CustomBubbleAttachPopup(
it1,
viewPager?.currentItem,
mode,
object : CustomPopupOnclick {
override fun onMode() {
when (viewPager?.currentItem) {
0 -> {
if (modeOne == 0) {
modeOne = 1
} else {
modeOne = 0
}
mode = modeOne
listTabOneFragment.setMode()
}
1 -> {
if (modeTwo == 0) {
modeTwo = 1
} else {
modeTwo = 0
}
mode = modeTwo
listTabTwoFragment.setMode()
}
}
}
override fun onEdit() {
if (viewPager?.currentItem == 0) {
tvCancel?.visibility = View.VISIBLE
ivMore?.visibility = View.GONE
tabView?.visibility = View.INVISIBLE
cbSelectCheck?.visibility = View.VISIBLE
listTabOneFragment.setEdit()
}
}
})
})
.show()
}
tvCancel?.setOnClickListener {
tvCancel?.visibility = View.GONE
ivMore?.visibility = View.VISIBLE
tabView?.visibility = View.VISIBLE
cbSelectCheck?.visibility = View.GONE
listTabOneFragment.setEdit()
}
cbSelectCheck?.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
listTabOneFragment.setAllSelect(true)
} else {
listTabOneFragment.setAllSelect(false)
}
}
viewModel.listTabAction.observe(this) { data ->
tvCancel?.visibility = View.GONE
ivMore?.visibility = View.VISIBLE
tabView?.visibility = View.VISIBLE
cbSelectCheck?.isChecked = false
cbSelectCheck?.visibility = View.GONE
listTabOneFragment.setEdit()
}
viewModel.meToHistoryAction.observe(this) { data ->
viewPager?.currentItem = data
when(data) {
0 -> {
listTabOneFragment.onRefreshData()
}
1 -> {
listTabTwoFragment.onRefreshData()
}
}
}
}
val listTabOneFragment: ListTabFragment = ListTabFragment.newInstance(0)
val listTabTwoFragment: ListTabFragment = ListTabFragment.newInstance(1)
fun initViewA() {
pagerAdapter = FragmentPagerAdapter(this)
pagerAdapter!!.addFragment(listTabOneFragment, "")
pagerAdapter!!.addFragment(listTabTwoFragment, "")
// 设置 Adapter
viewPager?.adapter = pagerAdapter
viewPager?.addOnPageChangeListener(this)
tabAdapter = TabAdapter(getAttachActivity()!!)
tabView?.adapter = tabAdapter
tabAdapter?.addItem("Follow List")
tabAdapter?.addItem("Play List")
tabAdapter?.setOnTabListener(this)
}
private var isDataLoaded = false
override fun onResume() {
super.onResume()
if (isVisible && !isDataLoaded) {
initViewA()
isDataLoaded = true
}
}
override fun initData() {}
override fun onTabSelected(recyclerView: RecyclerView?, position: Int): Boolean {
viewPager?.currentItem = position
return true
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
tabAdapter?.setSelectedPosition(position)
when (position) {
0 -> {
mode = modeOne
}
1 -> {
mode = modeTwo
}
}
}
override fun onPageScrollStateChanged(state: Int) {
}
}

View File

@ -0,0 +1,153 @@
package com.localee.mireo.app.ui.fragment
import android.content.Intent
import android.view.View
import android.widget.TextView
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.hjq.http.EasyHttp
import com.hjq.http.listener.HttpCallbackProxy
import com.localee.mireo.app.R
import com.localee.mireo.app.aop.SingleClick
import com.localee.mireo.app.app.TitleBarFragment
import com.localee.mireo.app.http.api.HistoryBean
import com.localee.mireo.app.http.api.MyHistoryApi
import com.localee.mireo.app.http.api.UserInfoApi
import com.localee.mireo.app.http.api.UserInfoRes
import com.localee.mireo.app.http.model.HttpData
import com.localee.mireo.app.other.MsConstants
import com.localee.mireo.app.other.MsConstants.CONSTANTS_short_play_id
import com.localee.mireo.app.ui.activity.AboutActivity
import com.localee.mireo.app.ui.activity.BrowserActivity
import com.localee.mireo.app.ui.activity.HomeActivity
import com.localee.mireo.app.ui.activity.SettingActivity
import com.localee.mireo.app.ui.activity.VideoPlayActivity
import com.localee.mireo.app.ui.adapter.MeHistoryAdapter
import com.localee.mireo.app.utils.MsMMKVUtils
class MineFragment : TitleBarFragment<HomeActivity>() {
private val tvId: TextView? by lazy { findViewById(R.id.tv_id) }
private val recyclerView: RecyclerView? by lazy { findViewById(R.id.recyclerView) }
private var mAdapter: MeHistoryAdapter? = null
private val viewModel: SharedViewModel by activityViewModels()
companion object {
fun newInstance(): MineFragment {
return MineFragment()
}
}
override fun getLayoutId(): Int {
return R.layout.mine_fragment
}
override fun initView() {
setOnClickListener(
R.id.sb_play_list,
R.id.sb_setting,
R.id.sb_privacy,
R.id.sb_agreement,
R.id.sb_about
)
recyclerView?.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
mAdapter = MeHistoryAdapter()
recyclerView?.adapter = mAdapter
mAdapter?.setOnItemClickListener { adapter, view, position ->
val data: HistoryBean.Data = adapter.items[position]
startActivity(
Intent(
context,
VideoPlayActivity::class.java
).apply {
putExtra(CONSTANTS_short_play_id, data.short_play_id)
})
}
}
override fun initData() {
tvId?.text = "ID".plus(MsMMKVUtils.getUserInfo()?.customer_id)
}
private var isDataLoaded = false
override fun onResume() {
super.onResume()
if (isVisible && !isDataLoaded) {
getCustomerUser()
isDataLoaded = true
}
getMyHistory(1, 20)
}
@SingleClick
override fun onClick(view: View) {
when (view.id) {
R.id.sb_play_list -> {
viewModel.triggerAction(2)
viewModel.meToHistoryAction(1)
}
R.id.sb_setting -> {
startActivity(SettingActivity::class.java)
}
R.id.sb_privacy -> {
BrowserActivity.start(getAttachActivity()!!, MsConstants.Constants_privacy_policy)
}
R.id.sb_agreement -> {
BrowserActivity.start(getAttachActivity()!!, MsConstants.Constants_user_agreement)
}
R.id.sb_about -> {
startActivity(AboutActivity::class.java)
}
}
}
private fun getCustomerUser() {
EasyHttp.get(this)
.api(UserInfoApi().apply {
})
.request(object : HttpCallbackProxy<HttpData<UserInfoRes>>(this) {
override fun onHttpSuccess(result: HttpData<UserInfoRes>) {
result.getData()?.let {
MsMMKVUtils.saveUserInfo(it)
tvId?.text = "ID".plus(MsMMKVUtils.getUserInfo()?.customer_id)
}
}
})
}
private fun getMyHistory(currentPage: Int, pageSize: Int) {
EasyHttp.get(this)
.api(MyHistoryApi().apply {
current_page = currentPage
page_size = pageSize
})
.request(object : HttpCallbackProxy<HttpData<HistoryBean>>(this) {
override fun onHttpSuccess(result: HttpData<HistoryBean>) {
result.getData()?.let {
mAdapter?.submitList(it.list)
}
}
})
}
override fun isStatusBarEnabled(): Boolean {
return !super.isStatusBarEnabled()
}
}

View File

@ -0,0 +1,28 @@
package com.localee.mireo.app.ui.fragment
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class SharedViewModel : ViewModel() {
private val _action = MutableLiveData<Int>()
val action: LiveData<Int> get() = _action
fun triggerAction(data: Int) {
_action.value = data
}
private val _listTabAction = MutableLiveData<Int>()
val listTabAction: LiveData<Int> get() = _listTabAction
fun listTabAction(data: Int) {
_listTabAction.value = data
}
private val _meToHistoryAction = MutableLiveData<Int>()
val meToHistoryAction: LiveData<Int> get() = _meToHistoryAction
fun meToHistoryAction(data: Int) {
_meToHistoryAction.value = data
}
}

View File

@ -0,0 +1,45 @@
package com.localee.mireo.app.ui.popup
import android.content.Context
import android.view.View
import android.widget.TextView
import com.lxj.xpopup.core.BubbleAttachPopupView
import com.localee.mireo.app.R
class CustomBubbleAttachPopup(context: Context,var tabPosition: Int?,var mode: Int, val popupOnclick: CustomPopupOnclick?) :
BubbleAttachPopupView(context) {
interface CustomPopupOnclick {
fun onMode()
fun onEdit()
}
override fun getImplLayoutId(): Int {
return R.layout.custom_bubble_attach_popup
}
override fun onCreate() {
super.onCreate()
val tvMode = findViewById<TextView>(R.id.tv_mode)
val tvEdit = findViewById<TextView>(R.id.tv_edit)
if (tabPosition == 0) {
tvEdit.visibility = View.VISIBLE
} else {
tvEdit.visibility = View.GONE
}
if (mode == 0) {
tvMode.text = "List mode"
} else {
tvMode.text = "Grid mode"
}
tvMode.setOnClickListener {
popupOnclick?.onMode()
dismiss()
}
tvEdit.setOnClickListener {
popupOnclick?.onEdit()
dismiss()
}
}
}

View File

@ -0,0 +1,150 @@
package com.localee.mireo.app.ui.videoPaly
import android.os.Parcel
import android.os.Parcelable
data class ExamplePlayerDetailDataRes(
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 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 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().toString(),
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.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 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.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.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
)
}

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