This commit is contained in:
wangyu 2025-12-27 13:55:48 +08:00
commit a114220762
522 changed files with 28029 additions and 0 deletions

16
.gitignore vendored Normal file
View File

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

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

BIN
app/bidinfo.keystore Normal file

Binary file not shown.

184
app/build.gradle Normal file
View File

@ -0,0 +1,184 @@
plugins {
alias(libs.plugins.androidApplication)
alias(libs.plugins.jetbrainsKotlinAndroid)
id 'kotlin-kapt'
id 'kotlin-parcelize'
}
android {
namespace 'com.cheng.bole'
compileSdk 34
buildFeatures.buildConfig = true
lintOptions{
checkReleaseBuilds false
abortOnError false
}
defaultConfig {
applicationId "com.cheng.BoLe"
minSdk 26
targetSdk 34
versionCode 240
versionName "2.4.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
ndk {
abiFilters 'arm64-v8a' //'armeabi-v7a'
}
multiDexEnabled true
flavorDimensions = ["channel"]
productFlavors {
xiaomi {}
oppo {}
vivo {}
huawei {}
honor {}
baidu {}
yyb {}
upgrade {}
bd_tg {}
dy_tg {}
tx_tg {}
ks_tg {}
dd_tg {}
sm_tg {}
oc_tg {}
}
productFlavors.configureEach {
dimension "channel"
manifestPlaceholders = [UMENG_CHANNEL: name]
}
manifestPlaceholders = [
GETUI_APPID : "ej3hUPd0LR8G1CzkNtyZS3",
GT_INSTALL_CHANNEL: "test",
]
}
//
signingConfigs {
config {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
enableV1Signing true
enableV2Signing true
enableV3Signing true
}
}
buildTypes {
debug {
minifyEnabled false
shrinkResources false
signingConfig signingConfigs.config
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.config
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
applicationVariants.configureEach { variant ->
if (variant.buildType.name == "release") {
variant.outputs.forEach {
it.outputFileName = "material_v${defaultConfig.versionName}_${variant.productFlavors[0].name}.apk"
}
variant.assembleProvider.get().doLast {
copy {
variant.outputs.forEach { file ->
//
ant.move file: file.outputFile,
todir: "${project.rootDir}/apk"
}
}
}
variant.assembleProvider.get().doLast {
android.buildTypes.each { buildType ->
file("build/outputs/apk/$buildType").listFiles().each { channelFolder ->
if (channelFolder.isDirectory() && channelFolder.getName() != outputApkFolder) {
delete(channelFolder)
}
}
}
}
}
}
buildFeatures {
viewBinding true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
implementation project(':base')
implementation libs.androidx.appcompat
implementation libs.com.google.android.material.material
implementation libs.androidx.constraintlayout.constraintlayout
testImplementation libs.junit
androidTestImplementation libs.androidx.junit
androidTestImplementation libs.androidx.espresso.core
// implementation "androidx.core:core-splashscreen:1.0.1"
implementation 'com.jakewharton:disklrucache:2.0.2' // disklrucache
// tabLayout
implementation 'com.github.angcyo.DslTablayout:TabLayout:3.7.2'
implementation 'com.github.angcyo.DslTablayout:ViewPager1Delegate:3.7.2'
implementation 'com.github.FlyJingFish:GradientTextView:1.2.5' //
implementation 'com.github.aitsuki:SwipeMenuRecyclerView:2.1.5' //
implementation 'com.github.chrisbanes:PhotoView:2.3.0' //
implementation 'io.github.billywei01:fastaes:1.1.3' //
implementation 'com.github.gzu-liyujiang:Android_CN_OAID:4.2.12' //id
implementation 'com.google.android.flexbox:flexbox:3.0.0' //recyclerview flexbox
implementation files('libs/channelsdk-0.2.2.aar') //
implementation 'com.tencent.vasdolly:helper:3.0.4' //
implementation files('libs/humesdk-1.0.0.aar') //
implementation 'com.getui:gysdk:3.1.7.0' //sdk
implementation 'com.getui:gtc:3.2.16.0' //sdk则保留一个最高版本即可
implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0' //
//
implementation 'com.umeng.umsdk:common:9.6.3'//
implementation 'com.umeng.umsdk:asms:1.8.0'//
implementation 'com.umeng.umsdk:apm:1.9.1' // U-APM包依赖()
implementation 'com.umeng.umsdk:share-core:7.3.2'//
implementation 'com.umeng.umsdk:share-wx:7.3.2' //
implementation 'top.zibin:Luban:1.1.8' //
implementation 'com.github.Dimezis:BlurView:version-2.0.6' //
implementation 'com.bytedance.ads:AppConvert:2.0.0' //
implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.14' //
//media3视频播放
implementation "androidx.media3:media3-exoplayer:1.4.1"
implementation "androidx.media3:media3-ui:1.4.1"
implementation "androidx.media3:media3-common:1.4.1"
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
app/libs/humesdk-1.0.0.aar Normal file

Binary file not shown.

358
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,358 @@
# 代码混淆压缩比在0~7之间默认为5一般不做修改
-optimizationpasses 5
# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames
# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
# 这句话能够使我们的项目混淆后产生映射文件
# 包含有类名->混淆后类名的映射关系
-verbose
# 指定不去忽略非公共库的类成员
-dontskipnonpubliclibraryclassmembers
# 不做预校验preverify是proguard的四个步骤之一Android不需要preverify去掉这一步能够加快混淆速度
-dontpreverify
# 保留Annotation不混淆
-keepattributes *Annotation*,InnerClasses
# 避免混淆泛型
-keepattributes Signature
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
# 指定混淆是采用的算法,后面的参数是一个过滤器
# 这个过滤器是谷歌推荐的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*
#############################################
#
# Android开发中一些需要保留的公共部分
#
#############################################
# 保留我们使用的四大组件自定义的Application等等这些类不被混淆
# 因为这些子类都有可能被外部调用
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Appliction
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
# 保留support下的所有类及其内部类
-keep class android.support.** {*;}
#kotlin
-keep class kotlin.** { *; }
-keep class kotlin.Metadata { *; }
-dontwarn kotlin.**
-keepclassmembers class **$WhenMappings {
<fields>;
}
-keepclassmembers class kotlin.Metadata {
public <methods>;
}
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
}
# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
-keep class com.google.android.material.** {*;}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-dontwarn com.google.android.material.**
-dontnote com.google.android.material.**
-dontwarn androidx.**
# 保留R下面的资源
-keep class **.R$* {*;}
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 保留binding方法不被混淆
-keepclassmembers class ** implements androidx.viewbinding.ViewBinding {
public static ** bind(***);
public static ** inflate(***);
}
# 保留在Activity中的方法参数是view的方法
# 这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
# 保留我们自定义控件继承自View不被混淆
-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);
}
# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keep public class * implements java.io.Serializable {*;}
# 不混淆实体类
-keep class com.cheng.bole.bean.** { *; }
-keep class com.cheng.bole.bean.db.** { *; }
-keep class com.cheng.bole.net.model.** { *; }
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
void *(**On*Event);
void *(**On*Listener);
}
# 移除Log类打印各个等级日志的代码打正式包的时候可以做为禁log使用这里可以作为禁止log打印的功能使用
# 记得proguard-android.txt中一定不要加-dontoptimize才起作用
# 另外的一种实现方案是通过BuildConfig.DEBUG的变量来控制
-assumenosideeffects class android.util.Log {
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
}
# fastJson
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.** { *; }
-keepattributes *Annotation*
# gson
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
-keepattributes AnnotationDefault,RuntimeVisibleAnnotations
# 保留Gson核心类和方法防止它们被混淆
-dontwarn sun.misc.**
-keep class com.google.gson.** { *; }
-keep class com.google.gson.examples.android.model.** { <fields>; }
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# 保持Gson序列化和反序列化所需的注解不被混淆
-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
-keepclassmembernames class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# 保持枚举类型的序列化兼容性
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 防止R8或ProGuard移除未使用的元素如果这些元素是通过反射访问的比如Gson
-keep class * {
@com.google.gson.annotations.SerializedName *;
}
-keepclassmembers class com.example.base.extensions.GsonExtensionsKt {
<methods>;
}
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# OkHttp3
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**
# Okio
-dontwarn com.squareup.**
-dontwarn okio.**
-keep public class org.codehaus.* { *; }
-keep public class java.nio.* { *; }
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
# liveDataBus
-dontwarn com.jeremyliao.liveeventbus.**
-keep class com.jeremyliao.liveeventbus.** { *; }
-keep class androidx.lifecycle.** { *; }
-keep class androidx.arch.core.** { *; }
# 微信
-keep class com.tencent.mm.opensdk.** { *; }
-keep class com.tencent.wxop.** { *; }
-keep class com.tencent.mm.sdk.** { *; }
# 支付宝
-libraryjars libs/alipaysdk-15.8.03.210428205839.aar
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}
# 友盟
-keep class com.umeng.** {*;}
-keep class org.repackage.** {*;}
-keepclassmembers class * {
public <init> (org.json.JSONObject);
}
-keep public class com.chat.assistant.ai.R$*{
public static final int *;
}
#加载动画
-keep class com.wang.avi.** { *; }
-keep class com.wang.avi.indicators.** { *; }
#oss
-keep class com.alibaba.sdk.android.oss.** { *; }
-dontwarn okio.**
-dontwarn org.apache.commons.codec.binary.**
-keep class com.alibaba.idst.nui.*{*;}
##高德
#定位
-keep class com.amap.api.location.**{*;}
-keep class com.amap.api.fence.**{*;}
-keep class com.loc.**{*;}
-keep class com.autonavi.aps.amapapi.model.**{*;}
#地图
-keep class com.amap.api.maps.**{*;}
-keep class com.autonavi.**{*;}
-keep class com.amap.api.trace.**{*;}
#2D地图
-keep class com.amap.api.maps2d.**{*;}
-keep class com.amap.api.mapcore2d.**{*;}
#搜索
-keep class com.amap.api.services.**{*;}
#room
-keep class androidx.room.** { *; }
-keepclassmembers class * {
@androidx.room.* <methods>;
@androidx.room.* <fields>;
}
-keep interface com.cheng.bole.manager.db.* { *; }
-keepclassmembers class * extends androidx.room.RoomDatabase {
public <init>(...);
}
-keep class com.hjq.permissions.** {*;}
-keep class org.libpag.** {*;}
-keep class androidx.exifinterface.** {*;}
-dontwarn io.microshow.rxffmpeg.**
-keep class io.microshow.rxffmpeg.**{*;}
# 华为推送
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.huawei.hianalytics.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
#腾讯语音识别
-keepclasseswithmembernames class * {
native <methods>;
}
-keep public class com.tencent.cloud.qcloudasrsdk.*
-dontwarn com.bun.miitmdid.interfaces.IIdentifierListener
-dontwarn com.download.library.DownloadTask$DownloadTaskStatus
-dontwarn com.google.j2objc.annotations.Weak
-dontwarn com.oracle.svm.core.annotate.Delete
-dontwarn com.oracle.svm.core.annotate.TargetClass
-dontwarn com.sun.tools.javac.code.Attribute$UnresolvedClass
-dontwarn com.sun.tools.javac.code.Type$ClassType
-dontwarn javax.lang.model.SourceVersion
-dontwarn javax.lang.model.element.AnnotationMirror
-dontwarn javax.lang.model.element.AnnotationValue
-dontwarn javax.lang.model.element.AnnotationValueVisitor
-dontwarn javax.lang.model.element.Element
-dontwarn javax.lang.model.element.ElementKind
-dontwarn javax.lang.model.element.ExecutableElement
-dontwarn javax.lang.model.element.Modifier
-dontwarn javax.lang.model.element.Name
-dontwarn javax.lang.model.element.NestingKind
-dontwarn javax.lang.model.element.PackageElement
-dontwarn javax.lang.model.element.TypeElement
-dontwarn javax.lang.model.element.TypeParameterElement
-dontwarn javax.lang.model.element.VariableElement
-dontwarn javax.lang.model.type.DeclaredType
-dontwarn javax.lang.model.type.TypeKind
-dontwarn javax.lang.model.type.TypeMirror
-dontwarn javax.lang.model.type.TypeVariable
-dontwarn javax.lang.model.type.TypeVisitor
-dontwarn javax.lang.model.util.Elements
-dontwarn javax.lang.model.util.SimpleAnnotationValueVisitor7
-dontwarn javax.lang.model.util.SimpleTypeVisitor7
-dontwarn javax.lang.model.util.Types
-dontwarn org.bouncycastle.asn1.gm.GMNamedCurves
-dontwarn org.bouncycastle.asn1.x9.X9ECParameters
-dontwarn org.bouncycastle.crypto.digests.SM3Digest
-dontwarn org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey
-dontwarn org.bouncycastle.jce.provider.BouncyCastleProvider
-dontwarn org.bouncycastle.jce.spec.ECParameterSpec
-dontwarn org.bouncycastle.jce.spec.ECPublicKeySpec
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.bouncycastle.math.ec.ECCurve
-dontwarn org.bouncycastle.math.ec.ECPoint
-dontwarn org.bouncycastle.util.encoders.Hex
-dontwarn org.conscrypt.Conscrypt$Version
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE
-dontwarn com.efs.sdk.base.core.config.GlobalInfo
-dontwarn com.efs.sdk.base.core.config.GlobalInfoManager
-dontwarn coil.compose.EqualityDelegate
-dontwarn coil.compose.SingletonAsyncImageKt
-dontwarn android.os.SystemProperties

View File

@ -0,0 +1,24 @@
package com.cheng.bole
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.cheng.bole", appContext.packageName)
}
}

View File

@ -0,0 +1,205 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<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.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--通知相关-->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<queries>
<package android:name="com.eg.android.AlipayGphone" /> <!-- 支付宝 -->
<package android:name="hk.alipay.wallet" /> <!-- AlipayHK -->
</queries>
<queries>
<package android:name="com.tencent.mm" />
</queries>
<queries>
<intent>
<action android:name="com.getui.sdk.action" />
</intent>
</queries>
<queries package="${applicationId}">
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
<intent>
<action android:name="android.media.action.ACTION_VIDEO_CAPTURE" />
</intent>
</queries>
<application
android:name=".BaseApplication"
android:allowBackup="true"
android:enableOnBackInvokedCallback="true"
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher_icon"
android:label="@string/app_name"
android:maxAspectRatio="2.4"
android:requestLegacyExternalStorage="true"
android:resizeableActivity="true"
android:roundIcon="@mipmap/ic_launcher_icon"
android:supportsRtl="true"
android:theme="@style/Theme.Material"
android:usesCleartextTraffic="true"
tools:replace="android:allowBackup,android:supportsRtl">
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL}" />
<meta-data
android:name="UMENG_APPKEY"
android:value="" />
<uses-library
android:name="org.apache.http.legacy"
android:required="false" />
<meta-data
android:name="ScopedStorage"
android:value="true" />
<meta-data
android:name="android.max_aspect"
android:value="2.4" />
<!--适配华为huawei刘海屏-->
<meta-data
android:name="android.notch_support"
android:value="true" />
<!--适配小米xiaomi刘海屏-->
<meta-data
android:name="notch.config"
android:value="portrait|landscape" />
<activity
android:name="com.cheng.bole.ui.activity.LauncherActivity"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.cheng.bole.ui.activity.LoginActivity"
android:configChanges="keyboardHidden|smallestScreenSize|orientation|screenSize"
android:exported="true"
android:label="登录"
android:launchMode="singleTask"
android:screenOrientation="portrait" />
<activity
android:name="com.cheng.bole.ui.activity.MainActivity"
android:configChanges="keyboardHidden|smallestScreenSize|orientation|screenSize"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait">
<intent-filter tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<!-- 指定分享类型-->
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name="com.cheng.bole.ui.activity.GuideActivity"
android:configChanges="keyboardHidden|smallestScreenSize|orientation|screenSize"
android:exported="true"
android:label="引导页"
android:launchMode="singleTask"
android:screenOrientation="portrait" />
<activity
android:name="com.cheng.bole.ui.activity.PublicActivity"
android:configChanges="keyboardHidden|smallestScreenSize|orientation|screenSize"
android:label="通用的Activity"
android:launchMode="standard"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan|stateHidden" />
<activity
android:name="com.cheng.bole.ui.activity.DrawerActivity"
android:configChanges="keyboardHidden|smallestScreenSize|orientation|screenSize"
android:label="通用的Activity"
android:launchMode="standard"
android:screenOrientation="portrait"
android:theme="@style/TransparentTheme"
android:windowSoftInputMode="stateHidden" />
<activity
android:name="com.cheng.bole.ui.activity.VideoPlayerActivity"
android:configChanges="keyboardHidden|smallestScreenSize|orientation|screenSize"
android:label="视频播放器"
android:launchMode="standard"
android:screenOrientation="portrait" />
<activity
android:name="com.cheng.bole.wxapi.WXEntryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity
android:name="com.cheng.bole.wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepath_data" />
</provider>
</application>
</manifest>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,90 @@
package com.cheng.bole
import com.cheng.bole.utils.ChannelUtils
import com.cheng.bole.common.Constants
import com.example.base.MvvmApplication
import com.example.base.utils.L
import com.example.base.utils.MMKVUtils
import com.example.base.utils.Utils
import com.g.gysdk.GYManager
import com.g.gysdk.GYResponse
import com.g.gysdk.GyCallBack
import com.g.gysdk.GyConfig
import com.scwang.smart.refresh.header.MaterialHeader
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.tencent.mmkv.MMKV
import com.umeng.analytics.MobclickAgent
import com.umeng.commonsdk.UMConfigure
import com.umeng.socialize.PlatformConfig
class BaseApplication : MvvmApplication() {
override fun onCreate() {
super.onCreate()
Utils.init(this)
MMKV.initialize(this)
preInitUM()
preInitGT()
initRefreshLayout()
}
/**
* 初始化友盟
*/
private fun preInitUM() {
UMConfigure.setLogEnabled(true)
PlatformConfig.setFileProvider(Constants.AppFilter)
PlatformConfig.setWeixin(Constants.WechatAppId, Constants.WechatAppSecret)
MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.AUTO)
UMConfigure.setProcessEvent(true)
}
/**
* 个推初始化
*/
private fun preInitGT() {
if (MMKVUtils.getBoolean("isAgree")) {
try {
GYManager.getInstance().preInit(this) //个验SDK初始化
GYManager.getInstance().init(
GyConfig.with(this)
.preLoginUseCache(true)//预取号使用缓存可以提高预取号的成功率建议设置为true
.channel(ChannelUtils.getChannel())//应用渠道
.eLoginDebug(BuildConfig.DEBUG)//运营商debug调试模式
.debug(BuildConfig.DEBUG)//个验debug调试模式
.callBack(object : GyCallBack {
override fun onSuccess(gyResponse: GYResponse) {
L.d("TAG-->>GYManager init onSuccess =${gyResponse.code}")
}
override fun onFailed(gyResponse: GYResponse) {
L.d("TAG-->>GYManager init onFailed =${gyResponse.code}")
}
}).build()
)
//预登录
GYManager.getInstance().ePreLogin(8000, object : GyCallBack {
override fun onSuccess(gyResponse: GYResponse) {
L.d("TAG-->>GYManager ePreLogin onSuccess =${gyResponse.code}")
}
override fun onFailed(gyResponse: GYResponse) {
L.d("TAG-->>GYManager ePreLogin onFailed =${gyResponse.code}")
}
})
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun initRefreshLayout() {
//设置全局的Header构建器
SmartRefreshLayout.setDefaultRefreshHeaderCreator { context, _ ->
MaterialHeader(context)
}
}
}

View File

@ -0,0 +1,16 @@
package com.cheng.bole.bean
import java.io.Serializable
data class AccountEntity(
val avater: String,
val bind: List<String>,
val create_time: String,
val name: String,
val phone: String,
val role: Int,
val temp: Boolean,
val user_id: String,
val vip_name: String,
val vip_type: String
) : Serializable

View File

@ -0,0 +1,13 @@
package com.cheng.bole.bean
import java.io.Serializable
data class AdIncentiveEntity(
val ad_code: String,
val ad_count: Int,
val ad_height: Int,
val ad_width: Int,
val is_visible: Boolean,
val reward_count: Int,
val reward_name: String
) : Serializable

View File

@ -0,0 +1,9 @@
package com.cheng.bole.bean
import java.io.Serializable
data class BannerEntity(
val image: String,
val page: String,
val type: String
) : Serializable

View File

@ -0,0 +1,39 @@
package com.cheng.bole.bean
import com.google.gson.annotations.SerializedName
class ConfigEntity {
@SerializedName("client.version.upgrade")
var versionEntity: com.cheng.bole.bean.VersionEntity? = null
@SerializedName("client.weixin.share") //微信分享
var wxShareEntity: com.cheng.bole.bean.WxShareEntity? = null
@SerializedName("client.guide.pay.enable")
var guidePayEnable: Boolean? = true //引导页是否开启支付,默认可以
@SerializedName("client.guide.enable")
var guideEnable: Boolean? = true //是否开启引导页
@SerializedName("client.start.function.hint")
var guideHint: String? = ""
@SerializedName("client.nologin.pay.enable")
var noLoginPayEnable: Boolean? = false
@SerializedName("client.pay.agreement") //是否显示支付协议
var payAgreementEnable: Boolean? = true
@SerializedName("client.login.type") //登录方式
var loginType: List<String>? = emptyList()
@SerializedName("client.banner.urls") //首页banner
var banners: List<com.cheng.bole.bean.BannerEntity>? = emptyList()
@SerializedName("client.ad.switch") //广告总开关
var adSwitch: Boolean = false
@SerializedName("client.service.phone") //客服电话
var servicePhoneList: List<String> = emptyList()
}

View File

@ -0,0 +1,14 @@
package com.ylqh.cube.bean
import java.io.Serializable
data class CouponActivityEntity(
val id: String = "",
val activity_desc: String = "",
val activity_name: String = "",
val activity_threshold: String = "",
val activity_type: String = "",
val activity_type_name: String = "",
val activity_value: String = "",
var enableAnim: Boolean = true
): Serializable

View File

@ -0,0 +1,25 @@
package com.cheng.bole.bean
import java.io.Serializable
data class CouponEntity(
val id: String,
val status: String,
val status_name: String,
val threshold: String,
val coupon_desc: String,
val coupon_name: String,
val coupon_type: String,
val coupon_type_name: String,
val coupon_value: String,
val coupon_value_name: String,
val create_time: String,
val expire_time: String,
val expire_timestamp: String,
var isChecked: Boolean = false
) : Serializable {
companion object {
const val TYPE_CASH = "1"
const val TYPE_DISCOUNT = "2"
}
}

View File

@ -0,0 +1,8 @@
package com.cheng.bole.bean
class LoginEntity {
val user_id: String = ""
val name: String = ""
val avater: String = ""
val token: String = ""
}

View File

@ -0,0 +1,11 @@
package com.cheng.bole.bean
data class NoticeEntity(
val loop: Boolean,
val notice: List<String>?
) {
data class NoticeItem(
val message: String,
var loop: Boolean = false
)
}

View File

@ -0,0 +1,16 @@
package com.cheng.bole.bean
class OrderPayEntity {
var appId = ""
var orderId = ""
var outTradeNo = ""
var payParam = ""
var payType = ""
var nonceStr = ""
var `package` = ""
var partnerId = ""
var prepayId = ""
var sign = ""
var timeStamp = ""
}

View File

@ -0,0 +1,9 @@
package com.cheng.bole.bean
import java.io.Serializable
data class PushPayloadEntity(
val msgId: String,
val page: String,
val params: String
): Serializable

View File

@ -0,0 +1,5 @@
package com.cheng.bole.bean
class SendCodeEntity {
val timestamp: String = ""
}

View File

@ -0,0 +1,8 @@
package com.cheng.bole.bean
import java.io.Serializable
class UploadImgEntity : Serializable {
var id = ""
var url = ""
}

View File

@ -0,0 +1,11 @@
package com.cheng.bole.bean
import java.io.Serializable
class UserConfigEntity : Serializable{
var token = ""
var temp = false
var name = ""
var user_id = ""
var config: com.cheng.bole.bean.ConfigEntity? = null
}

View File

@ -0,0 +1,34 @@
package com.cheng.bole.bean
import java.io.Serializable
data class UserEntity(
val appleid: String,
val avater: String,
val balance: String,
val city: String,
val client_cid: String,
val country: String,
val coupon_count: Int,
val imei: String,
val month_download_count: String,
val month_download_size: String,
val name: String,
val oaid: String,
val os_version: String,
val phone: String,
val province: String,
val role: String,
val sex: Int,
val show_contact_menu: Boolean,
val show_masonry_menu: Boolean,
val temp: Boolean,
val unionid: String,
val user_id: String,
val vip: String, // 1非会员 2会员 3终生会员
val vip_expire: String,
val vip_expire_time: String,
val vip_name: String,
val weixinAppOpenId: String,
val ip_area: String
) : Serializable

View File

@ -0,0 +1,15 @@
package com.cheng.bole.bean
import java.io.Serializable
class VersionEntity : Serializable {
var description = ""
var force = false
var last_version_force = ""
var title = ""
var url = ""
var app_size = ""
var version = ""
}

View File

@ -0,0 +1,14 @@
package com.cheng.bole.bean
class VipGoodsEntity {
var checked: Boolean = false
var goods_id: String = ""
var goods_name: String = ""
var origin_price: String = ""
var pay_type: String = ""
var price: String = ""
var single_pay_price: String = ""
var tips: String = ""
var sign_value = ""
var value: String = ""
}

View File

@ -0,0 +1,23 @@
package com.cheng.bole.bean
import java.io.Serializable
data class VipPermissionEntity(
val auth: Boolean,
val auth_ad: Boolean,
val scene: String,
val user_id: Int,
val vip: Int,
val vip_expire: String,
val vip_expire_time: String,
val vip_goods_type: String,
val vip_message: String,
val vip_name: String,
var type: Int
) : Serializable {
companion object {
const val TYPE_SHARE = 1
const val TYPE_DOWNLOAD = 2
}
}

View File

@ -0,0 +1,24 @@
package com.cheng.bole.bean
import com.cheng.bole.R
class VipTipItemEntity(var icon: Int, var name: String) {
companion object {
fun getVipTipList(): List<com.cheng.bole.bean.VipTipItemEntity> {
val list = ArrayList<com.cheng.bole.bean.VipTipItemEntity>()
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item1, "素材图库"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item2, "魔方工具"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item3, "高清图片"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item4, "AI创作"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item5, "视频提取"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item6, "音频提取"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item7, "文案提取"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item8, "无广告"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item9, "海量次数"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item10, "海量流量"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item11, "专属客服"))
list.add(com.cheng.bole.bean.VipTipItemEntity(R.mipmap.ic_vip_item12, "在线浏览"))
return list
}
}
}

View File

@ -0,0 +1,10 @@
package com.cheng.bole.bean
import com.google.gson.annotations.SerializedName
class WxServiceEntity {
var corpid = ""
@SerializedName("kf.address")
var address = ""
}

View File

@ -0,0 +1,10 @@
package com.cheng.bole.bean
import java.io.Serializable
data class WxShareEntity(
val content: String = "",
val image: String = "",
val link: String = "",
val title: String = ""
) : Serializable

View File

@ -0,0 +1,75 @@
package com.cheng.bole.common
import android.app.Activity
import android.graphics.Color
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.azhon.appupdate.manager.DownloadManager
import com.cheng.bole.BuildConfig
import com.cheng.bole.R
import com.cheng.bole.manager.UserConfigManager
import com.cheng.bole.ui.dialog.UpdateVersionDialog
import com.cheng.bole.utils.UIUtils
import com.example.base.extensions.toast
object AppUpdate {
private val apkName = "appupdate.apk"
fun checkUpdate(fragment: Fragment, isManual: Boolean, clickFun: () -> Unit?) {
if (isManual) {
toast(fragment.getString(R.string.check_version_ing))
}
val result: com.cheng.bole.bean.VersionEntity? = UserConfigManager.userConfig?.config?.versionEntity
result?.apply {
if (UIUtils.checkVersion(version, BuildConfig.VERSION_NAME)) {
if (last_version_force == BuildConfig.VERSION_NAME) {
force = true
} else if (UIUtils.checkVersion(last_version_force, BuildConfig.VERSION_NAME)) {
force = true
}
clickFun.invoke()
com.cheng.bole.common.AppUpdate.startUpdate(result, fragment)
} else {
if (isManual) {
toast(fragment.getString(R.string.curr_new_version))
}
}
}
}
private fun startUpdate(versionEntity: com.cheng.bole.bean.VersionEntity, fragment: Fragment) {
UpdateVersionDialog.newInstance(versionEntity).show(fragment.childFragmentManager, null)
}
private fun startUpdateDialog(result: com.cheng.bole.bean.VersionEntity?, activity: Activity) {
if (result == null) return
val manager = DownloadManager.Builder(activity).run {
apkUrl(result.url)
apkName(com.cheng.bole.common.AppUpdate.apkName)
smallIcon(R.mipmap.ic_launcher_icon)
dialogImage(R.mipmap.ic_update_version_bg_z)
showNewerToast(true)
apkVersionName(result.version)
apkSize(result.app_size)
apkDescription(result.description)
enableLog(true)
jumpInstallPage(true)
dialogButtonTextColor(Color.WHITE)
showNotification(true)
showBgdToast(false)
when (result.force) {
true -> forcedUpgrade(true)
else -> forcedUpgrade(false)
}
dialogButtonColor(ContextCompat.getColor(activity, R.color.colorAccent))
dialogProgressBarColor(ContextCompat.getColor(activity, R.color.colorAccent))
notifyId(1011)
build()
}
manager.download()
}
}

View File

@ -0,0 +1,34 @@
package com.cheng.bole.common
import android.graphics.Typeface
import com.cheng.bole.BuildConfig
import com.example.base.utils.Utils
object Constants {
const val BaseUrl = "http://bid7.yua8.cn"//正式地址
const val TestUrl = "http://bid7.yua8.cn"//测试地址
const val APP_ID = "10055"
const val AppFilter = "${BuildConfig.APPLICATION_ID}.fileprovider"
const val WechatAppId = ""//微信APPID
const val WechatAppSecret = ""//微信secret
const val UmengAppkey = "692528cc8560e34872f36551"//友盟appKey
const val userAgreement = "$BaseUrl/static/new5/user.html"//用户协议
const val privacyPolicy = "$BaseUrl/static/new5/provacy.html"//隐私政策
const val renewAgreement = "$BaseUrl/static/new5/renew.html"//自动续费协议
const val permissionList: String = "${BaseUrl}/static/new5/limits.html"//权限说明
const val shareList: String = "${BaseUrl}/static/new5/shareList.html"//第三方共享清单
const val sdkList: String = "${BaseUrl}/static/new5/sdkList.html"//第三方SDK目录
const val Encrypt = "zpzkfp72v3hgatzg5w7pyg86x5342kxt"
const val Signature = "ckBHUSWBx3TqwNT2kxMrsXyXFuA3PW"
val almmsht = Typeface.createFromAsset(Utils.getApp().assets, "fonts/Alimama ShuHeiTi.ttf")
val dDIN_PRO_M = Typeface.createFromAsset(Utils.getApp().assets, "fonts/D-DIN-PRO-500-Medium.otf")
val youSheBiaoTiHei = Typeface.createFromAsset(Utils.getApp().assets, "fonts/YouSheBiaoTiHei.ttf")
}

View File

@ -0,0 +1,270 @@
package com.cheng.bole.common
object EventConstants {
const val APP_LAUNCH = "client.launch" //app启动
const val GUIDE_LAUNCH = "client.guide.launch" //引导页启动
const val GUIDE_OPPORTUNITY_SCROLL = "client.guide.content.scroll" //滑动切换引导页内容
const val GUIDE_SKIP = "client.guide.pay.skip" //跳过引导页支付
const val HOME_BOTTOM_TAB_CHECK = "client.main.bottom.tab.check" //底部tab切换
const val HOME_NOTICE_CHECK = "client.main.notice.check" //首页通知点击
const val GOODS_SELECT = "client.goods.select" //点击切换支付的会员类型
const val PAY_SELECT = "client.pay.select" //点击切换支付类型
const val PAY_PAY = "client.pay.pay" //支付按钮点击
const val CHALLENGE_TASK_PAY_PAY = "client.challenge.task.pay.pay" //0元挑战支付按钮点击
const val PAY_SUCCESS = "client.pay.success" //支付成功
const val PAY_CANCEL = "client.pay.cancel" //支付取消
const val ERROR_CLIENT_WXPAY_ERR = "client.wxpay.err" //微信支付失败
const val ERROR_CLIENT_ALIPAY_ERR = "client.alipay.err" //支付宝支付失败
const val ERROR_CLIENT_DOWNLOAD_IMG = "client.download.img.err" //图片下载失败
const val ERROR_CLIENT_DOWNLOAD_VIDEO = "client.download.video.err" //视频下载失败
const val ERROR_CLIENT_DOWNLOAD_AUDIO = "client.download.audio.err" //音频下载失败
const val CANCEL_DOWNLOAD_VIDEO = "client.download.video.cancel" //取消视频下载
const val PAUSE_DOWNLOAD_VIDEO = "client.download.video.pause" //暂停视频下载
const val CONTINUE_DOWNLOAD_VIDEO = "client.download.video.continue" //继续视频下载
const val RESTART_DOWNLOAD_VIDEO = "client.download.video.restart" //重新视频下载
const val SPEED_UP_DOWNLOAD_VIDEO = "client.download.video.speed.up" //加速视频下载
const val BACKGROUND_CLIENT_DOWNLOAD = "client.download.background" //后台下载
const val FLOAT_WINDOW_CLICK = "client.float.window.click" //点击悬浮窗
const val SAVE_AI_MEDIA = "client.ai.media.save" //ai生成文件保存
const val RECOGNIZE_AUDIO_TO_TEXT = "client.audio.text.recognize" //音频转文字
const val PKG_UPDATE = "client.pkg.update" //升级弹窗点击更新
const val PKG_CANCEL = "client.pkg.cancel" //升级弹窗点击取消
const val GET_MATERIAL = "client.get.material" //获取素材
const val GET_MATERIAL_CANCEL = "client.get.material.cancel" //取消获取素材
const val DIALOG_CONFIRM_SAVE_FILE = "client.dialog.confirm.save.file" //保存文件地址弹框确认
const val DIALOG_GO_TO_VIEW = "client.dialog.go.to.view" //前往保存文件的地址查看
const val JUMP_TO_ABOUT_US = "client.jump.to.about.us" //界面跳转
const val JUMP_TO_LINK_EXTRACT = "client.jump.to.link.extract" //跳转链接提取
const val JUMP_TO_WECHAT_VIDEO = "client.jump.to.wechat.video" //跳转视频号
const val JUMP_TO_WECHAT_PLAYBACK = "client.jump.to.wechat.video.playback" //跳转直播回放
const val JUMP_TO_COURSE_WX_VIDEO = "client.course.wechat.video" //视频号视频教程
const val JUMP_TO_COURSE_PLAYBACK = "client.course.playback" //直播回放视频教程
const val JUMP_TO_TOOL = "client.jump.to.home.tool" //跳转工具
const val MAIN_CENTER_ENABLE = "client.main.center.enable" //首页跳转个人中心
const val JUMP_TO_MEMBER_RECHARGE = "client.jump.to.member.recharge" //跳转到充值页
const val JUMP_TO_LOGIN = "client.jump.to.login" //跳转到登录页
const val JUMP_TO_SYSTEM_SETTING = "client.jump.to.system.setting" //跳转到系统设置
const val JUMP_TO_USER_SETTING = "client.jump.to.user.setting" //跳转到用户设置
const val JUMP_TO_FEEDBACK = "client.jump.to.feedback" //跳转到意见反馈
const val JUMP_TO_ACCOUNT_BIND = "client.jump.to.account.bind" //跳转到账号绑定
const val JUMP_TO_ACCOUNT_MANAGE = "client.jump.to.account.manage" //跳转到账号管理
const val JUMP_TO_DOWNLOAD_HISTORY = "client.jump.to.download.history" //跳转到下载记录
const val JUMP_TO_DOWNLOAD_TASK_LIST = "client.jump.to.download.task.list" //跳转到下载任务列表
const val JUMP_TO_RECHARGE_DIAMOND = "client.jump.to.recharge.diamond" //跳转到M币充值
const val JUMP_TO_COUPON_LIST = "client.jump.to.coupon.list" //跳转优惠券列表
const val JUMP_TO_CHALLENGE_TASK = "client.jump.to.challenge.task" //跳转到0元挑战
const val JUMP_TO_SHARE_WX_VIDEO = "client.jump.to.wechat.share.video" //跳转到视频号分享
const val JUMP_TO_SHARE_WX_PLAYBACK = "client.jump.to.wechat.share.playback" //跳转到直播回放分享
const val JUMP_TO_COURSE = "client.jump.to.course" //跳转到指导教程
const val DOWNLOAD_FILE = "client.download.file" //下载文件
const val DOWNLOAD_FILE_SUCCESS = "client.download.file.success" //下载文件成功
const val DOWNLOAD_FILE_ERROR = "client.download.file.error" //下载文件失败
const val TRANSPOND_FILE = "client.transpond.file" //转发文件
const val MATERIAL_COPY_TEXT = "client.material.copy.text" //复制文字
const val MATERIAL_TYPE_CHECK = "client.material.type.check" //素材切换
const val MATERIAL_ALL_SELECT = "client.material.all.select" //全部选中素材
const val MATERIAL_SELECT = "client.material.select" //选择素材
const val TOOLS_VIDEO_EXTRACT_AUDIO = "client.tools.video.audio" //提取音频
const val MATERIAL_PLAY_VIDEO = "client.material.play.video" //播发视频
const val GET_CODE = "client.get.code" //获取验证码
const val LOGIN = "client.login" //登录
const val SWITCH_ACCOUNT = "client.switch.account" //切换账户
const val ACCOUNT_BIND = "client.account.bind" //绑定账号
const val ACCOUNT_BIND_CANCEL = "client.account.bind.cancel" //取消绑定账号
const val CHECK_AGREEMENT = "client.check.agreement" //切换协议状态
const val VIEW_AGREEMENT = "client.view.agreement" //查看用户协议
const val PRIVACY_POLICY_CLICK_OK = "client.privacy.policy.click.ok" //同意隐私协议
const val SAVE_USER_CONFIG_ERROR = "client.save.user.config.error" //保存用户配置错误
const val SHARE_APP = "client.share.app" //分享app
const val CLEAR_CACHE = "client.clear.cache" //清除缓存
const val CONTACT_SERVICE = "client.contact.service" //联系客服
const val EXIT_LOGIN = "client.exit.login" //退出登录
const val CANCEL_ACCOUNT = "client.cancel.account" //注销账户
const val MEMBER_FORCE_LOGIN = "client.member.force.login" //会员强制登录
const val GET_MATERIAL_TIMES_USE_UP = "client.times.use.up.get.material" //获取素材次数已用完
const val PICTURE_HANDLE_TIMES_USE_UP = "client.times.use.up.picture.handle" //图片处理次数已用完
const val CHECK_LOGIN_TYPE = "client.check.login.type" //切换登录方式
const val OPEN_SCREEN_AD_SHOW = "client.ad.open.screen.show" //开屏广告展示
const val OPEN_SCREEN_AD_SKIP = "client.ad.open.screen.skip" //开屏广告跳过
const val OPEN_SCREEN_AD_CLICK = "client.ad.open.screen.click" //开屏广告点击
const val BANNER_AD_SHOW = "client.ad.banner.show" //banner广告展示
const val BANNER_AD_CLOSE = "client.ad.banner.close" //banner广告关闭
const val BANNER_AD_CLICK = "client.ad.banner.click" //banner广告点击
const val INSERT_SCREEN_AD_SHOW = "client.ad.insert.screen.show" //插屏广告展示
const val INSERT_SCREEN_AD_CLOSE = "client.ad.insert.screen.close" //插屏广告关闭
const val INSERT_SCREEN_AD_CLICK = "client.ad.insert.screen.click" //插屏广告点击
const val INSERT_SCREEN_AD_SKIP_VIDEO = "client.ad.insert.screen.skip.video" //跳过插屏广告
const val INCENTIVE_AD_SHOW = "client.ad.incentive.show" //激励广告展示
const val INCENTIVE_AD_CLOSE = "client.ad.incentive.close" //激励广告关闭
const val INCENTIVE_AD_REWARD = "client.ad.incentive.reward" //激励广告已获取到奖励
const val INCENTIVE_AD_SKIP_VIDEO = "client.ad.incentive.skip.video" //跳过激励广告
const val ACCOUNT_UNBIND = "client.account.unbind" //解除绑定账号
const val HISTORY_RECORD_TYPE_CHECK = "client.history.record.type.check" //历史记录切换
const val CLOSE_FREE_TIME_USES_UP_DIALOG =
"client.free.time.uses.up.dialog.close" //关闭免费次数用完的提示框
const val CHECK_FREE_TIME_USES_UP_DIALOG =
"client.free.time.uses.up.dialog.check" //免费次数用完的提示框切换充值类型
const val CONFIRM_FREE_TIME_USES_UP_DIALOG =
"client.free.time.uses.up.dialog.confirm" //确认免费次数用完的提示框
const val MULTI_DELETE_FILE = "client.multi.delete.file" //批量删除文件
const val MULTI_TRANSMIT_FILE = "client.multi.transmit.file" //批量转发文件
const val PREVIEW_DELETE_FILE = "client.preview.delete.file" //预览时删除文件
const val PREVIEW_TRANSMIT_FILE = "client.preview.transmit.file" //预览时删除文件
const val PREVIEW_HANDLE_IMAGE = "client.preview.handle.image" //预览时进行图片处理
const val TOOLS_HANDLE_IMAGE_START = "client.tools.handle.image.start" //图片处理开始
const val TOOLS_HANDLE_SAVE_IMAGE = "client.tools.handle.save.image" //保存已处理过的图片至相册
const val AUTO_SWITCH_DOWNLOAD_URL = "client.auto.switch.download.url" //自动切换下载链接
const val HAND_SWITCH_DOWNLOAD_URL = "client.hand.switch.download.url" //手动切换下载链接立即加速
const val HOME_BANNER_CLICK = "client.home.banner.click"
const val COUPON_ANIMATION_PLAY = "client.coupon.animation.play" //播放优惠券动画
const val COUPON_ANIMATION_CLOSE = "client.coupon.animation.close" //关闭优惠券动画
const val COUPON_RECEIVE = "client.coupon.receive" //领取优惠券
const val COUPON_REDEEM_ENABLE = "client.coupon.redeem.enable" //优惠券兑换按钮点击
const val COUPON_REDEEM_INFO = "client.coupon.redeem.info" //优惠券兑换详情
const val COUPON_REDEEM = "client.coupon.redeem" //优惠券兑换
const val COUPON_REDEEM_SUCCESS = "client.coupon.redeem.success" //优惠券兑换成功
const val COUPON_REDEEM_SUCCESS_CONFIRM = "client.coupon.redeem.success.confirm" //优惠券兑换成功
const val COUPON_VIEW = "client.coupon.view" //查看优惠券
const val COUPON_DIALOG_CHECK = "client.coupon.dialog.check" //切换优惠券
const val COUPON_DIALOG_CLOSE = "client.coupon.dialog.close" //关闭优惠券
const val COUPON_DIALOG_CONFIRM = "client.coupon.dialog.confirm" //确认优惠券
const val COPY_USER_ID = "client.copy_user_id" //复制用户id
const val SHOW_PALYBACK_HINT_DIALOG = "client.show.playback.hint.dialog"
const val EXIT_APP = "client.exit.app" //退出APP
const val SHOW_DIALOG = "client.show.dialog" //弹出退出app的弹框
const val START_COUPON_ANIMATION = "client.start.coupon.animation"
const val CHALLENGE_TASK_SIGN_IN = "client.challenge.tasK.sign.in" //签到
const val CHALLENGE_TASK_SIGN_IN_SUCCESS = "client.challenge.tasK.sign.in.success" //签到成功
const val CHALLENGE_TASK_SIGN_IN_FAIL = "client.challenge.tasK.sign.in.fail" //签到失败
}

View File

@ -0,0 +1,3 @@
package com.cheng.bole.event
class ClipboardEvent(var text: String)

View File

@ -0,0 +1,5 @@
package com.cheng.bole.event
import com.ylqh.cube.bean.CouponActivityEntity
class CouponActivityEvent(var list: List<CouponActivityEntity>, var type: Int)// 0 首页, 1 enter, 2 exit

View File

@ -0,0 +1,4 @@
package com.cheng.bole.event
class CouponRefreshEvent {
}

View File

@ -0,0 +1,4 @@
package com.cheng.bole.event
class HomeRefreshEvent {
}

View File

@ -0,0 +1,4 @@
package com.cheng.bole.event
class LoginSuccessEvent {
}

View File

@ -0,0 +1,4 @@
package com.cheng.bole.event
class LogoutSuccessEvent {
}

View File

@ -0,0 +1,4 @@
package com.cheng.bole.event
class MineRefreshEvent {
}

View File

@ -0,0 +1,5 @@
package com.cheng.bole.event
enum class PayStatusEnum {
PAY_SUCCESS, PAY_ERROR, PAY_CANCEL
}

View File

@ -0,0 +1,3 @@
package com.cheng.bole.event
class PayStatusEvent(var payStatus: com.cheng.bole.event.PayStatusEnum, var message: String = "")

View File

@ -0,0 +1,6 @@
package com.cheng.bole.event
class PushMessageEvent(
var payload: String,
var type: Int //2展示通知 3点击通知
)

View File

@ -0,0 +1,4 @@
package com.cheng.bole.event
class UserInfoEvent {
}

View File

@ -0,0 +1,4 @@
package com.cheng.bole.event
class VipPaySuccessEvent {
}

View File

@ -0,0 +1,3 @@
package com.cheng.bole.event
class WxLoginEvent(var code: String, var state: String)

View File

@ -0,0 +1,7 @@
package com.cheng.bole.ext
import java.text.DecimalFormat
fun Number.format(pattern: String = "0.##"): String {
return DecimalFormat(pattern).format(this)
}

View File

@ -0,0 +1,9 @@
package com.cheng.bole.ext
import java.math.BigDecimal
import java.math.RoundingMode
fun String.format(newScale: Int = 2, roundingMode: RoundingMode = RoundingMode.HALF_UP): BigDecimal {
val bd = BigDecimal(this)
return bd.setScale(newScale, roundingMode)
}

View File

@ -0,0 +1,34 @@
package com.cheng.bole.ext
import android.animation.Animator
import android.animation.TimeInterpolator
import android.animation.ValueAnimator
import android.view.animation.AccelerateDecelerateInterpolator
import androidx.viewpager2.widget.ViewPager2
fun ViewPager2.setCurrentItem(
item: Int,
duration: Long,
interpolator: TimeInterpolator = AccelerateDecelerateInterpolator(),
pagePxWidth: Int = width,
pagePxHeight: Int = height
) {
val pxToDrag: Int = if (orientation == ViewPager2.ORIENTATION_HORIZONTAL) pagePxWidth * (item - currentItem) else pagePxHeight * (item - currentItem)
val animator = ValueAnimator.ofInt(0, pxToDrag)
var previousValue = 0
animator.addUpdateListener { valueAnimator ->
val currentValue = valueAnimator.animatedValue as Int
val currentPxToDrag = (currentValue - previousValue).toFloat()
fakeDragBy(-currentPxToDrag)
previousValue = currentValue
}
animator.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) { beginFakeDrag() }
override fun onAnimationEnd(animation: Animator) { endFakeDrag() }
override fun onAnimationCancel(animation: Animator) { /* Ignored */ }
override fun onAnimationRepeat(animation: Animator) { /* Ignored */ }
})
animator.interpolator = interpolator
animator.duration = duration
animator.start()
}

View File

@ -0,0 +1,19 @@
package com.cheng.bole.impl
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
abstract class OnSeekBarChangeListenerImpl: OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
}

View File

@ -0,0 +1,19 @@
package com.cheng.bole.impl
import android.text.Editable
import android.text.TextWatcher
abstract class TextWatcherImpl: TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
}
}

View File

@ -0,0 +1,6 @@
package com.cheng.bole.manager
enum class DialogEnum {
CLICK_OK,
CLICK_CANCEL
}

View File

@ -0,0 +1,31 @@
package com.cheng.bole.manager
import com.alibaba.fastjson.JSONObject
import com.cheng.bole.net.ApiFactory
import com.example.base.utils.L
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
object EventReportManager {
fun eventReport(key: String?, value: String?, extra: String) {
GlobalScope.launch {
try {
val jsonObject = JSONObject()
jsonObject["source"] = "android"
jsonObject["type"] = "click"
jsonObject["key"] = key//点击的地方
jsonObject["value"] = value
jsonObject["extra"] = extra//附加参数
L.d("TAG-->>${jsonObject}")
ApiFactory.apiService.eventReport(jsonObject.toString().toRequestBody("application/json".toMediaType()))
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}

View File

@ -0,0 +1,39 @@
package com.cheng.bole.manager
import com.example.base.utils.MMKVUtils
object LoginManager {
fun saveToken(token: String) {
MMKVUtils.put("x-token", token)
}
fun getToken(): String {
return MMKVUtils.getString("x-token") ?: ""
}
fun isLogin(): Boolean {
return !UserConfigManager.getIsTemp()
}
fun saveLastLoginType(type: String) {
MMKVUtils.put("last_login_type", type)
}
fun getLastLoginType(): String? {
return MMKVUtils.getString("last_login_type")
}
/**
* 退出登录
*/
fun logout() {
// 1. 清除用户数据
MMKVUtils.put("x-role", true)
MMKVUtils.removeKey("userConfig")
MMKVUtils.removeKey("x-token")
MMKVUtils.removeKey("guide_pay")
MMKVUtils.removeKey("guide")
MMKVUtils.removeKey("nologin_pay")
}
}

View File

@ -0,0 +1,117 @@
package com.cheng.bole.manager
import android.app.Activity
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.fragment.app.FragmentManager
import com.cheng.bole.R
import com.cheng.bole.ui.dialog.TipDialog
import com.example.base.extensions.toast
import com.example.base.utils.Utils
object NotificationHelper {
private val notificationManager by lazy { Utils.getApp().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager }
private const val DEFAULT_CHANNEL_ID = "default"
private const val DOWNLOAD_CHANNEL_ID = "download"
private const val FOREGROUND_CHANNEL_ID = "foreground"
private const val DOWNLOAD_GROUP = "download_group"
private const val DOWNLOAD_CANCEL_CODE = 2000
private const val DOWNLOAD_RETRY_CODE = 3000
private var _notificationId = 1000
/**
* 创建默认通知通道
*/
fun createDefaultChannel() {
createNotificationChannel(DEFAULT_CHANNEL_ID, "Default", NotificationManager.IMPORTANCE_DEFAULT)
}
/**
* 前台通知
*/
fun startForeground(service: Service) {
val channelId = createNotificationChannel(FOREGROUND_CHANNEL_ID, "Foreground", NotificationManager.IMPORTANCE_LOW)
val builder = NotificationCompat.Builder(service, channelId)
val notification = builder
.setContentText("文件下载服务运行中")
.setSmallIcon(R.mipmap.ic_launcher_icon)
.setCategory(Notification.CATEGORY_SERVICE)
.build()
service.startForeground(1, notification)
}
/**
* 取消通知
*/
fun cancelNotification(id: Int) {
notificationManager.cancel(id)
}
/**
* 创建通知通道
*
* @param channelId
* @param channelName
* @return
*/
private fun createNotificationChannel(channelId: String, channelName: String, importance: Int): String {
val channel = NotificationChannel(channelId, channelName, importance)
channel.setSound(null, null)
notificationManager.createNotificationChannel(channel)
return channelId
}
fun getNotificationId(): Int {
return ++_notificationId
}
/**
* 判断通知权限是否开启
*/
fun isNotificationEnabled(context: Context): Boolean {
return NotificationManagerCompat.from(context).areNotificationsEnabled()
}
/**
* 通知被禁用时显示提示
*/
fun showDisabledTip(activity: Activity, fm: FragmentManager, isHomePage: Boolean = false) {
if (isHomePage) {
toast("平台推送消息需要通知权限,检测到您已关闭相关权限,请前往设置手动打开")
} else {
val f = TipDialog.newInstance("请开启通知权限", "为方便查看下载进度,请在设置中打开【允许通知】")
f.setOnSelectListener {
if (it == DialogEnum.CLICK_OK) {
try {
//8.0及以上
val intent = Intent()
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.packageName)
activity.startActivity(intent)
} catch (e: Exception) {
val intent = Intent()
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.setData(Uri.fromParts("package", activity.packageName, null))
activity.startActivity(intent)
}
}
}
f.show(fm, TipDialog::class.java.simpleName)
}
}
}

View File

@ -0,0 +1,166 @@
package com.cheng.bole.manager
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.text.TextUtils
import androidx.core.content.FileProvider
import androidx.fragment.app.FragmentActivity
import com.cheng.bole.R
import com.example.base.extensions.toast
import com.umeng.socialize.ShareAction
import com.umeng.socialize.UMShareListener
import com.umeng.socialize.bean.SHARE_MEDIA
import com.umeng.socialize.media.UMImage
import com.umeng.socialize.media.UMVideo
import com.umeng.socialize.media.UMWeb
import java.io.File
object ShareManager {
/**
* 分享媒体文件
*/
fun shareFile(context: Context, file: File) {
val uri = FileProvider.getUriForFile(context,"${context.packageName}.fileprovider", file)
val intent = Intent(Intent.ACTION_SEND)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.setType(if (file.extension == "mp4") "video/mp4" else if (file.extension == "mp3") "audio/x-mpeg" else "image/jpeg") //分享文件类型
context.startActivity(Intent.createChooser(intent, "分享"))
}
/**
* 分享
*/
fun shareUrl(
activity: FragmentActivity,
shareMedia: SHARE_MEDIA,
shareBean: com.cheng.bole.bean.WxShareEntity,
clickFun: () -> Unit,
) {
if (!TextUtils.isEmpty(shareBean.link)) {
val web = UMWeb(shareBean.link)
web.title = shareBean.title
web.setThumb(UMImage(activity, R.mipmap.ic_launcher_icon))
web.description = shareBean.content
ShareAction(activity).withMedia(web).setPlatform(shareMedia)
.setCallback(object : UMShareListener {
/**
* 分享成功的回调
* @param platform 平台类型
*/
override fun onResult(platform: SHARE_MEDIA) {
clickFun.invoke()
}
/**
* 分享取消的回调
* @param platform 平台类型
*/
override fun onCancel(platform: SHARE_MEDIA) {
toast("取消分享")
}
/**
* 分享失败的回调
* @param platform 平台类型
* @param t 错误原因
*/
override fun onError(platform: SHARE_MEDIA, t: Throwable) {
toast("分享失败,请重试")
}
/**
* 分享开始的回调
* @param platform 平台类型
*/
override fun onStart(platform: SHARE_MEDIA) {}
}).share()
}
}
fun shareImageOnWeChat(activity: Activity, image: UMImage) {
image.title = ""
image.description = ""
image.setThumb(image)
ShareAction(activity).withMedia(image).withText("")
.setPlatform(SHARE_MEDIA.WEIXIN)
.setCallback(object : UMShareListener {
/**
* 分享成功的回调
* @param platform 平台类型
*/
override fun onResult(platform: SHARE_MEDIA) {
toast("分享成功")
}
/**
* 分享取消的回调
* @param platform 平台类型
*/
override fun onCancel(platform: SHARE_MEDIA) {
toast("取消分享")
}
/**
* 分享失败的回调
* @param platform 平台类型
* @param t 错误原因
*/
override fun onError(platform: SHARE_MEDIA, t: Throwable) {
toast("分享失败,请重试")
}
/**
* 分享开始的回调
* @param platform 平台类型
*/
override fun onStart(platform: SHARE_MEDIA) {}
}).share()
}
fun shareFileOnWeChat(activity: Activity, file: File) {
val video = UMVideo(file)
ShareAction(activity).withMedia(video)
.setPlatform(SHARE_MEDIA.WEIXIN)
.setCallback(object : UMShareListener {
/**
* 分享成功的回调
* @param platform 平台类型
*/
override fun onResult(platform: SHARE_MEDIA) {
toast("分享成功")
}
/**
* 分享取消的回调
* @param platform 平台类型
*/
override fun onCancel(platform: SHARE_MEDIA) {
toast("取消分享")
}
/**
* 分享失败的回调
* @param platform 平台类型
* @param t 错误原因
*/
override fun onError(platform: SHARE_MEDIA, t: Throwable) {
toast("分享失败,请重试")
}
/**
* 分享开始的回调
* @param platform 平台类型
*/
override fun onStart(platform: SHARE_MEDIA) {}
}).share()
}
}

View File

@ -0,0 +1,273 @@
package com.cheng.bole.manager
import android.os.Build
import android.text.TextUtils
import androidx.lifecycle.MutableLiveData
import com.example.base.extensions.toast
import com.example.base.utils.MMKVUtils
import com.example.base.utils.Utils
import com.github.gzuliyujiang.oaid.DeviceID
import com.github.gzuliyujiang.oaid.DeviceIdentifier
import com.github.gzuliyujiang.oaid.IGetter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.cheng.bole.net.ApiFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
object UserConfigManager {
val _userConfigLiveData = MutableLiveData<com.cheng.bole.bean.UserConfigEntity?>()
val userConfig: com.cheng.bole.bean.UserConfigEntity? get() = _userConfigLiveData.value
val userInfoLiveData = MutableLiveData<com.cheng.bole.bean.UserEntity?>()
val userInfo: com.cheng.bole.bean.UserEntity? get() = userInfoLiveData.value
fun getUserConfig(clickFun: () -> Unit?) {
if (!TextUtils.isEmpty(MMKVUtils.getString("userConfig"))) {
val data = Gson().fromJson(MMKVUtils.getString("userConfig"), com.cheng.bole.bean.UserConfigEntity::class.java)
_userConfigLiveData.postValue(data)
getOaId()
saveUserConfig(data)
clickFun.invoke()
return
}
getOaId {
userConfig { clickFun.invoke() }
}
}
fun userConfig(clickFun: () -> Unit?) {
GlobalScope.launch {
try {
val oaid = MMKVUtils.getString("oaid") ?: ""
val response = ApiFactory.apiService.getUserConfig(oaid, Build.VERSION.SDK_INT, "", DeviceIdentifier.getAndroidID(Utils.getApp()), getGTCid())
if (response.status) {
_userConfigLiveData.postValue(response.data)
MMKVUtils.put("userConfig", Gson().toJson(response.data))
saveUserConfig(response.data)
withContext(Dispatchers.Main) {
clickFun.invoke()
}
} else {
withContext(Dispatchers.Main) {
toast(response.message, true)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun saveUserConfig(data: com.cheng.bole.bean.UserConfigEntity) {
try {
LoginManager.saveToken(data.token)
saveIsTemp(data.temp)
if (data.config != null){
saveGuidePayEnable(data.config!!.guidePayEnable!!)
saveGuideEnable(data.config!!.guideEnable!!)
saveGuideHint(data.config!!.guideHint)
saveNoLoginPay(data.config!!.noLoginPayEnable!!)
savePayAgreementEnable(data.config!!.payAgreementEnable!!)
saveLoginType(data.config!!.loginType!!)
saveBanners(data.config!!.banners!!)
saveShareEntity(data.config!!.wxShareEntity)
saveAdSwitch(data.config!!.adSwitch)
saveServicePhoneList(data.config!!.servicePhoneList)
}
} catch (e : Exception) {
e.printStackTrace()
}
}
fun saveLastUserinfo(userinfo: com.cheng.bole.bean.UserEntity?) {
MMKVUtils.put("last_userinfo", Gson().toJson(userinfo))
}
fun getLastUserinfo(): com.cheng.bole.bean.UserEntity? {
val str = MMKVUtils.getString("last_userinfo")
if (!TextUtils.isEmpty(str)) {
return Gson().fromJson(str, com.cheng.bole.bean.UserEntity::class.java)
}
return null
}
private fun saveGuidePayEnable(temp: Boolean) {
MMKVUtils.put("guide_pay", temp)//引导页是否可以支付
}
fun getGuidePayEnable(): Boolean {
return MMKVUtils.getBoolean("guide_pay", true)
}
private fun saveGuideEnable(temp: Boolean) {
MMKVUtils.put("guide", temp)//是否开启引导页
}
fun getGuideEnable(): Boolean {
return MMKVUtils.getBoolean("guide", true)
}
private fun saveGuideHint(hint: String?) {
MMKVUtils.put("guide_hint", hint)
}
fun getGuideHint(): String {
return MMKVUtils.getString("guide_hint") ?: ""
}
fun saveIsTemp(temp: Boolean) {
MMKVUtils.put("x-role", temp)//true临时用户 ,false登录用户
}
fun getIsTemp(): Boolean {
return MMKVUtils.getBoolean("x-role", true)
}
fun isFirstUseApp(): Boolean {
return MMKVUtils.getBoolean("isFirstUse", true)
}
fun saveFirstUseApp(isFirst: Boolean) {
MMKVUtils.put("isFirstUse", isFirst)
}
private fun saveNoLoginPay(noLoginPay: Boolean) {
MMKVUtils.put("nologin_pay", noLoginPay)
}
fun getNoLoginPay(): Boolean {
return MMKVUtils.getBoolean("nologin_pay", true)
}
private fun savePayAgreementEnable(payAgreement: Boolean) {
MMKVUtils.put("pay_agreement", payAgreement)
}
fun isPayAgreementEnable(): Boolean {
return MMKVUtils.getBoolean("pay_agreement", true)
}
private fun saveLoginType(list: List<String>) {
MMKVUtils.put("login_type", Gson().toJson(list))
}
fun getLoginType(): List<String> {
val s = MMKVUtils.getString("login_type")
if (!TextUtils.isEmpty(s)) {
return Gson().fromJson(s, object : TypeToken<List<String>>() {}.type)
}
return emptyList()
}
private fun saveBanners(list: List<com.cheng.bole.bean.BannerEntity>) {
MMKVUtils.put("home_banner", Gson().toJson(list))
}
fun getBanners(): List<com.cheng.bole.bean.BannerEntity> {
val s = MMKVUtils.getString("home_banner")
if (!TextUtils.isEmpty(s)) {
return Gson().fromJson(s, object : TypeToken<List<com.cheng.bole.bean.BannerEntity>>() {}.type)
}
return emptyList()
}
private fun saveShareEntity(entity: com.cheng.bole.bean.WxShareEntity?) {
MMKVUtils.put("weixin_share", Gson().toJson(entity))
}
fun getShareEntity(): com.cheng.bole.bean.WxShareEntity? {
val s = MMKVUtils.getString("weixin_share")
if (!TextUtils.isEmpty(s)) {
return Gson().fromJson(s, com.cheng.bole.bean.WxShareEntity::class.java)
}
return null
}
private fun saveAdSwitch(switch: Boolean) {
MMKVUtils.put("ad_switch", switch)
}
fun isAdSwitch(): Boolean {
return MMKVUtils.getBoolean("ad_switch")
}
private fun saveServicePhoneList(list: List<String>) {
MMKVUtils.put("service_phone_list", Gson().toJson(list))
}
fun getServicePhoneList(): List<String> {
val str = MMKVUtils.getString("service_phone_list")
if (!TextUtils.isEmpty(str)) {
return Gson().fromJson(str, object : TypeToken<List<String>>() {}.type)
}
return emptyList()
}
/**
* 保存个推cid
*/
fun saveGTCid(cid: String) {
MMKVUtils.put("gt_cid", cid)
}
/**
* 获取个推cid
*/
fun getGTCid(): String {
return MMKVUtils.getString("gt_cid") ?: ""
}
private fun getOaId(callback: ((String) -> Unit)? = null) {
val oaid = DeviceIdentifier.getOAID(Utils.getApp())
if (TextUtils.isEmpty(oaid)) {
DeviceID.getOAID(Utils.getApp(), object : IGetter {
override fun onOAIDGetComplete(result: String) {
MMKVUtils.put("oaid", result)
callback?.invoke(result)
}
override fun onOAIDGetError(error: Exception) {
callback?.invoke("")
}
})
} else {
MMKVUtils.put("oaid", oaid)
callback?.invoke(oaid)
}
}
/**
* 保存百度归因bd_vid
*/
fun saveBDVID() {
try {
val str = com.cheng.bole.utils.appwalle.ChannelReader.get(Utils.getApp())
if (!TextUtils.isEmpty(str)) {
val jsonObj = JSONObject(str)
jsonObj.getString("bd_vid").let {
MMKVUtils.put("bd_vid", it)
}
} else {
MMKVUtils.put("bd_vid", "")
}
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 获取百度归因bd_vid
*/
fun getBDVID(): String {
return MMKVUtils.getString("bd_vid") ?: ""
}
}

View File

@ -0,0 +1,8 @@
package com.cheng.bole.net
object ApiFactory {
val apiService: ApiService by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
HttpRetrofit().apiService
}
}

View File

@ -0,0 +1,158 @@
package com.cheng.bole.net
import com.cheng.bole.net.model.HttpBaseResult
import com.cheng.bole.net.model.HttpListResult
import com.ylqh.cube.bean.CouponActivityEntity
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Part
import retrofit2.http.Query
import retrofit2.http.QueryMap
interface ApiService {
/**
* 获取客户端配置
*/
@GET("/api/user/config")
suspend fun getUserConfig(
@Query("oaid") oaid: String,
@Query("os_version") osVersion: Int,
@Query("ua") ua: String,
@Query("imei") imei: String,
@Query("cid") cid: String,
): HttpBaseResult<com.cheng.bole.bean.UserConfigEntity>
/**
* 发送验证码
*/
@POST("/api/user/code")
suspend fun sendCode(@Body params: Map<String, String>): HttpBaseResult<com.cheng.bole.bean.SendCodeEntity>
/**
* 登录
*/
@POST("/api/user/login")
suspend fun login(@Body requestBody: RequestBody): HttpBaseResult<com.cheng.bole.bean.LoginEntity>
/**
* 退出登录
*/
@POST("/api/user/logout")
suspend fun logout(): HttpBaseResult<Any>
/**
*更新用户信息
*/
@PUT("/api/user")
suspend fun changUser(@Body requestBody: RequestBody): HttpBaseResult<Any>
/**
* 注销
*/
@POST("/api/user/destroy")
suspend fun userDestroy(): HttpBaseResult<Any>
/**
* 获取用户信息
*/
@GET("/api/user")
suspend fun userInfo(): HttpBaseResult<com.cheng.bole.bean.UserEntity>
/**
* 获取账号列表
*/
@GET("/api/user/account")
suspend fun accountList(@Query("scene") scene: String): HttpBaseResult<List<com.cheng.bole.bean.AccountEntity>>
/**
* 上传图片
*/
@Multipart
@POST("/api/user/upload")
suspend fun upload(@Part part: MultipartBody.Part, @Query("scene") scene: String): HttpBaseResult<com.cheng.bole.bean.UploadImgEntity>
/**
*删除用户文件
*/
@DELETE("/api/user/upload")
suspend fun delUserFile(@Query("id") id: String): HttpBaseResult<Any>
/**
* 联系客服
*/
@GET("/api/weixin/service")
suspend fun wxService(): HttpBaseResult<com.cheng.bole.bean.WxServiceEntity>
/**
* 事件上报
*/
@POST("/api/user/event")
suspend fun eventReport(@Body requestBody: RequestBody): HttpBaseResult<Any>
/**
* 推送回执接口
*/
@PUT("/api/push/receipt")
suspend fun reportPushReceipt(@Body requestBody: RequestBody): HttpBaseResult<Any>
/**
* 意见反馈
*/
@POST("/api/user/feedback")
suspend fun feedback(@Body requestBody: RequestBody): HttpBaseResult<Any>
/**
* 用户公告
*/
@GET("/api/user/notice")
suspend fun notice(): HttpBaseResult<com.cheng.bole.bean.NoticeEntity>
/**
* 获取VIP套餐列表
*/
@GET("/api/order/goods")
suspend fun getGoodsList(@Query("type") type: String = "member"): HttpBaseResult<List<com.cheng.bole.bean.VipGoodsEntity>>
/**
* 优惠券列表
*/
@GET("/api/activity/coupon")
suspend fun couponList(@QueryMap params: Map<String, String>): HttpBaseResult<HttpListResult<com.cheng.bole.bean.CouponEntity>>
/**
* 获取优惠活动列表
*/
@GET("/api/activity")
suspend fun couponActivityList(@Query("scene") scene: String): HttpBaseResult<List<CouponActivityEntity>>
/**
* 领取活动优惠券
*/
@POST("/api/activity")
suspend fun getActivityCoupons(@Query("activity_id") ids: String): HttpBaseResult<Any>
/**
* 创建支付订单
*/
@POST("/api/order")
suspend fun payCreateOrder(@Body requestBody: RequestBody): HttpBaseResult<com.cheng.bole.bean.OrderPayEntity>
/**
* 权限验证
*/
@GET("/api/user/auth")
suspend fun checkPermission(@Query("scene") info: String?): HttpBaseResult<com.cheng.bole.bean.VipPermissionEntity>
/**
* 权限上报
*/
@POST("/api/user/auth")
suspend fun sendCheckPermission(@Body requestBody: RequestBody): HttpBaseResult<Any>
}

View File

@ -0,0 +1,24 @@
package com.cheng.bole.net
import okhttp3.Interceptor
import okhttp3.Response
import java.util.Locale
class ContentTypeInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val url = String.format("%s", originalRequest.url)
val method = originalRequest.method.lowercase(Locale.getDefault()).trim { it <= ' ' }
if (!url.contains("user/upload")) {
if(method == "post" || method == "put"){
val newRequest = originalRequest.newBuilder()
.header("Content-Type", "application/json; charset=utf-8")
.method(originalRequest.method, originalRequest.body)
.build()
return chain.proceed(newRequest)
}
}
return chain.proceed(originalRequest)
}
}

View File

@ -0,0 +1,48 @@
package com.cheng.bole.net
import com.cheng.bole.BuildConfig
import com.cheng.bole.common.Constants
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
/**
* 网络请求方法 结合了rxJava
*/
class HttpRetrofit internal constructor() {
companion object {
private const val DEFAULT_TIMEOUT = 20L
}
val apiService: ApiService
init {
//手动创建一个OkHttpClient并设置超时时间
val httpClient = OkHttpClient.Builder()
httpClient.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
//header拦截
httpClient.addInterceptor(RequestHeaderInterceptor())
httpClient.addInterceptor(ContentTypeInterceptor())
//请求拦截
httpClient.addInterceptor(RequestInterceptor())
//响应拦截
httpClient.addInterceptor(ResponseInterceptor())
val gson = GsonBuilder().setLenient().registerTypeAdapterFactory(MyTypeAdapterFactory()).create()
val retrofit = Retrofit.Builder()
.client(httpClient.build())
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(if (BuildConfig.DEBUG) Constants.TestUrl else Constants.BaseUrl)
.build()
apiService = retrofit.create(ApiService::class.java)
}
}

View File

@ -0,0 +1,128 @@
package com.cheng.bole.net
import com.google.gson.Gson
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException
/**
* @date 2020-06-05 13:53
* @desc gson数据类型转换处理
*/
class MyTypeAdapterFactory : TypeAdapterFactory {
@Suppress("UNCHECKED_CAST")
override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
//type.rawType 这个类型是实体的类型 不是服务器返回的数据类型
return when (type.rawType) {
String::class.java -> StringNullAdapter() as TypeAdapter<T>
Int::class.java -> IntNullAdapter() as TypeAdapter<T>
Long::class.java -> LongNullAdapter() as TypeAdapter<T>
Double::class.java -> DoubleNullAdapter() as TypeAdapter<T>
else -> null
}
}
//字符串处理
class StringNullAdapter : TypeAdapter<String>() {
@Throws(IOException::class)
override fun read(reader: JsonReader): String {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull()
return ""
}
return reader.nextString()
}
@Throws(IOException::class)
override fun write(writer: JsonWriter, value: String?) {
if (value == null) {
writer.nullValue()
return
}
writer.value(value)
}
}
//Int处理
inner class IntNullAdapter : TypeAdapter<Int>() {
@Throws(IOException::class)
override fun read(reader: JsonReader): Int {
val jt = reader.peek()
if (jt == JsonToken.NULL) {
reader.nextNull()
return 0
}
if (jt == JsonToken.STRING) {
return reader.nextString().toIntOrNull() ?: 0
}
return reader.nextInt()
}
@Throws(IOException::class)
override fun write(writer: JsonWriter, value: Int?) {
if (value == null) {
writer.nullValue()
return
}
writer.value(value)
}
}
//Long处理
inner class LongNullAdapter : TypeAdapter<Long>() {
@Throws(IOException::class)
override fun read(reader: JsonReader): Long {
val jt = reader.peek()
if (jt == JsonToken.NULL) {
reader.nextNull()
return 0
}
if (jt == JsonToken.STRING) {
return reader.nextString().toLongOrNull() ?: 0L
}
return reader.nextLong()
}
@Throws(IOException::class)
override fun write(writer: JsonWriter, value: Long?) {
if (value == null) {
writer.nullValue()
return
}
writer.value(value)
}
}
//Double处理
inner class DoubleNullAdapter : TypeAdapter<Double>() {
@Throws(IOException::class)
override fun read(reader: JsonReader): Double {
val jt = reader.peek()
if (jt == JsonToken.NULL) {
reader.nextNull()
return 0.0
}
if (jt == JsonToken.STRING) {
return reader.nextString().toDoubleOrNull() ?: 0.0
}
return reader.nextDouble()
}
@Throws(IOException::class)
override fun write(writer: JsonWriter, value: Double?) {
if (value == null) {
writer.nullValue()
return
}
writer.value(value)
}
}
}

View File

@ -0,0 +1,53 @@
package com.cheng.bole.net
import com.cheng.bole.BuildConfig
import com.cheng.bole.manager.LoginManager
import com.cheng.bole.utils.ChannelUtils
import com.example.base.utils.AppUtils
import com.example.base.utils.L
import com.example.base.utils.Utils
import com.github.gzuliyujiang.oaid.DeviceIdentifier
import com.cheng.bole.common.Constants
import com.cheng.bole.manager.UserConfigManager
import okhttp3.Interceptor
import okhttp3.Response
class RequestHeaderInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val requestBuilder = request.newBuilder()
//添加header
request = requestBuilder
.addHeader("x-token", LoginManager.getToken())
.addHeader("x-version", AppUtils.getAppVersionName())
.addHeader("x-platform", "android")
.addHeader("x-device-id", DeviceIdentifier.getAndroidID(Utils.getApp()))
.addHeader("x-mobile-brand", android.os.Build.BRAND)
.addHeader("x-mobile-model", android.os.Build.MODEL)
.addHeader("x-base-version", AppUtils.getAppVersionName())
.addHeader("x-channel", "jk_${ChannelUtils.getChannel()}")
.addHeader("x-click-id", UserConfigManager.getBDVID())
.addHeader("x-app-id", Constants.APP_ID)
.addHeader("x-package", BuildConfig.APPLICATION_ID)
.build()
val stringBuilder = StringBuilder()
stringBuilder.append("-------------header start-------------\n")
stringBuilder.append("x-token = ${LoginManager.getToken()}\n")
stringBuilder.append("x-version = ${AppUtils.getAppVersionName()}\n")
stringBuilder.append("x-device-id = ${DeviceIdentifier.getAndroidID(Utils.getApp())}\n")
stringBuilder.append("x-mobile-brand = ${android.os.Build.BRAND}\n")
stringBuilder.append("x-mobile-model = ${android.os.Build.MODEL}\n")
stringBuilder.append("x-base-version = ${AppUtils.getAppVersionName()}\n")
stringBuilder.append("x-channel = jk_${ChannelUtils.getChannel()}\n")
stringBuilder.append("x-click-id = ${UserConfigManager.getBDVID()}\n")
stringBuilder.append("x-package = ${BuildConfig.APPLICATION_ID}\n")
stringBuilder.append("-------------header end-------------")
L.d(stringBuilder)
return chain.proceed(request)
}
}

View File

@ -0,0 +1,77 @@
package com.cheng.bole.net
import android.text.TextUtils
import com.cheng.bole.common.Constants
import com.cheng.bole.utils.StringUtils
import com.example.base.utils.L
import okhttp3.Interceptor
import okhttp3.Response
import okio.Buffer
import java.nio.charset.StandardCharsets
import java.util.Arrays
import java.util.Locale
/**
* @date 2020-06-05 13:53
* @desc 网络请求可以在此处添加n多的请求拦截-加密数据
*/
class RequestInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val method = request.method.lowercase(Locale.getDefault()).trim { it <= ' ' }
val url = request.url
val apiPath = String.format("%s", url)
L.d("TAG-->>url=$apiPath")
//如果请求的不是服务端的接口则不用加密
if (!apiPath.startsWith(Constants.BaseUrl)) {
L.d("TAG-->>content-type=${request.headers["Content-Type"]}")
val requestBody = request.body
L.d("TAG-->>${requestBody.toString()}")
return chain.proceed(request)
}
var queryString = url.encodedQuery
queryString = if (!TextUtils.isEmpty(queryString)) {
(queryString + "&nonce=" + StringUtils.createUUID()) + "&timestamp=" + System.currentTimeMillis() / 1000
} else {
("nonce=" + StringUtils.createUUID()) + "&timestamp=" + System.currentTimeMillis() / 1000
}
val sortQueryString = Arrays.stream(queryString.split("&".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray())
.sorted { obj: String, anotherString: String? -> obj.compareTo(anotherString!!) }
.reduce { x: String, y: String -> "$x&$y" }
.get()
//如果请求方式是get或者delete 则没有body
var paramsStr = ""
var bytes = ByteArray(0)
var signature: String? = ""
if (method == "put" || method == "post") {
val requestBody = request.body
L.d("TAG-->>${requestBody.toString()}")
val buffer = Buffer()
requestBody!!.writeTo(buffer)
bytes = StringUtils.addByte(bytes, buffer.readByteArray())
L.e("签名后bodyByte的长度为" + bytes.size)
paramsStr = String(bytes, StandardCharsets.UTF_8)
// paramsStr = buffer.readUtf8();
L.e("签名后body的长度为" + paramsStr.length)
}
signature = if (bytes.isNotEmpty()) {
L.e("当前的数组长度为----" + bytes.size)
StringUtils.getMD5Byte(
StringUtils.addByte(
StringUtils.addByte("$sortQueryString&".toByteArray(), bytes),
("&" + StringUtils.getMD5String(Constants.Signature)).toByteArray()
)
)
} else {
StringUtils.getMD5String(sortQueryString + "&" + StringUtils.getMD5String(Constants.Signature))
}
val newUrl = apiPath.split("\\?".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0] + "?" + queryString + "&signature=" + signature
L.e("签名后的路径---", newUrl)
request = request.newBuilder().url(newUrl).build()
return chain.proceed(request)
}
}

View File

@ -0,0 +1,109 @@
package com.cheng.bole.net
import android.content.Intent
import android.text.TextUtils
import android.util.Log
import com.alibaba.fastjson.JSON
import com.example.base.common.RxBus
import com.example.base.utils.L
import com.example.base.utils.Utils
import com.cheng.bole.BuildConfig
import com.cheng.bole.common.Constants
import com.cheng.bole.manager.LoginManager
import com.cheng.bole.ui.activity.LoginActivity
import com.cheng.bole.ui.activity.PublicActivity
import com.cheng.bole.ui.fragment.mine.vip.VipFragment
import com.cheng.bole.utils.AESpkcs7paddingUtil
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Response
import okhttp3.ResponseBody
import java.nio.charset.Charset
import java.nio.charset.UnsupportedCharsetException
/**
* @date 2020-06-05 13:55
* @desc 可以在此处添加n多的响应拦截- 比如解密数据
*/
class ResponseInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val url = request.url
val apiPath = String.format("%s", url)
//如果请求的不是服务端的接口则不用加密
if (!apiPath.startsWith(if (BuildConfig.DEBUG) Constants.TestUrl else Constants.BaseUrl)) {
return chain.proceed(request)
}
val response = chain.proceed(request)
var charset = Charset.forName("UTF-8")
val contentType = response.header("Content-Type")
if (contentType != null && contentType.contains("application/json")) {
val responseBody = response.body
if (responseBody != null) {
val source = responseBody.source()
source.request(Long.MAX_VALUE)
val buffer = source.buffer
val mediaType = responseBody.contentType()
if (mediaType != null) {
try {
charset = mediaType.charset(Charset.forName("UTF-8"))
} catch (e: UnsupportedCharsetException) {
e.printStackTrace()
}
}
val respBody = buffer.clone().readString(charset!!)
L.d("response=${respBody}")
if (TextUtils.isEmpty(respBody)) {
return response
}
val code = JSON.parseObject(respBody).getInteger("code")
if (code == 1001003 || code == 1001004 || code == 1001005) {
LoginManager.logout()
val intent = Intent(Utils.getApp(), LoginActivity::class.java)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Utils.getApp().startActivity(intent)
}
val isEncrypt = JSON.parseObject(respBody).getBoolean("encrypt")
L.e("是否需要解密$isEncrypt")
if (isEncrypt == null || !isEncrypt) { //如果不需要加密 直接返回
L.d("response=${response.body}")
return response
}
val decrybody = JSON.parseObject(respBody).getString("data")
L.e("Json解析后的字符串为$decrybody")
var decryString: String?
try {
decryString = AESpkcs7paddingUtil.decryptNormal(decrybody, Constants.Encrypt)
Log.e("ResponseInterceptor", "解密后返回的字符串为$decryString")
val decCode = JSON.parseObject(decryString).getInteger("code")
when (decCode) {
11018 -> {
RxBus.defaultInstance.post(com.cheng.bole.event.HomeRefreshEvent())
}
19000 -> {
PublicActivity.newStart(Utils.getApp(), VipFragment::class.java, Pair("origin", "interceptor"))
}
1001003, 1001004, 1001005 -> {
LoginManager.logout()
val intent = Intent(Utils.getApp(), LoginActivity::class.java)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Utils.getApp().startActivity(intent)
}
}
//返回新创建的response
return response.newBuilder().body(ResponseBody.create("text/plain".toMediaType(), decryString)).build()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
return response
}
}

View File

@ -0,0 +1,38 @@
package com.cheng.bole.net.model
/**
* @date 2021-08-05 09:45
* @desc 数据基本结构
*/
data class HttpBaseResult<T>(val code: Int, val data: T) {
val status: Boolean
get() {
return code == 0
}
val message: String = ""
}
/**
* @param
* 获取数据转成 Result<T>
*/
fun <T> HttpBaseResult<T>.toResult(): Result<T> {
return if (this.status) {
Result.success(this.data)
} else {
Result.failure(RuntimeException(this.message))
}
}
/**
* @param
* 获取数据转成 Result<List<T>>
*/
fun <T> HttpBaseResult<HttpListResult<T>>.toListResult(): Result<List<T>> {
return if (this.status) {
Result.success(this.data.items)
} else {
Result.failure(RuntimeException(this.message))
}
}

View File

@ -0,0 +1,39 @@
package com.cheng.bole.net.model
/**
* 列表基本结构(服务返回)
*/
open class HttpListResult<T> {
var total: String = "0" //总条数
var total_amount:String = "0.00" //总金额
private var content = listOf<T>() //列表数据
private var records = listOf<T>() //列表数据
private var list = listOf<T>() //列表数据
val items = listOf<T>() //列表数据
get() {
if (content.isNotEmpty()) {
return content
}
if (records.isNotEmpty()) {
return records
}
if (list.isNotEmpty()) {
return list
}
return field // 防止服务器数据为null 蛋疼
}
override fun toString(): String {
return "HttpListResult{" +
"total=" + total +
"total_amount="+total_amount+
", rows=" + items +
'}'
}
}

View File

@ -0,0 +1,78 @@
package com.cheng.bole.ui.activity
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentContainerView
import com.example.base.extensions.onClick
import com.example.base.ui.BaseActivity
import com.example.base.utils.ScreenUtils
import org.jetbrains.anko.find
/**
* 仿抽屉activity
*/
class DrawerActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val containerView = find<FragmentContainerView>(com.example.base.R.id.fcvContainer)
val lp = containerView.layoutParams as FrameLayout.LayoutParams
lp.width = (ScreenUtils.getWindowSize().x * 0.75).toInt()
lp.height = ViewGroup.LayoutParams.MATCH_PARENT
lp.gravity = Gravity.END
containerView.layoutParams = lp
window.decorView.find<View>(android.R.id.content).onClick { finish() }
}
override fun onResume() {
window.setBackgroundDrawable(ColorDrawable(Color.parseColor("#80000000")))
super.onResume()
}
override fun onPause() {
window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
super.onPause()
}
override fun getFragment(): Fragment {
val className = intent.getStringExtra(FRAGMENT_CLASS_NAME)!!
val clazz = Class.forName(className)
val fragment = clazz.getDeclaredConstructor().newInstance() as Fragment
fragment.arguments = intent.extras
return fragment
}
companion object {
const val FRAGMENT_CLASS_NAME = "fragment_class_name"
fun start(context: Context?, clazz: Class<out Fragment>, vararg args: Pair<String, *>) {
val intent = Intent(context, DrawerActivity::class.java)
intent.putExtra(FRAGMENT_CLASS_NAME, clazz.name)
intent.putExtras(bundleOf(*args))
context?.startActivity(intent)
}
fun newStart(context: Context?, clazz: Class<out Fragment>, vararg args: Pair<String, *>) {
val intent = Intent(context, DrawerActivity::class.java)
intent.putExtra(FRAGMENT_CLASS_NAME, clazz.name)
intent.putExtras(bundleOf(*args))
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context?.startActivity(intent)
}
}
}

View File

@ -0,0 +1,45 @@
package com.cheng.bole.ui.activity
import android.annotation.SuppressLint
import android.os.Bundle
import android.window.OnBackInvokedDispatcher
import androidx.activity.addCallback
import androidx.core.os.BuildCompat
import com.cheng.bole.R
import com.cheng.bole.ui.fragment.guide.GuideFragment
import com.example.base.common.ActivityManager
import com.example.base.extensions.toast
import com.example.base.ui.BaseActivity
class GuideActivity :BaseActivity(){
private var lastBackClickTime = 0L
override fun getFragment() = GuideFragment()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
backApp()
}
@SuppressLint("UnsafeOptInUsageError")
private fun backApp() {
if (BuildCompat.isAtLeastT()) {
onBackInvokedDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT) {
exitApp()
}
} else {
onBackPressedDispatcher.addCallback(this) {
exitApp()
}
}
}
private fun exitApp() {
if (System.currentTimeMillis() - lastBackClickTime > 1500) {
toast(getString(R.string.exit_app))
lastBackClickTime = System.currentTimeMillis()
} else {
ActivityManager.exitApp()
}
}
}

View File

@ -0,0 +1,184 @@
package com.cheng.bole.ui.activity
import android.annotation.SuppressLint
import android.os.Bundle
import android.text.TextUtils
import android.window.OnBackInvokedDispatcher
import androidx.activity.addCallback
import androidx.core.os.BuildCompat
import androidx.fragment.app.Fragment
import com.bytedance.ads.convert.BDConvert
import com.cheng.bole.BuildConfig
import com.cheng.bole.R
import com.cheng.bole.common.Constants
import com.cheng.bole.common.EventConstants
import com.cheng.bole.manager.DialogEnum
import com.cheng.bole.manager.EventReportManager
import com.cheng.bole.manager.LoginManager
import com.cheng.bole.manager.UserConfigManager
import com.cheng.bole.ui.dialog.PrivacyPolicyDialog
import com.cheng.bole.utils.ChannelUtils
import com.example.base.dialog.LoadingDialog
import com.example.base.ui.BaseActivity
import com.example.base.utils.L
import com.example.base.utils.MMKVUtils
import com.example.base.utils.Utils
import com.g.gysdk.GYManager
import com.g.gysdk.GYResponse
import com.g.gysdk.GyCallBack
import com.g.gysdk.GyConfig
import com.gyf.immersionbar.BarHide
import com.gyf.immersionbar.ImmersionBar
import com.umeng.analytics.MobclickAgent
import com.umeng.commonsdk.UMConfigure
import org.jetbrains.anko.startActivity
/**
* 闪屏页
*/
class LauncherActivity : BaseActivity() {
private val privacyPolicyDialog by lazy {
PrivacyPolicyDialog()
}
private val loadingDialog by lazy {
LoadingDialog(this)
}
override fun getFragment() = Fragment(R.layout.activity_launcher)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ImmersionBar.with(this).hideBar(BarHide.FLAG_HIDE_NAVIGATION_BAR).init()
backApp()
if (MMKVUtils.getBoolean("isAgree")) {
loadingDialog.show()
UserConfigManager.saveBDVID()
UserConfigManager.getUserConfig {
EventReportManager.eventReport(EventConstants.APP_LAUNCH, "", "")
loadingDialog.dismiss()
initUM()
initBD()
initGT()
intentMain()
}
} else {
privacyDialog()
}
}
private fun privacyDialog() {
privacyPolicyDialog.setOnSelectListener {
if (it == DialogEnum.CLICK_OK) {
loadingDialog.show()
MMKVUtils.put("isAgree", true)
UserConfigManager.saveBDVID()
UserConfigManager.getUserConfig {
EventReportManager.eventReport(EventConstants.APP_LAUNCH, "", "")
loadingDialog.dismiss()
initUM()
initBD()
initGT()
intentMain()
}
} else {
finish()
}
}
privacyPolicyDialog.show(supportFragmentManager, null)
}
private fun intentMain() {
if (UserConfigManager.isFirstUseApp()) {
UserConfigManager.saveFirstUseApp(false)
if (UserConfigManager.getGuideEnable()) {
startActivity<GuideActivity>()
} else {
if (!LoginManager.isLogin()) {
if (TextUtils.isEmpty(LoginManager.getLastLoginType())) {
startActivity<MainActivity>()
} else {
LoginActivity.start(this@LauncherActivity)
}
} else {
startActivity<MainActivity>()
}
}
finish()
} else {
if (!LoginManager.isLogin()) {
if (TextUtils.isEmpty(LoginManager.getLastLoginType())) {
startActivity<MainActivity>()
} else {
LoginActivity.start(this@LauncherActivity)
}
} else {
startActivity<MainActivity>()
}
finish()
}
}
/**
* 初始化友盟
*/
private fun initUM() {
UMConfigure.preInit(Utils.getApp(), Constants.UmengAppkey, ChannelUtils.getChannel())
UMConfigure.init(this, Constants.UmengAppkey, ChannelUtils.getChannel(), UMConfigure.DEVICE_TYPE_PHONE, "")
MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.AUTO)
}
/**
* 巨量融合初始化
*/
private fun initBD() {
BDConvert.init(Utils.getApp(), this)
}
/**
* 个推初始化
*/
private fun initGT() {
GYManager.getInstance().preInit(this) //个验SDK初始化
GYManager.getInstance().init(
GyConfig.with(this)
.preLoginUseCache(true)//预取号使用缓存可以提高预取号的成功率建议设置为true
.channel(ChannelUtils.getChannel())//应用渠道
.eLoginDebug(BuildConfig.DEBUG)//运营商debug调试模式
.debug(BuildConfig.DEBUG)//个验debug调试模式
.callBack(object : GyCallBack {
override fun onSuccess(gyResponse: GYResponse) {
L.d("TAG-->>GYManager init onSuccess =${gyResponse.code}")
}
override fun onFailed(gyResponse: GYResponse) {
L.d("TAG-->>GYManager init onFailed =${gyResponse.code}")
}
}).build()
)
//预登录
GYManager.getInstance().ePreLogin(8000, object : GyCallBack {
override fun onSuccess(gyResponse: GYResponse) {
L.d("TAG-->>GYManager ePreLogin onSuccess =${gyResponse.code}")
}
override fun onFailed(gyResponse: GYResponse) {
L.d("TAG-->>GYManager ePreLogin onFailed =${gyResponse.code}")
}
})
}
@SuppressLint("UnsafeOptInUsageError")
private fun backApp() {
if (BuildCompat.isAtLeastT()) {
onBackInvokedDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT) {
}
} else {
onBackPressedDispatcher.addCallback(this) {
}
}
}
}

View File

@ -0,0 +1,72 @@
package com.cheng.bole.ui.activity
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.window.OnBackInvokedDispatcher
import androidx.activity.addCallback
import androidx.core.os.BuildCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import com.cheng.bole.R
import com.cheng.bole.common.EventConstants
import com.cheng.bole.manager.EventReportManager
import com.cheng.bole.ui.fragment.login.LoginFragment
import com.cheng.bole.ui.fragment.login.onekey.OneKeyLoginFragment
import com.example.base.common.ActivityManager
import com.example.base.extensions.toast
import com.example.base.ui.BaseActivity
import com.g.gysdk.GYManager
class LoginActivity : BaseActivity() {
private var lastBackClickTime = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val from = intent.getIntExtra("from", 0)
if (from == 0) backApp()
}
override fun getFragment(): Fragment {
val fragment = if (GYManager.getInstance().isPreLoginResultValid) {
OneKeyLoginFragment()
} else {
LoginFragment()
}
fragment.arguments = intent.extras
return fragment
}
companion object {
fun start(activity: Activity?, vararg args: Pair<String, *>) {
val intent = Intent(activity, LoginActivity::class.java)
intent.putExtras(bundleOf(*args))
activity?.startActivity(intent)
}
}
@SuppressLint("UnsafeOptInUsageError")
private fun backApp() {
if (BuildCompat.isAtLeastT()) {
onBackInvokedDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT) {
exitApp()
}
} else {
onBackPressedDispatcher.addCallback(this) {
exitApp()
}
}
}
private fun exitApp() {
if (System.currentTimeMillis() - lastBackClickTime > 1500) {
toast(getString(R.string.exit_app))
lastBackClickTime = System.currentTimeMillis()
} else {
EventReportManager.eventReport(EventConstants.EXIT_APP, "login", "")
ActivityManager.exitApp()
}
}
}

View File

@ -0,0 +1,78 @@
package com.cheng.bole.ui.activity
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.window.OnBackInvokedDispatcher
import androidx.activity.addCallback
import androidx.core.os.BuildCompat
import com.cheng.bole.R
import com.cheng.bole.common.EventConstants
import com.cheng.bole.event.LogoutSuccessEvent
import com.cheng.bole.event.PushMessageEvent
import com.cheng.bole.manager.EventReportManager
import com.cheng.bole.ui.fragment.main.MainFragment
import com.example.base.common.ActivityManager
import com.example.base.common.RxBus
import com.example.base.extensions.toast
import com.example.base.ui.BaseActivity
import com.example.base.utils.ClipboardUtils
class MainActivity : BaseActivity() {
private var lastBackClickTime = 0L
override fun getFragment() = MainFragment()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
backApp()
RxBus.defaultInstance.toObservable(LogoutSuccessEvent::class.java).subscribe { finish() }
handleIntent(intent)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
val payload = intent?.getStringExtra("payload")
if (!TextUtils.isEmpty(payload)) {
RxBus.defaultInstance.post(PushMessageEvent(payload!!, 3))
} else {
if (intent?.action == Intent.ACTION_SEND && intent.type == "text/plain") {
val text = intent.getStringExtra(Intent.EXTRA_TEXT)
ClipboardUtils.copyText(text)
toast("复制成功")
return
}
}
}
@SuppressLint("UnsafeOptInUsageError")
private fun backApp() {
if (BuildCompat.isAtLeastT()) {
onBackInvokedDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT) {
exitApp()
}
} else {
onBackPressedDispatcher.addCallback(this) {
exitApp()
}
}
}
private fun exitApp() {
if (System.currentTimeMillis() - lastBackClickTime > 1500) {
toast(getString(R.string.exit_app))
lastBackClickTime = System.currentTimeMillis()
} else {
EventReportManager.eventReport(EventConstants.EXIT_APP, "main", "")
ActivityManager.exitApp()
}
}
}

View File

@ -0,0 +1,47 @@
package com.cheng.bole.ui.activity
import android.content.Context
import android.content.Intent
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import com.example.base.ui.BaseActivity
/**
* 所有的普通的fragment页面启动都用此activity装载
*/
class PublicActivity : BaseActivity() {
private var mFragment: Fragment? = null
val attachedFragment: Fragment?
get() = mFragment
override fun getFragment(): Fragment {
val className = intent.getStringExtra(FRAGMENT_CLASS_NAME)!!
val clazz = Class.forName(className)
mFragment = clazz.getDeclaredConstructor().newInstance() as Fragment
mFragment!!.arguments = intent.extras
return mFragment!!
}
companion object {
const val FRAGMENT_CLASS_NAME = "fragment_class_name"
fun start(context: Context?, clazz: Class<out Fragment>, vararg args: Pair<String, *>) {
val intent = Intent(context, PublicActivity::class.java)
intent.putExtra(FRAGMENT_CLASS_NAME, clazz.name)
intent.putExtras(bundleOf(*args))
context?.startActivity(intent)
}
fun newStart(context: Context?, clazz: Class<out Fragment>, vararg args: Pair<String, *>) {
val intent = Intent(context, PublicActivity::class.java)
intent.putExtra(FRAGMENT_CLASS_NAME, clazz.name)
intent.putExtras(bundleOf(*args))
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context?.startActivity(intent)
}
}
}

View File

@ -0,0 +1,23 @@
package com.cheng.bole.ui.activity
import android.annotation.SuppressLint
import android.os.Bundle
import com.cheng.bole.ui.fragment.video.VideoPlayerFragment
import com.example.base.ui.BaseActivity
class VideoPlayerActivity : BaseActivity() {
private var fragment: VideoPlayerFragment? = null
override fun getFragment() = fragment!!
@SuppressLint("SourceLockedOrientationActivity")
override fun onCreate(savedInstanceState: Bundle?) {
val title = intent.getStringExtra("title") ?: ""
val url = intent.getStringExtra("url") ?: ""
fragment = VideoPlayerFragment.newInstance(url, title)
fragment!!.setFullScreenChangedListener {
// requestedOrientation = it
}
super.onCreate(savedInstanceState)
}
}

View File

@ -0,0 +1,31 @@
package com.cheng.bole.ui.base
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.KeyEvent
import com.cheng.bole.R
open class BaseDialog @JvmOverloads constructor(
context: Context,
styleRes: Int = R.style.BaseStyleDialog,
private val isNoReturn: Boolean = false
) : Dialog(context, styleRes) {
@SuppressLint("GestureBackNavigation")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (isNoReturn) {
setOnKeyListener { _, keyCode, _ ->
var isShield = false
if (keyCode == KeyEvent.KEYCODE_BACK) {
isShield = true
}
isShield
}
}
}
}

View File

@ -0,0 +1,42 @@
package com.cheng.bole.ui.base
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
class BasePageAdapter(
private val fm: FragmentManager,
private val titles: List<String>,
private val mList: MutableList<Fragment>,
behavior: Int = BEHAVIOR_SET_USER_VISIBLE_HINT
) : FragmentStatePagerAdapter(fm, behavior) {
override fun getItem(position: Int): Fragment {
return mList[position]
}
override fun getCount(): Int {
return mList.size
}
override fun getPageTitle(position: Int): CharSequence? {
if (titles.isEmpty()) return null
return titles[position]
}
override fun instantiateItem(container: View, position: Int): Any {
val fragment = super.instantiateItem(container, position) as Fragment
this.fm.beginTransaction().show(fragment).commit()
return fragment
}
override fun destroyItem(container: View, position: Int, `object`: Any) {
val fragment = mList[position]
fm.beginTransaction().hide(fragment).commitAllowingStateLoss()
}
override fun getItemPosition(`object`: Any): Int {
return POSITION_NONE
}
}

View File

@ -0,0 +1,112 @@
package com.cheng.bole.ui.dialog
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.base.decoration.SpacesItemDecoration
import com.example.base.extensions.onClick
import com.example.base.utils.DensityUtils
import com.example.base.utils.ScreenUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.cheng.bole.R
import com.cheng.bole.common.Constants
import com.cheng.bole.databinding.DialogAccountListBinding
import com.cheng.bole.manager.DialogEnum
class AccountListDialog : DialogFragment() {
private val btnText by lazy { arguments?.getString("btnText") ?: "我知道了" }
private val mAdapter by lazy { AccountAdapter() }
private var mOnBackListener: ((DialogEnum) -> Unit)? = null //回调事件
lateinit var binding: DialogAccountListBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.8).toInt()
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog?.setCancelable(false)
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_account_list, null)
binding = DialogAccountListBinding.bind(view)
binding.tvTitle.typeface = Constants.youSheBiaoTiHei
binding.mRecyclerView.adapter = mAdapter
binding.mRecyclerView.addItemDecoration(SpacesItemDecoration(DensityUtils.dp2px(10f)))
val listStr = arguments?.getString("list")
if (!TextUtils.isEmpty(listStr)) {
val list = Gson().fromJson<List<com.cheng.bole.bean.AccountEntity>>(listStr, object : TypeToken<List<com.cheng.bole.bean.AccountEntity>>(){}.type)
mAdapter.setList(list)
}
binding.tvOk.text = btnText
binding.tvOk.onClick {
mOnBackListener?.invoke(DialogEnum.CLICK_OK)
dismiss()
}
binding.ivClose.onClick { dismiss() }
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
fun setOnSelectListener(listener: ((DialogEnum) -> Unit)) {
mOnBackListener = listener
}
companion object {
fun newInstance(list: List<com.cheng.bole.bean.AccountEntity>, btnText: String? = null): AccountListDialog {
val arg = Bundle()
arg.putString("list", Gson().toJson(list))
arg.putString("btnText", btnText)
val fragment = AccountListDialog()
fragment.arguments = arg
return fragment
}
}
class AccountAdapter: BaseQuickAdapter<com.cheng.bole.bean.AccountEntity, BaseViewHolder>(R.layout.listitem_account_login_tip) {
override fun convert(holder: BaseViewHolder, item: com.cheng.bole.bean.AccountEntity) {
if (item.vip_type == "1") {
holder.setGone(R.id.tv_vip_tag, true)
} else if (item.vip_type == "2" || item.vip_type == "3") {
holder.setText(R.id.tv_vip_tag, if (item.vip_type == "2") "会员" else "终生会员")
holder.setGone(R.id.tv_vip_tag, false)
}
holder.setText(R.id.tv_username, item.name)
holder.setText(R.id.tv_create_time, "${item.create_time} 注册")
holder.setGone(R.id.iv_bind_wx, !item.bind.contains("weixin"))
holder.setGone(R.id.iv_bind_phone, !item.bind.contains("phone"))
if (!TextUtils.isEmpty(item.phone)) {
holder.setText(R.id.tv_phone, item.phone.replaceRange(3, 7, "****"))
} else {
holder.setText(R.id.tv_phone, "")
}
}
}
}

View File

@ -0,0 +1,158 @@
package com.cheng.bole.ui.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.TextUtils
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.DialogFragment
import com.example.base.common.RxCountDown
import com.example.base.extensions.onClick
import com.example.base.extensions.toast
import com.example.base.utils.RegexUtils
import com.example.base.utils.ScreenUtils
import com.cheng.bole.R
import com.cheng.bole.databinding.DialogBindPhoneBinding
import com.cheng.bole.impl.TextWatcherImpl
import com.cheng.bole.utils.KeyboardUtils
import io.reactivex.rxjava3.disposables.Disposable
class BindPhoneDialog : DialogFragment(), KeyboardUtils.OnSoftInputChangedListener {
private var mOnBackListener: ((String, String, String) -> Unit)? = null //回调事件
private var mOnSendCodeClickListener:((String) -> Unit)? = null
private var disposable: Disposable? = null
private var timestamp = ""
lateinit var binding: DialogBindPhoneBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = ScreenUtils.getWindowSize().x
windowParams?.gravity = Gravity.BOTTOM
windowParams?.windowAnimations = R.style.dialog_bottom
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
setCancelable(false)
KeyboardUtils.registerSoftInputChangedListener(requireActivity(), this)
return super.onCreateView(inflater, container, savedInstanceState)
}
private val textWatcher = object : TextWatcherImpl() {
@SuppressLint("SetTextI18n")
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
binding.ivClearText.visibility = if (TextUtils.isEmpty(s)) View.GONE else View.VISIBLE
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_bind_phone, null)
binding = DialogBindPhoneBinding.bind(view)
binding.etPhone.addTextChangedListener(textWatcher)
binding.ivClose.onClick {
dismiss()
}
binding.ivClearText.onClick {
binding.etPhone.setText("")
}
binding.tvSendCode.onClick {
val phone = binding.etPhone.text?.trim().toString()
if (TextUtils.isEmpty(phone)) {
toast("请输入手机号")
return@onClick
}
if (!RegexUtils.isMobileSimple(phone)) {
toast("请输入正确的手机号")
return@onClick
}
mOnSendCodeClickListener?.invoke(phone)
}
binding.btnNext.onClick {
val phone = binding.etPhone.text?.trim().toString()
val code = binding.etCode.text?.trim().toString()
if (TextUtils.isEmpty(phone)) {
toast("请输入手机号")
return@onClick
}
if (!RegexUtils.isMobileSimple(phone)) {
toast("请输入正确的手机号")
return@onClick
}
if (TextUtils.isEmpty(code)) {
toast("请输入验证码")
return@onClick
}
mOnBackListener?.invoke(phone, code, timestamp)
dismiss()
}
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
@SuppressLint("SetTextI18n")
private fun startTimer() {
disposable?.dispose()
disposable = RxCountDown.countdown(60).subscribe {
if (it > 0) {
binding.tvSendCode.text = "${it}s"
binding.tvSendCode.isEnabled = false
binding.tvSendCode.alpha = 0.5f
} else {
binding.tvSendCode.text = "重新发送"
binding.tvSendCode.isEnabled = true
binding.tvSendCode.alpha = 1f
}
}
}
fun setOnSendCodeClickListener(listener: (String) -> Unit) {
mOnSendCodeClickListener = listener
}
fun setOnBackListener(listener: (String, String, String) -> Unit) {
mOnBackListener = listener
}
fun setTimestamp(timestamp:String) {
this.timestamp = timestamp
startTimer()
}
override fun onSoftInputChanged(height: Int) {
val lp = binding.layoutContent.layoutParams as ConstraintLayout.LayoutParams
lp.bottomMargin = height
binding.layoutContent.layoutParams = lp
}
override fun onDestroyView() {
KeyboardUtils.unregisterSoftInputChangedListener(requireActivity().window)
binding.etPhone.removeTextChangedListener(textWatcher)
super.onDestroyView()
}
companion object {
fun newInstance(): BindPhoneDialog {
val arg = Bundle()
val fragment = BindPhoneDialog()
fragment.arguments = arg
return fragment
}
}
}

View File

@ -0,0 +1,123 @@
package com.cheng.bole.ui.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.InputType
import android.text.TextUtils
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.DialogFragment
import com.example.base.extensions.onClick
import com.example.base.extensions.toast
import com.example.base.utils.ScreenUtils
import com.cheng.bole.R
import com.cheng.bole.databinding.DialogEditTextBinding
import com.cheng.bole.impl.TextWatcherImpl
import com.cheng.bole.utils.KeyboardUtils
class EditTextDialog : DialogFragment(), KeyboardUtils.OnSoftInputChangedListener {
private val title by lazy { arguments?.getString("title") ?: "" }
private val content by lazy { arguments?.getString("content") ?: "" }
private val hint by lazy { arguments?.getString("hint") }
private val inputType by lazy { arguments?.getInt("input_type") ?: InputType.TYPE_CLASS_TEXT }
private var mOnBackListener: ((String) -> Unit)? = null //回调事件
lateinit var binding: DialogEditTextBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = ScreenUtils.getWindowSize().x
windowParams?.gravity = Gravity.BOTTOM
windowParams?.windowAnimations = R.style.dialog_bottom
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
KeyboardUtils.registerSoftInputChangedListener(requireActivity(), this)
return super.onCreateView(inflater, container, savedInstanceState)
}
private val textWatcher = object : TextWatcherImpl() {
@SuppressLint("SetTextI18n")
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
binding.ivClearText.visibility = if (TextUtils.isEmpty(s)) View.GONE else View.VISIBLE
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_edit_text, null)
binding = DialogEditTextBinding.bind(view)
binding.etContent.addTextChangedListener(textWatcher)
binding.tvTitle.text = title
binding.etContent.hint = hint ?: "请输入"
binding.etContent.setText(content)
binding.etContent.inputType = inputType
binding.ivClose.onClick {
dismiss()
}
binding.ivClearText.onClick {
binding.etContent.setText("")
}
binding.btnNext.onClick {
val content = binding.etContent.text?.trim().toString()
if (TextUtils.isEmpty(content)) {
toast(hint ?: "请输入内容")
return@onClick
}
mOnBackListener?.invoke(content)
dismiss()
}
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
fun setOnTextListener(listener: ((String) -> Unit)) {
mOnBackListener = listener
}
override fun onSoftInputChanged(height: Int) {
val lp = binding.layoutContent.layoutParams as ConstraintLayout.LayoutParams
lp.bottomMargin = height
binding.layoutContent.layoutParams = lp
}
override fun onDestroyView() {
KeyboardUtils.unregisterSoftInputChangedListener(requireActivity().window)
binding.etContent.removeTextChangedListener(textWatcher)
super.onDestroyView()
}
companion object {
fun newInstance(
title: String? = null,
content: String? = null,
hint: String? = null,
inputType: Int = InputType.TYPE_CLASS_TEXT
): EditTextDialog {
val arg = Bundle()
val fragment = EditTextDialog()
arg.putString("title", title)
arg.putString("content", content)
arg.putString("hint", hint)
arg.putInt("input_type", inputType)
fragment.arguments = arg
return fragment
}
}
}

View File

@ -0,0 +1,115 @@
package com.cheng.bole.ui.dialog
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.base.browser.BrowserActivity
import com.example.base.extensions.getColor
import com.example.base.extensions.onClick
import com.example.base.utils.ScreenUtils
import com.example.base.utils.SpanUtils
import com.g.gysdk.GYManager
import com.cheng.bole.R
import com.cheng.bole.common.Constants
import com.cheng.bole.databinding.DialogLoginTipBinding
import com.cheng.bole.utils.UrlHelper
class LoginTipDialog :DialogFragment(){
private val type by lazy { arguments?.getInt("type") ?: 0 }
private var mOnBackListener: (() -> Unit)? = null //回调事件
lateinit var binding: DialogLoginTipBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.8).toInt()
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_login_tip, null)
binding = DialogLoginTipBinding.bind(view)
binding.tvTitle.typeface = Constants.youSheBiaoTiHei
if (type == 0){
initLoginPrivacyTv()
} else {
initOneKeyLoginPrivacyTv()
}
binding.ivClose.onClick { dismiss() }
binding.tvOk.onClick {
mOnBackListener?.invoke()
dismiss()
}
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
fun setOnSelectListener(listener: (() -> Unit)) {
mOnBackListener = listener
}
private fun initLoginPrivacyTv() {
SpanUtils.with(binding.tvTip)
.append("登录之前须先查看并同意")
.append("《用户协议》")
.setClickSpan(getColor(R.color.color_466afd), false) {
UrlHelper.startUserAgreement(requireContext())
}
.append("")
.append("《隐私政策》")
.setClickSpan(getColor(R.color.color_466afd), false) {
UrlHelper.startPrivacyPolicy(requireContext())
}
.create()
}
private fun initOneKeyLoginPrivacyTv() {
val preLoginResult = GYManager.getInstance().preLoginResult
SpanUtils.with(binding.tvTip)
.append("登录之前须先查看并同意")
.append("${preLoginResult.privacyName}")
.setClickSpan(getColor(R.color.color_466afd), false) {
BrowserActivity.start(requireContext(), preLoginResult.privacyName, preLoginResult.privacyUrl, false)
}
.append("")
.append("《用户协议》")
.setClickSpan(getColor(R.color.color_466afd), false) {
UrlHelper.startUserAgreement(requireContext())
}
.append("")
.append("《隐私政策》")
.setClickSpan(getColor(R.color.color_466afd), false) {
UrlHelper.startPrivacyPolicy(requireContext())
}
.create()
}
companion object {
fun newInstance(type: Int = 0): LoginTipDialog {
val arg = Bundle()
val fragment = LoginTipDialog()
arg.putInt("type", type)
fragment.arguments = arg
return fragment
}
}
}

View File

@ -0,0 +1,94 @@
package com.cheng.bole.ui.dialog
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.base.extensions.getColor
import com.example.base.extensions.onClick
import com.example.base.utils.ScreenUtils
import com.example.base.utils.SpanUtils
import com.cheng.bole.R
import com.cheng.bole.common.Constants
import com.cheng.bole.databinding.DialogPayTipBinding
import com.cheng.bole.manager.DialogEnum
import com.cheng.bole.utils.UrlHelper
class PayTipDialog : DialogFragment() {
private val showRenew by lazy { arguments?.getBoolean("show_renew") ?: false }
private var mOnBackListener: ((DialogEnum) -> Unit)? = null //回调事件
lateinit var binding: DialogPayTipBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.8).toInt()
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_pay_tip, null)
binding = DialogPayTipBinding.bind(view)
binding.tvTitle.typeface = Constants.youSheBiaoTiHei
binding.tvOk.onClick {
mOnBackListener?.invoke(DialogEnum.CLICK_OK)
dismiss()
}
binding.tvClose.onClick { dismiss() }
binding.ivClose.onClick { dismiss() }
initAgreement()
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
private fun initAgreement() {
val spanUtils = SpanUtils.with(binding.tvContent)
.append("我已阅读并同意")
.append("《会员服务协议规则》")
.setClickSpan(getColor(R.color.color_466afd), false) {
UrlHelper.startUserAgreement(requireContext(), "会员服务协议规则")
}
if (showRenew) {
spanUtils.append("")
spanUtils.append("《自动续费服务规则》")
spanUtils.setClickSpan(getColor(R.color.color_466afd), false) {
UrlHelper.startRenewAgreement(requireContext())
}
}
spanUtils.create()
}
fun setOnSelectListener(listener: ((DialogEnum) -> Unit)) {
mOnBackListener = listener
}
companion object {
fun newInstance(showRenew: Boolean = false): PayTipDialog {
val arg = Bundle()
arg.putBoolean("show_renew", showRenew)
val fragment = PayTipDialog()
fragment.arguments = arg
return fragment
}
}
}

View File

@ -0,0 +1,65 @@
package com.cheng.bole.ui.dialog
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.TextUtils
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.base.utils.ScreenUtils
import com.cheng.bole.R
import com.cheng.bole.databinding.DialogPermissionTipBinding
class PermissionTipDialog : DialogFragment() {
private var content: CharSequence? = null
lateinit var binding: DialogPermissionTipBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.9).toInt()
windowParams?.gravity = Gravity.TOP
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_permission_tip, null)
binding = DialogPermissionTipBinding.bind(view)
content = arguments?.getCharSequence("content")
if (!TextUtils.isEmpty(content)) {
binding.tvContent.text = content
}
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
companion object {
fun newInstance(
content: CharSequence,
): PermissionTipDialog {
val arg = Bundle()
val fragment = PermissionTipDialog()
arg.putCharSequence("content", content)
fragment.arguments = arg
return fragment
}
}
}

View File

@ -0,0 +1,42 @@
package com.cheng.bole.ui.dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import com.example.base.extensions.onClick
import com.cheng.bole.R
import com.cheng.bole.databinding.PopAboutTipBinding
import com.cheng.bole.ui.activity.PublicActivity
import com.cheng.bole.ui.fragment.guide.GuideFragment
import com.cheng.bole.ui.fragment.mine.about.AppConfigFragment
object PopupDialog {
fun showAboutTip(context: Context,v:View){
val view = LayoutInflater.from(context).inflate(R.layout.pop_about_tip,null,false)
val binding = PopAboutTipBinding.bind(view)
binding.tvTip1.onClick {
PublicActivity.start(context, AppConfigFragment::class.java)
}
binding.tvTip2.onClick {
PublicActivity.start(context, GuideFragment::class.java)
}
val popWindow = PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true)
popWindow.isClippingEnabled = false
popWindow.isFocusable = true
popWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val location = IntArray(2)
v.getLocationOnScreen(location)
val y: Int = location[1] + v.height
val height = context.resources.displayMetrics.heightPixels - y
popWindow.showAsDropDown(v, 0, 0)
}
}

View File

@ -0,0 +1,94 @@
package com.cheng.bole.ui.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.base.extensions.getColor
import com.example.base.extensions.onClick
import com.example.base.utils.ScreenUtils
import com.example.base.utils.SpanUtils
import com.cheng.bole.R
import com.cheng.bole.common.Constants
import com.cheng.bole.databinding.DialogPrivacyPolicyBinding
import com.cheng.bole.manager.DialogEnum
import com.cheng.bole.utils.UrlHelper
class PrivacyPolicyDialog : DialogFragment() {
private var mOnBackListener: ((DialogEnum) -> Unit)? = null //回调事件
lateinit var binding: DialogPrivacyPolicyBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.8).toInt()
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog?.setCancelable(false)
return super.onCreateView(inflater, container, savedInstanceState)
}
@SuppressLint("SetTextI18n")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_privacy_policy, null)
binding = DialogPrivacyPolicyBinding.bind(view)
binding.tvTitle.typeface = Constants.youSheBiaoTiHei
binding.btnNext.onClick {
mOnBackListener?.invoke(DialogEnum.CLICK_OK)
dismiss()
}
binding.btnDisagree.onClick {
mOnBackListener?.invoke(DialogEnum.CLICK_CANCEL)
dismiss()
}
initAgreement()
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
fun setOnSelectListener(listener: ((DialogEnum) -> Unit)) {
mOnBackListener = listener
}
private fun initAgreement() {
SpanUtils.with(binding.tvContent)
.append("请你务必审慎阅读、充分理解")
.append("《服务协议》")
.setBold()
.setClickSpan(getColor(R.color.color_466afd), false) {
UrlHelper.startUserAgreement(requireContext())
}
.append("")
.append("《隐私政策》")
.setBold()
.setClickSpan(getColor(R.color.color_466afd), false) {
UrlHelper.startPrivacyPolicy(requireContext())
}
.append("各条款,包括但不限于:为了更好的向你提供服务,我们需要访问你的相册、位置信息等。你可阅读")
.append("《隐私政策》")
.setBold()
.setClickSpan(getColor(R.color.color_466afd), false) {
UrlHelper.startPrivacyPolicy(requireContext())
}
.append("了解详细信息。如果你同意,请点击下面同意按钮开始接受我们的服务。")
.create()
}
}

View File

@ -0,0 +1,190 @@
package com.cheng.bole.ui.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.TextUtils
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.DialogFragment
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.base.extensions.getColor
import com.example.base.extensions.getYYYYMMDD2
import com.example.base.extensions.gone
import com.example.base.extensions.onClick
import com.example.base.extensions.visible
import com.example.base.utils.ScreenUtils
import com.example.base.utils.SpanUtils
import com.example.base.widget.EmptyView
import com.example.base.widget.PageStatus
import com.cheng.bole.R
import com.cheng.bole.common.Constants
import com.cheng.bole.databinding.DialogSelectCouponBinding
import com.cheng.bole.ui.fragment.mine.vip.VipFragment
import java.text.DecimalFormat
class SelectCouponDialog : DialogFragment() {
private val id by lazy { arguments?.getString("id") ?: "" }
private val price by lazy { arguments?.getString("price") ?: "" }
private val mAdapter by lazy { CouponAdapter(price) }
private val mEmptyView by lazy { EmptyView(requireContext()) }
private var mOnBackListener: ((com.cheng.bole.bean.CouponEntity?) -> Unit)? = null
private var selectedCoupon: com.cheng.bole.bean.CouponEntity? = null
lateinit var binding: DialogSelectCouponBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = ScreenUtils.getWindowSize().x
windowParams?.gravity = Gravity.BOTTOM
windowParams?.windowAnimations = R.style.dialog_bottom
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return super.onCreateView(inflater, container, savedInstanceState)
}
@SuppressLint("NotifyDataSetChanged")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_select_coupon, null)
binding = DialogSelectCouponBinding.bind(view)
binding.mRecyclerView.adapter = mAdapter
mEmptyView.setBtnVisible(false)
mAdapter.setEmptyView(mEmptyView)
mAdapter.setOnItemClickListener { _, _, i ->
val item = mAdapter.getItem(i)
if (TextUtils.isEmpty(item.threshold) || item.threshold.toFloat() / 100 <= price.toFloat()) {
mAdapter.data.forEach {
if (it.id == item.id) {
it.isChecked = !it.isChecked
} else {
it.isChecked = false
}
}
selectedCoupon = if (item.isChecked) item else null
mAdapter.notifyDataSetChanged()
}
}
binding.ivClose.onClick {
dismiss()
}
binding.btnNext.onClick {
mOnBackListener?.invoke(selectedCoupon)
dismiss()
}
initData()
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
@SuppressLint("NotifyDataSetChanged")
private fun initData() {
val fragment = requireParentFragment()
if (fragment is VipFragment) {
fragment.mViewModel.couponListLiveData.observe(this) { list ->
mAdapter.setList(list)
mAdapter.data.forEach {
if (it.id == id) {
it.isChecked = true
selectedCoupon = it
}
}
mAdapter.notifyDataSetChanged()
if (mAdapter.data.isEmpty()) {
mEmptyView.setStatus(PageStatus.NO_DATA)
binding.layoutBottom.gone()
} else {
mEmptyView.setStatus(PageStatus.GONG)
binding.layoutBottom.visible()
}
}
fragment.mViewModel.couponList()
}
}
fun setOnBackListener(listener: (com.cheng.bole.bean.CouponEntity?) -> Unit) {
mOnBackListener = listener
}
companion object {
fun newInstance(id: String?, price: String): SelectCouponDialog {
val args = Bundle()
args.putString("id", id)
args.putString("price", price)
val fragment = SelectCouponDialog()
fragment.arguments = args
return fragment
}
}
internal class CouponAdapter(private val price: String) : BaseQuickAdapter<com.cheng.bole.bean.CouponEntity, BaseViewHolder>(R.layout.listitem_coupon_dialog) {
override fun convert(holder: BaseViewHolder, item: com.cheng.bole.bean.CouponEntity) {
holder.setText(
R.id.tv_name,
if (!TextUtils.isEmpty(item.coupon_name)) item.coupon_name else "${item.coupon_value_name}${item.coupon_type_name}"
)
holder.setText(R.id.tv_expire_time, "有效期至 ${(item.expire_timestamp.toLong() * 1000).getYYYYMMDD2()}")
holder.setText(R.id.tv_type, item.coupon_type_name)
holder.getView<TextView>(R.id.tv_discount_amount).typeface = Constants.dDIN_PRO_M
when (item.coupon_type) {
com.cheng.bole.bean.CouponEntity.TYPE_CASH -> {
SpanUtils.with(holder.getView(R.id.tv_discount_amount))
.append("")
.setFontSize(12, true)
.append(DecimalFormat("0.##").format(item.coupon_value.toFloat() / 100))
.create()
if (!TextUtils.isEmpty(item.threshold)) {
holder.setText(R.id.tv_threshold_amount, "${DecimalFormat("0.##").format(item.threshold.toFloat() / 100)}可用")
} else {
holder.setText(R.id.tv_threshold_amount, "无门槛")
}
}
com.cheng.bole.bean.CouponEntity.TYPE_DISCOUNT -> {
SpanUtils.with(holder.getView(R.id.tv_discount_amount))
.append(DecimalFormat("0.##").format(item.coupon_value.toFloat() * 10))
.append("")
.setFontSize(12, true)
.create()
if (!TextUtils.isEmpty(item.threshold)) {
holder.setText(R.id.tv_threshold_amount, "${DecimalFormat("0.##").format(item.threshold.toFloat() / 100)}可用")
} else {
holder.setText(R.id.tv_threshold_amount, "无门槛")
}
}
}
if (TextUtils.isEmpty(item.threshold) || item.threshold.toFloat() / 100 <= price.toFloat()) {
holder.setTextColor(R.id.tv_discount_amount, getColor(R.color.color_ff5846))
holder.setTextColor(R.id.tv_threshold_amount, getColor(R.color.color_ff5846))
holder.setBackgroundResource(R.id.layout_amount, R.drawable.shape_fdf4f2_cor6)
holder.setImageResource(R.id.iv_check, if (item.isChecked) R.mipmap.ic_coupon_check_true else R.mipmap.ic_coupon_check_false)
} else {
holder.setTextColor(R.id.tv_discount_amount, getColor(R.color.color_d8d8d8))
holder.setTextColor(R.id.tv_threshold_amount, getColor(R.color.color_d8d8d8))
holder.setBackgroundResource(R.id.layout_amount, R.drawable.shape_f6f6f6_cor6)
holder.setImageResource(R.id.iv_check, R.mipmap.ic_coupon_check_disable)
}
}
}
}

View File

@ -0,0 +1,85 @@
package com.cheng.bole.ui.dialog
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.base.extensions.onClick
import com.example.base.extensions.toast
import com.example.base.utils.ClipboardUtils
import com.example.base.utils.ScreenUtils
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.umeng.socialize.bean.SHARE_MEDIA
import com.cheng.bole.R
import com.cheng.bole.common.Constants
import com.cheng.bole.common.EventConstants
import com.cheng.bole.databinding.DialogShareBinding
import com.cheng.bole.manager.EventReportManager
import com.cheng.bole.manager.ShareManager
import com.cheng.bole.manager.UserConfigManager
class ShareDialog : DialogFragment() {
private lateinit var api: IWXAPI
lateinit var binding: DialogShareBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = ScreenUtils.getWindowSize().x
windowParams?.gravity = Gravity.BOTTOM
windowParams?.windowAnimations = R.style.dialog_bottom
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
api = WXAPIFactory.createWXAPI(requireContext(), Constants.WechatAppId)
val view = layoutInflater.inflate(R.layout.dialog_share, null)
binding = DialogShareBinding.bind(view)
binding.ivWxShare.onClick {
if (!api.isWXAppInstalled) {
toast("您没有安装微信客户端,请先下载安装")
return@onClick
}
ShareManager.shareUrl(requireActivity(), SHARE_MEDIA.WEIXIN, UserConfigManager.getShareEntity()!!) {}
EventReportManager.eventReport(EventConstants.SHARE_APP, "", "weixin")
dismiss()
}
binding.ivWxCircleShare.onClick {
if (!api.isWXAppInstalled) {
toast("您没有安装微信客户端,请先下载安装")
return@onClick
}
ShareManager.shareUrl(requireActivity(), SHARE_MEDIA.WEIXIN_CIRCLE, UserConfigManager.getShareEntity()!!) {}
EventReportManager.eventReport(EventConstants.SHARE_APP, "", "weixin_friend")
dismiss()
}
binding.ivLinkShare.onClick {
ClipboardUtils.copyText(UserConfigManager.getShareEntity()!!.link)
EventReportManager.eventReport(EventConstants.SHARE_APP, "", "copy_url")
toast("复制成功")
dismiss()
}
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
}

View File

@ -0,0 +1,99 @@
package com.cheng.bole.ui.dialog
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.base.extensions.gone
import com.example.base.extensions.onClick
import com.example.base.extensions.visible
import com.example.base.utils.ScreenUtils
import com.cheng.bole.R
import com.cheng.bole.databinding.DialogSimpleTipBinding
import com.cheng.bole.manager.DialogEnum
class SimpleTipDialog : DialogFragment() {
private var mOnBackListener: ((DialogEnum) -> Unit)? = null //回调事件
private var content: CharSequence? = null
private var leftText: String? = null
private var rightText: String? = null
lateinit var binding: DialogSimpleTipBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.8).toInt()
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_simple_tip, null)
binding = DialogSimpleTipBinding.bind(view)
content = arguments?.getCharSequence("content")
leftText = arguments?.getString("leftText")
rightText = arguments?.getString("rightText")
if (!TextUtils.isEmpty(content)) {
binding.tvContent.text = content
}
if (!TextUtils.isEmpty(leftText)) {
binding.tvCancel.text = leftText
binding.tvCancel.visible()
} else {
binding.tvCancel.gone()
}
if (!TextUtils.isEmpty(rightText)) {
binding.tvOk.text = rightText
}
binding.tvCancel.onClick {
mOnBackListener?.invoke(DialogEnum.CLICK_CANCEL)
dismiss()
}
binding.tvOk.onClick {
mOnBackListener?.invoke(DialogEnum.CLICK_OK)
dismiss()
}
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
fun setOnSelectListener(listener: ((DialogEnum) -> Unit)) {
mOnBackListener = listener
}
companion object {
fun newInstance(
content: CharSequence? = null,
leftText: String? = null,
rightText: String? = null,
): SimpleTipDialog {
val arg = Bundle()
val fragment = SimpleTipDialog()
arg.putCharSequence("content", content)
arg.putString("leftText", leftText)
arg.putString("rightText", rightText)
fragment.arguments = arg
return fragment
}
}
}

View File

@ -0,0 +1,110 @@
package com.cheng.bole.ui.dialog
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.base.extensions.onClick
import com.example.base.utils.ScreenUtils
import com.cheng.bole.R
import com.cheng.bole.common.Constants
import com.cheng.bole.databinding.DialogTipBinding
import com.cheng.bole.manager.DialogEnum
class TipDialog : DialogFragment() {
private var mOnBackListener: ((DialogEnum) -> Unit)? = null //回调事件
private var title: String? = null
private var content: CharSequence? = null
private var leftText: String? = null
private var rightText: String? = null
private var cancelable: Boolean = true
lateinit var binding: DialogTipBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.8).toInt()
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
setCancelable(cancelable)
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_tip, null)
binding = DialogTipBinding.bind(view)
binding.tvTitle.typeface = Constants.youSheBiaoTiHei
title = arguments?.getString("title")
content = arguments?.getCharSequence("content")
leftText = arguments?.getString("leftText")
rightText = arguments?.getString("rightText")
cancelable = arguments?.getBoolean("cancelable") ?: true
if (!TextUtils.isEmpty(title)) {
binding.tvTitle.text = title
}
if (!TextUtils.isEmpty(content)) {
binding.tvContent.text = content
}
if (!TextUtils.isEmpty(leftText)) {
binding.tvCancel.text = leftText
}
if (!TextUtils.isEmpty(rightText)) {
binding.tvOk.text = rightText
}
binding.tvCancel.onClick {
mOnBackListener?.invoke(DialogEnum.CLICK_CANCEL)
dismiss()
}
binding.tvOk.onClick {
mOnBackListener?.invoke(DialogEnum.CLICK_OK)
dismiss()
}
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
fun setOnSelectListener(listener: ((DialogEnum) -> Unit)) {
mOnBackListener = listener
}
companion object {
fun newInstance(
title: String? = null,
content: CharSequence? = null,
leftText: String? = null,
rightText: String? = null,
cancelable: Boolean = true
): TipDialog {
val arg = Bundle()
val fragment = TipDialog()
arg.putString("title", title)
arg.putCharSequence("content", content)
arg.putString("leftText", leftText)
arg.putString("rightText", rightText)
arg.putBoolean("cancelable", cancelable)
fragment.arguments = arg
return fragment
}
}
}

View File

@ -0,0 +1,208 @@
package com.cheng.bole.ui.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.FileProvider
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import com.cheng.bole.R
import com.cheng.bole.common.EventConstants
import com.cheng.bole.databinding.DialogUpdateVerisonBinding
import com.cheng.bole.manager.DialogEnum
import com.cheng.bole.manager.EventReportManager
import com.cheng.bole.utils.DownLoadUtils
import com.cheng.bole.utils.PermissionUtils
import com.cheng.bole.utils.UIUtils
import com.example.base.extensions.gone
import com.example.base.extensions.onClick
import com.example.base.extensions.visible
import com.example.base.utils.ScreenUtils
import com.cheng.bole.common.Constants
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
class UpdateVersionDialog : DialogFragment() {
private var mOnBackListener: ((DialogEnum) -> Unit)? = null //回调事件
var apkFilePath = ""
lateinit var binding: DialogUpdateVerisonBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.7).toInt()
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_update_verison, null)
binding = DialogUpdateVerisonBinding.bind(view)
binding.tvUpdateTitle.typeface = Constants.youSheBiaoTiHei
val versionEntity = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
arguments?.getSerializable("versionEntity", com.cheng.bole.bean.VersionEntity::class.java)
} else {
arguments?.getSerializable("versionEntity") as com.cheng.bole.bean.VersionEntity?
}
binding.cancelBtn.onClick {
dismiss()
EventReportManager.eventReport(EventConstants.PKG_CANCEL, "", "升级的版本号${versionEntity?.version}")
}
versionEntity?.apply {
binding.tvVersionName.text = version
binding.tvUpdateTitle.text = title
binding.tvUpdateDesc.text = description
if (force) {
binding.cancelBtn.gone()
} else {
binding.cancelBtn.visible()
}
}
binding.ivClose.onClick {
val f = TipDialog.newInstance("提示", "确定取消下载?")
f.setOnSelectListener {
if (it == DialogEnum.CLICK_OK) {
DownLoadUtils.getInstance().cancel()
dismiss()
}
}
f.show(childFragmentManager, TipDialog::class.java.simpleName)
}
binding.updateBtn.onClick {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (binding.updateBtn.text.toString() == "立即安裝" && !TextUtils.isEmpty(apkFilePath)) {
install()
} else {
versionEntity?.apply {
download(url, force)
EventReportManager.eventReport(EventConstants.PKG_UPDATE, "", "升级的版本号${versionEntity.version}")
}
}
} else {
PermissionUtils.checkStoragePermission(requireActivity(), childFragmentManager) { isGranted ->
if (isGranted) {
if (binding.updateBtn.text.toString() == "立即安裝" && !TextUtils.isEmpty(apkFilePath)) {
install()
} else {
versionEntity?.apply {
download(url, force)
EventReportManager.eventReport(EventConstants.PKG_UPDATE, "", "升级的版本号${versionEntity.version}")
}
}
}
}
}
}
isCancelable = false
val dialog = Dialog(requireContext())
dialog.setContentView(view)
dialog.setCancelable(false)
dialog.setCanceledOnTouchOutside(false)
return dialog
}
@SuppressLint("SetTextI18n")
private fun download(url: String, force: Boolean) {
if (force) {
binding.ivClose.gone()
} else {
binding.ivClose.visible()
}
binding.cancelBtn.gone()
binding.updateBtn.gone()
binding.progressbar.visible()
binding.tvProgress.visible()
lifecycleScope.launch(Dispatchers.IO) {
var totalProgress = 0L
DownLoadUtils.getInstance()
.setReadTImeOut(10L)
.setDeleteWhenException(false)
.initUrl(url, null)
.setFilePath(com.cheng.bole.utils.FileUtils.getInstance().cacheDownLoderDir.absolutePath)
.setFileName(UIUtils.getFileNameFromUrl(url))
.setActionCallBack(
{ totalProgress = it },
{
val percent = it.toDouble() / totalProgress.toDouble() * 100
val curProgress = percent.toInt()
binding.tvProgress.text = "${curProgress}%"
binding.progressbar.progress = curProgress
},
{
binding.tvProgress.text = "100%"
apkFilePath = it.absolutePath
binding.updateBtn.text = "立即安裝"
binding.updateBtn.visible()
binding.progressbar.gone()
binding.tvProgress.gone()
install()
}, {
binding.updateBtn.text = "下载失败,点击重试"
binding.updateBtn.visible()
binding.progressbar.gone()
binding.tvProgress.gone()
}).down()
}
}
fun setOnSelectListener(listener: ((DialogEnum) -> Unit)) {
mOnBackListener = listener
}
companion object {
fun newInstance(versionEntity: com.cheng.bole.bean.VersionEntity): UpdateVersionDialog {
val arg = Bundle()
val fragment = UpdateVersionDialog()
arg.putSerializable("versionEntity", versionEntity)
fragment.arguments = arg
return fragment
}
}
private fun install() {
try {
val apkFile = File(com.cheng.bole.utils.FileUtils.getInstance().cacheDownLoderDir, UIUtils.getFileNameFromUrl(apkFilePath))
if (!apkFile.exists()) {
return
}
val apkUri = FileProvider.getUriForFile(requireContext(), requireContext().packageName + ".fileprovider", apkFile)
val intent = Intent(Intent.ACTION_VIEW)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View File

@ -0,0 +1,43 @@
package com.cheng.bole.ui.dialog
import android.os.Bundle
import androidx.fragment.app.Fragment
import com.example.base.extensions.onClick
import com.example.base.utils.ScreenUtils
import com.cheng.bole.R
import com.cheng.bole.common.Constants
import com.cheng.bole.databinding.DialogVipLoginTipBinding
import com.cheng.bole.ui.base.BaseDialog
class VipLoginTipDialog(mFragment: Fragment) : BaseDialog(mFragment.requireContext()){
private var mOnBackListener: (() -> Unit)? = null //回调事件
lateinit var binding: DialogVipLoginTipBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val view = layoutInflater.inflate(R.layout.dialog_vip_login_tip, null)
setContentView(view)
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.8).toInt()
window?.attributes = windowParams
setCancelable(false)
binding = DialogVipLoginTipBinding.bind(view)
binding.tvTitle.typeface = Constants.youSheBiaoTiHei
binding.btnOk.onClick {
mOnBackListener?.invoke()
dismiss()
}
}
fun setOnSelectListener(listener: (() -> Unit)) {
mOnBackListener = listener
}
}

View File

@ -0,0 +1,103 @@
package com.cheng.bole.ui.fragment.guide
import android.annotation.SuppressLint
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import com.example.base.extensions.gone
import com.example.base.extensions.onClick
import com.example.base.ui.BaseFragment
import com.cheng.bole.ui.activity.MainActivity
import com.cheng.bole.ui.activity.PublicActivity
import com.cheng.bole.common.Constants
import com.cheng.bole.common.EventConstants
import com.cheng.bole.databinding.FragmentGuideContentBinding
import com.cheng.bole.manager.EventReportManager
import com.cheng.bole.manager.UserConfigManager
import com.cheng.bole.ui.base.BasePageAdapter
import com.cheng.bole.ui.fragment.mine.vip.VipFragment
import org.jetbrains.anko.startActivity
class GuideFragment :BaseFragment<FragmentGuideContentBinding, GuideViewModel>(){
private var titles = listOf("guide1", "guide2", "guide3","guide4")
private val list by lazy {
ArrayList<Fragment>()
}
private val indicatorAdapter by lazy { IndicatorAdapter() }
private var mIsScrolled = false
private var currentPosition = 0
override fun initView() {
super.initView()
titles.forEachIndexed { index, s ->
list.add(GuideItemFragment.newInstance(index))
}
val pageAdapter = BasePageAdapter(childFragmentManager, titles, list)
binding.viewPager.adapter = pageAdapter
binding.viewPager.offscreenPageLimit = list.size
indicatorAdapter.setList(MutableList(titles.size) { i -> i })
binding.rvIndicator.adapter = indicatorAdapter
binding.tvTitle.typeface = Constants.almmsht
}
override fun initData() {
super.initData()
binding.tvDesc.text = UserConfigManager.getGuideHint()
EventReportManager.eventReport(EventConstants.GUIDE_LAUNCH, "", "")
}
override fun initListener() {
super.initListener()
binding.btnStart.onClick {
binding.btnStart.postDelayed({
binding.layoutGuide.gone()
}, 200)
}
binding.viewPager.addOnPageChangeListener(object :OnPageChangeListener{
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
@SuppressLint("NotifyDataSetChanged")
override fun onPageSelected(position: Int) {
currentPosition = position
indicatorAdapter.currentIndex = currentPosition
indicatorAdapter.notifyDataSetChanged()
EventReportManager.eventReport(EventConstants.GUIDE_OPPORTUNITY_SCROLL, "${currentPosition + 1}", "")
}
override fun onPageScrollStateChanged(state: Int) {
when(state){
ViewPager.SCROLL_STATE_DRAGGING->{
mIsScrolled = false
return
}
ViewPager.SCROLL_STATE_SETTLING->{
mIsScrolled = true
return
}
ViewPager.SCROLL_STATE_IDLE->{
if (!mIsScrolled && currentPosition == indicatorAdapter.itemCount - 1){
if (UserConfigManager.getGuidePayEnable()){
PublicActivity.start(requireActivity(), VipFragment::class.java, Pair("origin", "guide"))
}else{
requireActivity().startActivity<MainActivity>()
}
}
mIsScrolled = true
return
}
}
}
})
}
}

View File

@ -0,0 +1,36 @@
package com.cheng.bole.ui.fragment.guide
import android.os.Bundle
import com.cheng.bole.R
import com.cheng.bole.databinding.FragmentGuideItemBinding
import com.example.base.ui.BaseFragment
class GuideItemFragment : BaseFragment<FragmentGuideItemBinding, GuideViewModel>() {
private val curPos by lazy { arguments?.getInt("curPos") ?: 0 }
companion object {
fun newInstance(pos: Int): GuideItemFragment {
val bundle = Bundle()
bundle.putInt("curPos", pos)
val f = GuideItemFragment()
f.arguments = bundle
return f
}
}
override fun initView() {
super.initView()
when (curPos) {
0 -> binding.ivGuide.setBackgroundResource(R.mipmap.ic_guide_1)
1 -> binding.ivGuide.setBackgroundResource(R.mipmap.ic_guide_2)
2 -> binding.ivGuide.setBackgroundResource(R.mipmap.ic_guide_3)
3 -> binding.ivGuide.setBackgroundResource(R.mipmap.ic_guide_4)
}
}
override fun initListener() {
super.initListener()
}
}

View File

@ -0,0 +1,6 @@
package com.cheng.bole.ui.fragment.guide
import com.example.base.viewmodel.BaseViewModel
class GuideViewModel :BaseViewModel(){
}

View File

@ -0,0 +1,13 @@
package com.cheng.bole.ui.fragment.guide
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.R
class IndicatorAdapter: BaseQuickAdapter<Int, BaseViewHolder>(R.layout.listitem_indicator) {
var currentIndex = 0
override fun convert(holder: BaseViewHolder, item: Int) {
holder.setImageResource(R.id.iv_indicator, if (item == currentIndex) R.drawable.shape_indicator_select else R.drawable.shape_indicator_default)
}
}

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