commit d4c300b19f01e65b4217ecb39615cf859667609e Author: lijia Date: Mon Jan 29 16:19:11 2024 +0800 好运司机端2.0初始化 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..0c0c338 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..2266b30 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..8d81632 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f392494 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..229165a --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,110 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} +def releaseTime() { + return new Date().format("yyyyMMddHHmm", TimeZone.getTimeZone("GMT+08:00")) +} +android { + compileSdk rootProject.ext.android["compileSdkVersion"] + + defaultConfig { + applicationId rootProject.ext.android["applicationId"] + minSdkVersion rootProject.ext.android["minSdkVersion"] + targetSdkVersion rootProject.ext.android["targetSdkVersion"] + versionCode rootProject.ext.android["versionCode"] + versionName rootProject.ext.android["versionName"] + flavorDimensions "CHANNEL_VALUE" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = '11' + } + + buildFeatures { + viewBinding = true + } + + sourceSets { + main { + jniLibs.srcDir 'libs' + //说明so的路径为该libs路径,关联所有地图SDK的so文件 + } + } + + productFlavors { + + dev { + applicationId "com.dahe.gldriver" + manifestPlaceholders = [CHANNEL_VALUE: "审核端(测试)", +// app_icon : "@drawable/head_defaut", + JPUSH_PKGNAME: applicationId, + //JPush 上注册的包名对应的 Appkey. + JPUSH_APPKEY : "5d63ef6fdf58ada352bb8f07", + //暂时填写默认值即可. + JPUSH_CHANNEL: "developer-n"] + buildConfigField("String", "OPEN_AL_URL", "\"https://oapi-staging.alct56.com\"") + buildConfigField("String", "BASE_URL", "\"http://app.test.dahehuoyun.com/api/\"") + buildConfigField "boolean", "isTest", "true" + //APP名称,可以在androidMainfest中引用 + resValue "string", "appName", "审核测试" + } + prod { + applicationId "com.dahe.gldriver" + manifestPlaceholders = [CHANNEL_VALUE: "审核端", +// app_icon : "@drawable/ysxy", + JPUSH_PKGNAME: applicationId, + //JPush 上注册的包名对应的 Appkey. + JPUSH_APPKEY : "5d63ef6fdf58ada352bb8f07", + //暂时填写默认值即可. + JPUSH_CHANNEL: "developer-default"] + buildConfigField("String", "OPEN_AL_URL", "\"https://oapi.alct56.com\"") + buildConfigField("String", "BASE_URL", "\"http://app.dahehuoyun.com/api/\"") + buildConfigField "boolean", "isTest", "false" + resValue "string", "appName", "审核" + } + } + + android.applicationVariants.all { variant -> + variant.outputs.all { + //获取渠道名称 + def isText = variant.productFlavors[0].properties.get("buildConfigFields").getAt("isTest").properties.get("value") + def appName = null + if (isText == "true") { + appName = '司机端测试_' + } else { + appName = '司机端正式_' + } + outputFileName = appName + "${variant.buildType.name}_${defaultConfig.versionName}_${releaseTime()}.apk" + + } + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.annotation:annotation:1.2.0' + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + + + implementation project(path: ':mylibrary') +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/dahe/gldriver/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/dahe/gldriver/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..b14513d --- /dev/null +++ b/app/src/androidTest/java/com/dahe/gldriver/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.dahe.gldriver + +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.dahe.gldriver", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3f6cbde --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/adapter/GridItemAdapter.kt b/app/src/main/java/com/dahe/gldriver/adapter/GridItemAdapter.kt new file mode 100644 index 0000000..665d2f2 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/adapter/GridItemAdapter.kt @@ -0,0 +1,71 @@ +package com.dahe.gldriver.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.ImageView +import android.widget.TextView +import com.dahe.gldriver.R +import com.dahe.gldriver.bean.GridBean + + +/** + * @ClassName GridItemAdapter + * @Author 用户 + * @Date 2024/1/23 10:26 + * @Description TODO + */ +class GridItemAdapter(private val context: Context, private val dataList: MutableList) : + BaseAdapter() { + + private var cusLayout: Int = 0 + + constructor(context: Context, dataList: MutableList, mlayoutid: Int) : this( + context, + dataList + ) { + this.cusLayout = mlayoutid + } + + // 实现必要的方法... + override fun getCount(): Int { + return dataList.size + } + + override fun getItem(position: Int): Any { + return dataList[position] + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var view = convertView + var holder: ViewHolder + if (convertView == null) { + + view = LayoutInflater.from(context) + .inflate(if (cusLayout == 0) R.layout.grid_item else cusLayout, null) + holder = ViewHolder() + holder.title = view.findViewById(R.id.title) + holder.image = view.findViewById(R.id.image) + view?.tag = holder + } else { + holder = (view?.tag) as ViewHolder + } + val item = dataList[position] + holder.title?.text = item.title + holder.image?.setBackgroundResource(item.image) + + return view!! + } + + private class ViewHolder { + var title: TextView? = null + var image: ImageView? = null + } +} + diff --git a/app/src/main/java/com/dahe/gldriver/adapter/MessageAdapter.kt b/app/src/main/java/com/dahe/gldriver/adapter/MessageAdapter.kt new file mode 100644 index 0000000..7cdb9d1 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/adapter/MessageAdapter.kt @@ -0,0 +1,17 @@ +package com.dahe.gldriver.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.viewholder.BaseViewHolder +import com.dahe.gldriver.R +import com.dahe.glex.bean.WayBillBean + +/** + * @ClassName MessageAdapter + * @Author 用户 + * @Date 2024/1/24 14:40 + * @Description TODO + */ +class MessageAdapter: BaseQuickAdapter(R.layout.item_message) { + override fun convert(holder: BaseViewHolder, item: WayBillBean) { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/adapter/MyHomePagerAdapter.kt b/app/src/main/java/com/dahe/gldriver/adapter/MyHomePagerAdapter.kt new file mode 100644 index 0000000..665050f --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/adapter/MyHomePagerAdapter.kt @@ -0,0 +1,43 @@ +package com.dahe.gldriver.adapter + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter +import java.util.ArrayList + +/** + * Created by Administrator on 2018/7/16 0016. + */ +class MyHomePagerAdapter : FragmentStatePagerAdapter { + private lateinit var mTitles: Array + private var mFragments = ArrayList() + + constructor(fm: FragmentManager?) : super(fm!!) {} + constructor( + fm: FragmentManager?, + mTitles: Array, + mFragments: ArrayList + ) : super( + fm!!) { + this.mTitles = mTitles + this.mFragments = mFragments + } + + // 初始化每个页卡选项 + // @Override + // public Object instantiateItem(ViewGroup arg0, int arg1) { + // // TODO Auto-generated method stub + // node_return super.instantiateItem(arg0, arg1); + // } + override fun getCount(): Int { + return mFragments.size + } + + override fun getPageTitle(position: Int): CharSequence? { + return mTitles[position] + } + + override fun getItem(position: Int): Fragment { + return mFragments[position] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/adapter/WaybillAdapter.kt b/app/src/main/java/com/dahe/gldriver/adapter/WaybillAdapter.kt new file mode 100644 index 0000000..5ad9c52 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/adapter/WaybillAdapter.kt @@ -0,0 +1,19 @@ +package com.dahe.gldriver.adapter + +import android.widget.Button +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.viewholder.BaseViewHolder +import com.dahe.gldriver.R +import com.dahe.glex.bean.WayBillBean + +/** + * @ClassName WaybillAdapter + * @Author 用户 + * @Date 2024/1/23 16:27 + * @Description TODO + */ +class WaybillAdapter : + BaseQuickAdapter(R.layout.item_waybill) { + override fun convert(holder: BaseViewHolder, item: WayBillBean) { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/adapter/WaybillListAdapter.kt b/app/src/main/java/com/dahe/gldriver/adapter/WaybillListAdapter.kt new file mode 100644 index 0000000..a5ec7ab --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/adapter/WaybillListAdapter.kt @@ -0,0 +1,18 @@ +package com.dahe.gldriver.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.viewholder.BaseViewHolder +import com.dahe.gldriver.R +import com.dahe.glex.bean.WayBillBean + +/** + * @ClassName WaybillAdapter + * @Author 用户 + * @Date 2024/1/23 16:27 + * @Description TODO + */ +class WaybillListAdapter() : + BaseQuickAdapter(R.layout.item_waybill) { + override fun convert(holder: BaseViewHolder, item: WayBillBean) { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/base/App.kt b/app/src/main/java/com/dahe/gldriver/base/App.kt new file mode 100644 index 0000000..2e5297d --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/base/App.kt @@ -0,0 +1,86 @@ +package com.dahe.gldriver.base + +import android.app.Application +import android.content.Context +import com.dahe.gldriver.BuildConfig +import com.dahe.gldriver.base.App +import com.dahe.mylibrary.CommonBaseLibrary +import com.dahe.gldriver.net.Api +import java.lang.Exception +import java.security.SecureRandom +import java.security.cert.X509Certificate +import javax.net.ssl.HttpsURLConnection +import javax.net.ssl.SSLContext +import javax.net.ssl.TrustManager +import javax.net.ssl.X509TrustManager + +class App : Application() { + override fun onCreate() { + super.onCreate() + app = this + CommonBaseLibrary.getInstance().init(this, Api.BASE_URL) + if (BuildConfig.DEBUG) { +// CrashHandler.getInstance().init(this); +// CrashHandler2.getInstance().init(getApplicationContext()); + } + // CrashReport.initCrashReport(getApplicationContext(), AppConfig.BUGLY_APP_ID, false); + + +// SophixManager.getInstance().queryAndLoadNewPatch(); + +// OssServiceUtil.getInstance().init(); + +// PendingIntent pendingIntent = +// PendingIntent.getActivity(this, 0, new Intent(this, HomeActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); +// Cactus.getInstance() +// .isDebug(true) +// //可选,设置通知栏点击事件 +// .setPendingIntent(pendingIntent) +//// .setBackgroundMusicEnabled(true)//可选,退到后台是否可以播放音乐 +//// .setMusicId(R.raw.main) //可选,设置音乐 +//// .setPendingIntent(pendingIntent)//可选,设置通知栏点击事件 +//// .addCallback(new CactusCallback())//可选,运行时回调 +// .setCrashRestartUIEnabled(true) //可选,设置奔溃可以重启,google原生rom android 10以下可以正常重启 +// .setCrashRestartUIEnabled(true)//可选,设置奔溃可以重启,google原生rom android 10以下可以正常重启 +// .setTitle("大河好运") +// .hideNotificationAfterO(true) +// .setSmallIcon(R.drawable.right_icon) +// .addBackgroundCallback(new CactusBackgroundCallback() { +// @Override +// public void onBackground(boolean b) { +// if (b){ +//// getBillLocation(); +// } +// } +// }) +// .register(this); + } + + override fun attachBaseContext(base: Context) { + super.attachBaseContext(base) + } + + //忽略https的证书校验 + fun handleSSLHandshake() { + try { + val trustAllCerts = arrayOf(object : X509TrustManager { + override fun getAcceptedIssuers(): Array { + return arrayOfNulls(0) + } + + override fun checkClientTrusted(certs: Array, authType: String) {} + override fun checkServerTrusted(certs: Array, authType: String) {} + }) + val sc = SSLContext.getInstance("TLS") + // trustAllCerts信任所有的证书 + sc.init(null, trustAllCerts, SecureRandom()) + HttpsURLConnection.setDefaultSSLSocketFactory(sc.socketFactory) + HttpsURLConnection.setDefaultHostnameVerifier { hostname, session -> true } + } catch (ignored: Exception) { + } + } + + companion object { + var app: App? = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/base/AppConfig.kt b/app/src/main/java/com/dahe/gldriver/base/AppConfig.kt new file mode 100644 index 0000000..2c478ba --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/base/AppConfig.kt @@ -0,0 +1,16 @@ +package com.dahe.gldriver.base + +/** + * @ClassName AppConfig + * @Author 用户 + * @Date 2022/1/14 15:24 + * @Description TODO + */ +object AppConfig { + const val BUGLY_APP_ID = "a5b894cef7" + const val TIME = "DA_HE_TIME" + const val ID = "DA_HE_ID" + const val PWD = "DA_HE_PHONE" + const val CODE = "DA_HE_PHONE" + +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/bean/CheckCodeBean.kt b/app/src/main/java/com/dahe/gldriver/bean/CheckCodeBean.kt new file mode 100644 index 0000000..64e8f8f --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/CheckCodeBean.kt @@ -0,0 +1,9 @@ +package com.dahe.gldriver.bean + +import java.io.Serializable + +class CheckCodeBean : Serializable { + var image: String? = null + var expireTime: String? = null + var uuid: String? = null +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/bean/CommListBean.kt b/app/src/main/java/com/dahe/gldriver/bean/CommListBean.kt new file mode 100644 index 0000000..002c268 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/CommListBean.kt @@ -0,0 +1,13 @@ +package com.dahe.glex.bean + +/** + * @ClassName TextBean + * @Author 用户 + * @Date 2023/9/21 11:08 + * @Description TODO + */ +data class CommListBean( + val list: MutableList, + val num: Int, + val totalFreight: String +) diff --git a/app/src/main/java/com/dahe/gldriver/bean/GridBean.kt b/app/src/main/java/com/dahe/gldriver/bean/GridBean.kt new file mode 100644 index 0000000..529f9ac --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/GridBean.kt @@ -0,0 +1,12 @@ +package com.dahe.gldriver.bean + +/** + * @ClassName GridBean + * @Author 用户 + * @Date 2024/1/23 10:37 + * @Description TODO + */ +data class GridBean( + val title:String, + val image : Int +) diff --git a/app/src/main/java/com/dahe/gldriver/bean/LogBean.kt b/app/src/main/java/com/dahe/gldriver/bean/LogBean.kt new file mode 100644 index 0000000..ba53131 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/LogBean.kt @@ -0,0 +1,14 @@ +package com.dahe.glex.bean + +/** + * @ClassName LogBean + * @Author 用户 + * @Date 2022/1/17 15:18 + * @Description TODO + */ +data class LogBean( + var smscode: String, + var uname: String, + var registerType: Int, + var roleId: Int, +) diff --git a/app/src/main/java/com/dahe/gldriver/bean/OrderBean.kt b/app/src/main/java/com/dahe/gldriver/bean/OrderBean.kt new file mode 100644 index 0000000..c3cb0c7 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/OrderBean.kt @@ -0,0 +1,26 @@ +package com.dahe.glex.bean + +/** + * @ClassName OrderBean + * @Author 用户 + * @Date 2023/9/21 10:22 + * @Description TODO + */ +data class OrderBean( + var orderId: String, + var waybillId: String, + var orderNum: String, + var waybillNum: String, + var orderTime: String, + var totalFreight: String, + var dispatchType : Int, + var effectiveTime: String, + var sendPut: String, + var distance: String, + var loadingAddress: String, + var receiverAddress: String, + var waybillStatus: Int, + var evaluation: Int, + var complaint: Int, + var multipleScore: String, +) diff --git a/app/src/main/java/com/dahe/gldriver/bean/RefreshBean.kt b/app/src/main/java/com/dahe/gldriver/bean/RefreshBean.kt new file mode 100644 index 0000000..0f3877f --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/RefreshBean.kt @@ -0,0 +1,9 @@ +package com.dahe.glex.bean + +/** + * @ClassName RefreshBean + * @Author 用户 + * @Date 2023/9/21 10:53 + * @Description TODO + */ +data class RefreshBean(var page : Int,var limit : Int) diff --git a/app/src/main/java/com/dahe/gldriver/bean/TabBean.kt b/app/src/main/java/com/dahe/gldriver/bean/TabBean.kt new file mode 100644 index 0000000..b9952bc --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/TabBean.kt @@ -0,0 +1,26 @@ +package com.dahe.gldriver.bean + +import com.flyco.tablayout.listener.CustomTabEntity + +/** + * @ClassName TabBean2 + * @Author 用户 + * @Date 2023/12/28 15:27 + * @Description TODO + */ +data class TabBean(var title:String, + var selectedIcon:Int, + var unSelectedIcon:Int + ) : CustomTabEntity { + override fun getTabTitle(): String { + return title + } + + override fun getTabSelectedIcon(): Int { + return selectedIcon + } + + override fun getTabUnselectedIcon(): Int { + return unSelectedIcon + } +} diff --git a/app/src/main/java/com/dahe/gldriver/bean/UserBean.kt b/app/src/main/java/com/dahe/gldriver/bean/UserBean.kt new file mode 100644 index 0000000..c4eea85 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/UserBean.kt @@ -0,0 +1,27 @@ +package com.dahe.glex.bean + +/** + * @ClassName UserBean + * @Author 用户 + * @Date 2023/9/21 09:52 + * @Description TODO + */ +data class UserBean( + var token :String, + var id :String, + var roleId :String, + var uname :String, + var registerPhone :String, + var companyName :String, + var account :String, + var headportraitUrl :String, + var salt :String, + var jumpUrl :String, + var distance :String, + var idCardValidity :String, + var driverValidity :String, + var qualificationValidity :String, + var isCar :String, + var qrcodeUrl :String, + var credit :String + ) diff --git a/app/src/main/java/com/dahe/gldriver/bean/WayBill.kt b/app/src/main/java/com/dahe/gldriver/bean/WayBill.kt new file mode 100644 index 0000000..c36c99a --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/WayBill.kt @@ -0,0 +1,82 @@ + + +/** + * @ClassName WayBill2 + * @Author 用户 + * @Date 2023/9/21 17:48 + * @Description TODO + */ +data class WayBill2( + val acceptTime: String, + val avgScore: Int, + val carNumber: String, + val carType: String, + val contractUrl: String, + val distance: String, + val driverName: String, + val endCountrySubdivisionCode: String, + val isEvaluation: Int, + val nfcId: String, + val operation: Int, + val report: Int, + val reportAlct: Int, + val roleId: Int, + val serialNumber: String, + val shippingNoteNumber: String, + val startCountrySubdivisionCode: String, + val totalAmount: String, + val wayChildren: List, + val waybillId: Int, + val waybillStatus: String +) + +data class WayChildren( + val acceptTime: String, + val address: String, + val carNumber: String, + val carType: String, + val deadline: String, + val deadlineDate: Long, + val delay: Int, + val displayOrder: String, + val distance: String, + val driverName: String, + val goods: List, + val id: Long, + val imageTakenDate: String, + val isEvaluation: Int, + val latitude: String, + val longitude: String, + val name: String, + val orderId: Int, + val phone: String, + val realityTimeDate: Long, + val receiptLatitude: String, + val receiptLocationAddress: String, + val receiptLongitude: String, + val receiptTime: String, + val receiptUrl: List, + val report: Int, + val reportAlct: Int, + val sendPutImagesUrl: List, + val sendPutLatitude: String, + val sendPutLocationAddress: String, + val sendPutLongitude: String, + val shippingNoteNumber: String, + val status: Int, + val totalAmount: String, + val type: Int, + val updateTime: String, + val waybillStatus: String +) + +data class Good( + val childrenId: String, + val createTime: String, + val goodName: String, + val goodNum: String, + val goodPrice: String, + val goodUnit: String, + val id: String, + val packName: String +) \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/bean/WayBillBean.kt b/app/src/main/java/com/dahe/gldriver/bean/WayBillBean.kt new file mode 100644 index 0000000..37426f4 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/bean/WayBillBean.kt @@ -0,0 +1,9 @@ +package com.dahe.glex.bean + +/** + * @ClassName WayBillBean + * @Author 用户 + * @Date 2023/9/21 17:34 + * @Description TODO + */ +data class WayBillBean(var waybillId :String="") diff --git a/app/src/main/java/com/dahe/gldriver/net/Api.kt b/app/src/main/java/com/dahe/gldriver/net/Api.kt new file mode 100644 index 0000000..a74a32e --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/net/Api.kt @@ -0,0 +1,37 @@ +package com.dahe.gldriver.net + +import WayBill2 +import com.dahe.gldriver.BuildConfig +import com.dahe.glex.bean.* +import com.dahe.mylibrary.net.CommonResponseBean +import io.reactivex.rxjava3.core.Observable +import retrofit2.http.Body +import retrofit2.http.POST +import retrofit2.http.Query + + +/** + * Created by Administrator on 2018/8/8 0008. + */ +interface Api { + /*-------------------登录----------------------------*/ + @POST(BASE_URL + "common/register") + fun log(@Body logBean: LogBean?): Observable> + + //运单列表 + @POST(BASE_URL + "app/driver/waybill/listV2") + fun orderList(@Body bean: RefreshBean?): Observable> + + //获取正在执行的运单/运单详情 + @POST(BASE_URL + "app/driver/waybill/getExecuteWaybill") + fun getExecuteWaybill(@Body bean: WayBillBean?): Observable> + fun getExecuteWaybill2(@Query("waybillId") waybillId: String?): Observable> + + companion object { + // String BASE_URL = "https://tmstest.dahehuoyun.com/"; + const val BASE_URL = BuildConfig.BASE_URL + + //获取版本 + const val VERSION = BASE_URL + "app/version" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/net/BaseObserver.kt b/app/src/main/java/com/dahe/gldriver/net/BaseObserver.kt new file mode 100644 index 0000000..279245f --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/net/BaseObserver.kt @@ -0,0 +1,43 @@ +package com.dahe.gldriver.net + +import android.content.Context +import com.dahe.mylibrary.net.CommonResponseBean +import io.reactivex.rxjava3.core.Observer +import io.reactivex.rxjava3.disposables.Disposable + +/** + * 自定义观察者 + */ +class BaseObserver( + private val mContext: Context, + private val mRxHttpCallBack: RxHttpCallBack +) : Observer> { + private var disposable: Disposable? = null + + /** + * 订阅成功 + * + * @param d + */ + override fun onSubscribe(d: Disposable) { + disposable = d + mRxHttpCallBack.onStart() + } + + override fun onNext(tCommonResponseBean: CommonResponseBean) { + if (200 == tCommonResponseBean.code) { + mRxHttpCallBack.onSuccess(tCommonResponseBean) + } else { + mRxHttpCallBack.onCodeError(mContext, tCommonResponseBean) + } + } + + override fun onError(e: Throwable) { + mRxHttpCallBack.onFailure(mContext, e) + if (disposable != null && disposable!!.isDisposed) { + disposable!!.dispose() + } + } + + override fun onComplete() {} +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/net/DataManager.kt b/app/src/main/java/com/dahe/gldriver/net/DataManager.kt new file mode 100644 index 0000000..6a383d6 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/net/DataManager.kt @@ -0,0 +1,33 @@ +package com.dahe.gldriver.net + +import com.dahe.gldriver.utils.BaseSingNoParam +import com.dahe.mylibrary.CommonBaseLibrary +import com.dahe.mylibrary.net.JsonInterceptor +import okhttp3.OkHttpClient +import java.util.concurrent.TimeUnit + +/** + * @ClassName DataManager3 + * @Author 用户 + * @Date 2023/12/29 10:09 + * @Description TODO + */ +class DataManager private constructor(){ + + //伴生对象实现BaseSingleton抽象类 + companion object : BaseSingNoParam() { + //重写方法并给出具体实现 + override fun creator(): Api { + return CommonBaseLibrary.getRetrofit().newBuilder() + .client(OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .addInterceptor(JsonInterceptor()) + .addInterceptor(RequestHeadInterceptor()) + .build()) // .addNetworkInterceptor(new TokenInterceptor()) + .build().create(Api::class.java) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/net/RequestHeadInterceptor.kt b/app/src/main/java/com/dahe/gldriver/net/RequestHeadInterceptor.kt new file mode 100644 index 0000000..9444f66 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/net/RequestHeadInterceptor.kt @@ -0,0 +1,42 @@ +package com.dahe.gldriver.net + +import kotlin.Throws +import com.dahe.gldriver.base.App +import android.text.TextUtils +import android.util.Log +import com.dahe.gldriver.utils.SPUtils +import com.dahe.mylibrary.utils.BaseUtils +import com.dahe.mylibrary.utils.AppUtils +import com.dahe.mylibrary.utils.BaseSPUtils +import okhttp3.Interceptor +import okhttp3.Request +import okhttp3.Response +import java.io.IOException + +/** + * 头部Interceptor + */ +class RequestHeadInterceptor : Interceptor { + @Throws(IOException::class) + override fun intercept(chain: Interceptor.Chain): Response { + val builder: Request.Builder = chain.request().newBuilder() + if (BaseSPUtils.hasUserInfo(App.app) && !TextUtils.isEmpty(SPUtils.instance.getUserInfo(App.app)?.token)) { + +// builder.addHeader("Authorization", SPUtils.getUserInfo(App.getApp()).getToken()); + builder.addHeader("Authorization", + "Bearer " + SPUtils.instance.getUserInfo(App.app)?.token) + } + val request: Request = builder + .addHeader("versionCode", AppUtils.getAppVersionCode().toString() + "") + .addHeader("versionValue", AppUtils.getAppVersionName() + "") + .addHeader("deviceType", "ANDROID") + .addHeader("language", BaseUtils.getLanguage(App.app).toString() + "") + .build() + Log.i(TAG, "intercept: " + request.headers) + return chain.proceed(request) + } + + companion object { + private const val TAG = "RequestHeadInterceptor" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/net/RxHttpCallBack.kt b/app/src/main/java/com/dahe/gldriver/net/RxHttpCallBack.kt new file mode 100644 index 0000000..5874cf1 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/net/RxHttpCallBack.kt @@ -0,0 +1,126 @@ +package com.dahe.gldriver.net + +import android.accounts.NetworkErrorException +import android.app.Activity +import android.app.ProgressDialog +import com.dahe.gldriver.utils.UserUtils.Companion.instance +import android.content.Context +import android.text.TextUtils +import android.view.Window +import com.dahe.mylibrary.net.CommonResponseBean +import com.dahe.mylibrary.net.ResultException +import com.dahe.mylibrary.utils.ToastUtils +import java.net.ConnectException +import java.net.SocketTimeoutException +import java.net.UnknownHostException +import java.util.concurrent.TimeoutException +import javax.net.ssl.SSLException + +/** + * 统一的网络回调 + */ +abstract class RxHttpCallBack { + private var dialog: ProgressDialog? = null + private fun initDialog(activity: Activity, dialogMessage: String) { + dialog = ProgressDialog(activity) + dialog!!.requestWindowFeature(Window.FEATURE_NO_TITLE) + dialog!!.setCanceledOnTouchOutside(false) + dialog!!.setProgressStyle(ProgressDialog.STYLE_SPINNER) + dialog!!.setMessage(dialogMessage) + } + + constructor(activity: Activity, dialogMessage: String?) { + initDialog(activity, + (if (TextUtils.isEmpty(dialogMessage)) "网络请求中......" else dialogMessage)!!) + } + + constructor(activity: Activity) { + initDialog(activity, "网络请求中......") + } + + constructor() {} + + /** + * 订阅成功 + */ + fun onStart() { + if (dialog != null && !dialog!!.isShowing) { + dialog!!.show() + } + } + + fun onStop() { + if (dialog != null && dialog!!.isShowing) { + dialog!!.dismiss() + } + } + + /** + * 返回成功 + * + * @param t + * @throws Exception + */ + fun onSuccess(t: CommonResponseBean) { + if (dialog != null && dialog!!.isShowing) { + dialog!!.dismiss() + } + } + + /** + * 返回成功了,但是code错误 + * + * @param t + * @throws Exception + */ + fun onCodeError(mContext: Context?, t: CommonResponseBean) { + if (dialog != null && dialog!!.isShowing) { + dialog!!.dismiss() + } + if (t.code == 401) { + instance.loginOut(mContext!!) + // Intent intent = new Intent(mContext, LoginActivity.class); +// intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); +// mContext.startActivity(intent); + ToastUtils.showToast(mContext, "您的账号再异地登录,请重新登录") + } else { + ToastUtils.showToast(mContext, t.msg) + } + +// if (t.getMessage().getMsg_code() == 100 && SPUtils.hasUserInfo(mContext)) { +// SPUtils.remove(mContext, SPUtils.USER_INFO_KEY); +// } else { +// ToastUtils.showToast(mContext, t.getMessage().getMsg_desc()); +// } + } + + /** + * 返回失败 + * + * @param e + * @throws Exception + */ + fun onFailure(mContext: Context?, e: Throwable) { + if (dialog != null && dialog!!.isShowing) { + dialog!!.dismiss() + } + if (e is ConnectException + || e is TimeoutException + || e is SocketTimeoutException + || e is SSLException + || e is NetworkErrorException + || e is UnknownHostException + ) { + ToastUtils.showToast(mContext, "请检查您的网络~") + } else if (e is ResultException) { + e.printStackTrace() + //自定义的ResultException + //由于返回200,300返回格式不统一的问题,自定义GsonResponseBodyConverter凡是300的直接抛异常 +// System.out.println("---------errorCode------->"+((ResultException) e).getErrCode()); + } else if (e is SSLException) { + ToastUtils.showToast(mContext, "网络连接终端,请检查您的网络~") + } else { + ToastUtils.showToast(mContext, e.message) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/net/TokenInterceptor.kt b/app/src/main/java/com/dahe/gldriver/net/TokenInterceptor.kt new file mode 100644 index 0000000..f28f201 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/net/TokenInterceptor.kt @@ -0,0 +1,44 @@ +package com.dahe.gldriver.net + +import okhttp3.Interceptor +import okhttp3.Request +import okhttp3.Response +import kotlin.Throws +import org.json.JSONObject +import java.io.IOException +import java.lang.Exception +import java.nio.charset.StandardCharsets + +class TokenInterceptor : Interceptor { + @Throws(IOException::class) + override fun intercept(chain: Interceptor.Chain): Response { + val request: Request = chain.request() + val response: Response = chain.proceed(request) + val responseBody = response.body + if (responseBody != null) { + val source = responseBody.source() + source.request(Long.MAX_VALUE) // Buffer the entire body. + val buffer = source.buffer() + try { + val result = buffer.clone().readString(StandardCharsets.UTF_8) + val jsonObject = JSONObject(result) + val code = jsonObject.getInt("code") + if (code == -1) { //判断返回code + +// SPUtils.cleanUserInfo(App.getApp()); +// Intent intent = new Intent(App.getApp(), LoginActivity.class); +// intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); +// App.getApp().startActivity(intent); +// ToastUtils.showToast(App.getApp(), "您的账号再异地登录,请重新登录"); +// ToastUtils.showShort("身份过期,请重新登录"); + //跳转方式 + //1.使用MyApplication添加跳转 + //2.使用路由跳转 + } + } catch (e: Exception) { + e.printStackTrace() + } + } + return response + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/HomeActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/HomeActivity.kt new file mode 100644 index 0000000..7f613fb --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/HomeActivity.kt @@ -0,0 +1,106 @@ +package com.dahe.gldriver.ui + +import android.Manifest +import android.os.Build +import android.os.Bundle +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.viewpager.widget.ViewPager +import com.dahe.gldriver.R +import com.dahe.gldriver.adapter.MyHomePagerAdapter +import com.dahe.gldriver.bean.TabBean +import com.dahe.gldriver.databinding.ActivityHomeBinding +import com.dahe.gldriver.ui.home.HomeFragment +import com.dahe.gldriver.ui.message.MessageFragment +import com.dahe.gldriver.ui.mine.MineFragment +import com.dahe.gldriver.ui.waybill.WaybillFragment +import com.dahe.mylibrary.base.BaseActivity +import com.flyco.tablayout.listener.CustomTabEntity +import com.flyco.tablayout.listener.OnTabSelectListener +import com.permissionx.guolindev.PermissionX + +/** + * @ClassName HomeActivity + * @Author 用户 + * @Date 2023/12/27 17:12 + * @Description TODO + */ +class HomeActivity: BaseActivity(), OnTabSelectListener, + ViewPager.OnPageChangeListener { + + private val mNormalRes = mutableListOf( + R.drawable.tab_home_normal, + R.drawable.tab_message_normal, + R.drawable.tab_waybill_normal, + R.drawable.tab_mine_normal + ) + + + private val mSelectRes = mutableListOf( + R.drawable.tab_home_press, + R.drawable.tab_message_press, + R.drawable.tab_waybill_press, + R.drawable.tab_mine_press + ) + private var mTitles = arrayOf("首页","消息","运单","我的") + private var mTabEntities = arrayListOf( + TabBean(mTitles[0],mSelectRes[0],mNormalRes[0]), + TabBean(mTitles[1],mSelectRes[1],mNormalRes[1]), + TabBean(mTitles[2],mSelectRes[2],mNormalRes[2]), + TabBean(mTitles[3],mSelectRes[3],mNormalRes[3])) + private var mFragments = arrayListOf(HomeFragment(),MessageFragment(), WaybillFragment(),MineFragment()) + + override fun initView(savedInstanceState: Bundle?) { + + binding.homeTabLayout.run { + setTabData(mTabEntities) + setOnTabSelectListener(this@HomeActivity) + currentTab=0 + } + + binding.homeNoScrollViewPager.run { + adapter = MyHomePagerAdapter(this@HomeActivity.supportFragmentManager, mTitles, mFragments) + addOnPageChangeListener(this@HomeActivity) + offscreenPageLimit = 3 + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + getPermissions() + } + + + } + + override fun initDate() { + } + + private fun getPermissions() { + PermissionX.init(this) + .permissions( + Manifest.permission.CAMERA) + .request { allGranted, grantedList, deniedList -> + if (allGranted) { + + } else { + Toast.makeText(mContext, "开启权限失败,请在应用设置-权限-定位-始终允许", Toast.LENGTH_SHORT).show() + } + } + } + + override fun onTabSelect(position: Int) { + binding.homeNoScrollViewPager.setCurrentItem(position) + } + + override fun onTabReselect(position: Int) { + } + + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + } + + override fun onPageSelected(position: Int) { + binding.homeTabLayout.setCurrentTab(position) + } + + override fun onPageScrollStateChanged(state: Int) { + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/LauncherActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/LauncherActivity.kt new file mode 100644 index 0000000..85cf5d2 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/LauncherActivity.kt @@ -0,0 +1,86 @@ +package com.dahe.gldriver.ui + +import android.os.Bundle +import android.view.WindowManager +import com.dahe.gldriver.databinding.ActivityLauncherBinding +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils +import com.dahe.gldriver.ui.account.LoginActivity +import com.dahe.gldriver.utils.SPUtils +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Observable +import io.reactivex.rxjava3.disposables.Disposable +import io.reactivex.rxjava3.schedulers.Schedulers +import java.util.concurrent.TimeUnit + +class LauncherActivity : BaseActivity() { + + + override fun initView(savedInstanceState: Bundle?) { +// setStatusBarColorToLight2() + val extras = intent.extras + binding.llCount.setOnClickListener { + mDisposable?.dispose() + //已登录,直接跳转首页 +// val userInfo = SPUtils.getUserInfo(mContext) +// +// if (userInfo != null && StringUtils.isNotEmpty(userInfo.token)) { +// ActivityUtils.startActivity(mContext, HomeActivity::class.java,intent.extras) +// } else { +// ActivityUtils.startActivity(this@LauncherActivity, LoginActivity::class.java) +// } +// window.setFlags( +// WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, +// WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + ActivityUtils.startActivity(this@LauncherActivity, LoginActivity::class.java) + finish() + } + val count = 3 + mDisposable = Observable.interval(0, 1, TimeUnit.SECONDS) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { aLong: Long -> + binding.tvCount.setText((count - aLong).toString()) + if (count - aLong == 0L) { + mDisposable?.dispose() + //已登录,直接跳转首页 + //已登录,直接跳转首页 +// val userInfo: UserBean? = SPUtils.getUserInfo(mContext) +// +// if (userInfo != null && !TextUtils.isEmpty(userInfo.getToken())) { +// ActivityUtils.startActivity(mContext, HomeActivity::class.java,intent.extras) +// } else { +// ActivityUtils.startActivity( +// this@LauncherActivity, +// LoginActivity::class.java +// ) +// +// } + +// ActivityUtils.startActivity( +// this@LauncherActivity, +// LoginActivity::class.java +// ) + + +// window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) +// window.setFlags( +// WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, +// WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + +// finish() + } + + } + } + + private var mDisposable: Disposable? = null + + override fun initDate() { + } + + override fun onDestroy() { + super.onDestroy() + mDisposable?.dispose() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/CodeLoginActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/CodeLoginActivity.kt new file mode 100644 index 0000000..0d67b16 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/CodeLoginActivity.kt @@ -0,0 +1,39 @@ +package com.dahe.gldriver.ui.account + +import android.os.Bundle +import android.view.View +import com.dahe.gldriver.databinding.ActivityCodeBinding +import com.dahe.gldriver.databinding.ActivityLoginBinding +import com.dahe.gldriver.ui.HomeActivity +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils +import com.dahe.mylibrary.utils.SmsTimeUtils +import kotlin.math.log + +/** + * @ClassName LoginActivity + * @Author 用户 + * @Date 2024/1/17 08:51 + * @Description TODO + */ +class CodeLoginActivity : BaseActivity(), View.OnClickListener { + override fun initView(savedInstanceState: Bundle?) { + + + binding.tvLoginType.setOnClickListener(this) + } + + override fun initDate() { + } + + override fun onClick(view: View?) { + super.onClick(view) + } + + private fun changeLoginType() { + } + + private fun login(){ + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/LoginActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/LoginActivity.kt new file mode 100644 index 0000000..e3db6ac --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/LoginActivity.kt @@ -0,0 +1,81 @@ +package com.dahe.gldriver.ui.account + +import android.os.Bundle +import android.view.View +import com.dahe.gldriver.databinding.ActivityLoginBinding +import com.dahe.gldriver.ui.HomeActivity +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils + +/** + * @ClassName LoginActivity + * @Author 用户 + * @Date 2024/1/17 08:51 + * @Description TODO + */ +class LoginActivity : BaseActivity(), View.OnClickListener { + override fun initView(savedInstanceState: Bundle?) { + binding.cb.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { +// et_pass.setTransformationMethod(PasswordTransformationMethod.getInstance()) + } else { +// et_pass.setTransformationMethod(HideReturnsTransformationMethod.getInstance()) + } +// et_pass.setSelection(et_pass.getText().toString().length) + } +// +// binding.btnLogin.setOnClickListener { +// ActivityUtils.startActivity(this, HomeActivity::class.java) +//// ActivityUtils.startActivity(this, TextActivity::class.java) +// } +// +// binding.getCode.setOnClickListener { +// SmsTimeUtils.startCountdown(binding.getCode,mContext) +// } + + binding.tvLoginType.setOnClickListener(this) + binding.ok.setOnClickListener(this) + + binding.imgHead.setOnLongClickListener { + ActivityUtils.startActivity(mContext, HomeActivity::class.java) + return@setOnLongClickListener true + } + } + + override fun initDate() { + } + + override fun onClick(view: View?) { + super.onClick(view) + when (view?.id) { + binding.tvLoginType.id -> { + changeLoginType() + } + + binding.ok.id -> { + login() + } + } + } + + private fun changeLoginType() { + if ("手机号登录/注册" == binding.tvLoginType.text) { + binding.tvLoginType.text = "本机号码一键登录" + binding.ok.text = "获取验证码" + binding.llPhone.visibility = View.VISIBLE + } else { + binding.tvLoginType.text = "手机号登录/注册" + binding.ok.text = "本机号码一键登录/注册" + binding.llPhone.visibility = View.GONE + } + } + + private fun login() { + if ("获取验证码" == binding.ok.text) { + ActivityUtils.startActivity(mContext, CodeLoginActivity::class.java) + }else{ + ActivityUtils.startActivity(mContext, SelectRoleActivity::class.java) + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/SelectRoleActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/SelectRoleActivity.kt new file mode 100644 index 0000000..be793ac --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/SelectRoleActivity.kt @@ -0,0 +1,31 @@ +package com.dahe.gldriver.ui.account + +import android.os.Bundle +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivitySelectRoleBinding +import com.dahe.gldriver.ui.account.authperson.AuthPersonActivity +import com.dahe.gldriver.ui.account.authteam.AuthTeamActivity +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils + +/** + * @ClassName AuthRoleActivity + * @Author 用户 + * @Date 2024/1/25 11:15 + * @Description 选择角色 (独立司机或者运输公司) + */ +class SelectRoleActivity : BaseActivity() { + override fun initView(savedInstanceState: Bundle?) { + setStatusBarColor(R.color.white) + setTitleBar("选择角色",true) + binding.rlPerson.setOnClickListener { + ActivityUtils.startActivity(mContext, AuthPersonActivity::class.java) + } + binding.rlCom.setOnClickListener { + ActivityUtils.startActivity(mContext, AuthTeamActivity::class.java) + } + } + + override fun initDate() { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthBankCardActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthBankCardActivity.kt new file mode 100644 index 0000000..8244692 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthBankCardActivity.kt @@ -0,0 +1,26 @@ +package com.dahe.gldriver.ui.account.authperson + +import android.os.Bundle +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivityAuthBankcardBinding +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils + +/** + * @ClassName AuthBankCardActivity + * @Author john + * @Date 2024/1/25 15:31 + * @Description TODO + */ +class AuthBankCardActivity : BaseActivity() { + override fun initView(savedInstanceState: Bundle?) { + setStatusBarColor(R.color.white) + setTitleBar("实名认证",true) + binding.btnOk.setOnClickListener { + ActivityUtils.startActivity(mContext,AuthFaceActivity::class.java) + } + } + + override fun initDate() { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthDriverActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthDriverActivity.kt new file mode 100644 index 0000000..6ad1640 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthDriverActivity.kt @@ -0,0 +1,26 @@ +package com.dahe.gldriver.ui.account.authperson + +import android.os.Bundle +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivityAuthDriverBinding +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils + +/** + * @ClassName AuthRoleActivity + * @Author 用户 + * @Date 2024/1/25 11:15 + * @Description 驾驶证认证 + */ +class AuthDriverActivity : BaseActivity() { + override fun initView(savedInstanceState: Bundle?) { + setStatusBarColor(R.color.white) + setTitleBar("实名认证",true) + binding.btnOk.setOnClickListener { + ActivityUtils.startActivity(mContext,AuthQualificationActivity::class.java) + } + } + + override fun initDate() { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthDrivingActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthDrivingActivity.kt new file mode 100644 index 0000000..6a86e1a --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthDrivingActivity.kt @@ -0,0 +1,26 @@ +package com.dahe.gldriver.ui.account.authperson + +import android.os.Bundle +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivityAuthDrivingBinding +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils + +/** + * @ClassName AuthRoleActivity + * @Author 用户 + * @Date 2024/1/25 11:15 + * @Description 行驶证认证 + */ +class AuthDrivingActivity : BaseActivity() { + override fun initView(savedInstanceState: Bundle?) { + setStatusBarColor(R.color.white) + setTitleBar("实名认证",true) + binding.btnOk.setOnClickListener { + ActivityUtils.startActivity(mContext,AuthRoadActivity::class.java) + } + } + + override fun initDate() { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthFaceActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthFaceActivity.kt new file mode 100644 index 0000000..e7e6738 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthFaceActivity.kt @@ -0,0 +1,26 @@ +package com.dahe.gldriver.ui.account.authperson + +import android.os.Bundle +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivityAuthFaceBinding +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils + +/** + * @ClassName AuthFaceActivity + * @Author john + * @Date 2024/1/25 15:38 + * @Description TODO + */ +class AuthFaceActivity : BaseActivity() { + override fun initView(savedInstanceState: Bundle?) { + setStatusBarColor(R.color.white) + setTitleBar("实名认证",true) + binding.btnOk.setOnClickListener { + ActivityUtils.startActivity(mContext,AuthDrivingActivity::class.java) + } + } + + override fun initDate() { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthPersonActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthPersonActivity.kt new file mode 100644 index 0000000..316dc4f --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthPersonActivity.kt @@ -0,0 +1,26 @@ +package com.dahe.gldriver.ui.account.authperson + +import android.os.Bundle +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivityAuthPersonBinding +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils + +/** + * @ClassName AuthRoleActivity + * @Author 用户 + * @Date 2024/1/25 11:15 + * @Description 身份证认证 + */ +class AuthPersonActivity : BaseActivity() { + override fun initView(savedInstanceState: Bundle?) { + setStatusBarColor(R.color.white) + setTitleBar("实名认证",true) + binding.btnOk.setOnClickListener { + ActivityUtils.startActivity(mContext,AuthDriverActivity::class.java) + } + } + + override fun initDate() { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthQualificationActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthQualificationActivity.kt new file mode 100644 index 0000000..427dd87 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthQualificationActivity.kt @@ -0,0 +1,26 @@ +package com.dahe.gldriver.ui.account.authperson + +import android.os.Bundle +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivityAuthQualificationBinding +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils + +/** + * @ClassName AuthQualificationActivity + * @Author john + * @Date 2024/1/25 15:20 + * @Description 从业资格证认证 + */ +class AuthQualificationActivity : BaseActivity(){ + override fun initView(savedInstanceState: Bundle?) { + setStatusBarColor(R.color.white) + setTitleBar("实名认证",true) + binding.btnOk.setOnClickListener { + ActivityUtils.startActivity(mContext,AuthBankCardActivity::class.java) + } + } + + override fun initDate() { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthRoadActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthRoadActivity.kt new file mode 100644 index 0000000..5ae3a52 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/authperson/AuthRoadActivity.kt @@ -0,0 +1,27 @@ +package com.dahe.gldriver.ui.account.authperson + +import android.os.Bundle +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivityAuthRoadBinding +import com.dahe.gldriver.ui.account.SelectRoleActivity +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.utils.ActivityUtils + +/** + * @ClassName AuthRoadActivity + * @Author john + * @Date 2024/1/25 16:02 + * @Description 道路运输许可证认证 + */ +class AuthRoadActivity : BaseActivity() { + override fun initView(savedInstanceState: Bundle?) { + setStatusBarColor(R.color.white) + setTitleBar("实名认证",true) + binding.btnOk.setOnClickListener { + ActivityUtils.startActivity(mContext, SelectRoleActivity::class.java) + } + } + + override fun initDate() { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/account/authteam/AuthTeamActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/account/authteam/AuthTeamActivity.kt new file mode 100644 index 0000000..10c3d24 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/account/authteam/AuthTeamActivity.kt @@ -0,0 +1,41 @@ +package com.dahe.gldriver.ui.account.authteam + +import android.os.Bundle +import android.view.View +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivityAuthTeamBinding +import com.dahe.mylibrary.base.BaseActivity + +/** + * @ClassName AuthTeamActivity + * @Author john + * @Date 2024/1/25 16:44 + * @Description 个人车队认证 + */ +class AuthTeamActivity : BaseActivity() { + private var checkTeamType = 0 //0代表运输公司,1代表个人车队 + + + override fun initView(savedInstanceState: Bundle?) { + setStatusBarColor(R.color.white) + setTitleBar("身份认证",true) + + binding.rgTeam.setOnCheckedChangeListener { _, i -> + changeTeamType(if (i==binding.rbCom.id) 0 else 1) + } + } + + override fun initDate() { + } + + private fun changeTeamType(type : Int){ + checkTeamType = type + if (0==checkTeamType){ + binding.llCom.visibility = View.VISIBLE + binding.llPerson.visibility = View.GONE + }else{ + binding.llCom.visibility = View.GONE + binding.llPerson.visibility = View.VISIBLE + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/home/HomeFragment.kt b/app/src/main/java/com/dahe/gldriver/ui/home/HomeFragment.kt new file mode 100644 index 0000000..926e169 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/home/HomeFragment.kt @@ -0,0 +1,100 @@ +package com.dahe.gldriver.ui.home + +import android.graphics.Color +import android.widget.LinearLayout +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.listener.OnItemChildClickListener +import com.chad.library.adapter.base.listener.OnItemClickListener +import com.dahe.gldriver.R +import com.dahe.gldriver.adapter.GridItemAdapter +import com.dahe.gldriver.adapter.WaybillAdapter +import com.dahe.gldriver.bean.GridBean +import com.dahe.gldriver.databinding.FragmentHomeBinding +import com.dahe.gldriver.ui.HomeActivity +import com.dahe.gldriver.ui.waybill.activity.WaybillDetailActivity +import com.dahe.glex.bean.WayBillBean +import com.dahe.mylibrary.base.BaseFragment +import com.dahe.mylibrary.callback.RefreshCallBack +import com.dahe.mylibrary.recycleviewswipe.RecycleViewDivider +import com.dahe.mylibrary.utils.ActivityUtils +import com.dahe.mylibrary.utils.ConvertUtils +import com.dahe.mylibrary.utils.ToastUtils +import com.flyco.tablayout.listener.OnTabSelectListener +import okhttp3.internal.wait + +/** + * @ClassName HomeFragment + * @Author 用户 + * @Date 2023/9/21 10:13 + * @Description TODO + */ +class HomeFragment : BaseFragment(), RefreshCallBack { + private val gridDatas = mutableListOf( + GridBean("司机之家", R.drawable.home_driver), + GridBean("咨询客服", R.drawable.home_ask), + GridBean("问卷调查", R.drawable.home_que), + GridBean("知识竞赛", R.drawable.home_know), + ) + + override fun onFragmentVisibleChange(isVisible: Boolean) { + if (isVisible) { + } + + } + + override fun onFragmentFirstVisible() { + initRecy() + binding.gridView.run { + adapter = activity?.let { GridItemAdapter(it, gridDatas) } + setOnItemClickListener { adapterView, view, i, l -> +// println(i) + } + } + + binding.tvMar.isSelected = true + + } + + + override fun getRefreshDate(stat: Int, page: Int, count: Int) { + + } + + private fun initRecy() { + var datas = mutableListOf( + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean() + ) + var adapter = binding.recyclerView.run { + layoutManager = LinearLayoutManager(mContext, RecyclerView.VERTICAL, false) + setHasFixedSize(true) + addItemDecoration( + RecycleViewDivider( + LinearLayout.VERTICAL, + ConvertUtils.dp2px(16.0f), + Color.TRANSPARENT + ) + ) + adapter = WaybillAdapter() + adapter as WaybillAdapter + }.apply { + setOnItemClickListener(OnItemClickListener { adapter, view, position -> + ToastUtils.showToast(mContext,position.toString()) + }) + addChildClickViewIds(R.id.btnOk) + setOnItemChildClickListener() { adapter, view, position -> + ActivityUtils.startActivity(mContext,WaybillDetailActivity::class.java) + } + } + adapter.addData(datas) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/message/MessageFragment.kt b/app/src/main/java/com/dahe/gldriver/ui/message/MessageFragment.kt new file mode 100644 index 0000000..1e10d5d --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/message/MessageFragment.kt @@ -0,0 +1,80 @@ +package com.dahe.gldriver.ui.message + +import android.content.Context +import android.graphics.Color +import android.widget.LinearLayout +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.dahe.gldriver.R +import com.dahe.gldriver.adapter.MessageAdapter +import com.dahe.gldriver.databinding.FragmentMessageBinding +import com.dahe.gldriver.databinding.FragmentWaybillBinding +import com.dahe.glex.bean.WayBillBean +import com.dahe.mylibrary.base.BaseFragment +import com.dahe.mylibrary.callback.RefreshCallBack +import com.dahe.mylibrary.recycleviewswipe.RecycleViewDivider +import com.dahe.mylibrary.utils.ConvertUtils +import net.lucode.hackware.magicindicator.ViewPagerHelper +import net.lucode.hackware.magicindicator.buildins.commonnavigator.CommonNavigator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerTitleView +import net.lucode.hackware.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.ColorTransitionPagerTitleView + + +/** + * @ClassName HomeFragment + * @Author 用户 + * @Date 2023/9/21 10:13 + * @Description TODO + */ +class MessageFragment : BaseFragment(), RefreshCallBack { + + + override fun onFragmentVisibleChange(isVisible: Boolean) { + if (isVisible) { + } + + } + + override fun onFragmentFirstVisible() { + initRecy() + + } + + + override fun getRefreshDate(stat: Int, page: Int, count: Int) { + + } + + private fun initRecy() { + var datas = mutableListOf( + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean() + ) + + var adapter = binding.recyclerView.run { + layoutManager = LinearLayoutManager(mContext,RecyclerView.VERTICAL,false) + addItemDecoration( + RecycleViewDivider( + LinearLayout.VERTICAL, + ConvertUtils.dp2px(16.0f), + Color.TRANSPARENT + ) + ) + setHasFixedSize(true) + adapter = MessageAdapter() + adapter as MessageAdapter + } + + adapter.addData(datas) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/mine/MineFragment.kt b/app/src/main/java/com/dahe/gldriver/ui/mine/MineFragment.kt new file mode 100644 index 0000000..8b3e445 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/mine/MineFragment.kt @@ -0,0 +1,103 @@ +package com.dahe.gldriver.ui.mine + +import android.view.View +import com.dahe.gldriver.R +import com.dahe.gldriver.adapter.GridItemAdapter +import com.dahe.gldriver.bean.GridBean +import com.dahe.gldriver.databinding.FragmentMineBinding +import com.dahe.gldriver.utils.SPUtils +import com.dahe.mylibrary.base.BaseFragment +import com.dahe.mylibrary.utils.ToastUtils +import com.tencent.bugly.crashreport.CrashReport + +class MineFragment : BaseFragment(), View.OnClickListener { + private val tools = mutableListOf( + GridBean("车队管理", R.drawable.car_team), + GridBean("车辆管理", R.drawable.car_manage), + GridBean("司机课堂", R.drawable.mine_class), + GridBean("评价管理", R.drawable.rate) + ) + + private val plats = mutableListOf( + GridBean("平台规则", R.drawable.rules), + GridBean("常见问题", R.drawable.question), + GridBean("联系我们", R.drawable.call_us), + GridBean("意见反馈", R.drawable.opin), + GridBean("红色方向盘", R.drawable.part_dir), + GridBean("检查更新", R.drawable.update), + GridBean("关于我们", R.drawable.about), + GridBean("设置", R.drawable.setting) + ) + + override fun onFragmentVisibleChange(isVisible: Boolean) { + if (isVisible) { + } else { + } + } + + + override fun onFragmentFirstVisible() { + +// val userInfo = SPUtils.instance.getUserInfo(mContext) +// if (null==userInfo) +// return + + binding.gvTools.run { + + adapter = GridItemAdapter(mContext, tools, R.layout.grid_mine_item) + setOnItemClickListener { _, _, i, _ -> + goTools(i) + } + } + + binding.gvPlat.run { + adapter = GridItemAdapter(mContext, plats, R.layout.grid_mine_item) + setOnItemClickListener { _, _, i, _ -> + goPlats(i) + } + } + + } + + override fun onClick(v: View) { + when (v.id) { +// R.id.rlPass->ActivityUtils.startActivity(mContext,ChangePwdActivity::class.java) +// R.id.rlPhone-> AppActivityUtils.openWebViewActivity(mContext, "隐私政策", +// "http://tms.down.user.test.dahehuodongbao.com/user-privacy.html") +//// R.id.rlPhone->ActivityUtils.startActivity(mContext,ChangePhoneActivity::class.java) +// R.id.btnOut-> CrashReport.testJavaCrash(); + } + } + + fun logOut() { +// UserUtils.instance.loginOut(requireActivity()) +// val intent = Intent(mContext, LoginActivity::class.java) +// intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK +// requireActivity().startActivity(intent) + } + + + private fun goTools(pos: Int) { + when (pos) { + 0 -> { + ToastUtils.showToast(mContext, tools[pos].title) + } + 1 -> { + ToastUtils.showToast(mContext, tools[pos].title) + } + 2 -> { + ToastUtils.showToast(mContext, tools[pos].title) + } + 3 -> { + ToastUtils.showToast(mContext, tools[pos].title) + } + + } + } + + private fun goPlats(pos: Int) { + ToastUtils.showToast(mContext, plats[pos].title) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/waybill/WaybillFragment.kt b/app/src/main/java/com/dahe/gldriver/ui/waybill/WaybillFragment.kt new file mode 100644 index 0000000..3f6a9e0 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/waybill/WaybillFragment.kt @@ -0,0 +1,127 @@ +package com.dahe.gldriver.ui.waybill + +import android.content.Context +import android.graphics.Color +import androidx.fragment.app.Fragment +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.FragmentWaybillBinding +import com.dahe.gldriver.ui.waybill.fragment.AllWaybillFragment +import com.dahe.mylibrary.base.BaseFragment +import com.dahe.mylibrary.callback.RefreshCallBack +import net.lucode.hackware.magicindicator.FragmentContainerHelper +import net.lucode.hackware.magicindicator.buildins.UIUtil +import net.lucode.hackware.magicindicator.buildins.commonnavigator.CommonNavigator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerTitleView +import net.lucode.hackware.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.ColorTransitionPagerTitleView + + +/** + * @ClassName HomeFragment + * @Author 用户 + * @Date 2023/9/21 10:13 + * @Description TODO + */ +class WaybillFragment : BaseFragment(), RefreshCallBack { + + private val mFragmentContainerHelper = FragmentContainerHelper() + var mFragments = listOf(AllWaybillFragment(),AllWaybillFragment(),AllWaybillFragment(),AllWaybillFragment(),AllWaybillFragment()) + val titles = mutableListOf( + "全部", + "待装货", + "待卸货", + "待评价", + "取消" + ) + + override fun onFragmentVisibleChange(isVisible: Boolean) { + if (isVisible) { + } + + } + + override fun onFragmentFirstVisible() { + initRecy() + + + + mFragmentContainerHelper.handlePageSelected(0,true) + switchPages(0) + + var commonNavigator = CommonNavigator(mContext) + commonNavigator.run { + isAdjustMode = true + adapter = object : CommonNavigatorAdapter() { + override fun getCount(): Int { + return titles.size + } + + override fun getTitleView(context: Context?, index: Int): IPagerTitleView { + val colorTransitionPagerTitleView = ColorTransitionPagerTitleView(context) + colorTransitionPagerTitleView.normalColor = Color.BLACK + colorTransitionPagerTitleView.selectedColor = Color.RED + colorTransitionPagerTitleView.text = titles[index] + colorTransitionPagerTitleView.setOnClickListener { + mFragmentContainerHelper.handlePageSelected(index) + switchPages(index) + } + return colorTransitionPagerTitleView + } + + override fun getIndicator(context: Context?): IPagerIndicator { +// val indicator = LinePagerIndicator(context) +// indicator.mode = LinePagerIndicator.MODE_WRAP_CONTENT +// return indicator + + val indicator = LinePagerIndicator(context) + indicator.mode = LinePagerIndicator.MODE_WRAP_CONTENT + indicator.yOffset = + UIUtil.dip2px(context, 3.0).toFloat() + indicator.setColors(Color.RED) + return indicator + } + + } + } + + binding.magicIndicator.navigator = commonNavigator + mFragmentContainerHelper.attachMagicIndicator(binding.magicIndicator) +// ViewPagerHelper.bind(binding.magicIndicator, binding.viewPager); + } + + + override fun getRefreshDate(stat: Int, page: Int, count: Int) { + + } + + private fun initRecy() { + + } + private fun switchPages(index: Int) { + val fragmentManager = requireActivity().supportFragmentManager + val fragmentTransaction = fragmentManager.beginTransaction() + var fragment: Fragment + var i = 0 + val j: Int = mFragments.size + while (i < j) { + if (i == index) { + i++ + continue + } + fragment = mFragments[i] + if (fragment.isAdded) { + fragmentTransaction.hide(fragment) + } + i++ + } + fragment = mFragments[index] + if (fragment.isAdded) { + fragmentTransaction.show(fragment) + } else { + fragmentTransaction.add(R.id.fragmentContainer, fragment) + } + fragmentTransaction.commitAllowingStateLoss() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/waybill/activity/WaybillDetailActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/waybill/activity/WaybillDetailActivity.kt new file mode 100644 index 0000000..723764a --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/waybill/activity/WaybillDetailActivity.kt @@ -0,0 +1,21 @@ +package com.dahe.gldriver.ui.waybill.activity + +import android.graphics.Color +import android.os.Bundle +import com.dahe.gldriver.R +import com.dahe.gldriver.databinding.ActivityWaybillDetailBinding +import com.dahe.mylibrary.base.BaseActivity + +/** + * @ClassName WaybillDetailActivity + * @Author john + * @Date 2024/1/26 14:50 + * @Description 运单详情-接单 + */ +class WaybillDetailActivity :BaseActivity(){ + override fun initView(savedInstanceState: Bundle?) { + } + + override fun initDate() { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/waybill/fragment/AllWaybillFragment.kt b/app/src/main/java/com/dahe/gldriver/ui/waybill/fragment/AllWaybillFragment.kt new file mode 100644 index 0000000..db8595d --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/waybill/fragment/AllWaybillFragment.kt @@ -0,0 +1,43 @@ +package com.dahe.gldriver.ui.waybill.fragment + +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.dahe.gldriver.adapter.WaybillListAdapter +import com.dahe.gldriver.databinding.FragmentWaybillBinding +import com.dahe.gldriver.databinding.FragmentWaybillListBinding +import com.dahe.glex.bean.WayBillBean +import com.dahe.mylibrary.base.BaseFragment + +/** + * @ClassName AllWaybillFragment + * @Author 用户 + * @Date 2024/1/24 14:06 + * @Description TODO + */ +class AllWaybillFragment : BaseFragment() { + + + override fun onFragmentVisibleChange(isVisible: Boolean) { + + } + + override fun onFragmentFirstVisible() { + var datas = mutableListOf( + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean() + ) + var adapter = binding.recyclerView.run { + layoutManager = LinearLayoutManager(mContext,RecyclerView.VERTICAL,false) + setHasFixedSize(true) + adapter = WaybillListAdapter() + adapter as WaybillListAdapter + } + adapter.addData(datas) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/utils/BaseSingleton.kt b/app/src/main/java/com/dahe/gldriver/utils/BaseSingleton.kt new file mode 100644 index 0000000..b866cc4 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/utils/BaseSingleton.kt @@ -0,0 +1,38 @@ +package com.dahe.gldriver.utils + +/** + * @ClassName BaseSingleton + * @Author 用户 + * @Date 2023/12/29 09:49 + * @Description //要实现单例类,就只需要继承这个 BaseSingleton 即可 + //P为参数,T为返回值 + */ +abstract class BaseSingleton { + + @Volatile + private var instance: T? = null + + //抽象方法,需要我们在具体的单例子类当中实现此方法 + protected abstract fun creator(param: P?): T + + fun getInstance(param: P?): T = + instance ?: synchronized(this) { + instance ?: creator(param).also { instance = it } + } + +} + +abstract class BaseSingNoParam { + + @Volatile + private var instance: T? = null + + //抽象方法,需要我们在具体的单例子类当中实现此方法 + protected abstract fun creator(): T + + fun getInstance(): T = + instance ?: synchronized(this) { + instance ?: creator().also { instance = it } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/utils/SPUtils.kt b/app/src/main/java/com/dahe/gldriver/utils/SPUtils.kt new file mode 100644 index 0000000..405d712 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/utils/SPUtils.kt @@ -0,0 +1,127 @@ +package com.dahe.gldriver.utils + +import android.content.Context +import com.dahe.glex.bean.UserBean +import com.dahe.mylibrary.net.JsonUtils +import com.dahe.mylibrary.utils.BaseSPUtils + +/** + * @ClassName SPUtils2 + * @Author 用户 + * @Date 2023/12/29 08:52 + * @Description TODO + */ +class SPUtils private constructor() : BaseSPUtils() { + companion object{ + val instance = Holder.holder + } + + object Holder { + val holder = SPUtils() + } + + /** + * 存用户信息 + * + * @param context + * @param json + */ + fun setUserInfo(context: Context?, json: String?) { + BaseSPUtils.put(context, BaseSPUtils.USER_INFO_KEY, json) + } + + /** + * 拿用户信息 + * + * @param context + */ + fun getUserInfo(context: Context?): UserBean? { + return JsonUtils.getInstance() + .fromJson(BaseSPUtils.get(context, BaseSPUtils.USER_INFO_KEY, "") as String, + UserBean::class.java) + } + + /** + * 存服务器类型 + * + * @param context + * @param isTestService + */ + fun setNetServiceType(context: Context?, isTestService: Boolean) { + BaseSPUtils.put(context, BaseSPUtils.NET_SERVICE_TEST, isTestService) + } + + /** + * 拿服务器类型 + * + * @param context + */ + fun geNetServiceType(context: Context?): Boolean { + return BaseSPUtils.get(context, BaseSPUtils.NET_SERVICE_TEST, false) as Boolean + } + + /** + * 存搜索数据 + * + * @param context + * @param json + */ + fun setSearchCache(context: Context?, json: String?) { + BaseSPUtils.put(context, BaseSPUtils.SEARRH_CACHE, json) + } + + fun getSearchCache(context: Context?): String? { + return JsonUtils.getInstance() + .fromJson(BaseSPUtils.get(context, BaseSPUtils.SEARRH_CACHE, "") as String, + String::class.java) + } + + fun removeSearchCache(context: Context?) { + BaseSPUtils.remove(context, BaseSPUtils.SEARRH_CACHE) + } + + /** + * 导航偏好设置 + */ + fun setNaviPreferenceCache(context: Context?, json: String?) { + BaseSPUtils.put(context, BaseSPUtils.NAVI_PH_EDIT_CACHE, json) + } + + fun getNaviPreferenceCache(context: Context?): String? { + return JsonUtils.getInstance() + .fromJson(BaseSPUtils.get(context, BaseSPUtils.NAVI_PH_EDIT_CACHE, "") as String, + String::class.java) + } + + fun removeNaviPreference(context: Context?) { + BaseSPUtils.remove(context, BaseSPUtils.NAVI_PH_EDIT_CACHE) + } + + //第一次登录 + fun getIsFirstOpen(context: Context?): Boolean { + return BaseSPUtils.get(context, BaseSPUtils.FIRST_OPEN, true) as Boolean + } + + fun setIsFirstOpen(context: Context?, json: Boolean) { + BaseSPUtils.put(context, BaseSPUtils.FIRST_OPEN, json) + } + + + /** + * 设置隐私协议是否同意 + * + * @param value 是否同意 + */ + fun setAgreePrivacyAgreement(context: Context?, value: Boolean) { + BaseSPUtils.put(context, BaseSPUtils.KEY_PRIVACY_AGREEMENT, value) + } + + /** + * 是否同意了隐私协议 + * + * @return true 已经同意;false 还没有同意 + */ + fun hasAgreePrivacyAgreement(context: Context?): Boolean { + return BaseSPUtils.get(context, BaseSPUtils.KEY_PRIVACY_AGREEMENT, false) as Boolean + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/utils/UserUtils.kt b/app/src/main/java/com/dahe/gldriver/utils/UserUtils.kt new file mode 100644 index 0000000..1cc00a1 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/utils/UserUtils.kt @@ -0,0 +1,26 @@ +package com.dahe.gldriver.utils + +import android.content.Context +import com.dahe.mylibrary.utils.BaseSPUtils + +class UserUtils private constructor(){ + + companion object{ + val instance = Holder.holder + } + + private object Holder { + val holder = UserUtils() + } + + fun loginOut(context : Context){ + if (null== SPUtils.instance.getUserInfo(context)) + return +// PushAgent.getInstance(context).deleteAlias(SPUtils.getUserInfo(context).userInfo.userId,"uid"){ b, s -> } + BaseSPUtils.cleanUserInfo(context) +// val intent = Intent(context, LauncherActivity::class.java) +// intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK +// context.startActivity(intent) +// ToastUtils.showToast(context, "您的账号再异地登录,请重新登录") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/weight/NoScrollViewPager.kt b/app/src/main/java/com/dahe/gldriver/weight/NoScrollViewPager.kt new file mode 100644 index 0000000..87d0b1a --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/weight/NoScrollViewPager.kt @@ -0,0 +1,72 @@ +package com.dahe.gldriver.weight + +import android.content.Context +import android.util.AttributeSet +import androidx.viewpager.widget.ViewPager +import android.view.MotionEvent + +/** + * Created by Administrator on 2018/7/16 0016. + */ +class NoScrollViewPager : ViewPager { + private val isCanScroll = false + + constructor(context: Context?) : super(context!!) {} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {} + + /** + * 去掉viewpage滑动动画 + * + * @param item + */ + override fun setCurrentItem(item: Int) { + super.setCurrentItem(item, false) + } + + /** + * 1.dispatchTouchEvent一般情况不做处理 + * ,如果修改了默认的返回值,子孩子都无法收到事件 + */ + override fun dispatchTouchEvent(ev: MotionEvent): Boolean { + return super.dispatchTouchEvent(ev) // node_return true;不行 + } + + /** + * 是否拦截 + * 拦截:会走到自己的onTouchEvent方法里面来 + * 不拦截:事件传递给子孩子 + */ + override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { + // node_return false;//可行,不拦截事件, + // node_return true;//不行,孩子无法处理事件 + //node_return super.onInterceptTouchEvent(ev);//不行,会有细微移动 + return if (isCanScroll) { + super.onInterceptTouchEvent(ev) + } else { + false + } + } + + /** + * 是否消费事件 + * 消费:事件就结束 + * 不消费:往父控件传 + */ + override fun onTouchEvent(ev: MotionEvent): Boolean { + //node_return false;// 可行,不消费,传给父控件 + //node_return true;// 可行,消费,拦截事件 + //super.onTouchEvent(ev); //不行, + //虽然onInterceptTouchEvent中拦截了, + //但是如果viewpage里面子控件不是viewgroup,还是会调用这个方法. + return if (isCanScroll) { + super.onTouchEvent(ev) + } else { + true // 可行,消费,拦截事件 + } + } + + fun setScroll(isCanScroll: Boolean) { + var isCanScroll = isCanScroll + isCanScroll = isCanScroll + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/weight/ScaleTransitionPagerTitleView.kt b/app/src/main/java/com/dahe/gldriver/weight/ScaleTransitionPagerTitleView.kt new file mode 100644 index 0000000..37a1f9d --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/weight/ScaleTransitionPagerTitleView.kt @@ -0,0 +1,25 @@ +package com.dahe.gldriver.weight + +import android.content.Context +import net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.ColorTransitionPagerTitleView + +/** + * 带颜色渐变和缩放的指示器标题 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +class ScaleTransitionPagerTitleView(context: Context?) : ColorTransitionPagerTitleView(context) { + var minScale = 0.75f + override fun onEnter(index: Int, totalCount: Int, enterPercent: Float, leftToRight: Boolean) { + super.onEnter(index, totalCount, enterPercent, leftToRight) // 实现颜色渐变 + scaleX = minScale + (1.0f - minScale) * enterPercent + scaleY = minScale + (1.0f - minScale) * enterPercent + } + + override fun onLeave(index: Int, totalCount: Int, leavePercent: Float, leftToRight: Boolean) { + super.onLeave(index, totalCount, leavePercent, leftToRight) // 实现颜色渐变 + scaleX = 1.0f + (minScale - 1.0f) * leavePercent + scaleY = 1.0f + (minScale - 1.0f) * leavePercent + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/weight/VerifyEditText.kt b/app/src/main/java/com/dahe/gldriver/weight/VerifyEditText.kt new file mode 100644 index 0000000..a95fc1f --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/weight/VerifyEditText.kt @@ -0,0 +1,416 @@ +package com.dahe.gldriver.weight + +import android.animation.ObjectAnimator +import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.app.ActionBar +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ClipDrawable.HORIZONTAL +import android.graphics.drawable.Drawable +import android.text.* +import android.text.method.HideReturnsTransformationMethod +import android.text.method.PasswordTransformationMethod +import android.util.AttributeSet +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager +import android.widget.EditText +import android.widget.LinearLayout +import android.widget.RelativeLayout +import android.widget.TextView +import androidx.core.content.ContextCompat +import com.dahe.gldriver.R +import com.lxj.xpopup.util.KeyboardUtils +import java.security.AccessController.getContext + +/** + * @ClassName VerifyEditText + * @Author 用户 + * @Date 2024/1/25 09:55 + * @Description TODO + */ +class VerifyEditText @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + private val mTextViewList: MutableList = ArrayList() + private val mRelativeLayouts: MutableList = mutableListOf() + private val mCursorViews: MutableList = mutableListOf() + private var mShowCursor = false + private var mCursorColor: Int = Color.parseColor("#FFFFFF") + private var mEditText: EditText? = null + private var drawableNormal: Drawable? = null + private var drawableSelected: Drawable? = null + private var mContext: Context? = null + private var valueAnimator: ValueAnimator? = null + private var mItemCount = 0 + + //输入完成监听 + private var mInputCompleteListener: InputCompleteListener? = null + + init { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + mContext = context + orientation = HORIZONTAL + gravity = Gravity.CENTER + @SuppressLint("CustomViewStyleable") + val obtainStyledAttributes = + getContext().obtainStyledAttributes(attrs, R.styleable.verify_EditText) + drawableNormal = + obtainStyledAttributes.getDrawable(R.styleable.verify_EditText_verify_background_normal) + drawableSelected = + obtainStyledAttributes.getDrawable(R.styleable.verify_EditText_verify_background_selected) + val textColor = obtainStyledAttributes.getColor( + R.styleable.verify_EditText_verify_textColor, + ContextCompat.getColor(context, android.R.color.black) + ) + mItemCount = obtainStyledAttributes.getInt( + R.styleable.verify_EditText_verify_count, + DEFAULT_ITEM_COUNT + ) + val inputType = obtainStyledAttributes.getInt( + R.styleable.verify_EditText_verify_inputType, + InputType.TYPE_CLASS_NUMBER + ) + val passwordVisibleTime = obtainStyledAttributes.getInt( + R.styleable.verify_EditText_verify_password_visible_time, + DEFAULT_PASSWORD_VISIBLE_TIME + ) + val width = obtainStyledAttributes.getDimension( + R.styleable.verify_EditText_verify_width, + DEFAULT_ITEM_WIDTH.toFloat() + ).toInt() + val height = + obtainStyledAttributes.getDimension(R.styleable.verify_EditText_verify_height, 0f) + .toInt() + val cursorWidth = obtainStyledAttributes.getDimension( + R.styleable.verify_EditText_cursor_width, + 1F + ).toInt() + mCursorColor = obtainStyledAttributes.getColor( + R.styleable.verify_EditText_cursor_color, + ContextCompat.getColor(context, android.R.color.black) + ) + mShowCursor = + obtainStyledAttributes.getBoolean(R.styleable.verify_EditText_show_cursor, false) + val cursorHeight = obtainStyledAttributes.getDimension( + R.styleable.verify_EditText_cursor_height, + 20F + ).toInt() + val margin = obtainStyledAttributes.getDimension( + R.styleable.verify_EditText_verify_margin, + DEFAULT_ITEM_MARGIN.toFloat() + ).toInt() + val textSize = px2sp( + context, + obtainStyledAttributes.getDimension( + R.styleable.verify_EditText_verify_textSize, + sp2px(context, DEFAULT_ITEM_TEXT_SIZE.toFloat()).toFloat() + ) + ).toFloat() + val password = + obtainStyledAttributes.getBoolean(R.styleable.verify_EditText_verify_password, false) + obtainStyledAttributes.recycle() + if (mItemCount < 2) mItemCount = 2 //最少 2 个 item + mEditText = EditText(context) + mEditText?.run { + mEditText?.inputType = inputType + layoutParams = ActionBar.LayoutParams(1, 1) + isCursorVisible = false + background = null + filters = arrayOf(InputFilter.LengthFilter(mItemCount)) //限制输入长度为 count + addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged( + s: CharSequence, + start: Int, + count: Int, + after: Int + ) { + } + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + if (before == 0 && (start + count) < 7) {// 输入 + if (count > 1) {// 有复制内容进来 + for (i in start until start + count) { + val input = s.subSequence(i, i + 1) // 获取新输入的字 + inputText(i, password, passwordVisibleTime, input.toString()) + } + } else {// 逐步输入 + inputText( + start, + password, + passwordVisibleTime, + s.subSequence(start, s.length).toString() + ) + } + } else {// 删除 + val textView = mTextViewList[start] // 获取对应的 textview + textView.text = "" + setTextViewBackground(textView, drawableNormal) + } + if (mInputCompleteListener != null && s.length == mTextViewList.size) + mInputCompleteListener?.complete( + s.toString() + ) + } + + override fun afterTextChanged(s: Editable) { + setCursorColor() + } + }) + } + addView(mEditText) + //点击弹出软键盘 + setOnClickListener { v: View? -> + mEditText?.requestFocus() + showSoftKeyBoard() + } + //遍历生成 textview + for (i in 0 until mItemCount) { + val relativeLayout = RelativeLayout(context) + relativeLayout.layoutParams = getRelativeLayoutParams(i, margin, width, height) + mRelativeLayouts.add(relativeLayout) + + val textView = TextView(context) + textView.textSize = textSize + textView.maxEms = 1 + textView.maxLines = 1 +// textView.gravity = Gravity.CENTER + textView.setTextColor(textColor) +// textView.layoutParams = layoutParams + initTextView(textView) + setTextViewBackground(textView, drawableNormal) +// addView(textView) + relativeLayout.addView(textView) + mTextViewList.add(textView) + + if (mShowCursor) { + val cursorView = View(context) + initCursorView(cursorView, cursorWidth, cursorHeight) + relativeLayout.addView(cursorView) + mCursorViews.add(cursorView) + } + relativeLayout.setBackgroundColor(Color.TRANSPARENT) + addView(relativeLayout) + } + + setCursorColor() + } + + private fun getRelativeLayoutParams( + i: Int, + margin: Int, + width: Int, + height: Int + ): ActionBar.LayoutParams { + val layoutParams = ActionBar.LayoutParams( + width, + if (height == 0) ViewGroup.LayoutParams.WRAP_CONTENT else height + ) + if (i == 0) layoutParams.leftMargin = -1 else layoutParams.leftMargin = margin + return layoutParams + } + + private fun initTextView(textView: TextView) { + val lp: RelativeLayout.LayoutParams = RelativeLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + textView.gravity = Gravity.CENTER + textView.layoutParams = lp + } + + private fun initCursorView(cursorView: View, cursorWidth: Int, cursorHeight: Int) { + val lp: RelativeLayout.LayoutParams = RelativeLayout.LayoutParams( + cursorWidth, + cursorHeight + ) + lp.addRule(RelativeLayout.ALIGN_PARENT_START) + lp.addRule(RelativeLayout.CENTER_VERTICAL) + lp.marginStart = 6 + cursorView.layoutParams = lp + } + + private fun inputText(start: Int, password: Boolean, passwordVisibleTime: Int, input: String) { + val textView = mTextViewList[start] // 获取对应的 textview + textView.text = input + if (password) { //如果需要密文显示 + textView.transformationMethod = + HideReturnsTransformationMethod.getInstance() + //passwordVisibleTime 毫秒后设置为密文显示 + textView.postDelayed( + { + textView.transformationMethod = + PasswordTransformationMethod.getInstance() + }, + passwordVisibleTime.toLong() + ) + } + setTextViewBackground(textView, drawableSelected) + } + + /** + * view 添加到窗口时,延迟 500ms 弹出软键盘 + */ + override fun onAttachedToWindow() { + super.onAttachedToWindow() + mEditText?.postDelayed({ showSoftKeyBoard() }, 500) + } + + /** + * 设置背景 + * @param textView + * @param drawable + */ + private fun setTextViewBackground(textView: TextView, drawable: Drawable?) { + if (drawable != null) textView.background = drawable + } + + private fun setCursorColor() { + if (mShowCursor) { + valueAnimator?.cancel() + + for (i in 0 until mItemCount) { + val cursorView = mCursorViews[i] + cursorView.setBackgroundColor(Color.TRANSPARENT) + } + + val index = mEditText?.text?.length ?: 0 + if (index < mItemCount) { + setCursorView(mCursorViews[index]) + } + } + } + + /** + * 设置焦点色变换动画 + * + * @param view + */ + private fun setCursorView(view: View) { + this.valueAnimator = ObjectAnimator.ofInt( + view, + "backgroundColor", + mCursorColor, + android.R.color.transparent + ) + valueAnimator?.run { + duration = 1500 + repeatCount = -1 + repeatMode = ValueAnimator.RESTART + setEvaluator { fraction, startValue, endValue -> if (fraction <= 0.5f) startValue else endValue } + start() + } + } + + /** + * 获取当前输入的内容 + * + * @return + */ + val content: String + get() { + val text = mEditText?.text + return if (TextUtils.isEmpty(text)) "" else mEditText?.text.toString() + } + + /** + * 清除内容 + */ + fun clearContent() { + mEditText?.setText("") + for (i in mTextViewList.indices) { + val textView = mTextViewList[i] + textView.text = "" + setTextViewBackground(textView, drawableNormal) + } + } + + /** + * 设置默认的内容 + * + * @param content + */ + fun setDefaultContent(content: String) { + mEditText?.setText(content) + mEditText?.requestFocus() + val chars = content.toCharArray() + val min = Math.min(chars.size, mTextViewList.size) + for (i in 0 until min) { + val aChar = chars[i] + val s = aChar.toString() + val textView = mTextViewList[i] + textView.text = s + setTextViewBackground(textView, drawableSelected) + } + if (mInputCompleteListener != null && min == mTextViewList.size) mInputCompleteListener?.complete( + content.substring(0, min) + ) + } + + /** + * 显示软键盘 + */ + private fun showSoftKeyBoard() { + val imm = mContext?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput(mEditText, InputMethodManager.SHOW_FORCED) + } + + /** + * 添加输入完成的监听 + * + * @param inputCompleteListener + */ + fun addInputCompleteListener(inputCompleteListener: InputCompleteListener) { + mInputCompleteListener = inputCompleteListener + val content = mEditText?.text + if (!TextUtils.isEmpty(content) && content.toString().length == mTextViewList.size) { + mInputCompleteListener?.complete(content.toString()) + } + } + + interface InputCompleteListener { + fun complete(content: String) + } + + private fun px2sp(context: Context, pxValue: Float): Int { + val fontScale = context.resources.displayMetrics.scaledDensity + return (pxValue / fontScale + 0.5f).toInt() + } + + private fun sp2px(context: Context, spValue: Float): Int { + val fontScale = context.resources.displayMetrics.scaledDensity + return (spValue * fontScale + 0.5f).toInt() + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + KeyboardUtils.hideSoftInput(this) +// CommonUtil.hideKeyboard(this) + valueAnimator?.cancel() + } + + + companion object { + //默认 item 个数为 4 个 + private const val DEFAULT_ITEM_COUNT = 4 + + //默认每个 item 的宽度为 100 + private const val DEFAULT_ITEM_WIDTH = 100 + + //默认每个 item 的间距为 50 + private const val DEFAULT_ITEM_MARGIN = 50 + + //默认每个 item 的字体大小为 14 + private const val DEFAULT_ITEM_TEXT_SIZE = 14 + + //默认密码明文显示时间为 200ms,之后密文显示 + private const val DEFAULT_PASSWORD_VISIBLE_TIME = 200 + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xxhdpi/about.png b/app/src/main/res/drawable-xxhdpi/about.png new file mode 100644 index 0000000..e43ea82 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/about.png differ diff --git a/app/src/main/res/drawable-xxhdpi/auth_car.png b/app/src/main/res/drawable-xxhdpi/auth_car.png new file mode 100644 index 0000000..59fc2c7 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/auth_car.png differ diff --git a/app/src/main/res/drawable-xxhdpi/bank_card.png b/app/src/main/res/drawable-xxhdpi/bank_card.png new file mode 100644 index 0000000..1b8f54a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/bank_card.png differ diff --git a/app/src/main/res/drawable-xxhdpi/bobao.png b/app/src/main/res/drawable-xxhdpi/bobao.png new file mode 100644 index 0000000..6528012 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/bobao.png differ diff --git a/app/src/main/res/drawable-xxhdpi/call_us.png b/app/src/main/res/drawable-xxhdpi/call_us.png new file mode 100644 index 0000000..ebfaf0a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/call_us.png differ diff --git a/app/src/main/res/drawable-xxhdpi/car_manage.png b/app/src/main/res/drawable-xxhdpi/car_manage.png new file mode 100644 index 0000000..a612cb7 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/car_manage.png differ diff --git a/app/src/main/res/drawable-xxhdpi/car_photo.png b/app/src/main/res/drawable-xxhdpi/car_photo.png new file mode 100644 index 0000000..3c26602 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/car_photo.png differ diff --git a/app/src/main/res/drawable-xxhdpi/car_team.png b/app/src/main/res/drawable-xxhdpi/car_team.png new file mode 100644 index 0000000..9b887ab Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/car_team.png differ diff --git a/app/src/main/res/drawable-xxhdpi/driver_back.png b/app/src/main/res/drawable-xxhdpi/driver_back.png new file mode 100644 index 0000000..478a79d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/driver_back.png differ diff --git a/app/src/main/res/drawable-xxhdpi/driver_front.png b/app/src/main/res/drawable-xxhdpi/driver_front.png new file mode 100644 index 0000000..32cd952 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/driver_front.png differ diff --git a/app/src/main/res/drawable-xxhdpi/driving_back.png b/app/src/main/res/drawable-xxhdpi/driving_back.png new file mode 100644 index 0000000..7c0022e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/driving_back.png differ diff --git a/app/src/main/res/drawable-xxhdpi/driving_front.png b/app/src/main/res/drawable-xxhdpi/driving_front.png new file mode 100644 index 0000000..6007bcb Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/driving_front.png differ diff --git a/app/src/main/res/drawable-xxhdpi/face.png b/app/src/main/res/drawable-xxhdpi/face.png new file mode 100644 index 0000000..2849306 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/face.png differ diff --git a/app/src/main/res/drawable-xxhdpi/face1.png b/app/src/main/res/drawable-xxhdpi/face1.png new file mode 100644 index 0000000..7c4af57 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/face1.png differ diff --git a/app/src/main/res/drawable-xxhdpi/face2.png b/app/src/main/res/drawable-xxhdpi/face2.png new file mode 100644 index 0000000..9ef3bb0 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/face2.png differ diff --git a/app/src/main/res/drawable-xxhdpi/face3.png b/app/src/main/res/drawable-xxhdpi/face3.png new file mode 100644 index 0000000..691270b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/face3.png differ diff --git a/app/src/main/res/drawable-xxhdpi/go_right.png b/app/src/main/res/drawable-xxhdpi/go_right.png new file mode 100644 index 0000000..e48a021 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/go_right.png differ diff --git a/app/src/main/res/drawable-xxhdpi/head_defaut.png b/app/src/main/res/drawable-xxhdpi/head_defaut.png new file mode 100644 index 0000000..41ae40c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/head_defaut.png differ diff --git a/app/src/main/res/drawable-xxhdpi/home_all.png b/app/src/main/res/drawable-xxhdpi/home_all.png new file mode 100644 index 0000000..a768453 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/home_all.png differ diff --git a/app/src/main/res/drawable-xxhdpi/home_ask.png b/app/src/main/res/drawable-xxhdpi/home_ask.png new file mode 100644 index 0000000..bc2f97c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/home_ask.png differ diff --git a/app/src/main/res/drawable-xxhdpi/home_driver.png b/app/src/main/res/drawable-xxhdpi/home_driver.png new file mode 100644 index 0000000..33f305a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/home_driver.png differ diff --git a/app/src/main/res/drawable-xxhdpi/home_know.png b/app/src/main/res/drawable-xxhdpi/home_know.png new file mode 100644 index 0000000..86a3e90 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/home_know.png differ diff --git a/app/src/main/res/drawable-xxhdpi/home_logo.png b/app/src/main/res/drawable-xxhdpi/home_logo.png new file mode 100644 index 0000000..7ad24a4 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/home_logo.png differ diff --git a/app/src/main/res/drawable-xxhdpi/home_my.png b/app/src/main/res/drawable-xxhdpi/home_my.png new file mode 100644 index 0000000..86b13d2 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/home_my.png differ diff --git a/app/src/main/res/drawable-xxhdpi/home_que.png b/app/src/main/res/drawable-xxhdpi/home_que.png new file mode 100644 index 0000000..97bd6b1 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/home_que.png differ diff --git a/app/src/main/res/drawable-xxhdpi/home_top_bg.jpg b/app/src/main/res/drawable-xxhdpi/home_top_bg.jpg new file mode 100644 index 0000000..f77592e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/home_top_bg.jpg differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_go.png b/app/src/main/res/drawable-xxhdpi/icon_go.png new file mode 100644 index 0000000..189fac5 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_go.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_load.png b/app/src/main/res/drawable-xxhdpi/icon_load.png new file mode 100644 index 0000000..2c2202c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_load.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_route.png b/app/src/main/res/drawable-xxhdpi/icon_route.png new file mode 100644 index 0000000..e9b1548 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_route.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_unload.png b/app/src/main/res/drawable-xxhdpi/icon_unload.png new file mode 100644 index 0000000..bc1ca36 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_unload.png differ diff --git a/app/src/main/res/drawable-xxhdpi/kuaixun.png b/app/src/main/res/drawable-xxhdpi/kuaixun.png new file mode 100644 index 0000000..c214fb9 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/kuaixun.png differ diff --git a/app/src/main/res/drawable-xxhdpi/login_car.png b/app/src/main/res/drawable-xxhdpi/login_car.png new file mode 100644 index 0000000..c1f4cc6 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/login_car.png differ diff --git a/app/src/main/res/drawable-xxhdpi/login_top_bg.png b/app/src/main/res/drawable-xxhdpi/login_top_bg.png new file mode 100644 index 0000000..cb63a67 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/login_top_bg.png differ diff --git a/app/src/main/res/drawable-xxhdpi/message_noti.png b/app/src/main/res/drawable-xxhdpi/message_noti.png new file mode 100644 index 0000000..6418d86 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/message_noti.png differ diff --git a/app/src/main/res/drawable-xxhdpi/message_order.png b/app/src/main/res/drawable-xxhdpi/message_order.png new file mode 100644 index 0000000..329a2ee Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/message_order.png differ diff --git a/app/src/main/res/drawable-xxhdpi/message_sys.png b/app/src/main/res/drawable-xxhdpi/message_sys.png new file mode 100644 index 0000000..32665d4 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/message_sys.png differ diff --git a/app/src/main/res/drawable-xxhdpi/mine_bg.png b/app/src/main/res/drawable-xxhdpi/mine_bg.png new file mode 100644 index 0000000..09a08af Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/mine_bg.png differ diff --git a/app/src/main/res/drawable-xxhdpi/mine_class.png b/app/src/main/res/drawable-xxhdpi/mine_class.png new file mode 100644 index 0000000..2856365 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/mine_class.png differ diff --git a/app/src/main/res/drawable-xxhdpi/opin.png b/app/src/main/res/drawable-xxhdpi/opin.png new file mode 100644 index 0000000..15a029d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/opin.png differ diff --git a/app/src/main/res/drawable-xxhdpi/part_dir.png b/app/src/main/res/drawable-xxhdpi/part_dir.png new file mode 100644 index 0000000..5939ea1 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/part_dir.png differ diff --git a/app/src/main/res/drawable-xxhdpi/party.png b/app/src/main/res/drawable-xxhdpi/party.png new file mode 100644 index 0000000..a0af1ef Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/party.png differ diff --git a/app/src/main/res/drawable-xxhdpi/person.png b/app/src/main/res/drawable-xxhdpi/person.png new file mode 100644 index 0000000..89e17bd Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/person.png differ diff --git a/app/src/main/res/drawable-xxhdpi/person_back.png b/app/src/main/res/drawable-xxhdpi/person_back.png new file mode 100644 index 0000000..7366e46 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/person_back.png differ diff --git a/app/src/main/res/drawable-xxhdpi/person_front.png b/app/src/main/res/drawable-xxhdpi/person_front.png new file mode 100644 index 0000000..3f59b1e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/person_front.png differ diff --git a/app/src/main/res/drawable-xxhdpi/qualication.png b/app/src/main/res/drawable-xxhdpi/qualication.png new file mode 100644 index 0000000..ab13204 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/qualication.png differ diff --git a/app/src/main/res/drawable-xxhdpi/question.png b/app/src/main/res/drawable-xxhdpi/question.png new file mode 100644 index 0000000..bafd715 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/question.png differ diff --git a/app/src/main/res/drawable-xxhdpi/rate.png b/app/src/main/res/drawable-xxhdpi/rate.png new file mode 100644 index 0000000..3df8fa3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/rate.png differ diff --git a/app/src/main/res/drawable-xxhdpi/read_nor.png b/app/src/main/res/drawable-xxhdpi/read_nor.png new file mode 100644 index 0000000..5091cff Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/read_nor.png differ diff --git a/app/src/main/res/drawable-xxhdpi/read_select.png b/app/src/main/res/drawable-xxhdpi/read_select.png new file mode 100644 index 0000000..b9b0be7 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/read_select.png differ diff --git a/app/src/main/res/drawable-xxhdpi/right.png b/app/src/main/res/drawable-xxhdpi/right.png new file mode 100644 index 0000000..a2e9c54 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/right.png differ diff --git a/app/src/main/res/drawable-xxhdpi/right_black.png b/app/src/main/res/drawable-xxhdpi/right_black.png new file mode 100644 index 0000000..389e99b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/right_black.png differ diff --git a/app/src/main/res/drawable-xxhdpi/right_gray.png b/app/src/main/res/drawable-xxhdpi/right_gray.png new file mode 100644 index 0000000..fd71ccb Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/right_gray.png differ diff --git a/app/src/main/res/drawable-xxhdpi/road.png b/app/src/main/res/drawable-xxhdpi/road.png new file mode 100644 index 0000000..fa7e216 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/road.png differ diff --git a/app/src/main/res/drawable-xxhdpi/rules.png b/app/src/main/res/drawable-xxhdpi/rules.png new file mode 100644 index 0000000..2292e19 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/rules.png differ diff --git a/app/src/main/res/drawable-xxhdpi/search.png b/app/src/main/res/drawable-xxhdpi/search.png new file mode 100644 index 0000000..f273838 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/search.png differ diff --git a/app/src/main/res/drawable-xxhdpi/setting.png b/app/src/main/res/drawable-xxhdpi/setting.png new file mode 100644 index 0000000..13809a6 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/setting.png differ diff --git a/app/src/main/res/drawable-xxhdpi/start.png b/app/src/main/res/drawable-xxhdpi/start.png new file mode 100644 index 0000000..4ee7737 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/start.png differ diff --git a/app/src/main/res/drawable-xxhdpi/tab_home_normal.png b/app/src/main/res/drawable-xxhdpi/tab_home_normal.png new file mode 100644 index 0000000..3d53903 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/tab_home_normal.png differ diff --git a/app/src/main/res/drawable-xxhdpi/tab_home_press.png b/app/src/main/res/drawable-xxhdpi/tab_home_press.png new file mode 100644 index 0000000..68c7ffd Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/tab_home_press.png differ diff --git a/app/src/main/res/drawable-xxhdpi/tab_message_normal.png b/app/src/main/res/drawable-xxhdpi/tab_message_normal.png new file mode 100644 index 0000000..dbb980e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/tab_message_normal.png differ diff --git a/app/src/main/res/drawable-xxhdpi/tab_message_press.png b/app/src/main/res/drawable-xxhdpi/tab_message_press.png new file mode 100644 index 0000000..c5dac13 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/tab_message_press.png differ diff --git a/app/src/main/res/drawable-xxhdpi/tab_mine_normal.png b/app/src/main/res/drawable-xxhdpi/tab_mine_normal.png new file mode 100644 index 0000000..0b47cae Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/tab_mine_normal.png differ diff --git a/app/src/main/res/drawable-xxhdpi/tab_mine_press.png b/app/src/main/res/drawable-xxhdpi/tab_mine_press.png new file mode 100644 index 0000000..7933a27 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/tab_mine_press.png differ diff --git a/app/src/main/res/drawable-xxhdpi/tab_waybill_normal.png b/app/src/main/res/drawable-xxhdpi/tab_waybill_normal.png new file mode 100644 index 0000000..71e7097 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/tab_waybill_normal.png differ diff --git a/app/src/main/res/drawable-xxhdpi/tab_waybill_press.png b/app/src/main/res/drawable-xxhdpi/tab_waybill_press.png new file mode 100644 index 0000000..0bd6ad4 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/tab_waybill_press.png differ diff --git a/app/src/main/res/drawable-xxhdpi/title_bg.png b/app/src/main/res/drawable-xxhdpi/title_bg.png new file mode 100644 index 0000000..2d84409 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/title_bg.png differ diff --git a/app/src/main/res/drawable-xxhdpi/update.png b/app/src/main/res/drawable-xxhdpi/update.png new file mode 100644 index 0000000..875c503 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/update.png differ diff --git a/app/src/main/res/drawable-xxhdpi/waybill_top_bg.png b/app/src/main/res/drawable-xxhdpi/waybill_top_bg.png new file mode 100644 index 0000000..f1f33b0 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/waybill_top_bg.png differ diff --git a/app/src/main/res/drawable-xxhdpi/welcome_bg_default.png b/app/src/main/res/drawable-xxhdpi/welcome_bg_default.png new file mode 100644 index 0000000..2de19c6 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/welcome_bg_default.png differ diff --git a/app/src/main/res/drawable/bg_btn.xml b/app/src/main/res/drawable/bg_btn.xml new file mode 100644 index 0000000..77cc9da --- /dev/null +++ b/app/src/main/res/drawable/bg_btn.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_baseline_home_24.xml b/app/src/main/res/drawable/ic_baseline_home_24.xml new file mode 100644 index 0000000..a57d32f --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_home_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/marquee_bg.xml b/app/src/main/res/drawable/marquee_bg.xml new file mode 100644 index 0000000..6bf68f5 --- /dev/null +++ b/app/src/main/res/drawable/marquee_bg.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/search_bg.xml b/app/src/main/res/drawable/search_bg.xml new file mode 100644 index 0000000..af1c7f6 --- /dev/null +++ b/app/src/main/res/drawable/search_bg.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/select_auth_team.xml b/app/src/main/res/drawable/select_auth_team.xml new file mode 100644 index 0000000..6e21a2a --- /dev/null +++ b/app/src/main/res/drawable/select_auth_team.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/select_auth_team_text.xml b/app/src/main/res/drawable/select_auth_team_text.xml new file mode 100644 index 0000000..6ab59fa --- /dev/null +++ b/app/src/main/res/drawable/select_auth_team_text.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/select_read.xml b/app/src/main/res/drawable/select_read.xml new file mode 100644 index 0000000..db24025 --- /dev/null +++ b/app/src/main/res/drawable/select_read.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_bottom_5.xml b/app/src/main/res/drawable/shape_bottom_5.xml new file mode 100644 index 0000000..27d8c0c --- /dev/null +++ b/app/src/main/res/drawable/shape_bottom_5.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_btn_bg4.xml b/app/src/main/res/drawable/shape_btn_bg4.xml new file mode 100644 index 0000000..29f6fcb --- /dev/null +++ b/app/src/main/res/drawable/shape_btn_bg4.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_btn_empty_bg.xml b/app/src/main/res/drawable/shape_btn_empty_bg.xml new file mode 100644 index 0000000..05a5553 --- /dev/null +++ b/app/src/main/res/drawable/shape_btn_empty_bg.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_code_bg5.xml b/app/src/main/res/drawable/shape_code_bg5.xml new file mode 100644 index 0000000..79c1b2e --- /dev/null +++ b/app/src/main/res/drawable/shape_code_bg5.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_count_downbg.xml b/app/src/main/res/drawable/shape_count_downbg.xml new file mode 100644 index 0000000..670e2a9 --- /dev/null +++ b/app/src/main/res/drawable/shape_count_downbg.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_gray_5.xml b/app/src/main/res/drawable/shape_gray_5.xml new file mode 100644 index 0000000..879e36e --- /dev/null +++ b/app/src/main/res/drawable/shape_gray_5.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_message_item_bg.xml b/app/src/main/res/drawable/shape_message_item_bg.xml new file mode 100644 index 0000000..a506e83 --- /dev/null +++ b/app/src/main/res/drawable/shape_message_item_bg.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_mine_bg20.xml b/app/src/main/res/drawable/shape_mine_bg20.xml new file mode 100644 index 0000000..9cdff80 --- /dev/null +++ b/app/src/main/res/drawable/shape_mine_bg20.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_ok_bg.xml b/app/src/main/res/drawable/shape_ok_bg.xml new file mode 100644 index 0000000..e19f86c --- /dev/null +++ b/app/src/main/res/drawable/shape_ok_bg.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_orange_5.xml b/app/src/main/res/drawable/shape_orange_5.xml new file mode 100644 index 0000000..7b328d9 --- /dev/null +++ b/app/src/main/res/drawable/shape_orange_5.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_phone_bg.xml b/app/src/main/res/drawable/shape_phone_bg.xml new file mode 100644 index 0000000..be41ebe --- /dev/null +++ b/app/src/main/res/drawable/shape_phone_bg.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_search_bg.xml b/app/src/main/res/drawable/shape_search_bg.xml new file mode 100644 index 0000000..a7ef7a2 --- /dev/null +++ b/app/src/main/res/drawable/shape_search_bg.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_waybill_item_bg.xml b/app/src/main/res/drawable/shape_waybill_item_bg.xml new file mode 100644 index 0000000..8df683c --- /dev/null +++ b/app/src/main/res/drawable/shape_waybill_item_bg.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_white_12.xml b/app/src/main/res/drawable/shape_white_12.xml new file mode 100644 index 0000000..943aa17 --- /dev/null +++ b/app/src/main/res/drawable/shape_white_12.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auth_bankcard.xml b/app/src/main/res/layout/activity_auth_bankcard.xml new file mode 100644 index 0000000..97c1676 --- /dev/null +++ b/app/src/main/res/layout/activity_auth_bankcard.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auth_driver.xml b/app/src/main/res/layout/activity_auth_driver.xml new file mode 100644 index 0000000..3bc7411 --- /dev/null +++ b/app/src/main/res/layout/activity_auth_driver.xml @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auth_driving.xml b/app/src/main/res/layout/activity_auth_driving.xml new file mode 100644 index 0000000..5cea2f5 --- /dev/null +++ b/app/src/main/res/layout/activity_auth_driving.xml @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auth_face.xml b/app/src/main/res/layout/activity_auth_face.xml new file mode 100644 index 0000000..706f726 --- /dev/null +++ b/app/src/main/res/layout/activity_auth_face.xml @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auth_person.xml b/app/src/main/res/layout/activity_auth_person.xml new file mode 100644 index 0000000..ef6bc76 --- /dev/null +++ b/app/src/main/res/layout/activity_auth_person.xml @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auth_qualification.xml b/app/src/main/res/layout/activity_auth_qualification.xml new file mode 100644 index 0000000..3889ace --- /dev/null +++ b/app/src/main/res/layout/activity_auth_qualification.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auth_road.xml b/app/src/main/res/layout/activity_auth_road.xml new file mode 100644 index 0000000..74eb184 --- /dev/null +++ b/app/src/main/res/layout/activity_auth_road.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auth_team.xml b/app/src/main/res/layout/activity_auth_team.xml new file mode 100644 index 0000000..0d1a24a --- /dev/null +++ b/app/src/main/res/layout/activity_auth_team.xml @@ -0,0 +1,646 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_code.xml b/app/src/main/res/layout/activity_code.xml new file mode 100644 index 0000000..54efb36 --- /dev/null +++ b/app/src/main/res/layout/activity_code.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml new file mode 100644 index 0000000..f38d162 --- /dev/null +++ b/app/src/main/res/layout/activity_home.xml @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_launcher.xml b/app/src/main/res/layout/activity_launcher.xml new file mode 100644 index 0000000..39e6631 --- /dev/null +++ b/app/src/main/res/layout/activity_launcher.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml new file mode 100644 index 0000000..cec3ea9 --- /dev/null +++ b/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_waybill_list.xml b/app/src/main/res/layout/fragment_waybill_list.xml new file mode 100644 index 0000000..c90d627 --- /dev/null +++ b/app/src/main/res/layout/fragment_waybill_list.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml new file mode 100644 index 0000000..0dbf965 --- /dev/null +++ b/app/src/main/res/layout/grid_item.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/grid_mine_item.xml b/app/src/main/res/layout/grid_mine_item.xml new file mode 100644 index 0000000..bafe518 --- /dev/null +++ b/app/src/main/res/layout/grid_mine_item.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_message.xml b/app/src/main/res/layout/item_message.xml new file mode 100644 index 0000000..4685732 --- /dev/null +++ b/app/src/main/res/layout/item_message.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_waybill.xml b/app/src/main/res/layout/item_waybill.xml new file mode 100644 index 0000000..cd775cf --- /dev/null +++ b/app/src/main/res/layout/item_waybill.xml @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..34c7d6d --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..7df9d73 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,21 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + #E5E5E5 + #00000000 + + #EEEEEE + #333333 + #666666 + + #ED4C19 + #0256FF + #ED4C19 + #FF4A02 + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..2f1fa2b --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,436 @@ + + + + + @dimen/dp_15 + + + + -140dp + -60dp + -36dp + -30dp + -20dp + -12dp + -10dp + -8dp + -5dp + -2dp + -1dp + 0dp + 0.1dp + 0.5dp + 1dp + 1.5dp + 2dp + 2.5dp + 3dp + 3.5dp + 4dp + 4.5dp + 5dp + 6dp + 7dp + 7.5dp + 8dp + 9dp + 10dp + 11dp + 12dp + 13dp + 14dp + 15dp + 16dp + 17dp + 18dp + 19dp + 20dp + 21dp + 22dp + 23dp + 24dp + 25dp + 26dp + 27dp + 28dp + 29dp + 30dp + 31dp + 32dp + 33dp + 34dp + 35dp + 36dp + 37dp + 38dp + 39dp + 40dp + 41dp + 42dp + 43dp + 44dp + 45dp + 46dp + 47dp + 48dp + 49dp + 50dp + 51dp + 52dp + 53dp + 54dp + 55dp + 56dp + 57dp + 58dp + 59dp + 60dp + 61dp + 62dp + 63dp + 64dp + 65dp + 66dp + 67dp + 68dp + 69dp + 70dp + 71dp + 72dp + 73dp + 74dp + 75dp + 76dp + 77dp + 78dp + 79dp + 80dp + 81dp + 82dp + 83dp + 84dp + 85dp + 86dp + 87dp + 88dp + 89dp + 90dp + 91dp + 92dp + 93dp + 94dp + 95dp + 96dp + 97dp + 98dp + 99dp + 100dp + 101dp + 102dp + 103dp + 104dp + 104.5dp + 105dp + 106dp + 107dp + 108dp + 109dp + 110dp + 111dp + 112dp + 113dp + 114dp + 115dp + 116dp + 117dp + 118dp + 119dp + 120dp + 121dp + 122dp + 123dp + 124dp + 125dp + 126dp + 127dp + 128dp + 129dp + 130dp + 131dp + 132dp + 133dp + 134dp + 134.5dp + 135dp + 136dp + 137dp + 138dp + 139dp + 140dp + 141dp + 142dp + 143dp + 144dp + 145dp + 146dp + 147dp + 148dp + 149dp + 150dp + 151dp + 152dp + 153dp + 154dp + 155dp + 156dp + 157dp + 158dp + 159dp + 160dp + 161dp + 162dp + 163dp + 164dp + 165dp + 166dp + 167dp + 168dp + 169dp + 170dp + 171dp + 172dp + 173dp + 174dp + 175dp + 176dp + 177dp + 178dp + 179dp + 180dp + 181dp + 182dp + 183dp + 184dp + 185dp + 186dp + 187dp + 188dp + 189dp + 190dp + 191dp + 191.25dp + 192dp + 193dp + 194dp + 195dp + 196dp + 197dp + 198dp + 199dp + 200dp + 201dp + 202dp + 203dp + 204dp + 205dp + 206dp + 207dp + 208dp + 209dp + 210dp + 211dp + 212dp + 213dp + 214dp + 215dp + 216dp + 217dp + 218dp + 219dp + 220dp + 221dp + 222dp + 223dp + 224dp + 225dp + 226dp + 227dp + 228dp + 229dp + 230dp + 231dp + 232dp + 233dp + 234dp + 235dp + 236dp + 237dp + 238dp + 239dp + 240dp + 241dp + 242dp + 243dp + 244dp + 245dp + 246dp + 247dp + 248dp + 249dp + 250dp + 251dp + 252dp + 253dp + 254dp + 255dp + 256dp + 257dp + 258dp + 259dp + 260dp + 261dp + 262dp + 263dp + 264dp + 265dp + 266dp + 267dp + 268dp + 269dp + 270dp + 271dp + 272dp + 273dp + 274dp + 275dp + 276dp + 277dp + 278dp + 279dp + 280dp + 281dp + 282dp + 283dp + 284dp + 285dp + 286dp + 287dp + 288dp + 289dp + 290dp + 291dp + 292dp + 293dp + 294dp + 295dp + 296dp + 297dp + 298dp + 299dp + 300dp + 301dp + 302dp + 303dp + 304dp + 305dp + 306dp + 307dp + 308dp + 309dp + 310dp + 311dp + 312dp + 313dp + 314dp + 315dp + 316dp + 317dp + 318dp + 319dp + 320dp + 321dp + 322dp + 323dp + 324dp + 325dp + 326dp + 327dp + 328dp + 329dp + 330dp + 331dp + 332dp + 333dp + 334dp + 335dp + 336dp + 337dp + 338dp + 339dp + 340dp + 341dp + 342dp + 343dp + 344dp + 345dp + 346dp + 347dp + 348dp + 349dp + 350dp + 351dp + 352dp + 353dp + 354dp + 355dp + 356dp + 357dp + 358dp + 359dp + 360dp + 365dp + 370dp + 400dp + 410dp + 422dp + 472dp + 500dp + 600dp + 640dp + 720dp + + + 6sp + 7sp + 8sp + 9sp + 10sp + 11sp + 12sp + 13sp + 14sp + 15sp + 16sp + 17sp + 18sp + 19sp + 20sp + 21sp + 22sp + 23sp + 24sp + 25sp + 28sp + 30sp + 32sp + 34sp + 36sp + 38sp + 40sp + 42sp + 48sp + + 16dp + 16dp + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..fbeb744 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,12 @@ + + GLDriver + LoginActivity + Email + Password + Sign in or register + Sign in + "Welcome !" + Not a valid username + Password must be >5 characters + "Login failed" + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..9420c45 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..9848c4e --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,27 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..fa0f996 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/test/java/com/dahe/gldriver/ExampleUnitTest.kt b/app/src/test/java/com/dahe/gldriver/ExampleUnitTest.kt new file mode 100644 index 0000000..5d860ac --- /dev/null +++ b/app/src/test/java/com/dahe/gldriver/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.dahe.gldriver + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..600a467 --- /dev/null +++ b/build.gradle @@ -0,0 +1,10 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.2.2' apply false + id 'com.android.library' version '7.2.2' apply false + id 'org.jetbrains.kotlin.android' version '1.9.22' apply false +} +apply from: "compile.gradle" +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/compile.gradle b/compile.gradle new file mode 100644 index 0000000..f796287 --- /dev/null +++ b/compile.gradle @@ -0,0 +1,76 @@ +def CrashActivityVersion = '2.4.0' +def StatusBarVersion = '2.3.3' +def GsonVersion = '2.10.1' +def PhotoPickerVersion = 'v3.11.1' +def GlideVersion = '4.16.0' +def AgentWebVersion = 'v5.0.6-androidx' +def NiceDialogVersion = '1.1.9' +def AndPermissionVersion = '2.0.3' +def BannerVersion = '2.2.2' +def SmartRefreshLayoutVersion = '2.0.6' +def MultideXVersion = '2.0.1' +def RXJavaVersion = '3.1.7' +def RXAndroidVersion = '3.0.2' +def RetrofitVersion = '2.9.0' +def OkHttpVersion = '4.11.0' +def AutoSizeVersion = '1.1.2' +def FlycoTabLayoutVersion = '3.0.0' +def ZxingVersion = '1.3.8' +def BaseRecyclerViewAdapterHelper = '3.0.14' +def MagicIndicator = '1.7.0' +def PickerView = '4.1.9' +def Permissionx = '1.7.1' +def NiceSpinner = '1.4.4' +def Countdownview = '2.1.6' +def Xpopup = '2.9.19' +def CheckVersionLib = '2.4.2' +def BuglyVersion = 'latest.release' +project.ext { + android = [ + compileSdkVersion: 32, + buildToolsVersion: "32", + applicationId : "com.dahe.gldriver", + minSdkVersion : 24, + targetSdkVersion : 32, + versionCode : 1, + versionName : "1.0.5", + ] + dependencies = [ + "customactivityoncrash": "cat.ereza:customactivityoncrash:${CrashActivityVersion}", + "gson" : "com.google.code.gson:gson:${GsonVersion}", + "PhotoPicker" : "io.github.lucksiege:pictureselector:${PhotoPickerVersion}", +// "PhotoPicker" : "com.github.LuckSiege.PictureSelector:picture_library:${PhotoPickerVersion}", +// "PhotoPicker" : "io.github.lucksiege:pictureselector:${PhotoPickerVersion}", + "agentweb" : "com.github.Justson.AgentWeb:agentweb-core:${AgentWebVersion}", + "statusbaruitl" : "com.github.niorgai:StatusBarCompat:${StatusBarVersion}", + "glide" : "com.github.bumptech.glide:glide:${GlideVersion}", + "glide-compiler" : "com.github.bumptech.glide:compiler:${GlideVersion}", + "glide-okhttps" : "com.github.bumptech.glide:okhttp3-integration:${GlideVersion}", + "NiceDialog" : "com.github.Othershe:NiceDialog:${NiceDialogVersion}",//todo + "Banner" : "io.github.youth5201314:banner:${BannerVersion}", + "RefreshLayout" : "io.github.scwang90:refresh-layout-kernel:${SmartRefreshLayoutVersion}", + "Header" : "io.github.scwang90:refresh-header-classics:${SmartRefreshLayoutVersion}", + "Footer" : "io.github.scwang90:refresh-footer-classics:${SmartRefreshLayoutVersion}", + "Multidex" : "androidx.multidex:multidex:${MultideXVersion}",//todo + "rxjava" : "io.reactivex.rxjava3:rxjava:${RXJavaVersion}", + "rxandroid" : "io.reactivex.rxjava3:rxandroid:${RXAndroidVersion}", + "retrofit" : "com.squareup.retrofit2:retrofit:${RetrofitVersion}", + "converter-gson" : "com.squareup.retrofit2:converter-gson:${RetrofitVersion}", + "adapter-rxjava2" : "com.squareup.retrofit2:adapter-rxjava3:${RetrofitVersion}", + "okhttp" : "com.squareup.okhttp3:okhttp:${OkHttpVersion}", + "logging-interceptor" : "com.squareup.okhttp3:logging-interceptor:${OkHttpVersion}", + "AutoSize" : "me.jessyan:autosize:${AutoSizeVersion}",//todo + "FlycoTabLayout" : "io.github.h07000223:flycoTabLayout:${FlycoTabLayoutVersion}", + "AndPermission" : "com.yanzhenjie:permission:${AndPermissionVersion}", + "Zxing" : "com.github.bingoogolapple.BGAQRCode-Android:zxing:${ZxingVersion}", + "BaseRecyclerViewAdapterHelper" :"io.github.cymchad:BaseRecyclerViewAdapterHelper:${BaseRecyclerViewAdapterHelper}", + "MagicIndicator" :"com.github.hackware1993:MagicIndicator:${MagicIndicator}", + "NiceSpinner" :"com.github.arcadefire:nice-spinner:${NiceSpinner}", + "Countdownview" :"com.github.iwgang:countdownview:${Countdownview}", + "Xpopup" :"com.github.li-xiaojun:XPopup:${Xpopup}", + "CheckVersionLib" :"com.github.AlexLiuSheng:CheckVersionLib:${CheckVersionLib}", + "Bugly" :"com.tencent.bugly:crashreport:${BuglyVersion}",//todo + "PickerView" :"com.contrarywind:Android-PickerView:${PickerView}", + "Permissionx" :"com.guolindev.permissionx:permissionx:${Permissionx}" + ] +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..b6caa12 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,26 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true + +android.enableJetifier=true +android.useDeprecatedNdk=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..22b1f4e --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Dec 27 15:25:22 CST 2023 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/mylibrary/.gitignore b/mylibrary/.gitignore new file mode 100644 index 0000000..f7415cf --- /dev/null +++ b/mylibrary/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties \ No newline at end of file diff --git a/mylibrary/build.gradle b/mylibrary/build.gradle new file mode 100644 index 0000000..177a55d --- /dev/null +++ b/mylibrary/build.gradle @@ -0,0 +1,109 @@ +plugins { + id 'com.android.library' + id 'kotlin-android' +// id 'com.jakewharton.butterknife' +} + +android { + compileSdkVersion rootProject.ext.android["compileSdkVersion"] + + defaultConfig { + minSdkVersion rootProject.ext.android["minSdkVersion"] + targetSdkVersion rootProject.ext.android["targetSdkVersion"] + versionCode rootProject.ext.android["versionCode"] + versionName rootProject.ext.android["versionName"] + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = '11' + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + + + + api rootProject.ext.dependencies["gson"] + api rootProject.ext.dependencies["glide"] + annotationProcessor rootProject.ext.dependencies["glide-compiler"] + api rootProject.ext.dependencies["agentweb"] + api rootProject.ext.dependencies["Banner"] + api rootProject.ext.dependencies["RefreshLayout"] + api rootProject.ext.dependencies["Header"] + api rootProject.ext.dependencies["Footer"] + api rootProject.ext.dependencies["rxjava"] + api rootProject.ext.dependencies["rxandroid"] + api rootProject.ext.dependencies["retrofit"] + api rootProject.ext.dependencies["converter-gson"] + api rootProject.ext.dependencies["adapter-rxjava2"] + api rootProject.ext.dependencies["okhttp"] + api rootProject.ext.dependencies["logging-interceptor"] +// api rootProject.ext.dependencies["recyclerview"] + api rootProject.ext.dependencies["AutoSize"] + api rootProject.ext.dependencies["statusbaruitl"] + api rootProject.ext.dependencies["BaseRecyclerViewAdapterHelper"] + api rootProject.ext.dependencies["PhotoPicker"] + api rootProject.ext.dependencies["PickerView"] + api rootProject.ext.dependencies["Xpopup"] + api rootProject.ext.dependencies["Countdownview"] + api rootProject.ext.dependencies["CheckVersionLib"] + api rootProject.ext.dependencies["Bugly"] + api rootProject.ext.dependencies["Zxing"] + api rootProject.ext.dependencies["Multidex"] + api rootProject.ext.dependencies["FlycoTabLayout"] + api rootProject.ext.dependencies["NiceDialog"] + api rootProject.ext.dependencies["MagicIndicator"] + api rootProject.ext.dependencies["glide-okhttps"] + api rootProject.ext.dependencies["Permissionx"] + api 'pub.devrel:easypermissions:3.0.0' +// api 'com.gyf.cactus:cactus:1.1.3-beta13' + + + + + + + +// implementation "io.github.cymchad:BaseRecyclerViewAdapterHelper:4.0.1" + + //友盟基础库(必须) +// api 'com.umeng.umsdk:common:9.4.4' +// api 'com.umeng.umsdk:asms:1.4.1' +// +// //友盟推送库 +// api 'com.umeng.umsdk:push:6.4.5' +// +// api 'com.umeng.umsdk:huawei-umengaccs:1.3.5' +// api 'com.huawei.hms:push:5.3.0.304' + + + +// api('com.aliyun.ams:alicloud-android-hotfix:3.3.0') { +// exclude(module: 'alicloud-android-ut') +// exclude(module: 'alicloud-android-utdid') +// exclude(module: 'alicloud-android-utils') +// } + api 'com.aliyun.dpa:oss-android-sdk:2.9.5' + +} diff --git a/mylibrary/consumer-rules.pro b/mylibrary/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/mylibrary/proguard-rules.pro b/mylibrary/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/mylibrary/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/mylibrary/src/androidTest/java/com/dahe/mylibrary/ExampleInstrumentedTest.kt b/mylibrary/src/androidTest/java/com/dahe/mylibrary/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..c51c36c --- /dev/null +++ b/mylibrary/src/androidTest/java/com/dahe/mylibrary/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.dahe.mylibrary + +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.dahe.mylibrary.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/mylibrary/src/main/AndroidManifest.xml b/mylibrary/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2f43892 --- /dev/null +++ b/mylibrary/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/CommonBaseLibrary.java b/mylibrary/src/main/java/com/dahe/mylibrary/CommonBaseLibrary.java new file mode 100644 index 0000000..cfb0035 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/CommonBaseLibrary.java @@ -0,0 +1,138 @@ +package com.dahe.mylibrary; + +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import android.os.Bundle; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.scwang.smart.refresh.footer.ClassicsFooter; +import com.scwang.smart.refresh.header.ClassicsHeader; +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.scwang.smart.refresh.layout.api.RefreshFooter; +import com.scwang.smart.refresh.layout.api.RefreshHeader; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.DefaultRefreshFooterCreator; +import com.scwang.smart.refresh.layout.listener.DefaultRefreshHeaderCreator; + +import java.lang.ref.WeakReference; +import java.util.LinkedList; +import java.util.List; + +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * Created by Administrator on 2018/7/15 0015. + */ + +public class CommonBaseLibrary { + public volatile static CommonBaseLibrary mInstance = null; + private static Application mApplication = null; + public static WeakReference topActivity; + public static List activityList = new LinkedList<>(); + private static Retrofit mRetrofit; + + static { + SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() { + @Override + public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) { + return new ClassicsHeader(context); + } + }); + SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() { + @Override + public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) { + return new ClassicsFooter(context); + } + }); + } + + public CommonBaseLibrary() { + } + + public static CommonBaseLibrary getInstance() { + System.out.println("ceshi"); + if (null == mInstance) { + synchronized (CommonBaseLibrary.class) { + if (null == mInstance) { + mInstance = new CommonBaseLibrary(); + } + } + } + return mInstance; + } + + public CommonBaseLibrary init(Application application, String baseUrl) { + mApplication = application; + application.registerActivityLifecycleCallbacks(mCallbacks); + Gson gson = new GsonBuilder().setDateFormat("yyy-MM-dd HH:mm:ss").create(); + mRetrofit = new Retrofit.Builder() + .baseUrl(baseUrl) + .addConverterFactory(GsonConverterFactory.create(gson)) + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) + .build(); + +// .addConverterFactory(GsonConverterFactory.create(gson)) + return this; + } + + + + public static Application getApplication() { + return mApplication; + } + + public static Retrofit getRetrofit() { + if (null == mRetrofit) + throw new NullPointerException("please call CommonBaseLibrary.getInstance().init() first in application!"); + return mRetrofit; + + } + + private static Application.ActivityLifecycleCallbacks mCallbacks = new Application.ActivityLifecycleCallbacks() { + @Override + public void onActivityCreated(Activity activity, Bundle bundle) { + activityList.add(activity); + setTopActivityWeakRef(activity); + } + + @Override + public void onActivityStarted(Activity activity) { + setTopActivityWeakRef(activity); + } + + @Override + public void onActivityResumed(Activity activity) { + setTopActivityWeakRef(activity); + } + + @Override + public void onActivityPaused(Activity activity) { + + } + + @Override + public void onActivityStopped(Activity activity) { + + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + activityList.remove(activity); + } + }; + + private static void setTopActivityWeakRef(Activity activity) { + if (topActivity == null || !activity.equals(topActivity.get())) { + topActivity = new WeakReference<>(activity); + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CarAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CarAdapter.java new file mode 100644 index 0000000..516f707 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CarAdapter.java @@ -0,0 +1,30 @@ +package com.dahe.mylibrary.adapter; + +import android.widget.CheckBox; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.bean.CarBean; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class CarAdapter extends BaseQuickAdapter { + + public CarAdapter(int layoutResId, @Nullable List data) { + super(R.layout.item_car_select, data); + } + + @Override + protected void convert(@NotNull BaseViewHolder helper, CarBean item) { + helper.setText(R.id.tv_title, item.getVehicle()) + .setText(R.id.tv_lxr, "司机信息:"+item.getDriverName() + " " + item.getDriverPhone()) + .setText(R.id.tv_zz, "载重(Kg):"+item.getApprovedLoad()) + .setText(R.id.tv_ckg, "长宽高(毫米):"+item.getOutlineLong()+"*"+item.getOutlineWide()+"*"+item.getOutlineHigh()); + CheckBox cb = helper.getView(R.id.cb); + cb.setChecked(item.isSelect()); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CenterSimAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CenterSimAdapter.java new file mode 100644 index 0000000..27f52e7 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CenterSimAdapter.java @@ -0,0 +1,41 @@ +package com.dahe.mylibrary.adapter; + +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.bean.StateBean; + +import java.util.List; + +public class CenterSimAdapter extends BaseQuickAdapter { + private StateBean selectString=null; + + + public CenterSimAdapter(int layoutResId, @Nullable List data, StateBean selectString) { + super(R.layout.item_select, data); + this.selectString = selectString; + } + + @Override + protected void convert(BaseViewHolder helper, StateBean item) { + helper.setText(R.id.tv_content,item.getDictLabel()); + TextView tv = helper.getView(R.id.tv_content); + if (selectString!=null&&item.getDictValue()!=null){ + if (item.getDictValue().equals(selectString.getDictValue())){ + tv.setSelected(true); + }else{ + tv.setSelected(false); + } + } + + + } + + public void setSelect(StateBean selectString){ + this.selectString = selectString; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/GridImageAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/GridImageAdapter.java new file mode 100644 index 0000000..7c263b9 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/GridImageAdapter.java @@ -0,0 +1,222 @@ +package com.dahe.mylibrary.adapter; + +import android.content.Context; +import android.net.Uri; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.callback.OnItemLongClickListener; +import com.luck.picture.lib.config.PictureMimeType; +import com.luck.picture.lib.config.SelectMimeType; +import com.luck.picture.lib.entity.LocalMedia; +import com.luck.picture.lib.utils.DateUtils; + +import java.util.ArrayList; +import java.util.List; + + +/** + * @author:luck + * @date:2016-7-27 23:02 + * @describe:GridImageAdapter + */ +public class GridImageAdapter extends RecyclerView.Adapter { + public static final String TAG = "PictureSelector"; + public static final int TYPE_CAMERA = 1; + public static final int TYPE_PICTURE = 2; + private final LayoutInflater mInflater; + private final ArrayList list = new ArrayList<>(); + private int selectMax = 9; + + /** + * 删除 + */ + public void delete(int position) { + try { + + if (position != RecyclerView.NO_POSITION && list.size() > position) { + list.remove(position); + notifyItemRemoved(position); + notifyItemRangeChanged(position, list.size()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public GridImageAdapter(Context context, List result) { + this.mInflater = LayoutInflater.from(context); + this.list.addAll(result); + } + + public void setSelectMax(int selectMax) { + this.selectMax = selectMax; + } + + public int getSelectMax() { + return selectMax; + } + + public ArrayList getData() { + return list; + } + + public void remove(int position) { + if (position < list.size()) { + list.remove(position); + } + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + + ImageView mImg; + ImageView mIvDel; + TextView tvDuration; + + public ViewHolder(View view) { + super(view); + mImg = view.findViewById(R.id.fiv); + mIvDel = view.findViewById(R.id.iv_del); + tvDuration = view.findViewById(R.id.tv_duration); + } + } + + @Override + public int getItemCount() { + if (list.size() < selectMax) { + return list.size() + 1; + } else { + return list.size(); + } + } + + @Override + public int getItemViewType(int position) { + if (isShowAddItem(position)) { + return TYPE_CAMERA; + } else { + return TYPE_PICTURE; + } + } + + /** + * 创建ViewHolder + */ + @Override + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + View view = mInflater.inflate(R.layout.gv_filter_image, viewGroup, false); + return new ViewHolder(view); + } + + private boolean isShowAddItem(int position) { + int size = list.size(); + return position == size; + } + + /** + * 设置值 + */ + @Override + public void onBindViewHolder(final ViewHolder viewHolder, final int position) { + //少于MaxSize张,显示继续添加的图标 + if (getItemViewType(position) == TYPE_CAMERA) { + viewHolder.mImg.setImageResource(R.drawable.ic_add_image); + viewHolder.mImg.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mItemClickListener != null) { + mItemClickListener.openPicture(); + } + } + }); + viewHolder.mIvDel.setVisibility(View.INVISIBLE); + } else { + viewHolder.mIvDel.setVisibility(View.VISIBLE); + viewHolder.mIvDel.setOnClickListener(view -> { + int index = viewHolder.getAbsoluteAdapterPosition(); + if (index != RecyclerView.NO_POSITION && list.size() > index) { + list.remove(index); + notifyItemRemoved(index); + notifyItemRangeChanged(index, list.size()); + } + }); + LocalMedia media = list.get(position); + int chooseModel = media.getChooseModel(); + String path = media.getAvailablePath(); + long duration = media.getDuration(); + viewHolder.tvDuration.setVisibility(PictureMimeType.isHasVideo(media.getMimeType()) + ? View.VISIBLE : View.GONE); + if (chooseModel == SelectMimeType.ofAudio()) { + viewHolder.tvDuration.setVisibility(View.VISIBLE); + viewHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds + (R.drawable.ps_ic_audio, 0, 0, 0); + + } else { + viewHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds + (R.drawable.ps_ic_video, 0, 0, 0); + } + viewHolder.tvDuration.setText(DateUtils.formatDurationTime(duration)); + if (chooseModel == SelectMimeType.ofAudio()) { + viewHolder.mImg.setImageResource(R.drawable.ps_audio_placeholder); + } else { + Glide.with(viewHolder.itemView.getContext()) + .load(PictureMimeType.isContent(path) && !media.isCut() && !media.isCompressed() ? Uri.parse(path) + : path) + .centerCrop() + .placeholder(R.color.app_color_f6) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .into(viewHolder.mImg); + } + //itemView 的点击事件 + if (mItemClickListener != null) { + viewHolder.itemView.setOnClickListener(v -> { + int adapterPosition = viewHolder.getAbsoluteAdapterPosition(); + mItemClickListener.onItemClick(v, adapterPosition); + }); + } + + if (mItemLongClickListener != null) { + viewHolder.itemView.setOnLongClickListener(v -> { + int adapterPosition = viewHolder.getAbsoluteAdapterPosition(); + mItemLongClickListener.onItemLongClick(viewHolder, adapterPosition, v); + return true; + }); + } + } + } + + private OnItemClickListener mItemClickListener; + + public void setOnItemClickListener(OnItemClickListener l) { + this.mItemClickListener = l; + } + + public interface OnItemClickListener { + /** + * Item click event + * + * @param v + * @param position + */ + void onItemClick(View v, int position); + + /** + * Open PictureSelector + */ + void openPicture(); + } + + private OnItemLongClickListener mItemLongClickListener; + + public void setItemLongClickListener(OnItemLongClickListener l) { + this.mItemLongClickListener = l; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/NodeAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/NodeAdapter.java new file mode 100644 index 0000000..b4da2e0 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/NodeAdapter.java @@ -0,0 +1,30 @@ +package com.dahe.mylibrary.adapter; + +import android.widget.CheckBox; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.bean.NodeBean; +import com.dahe.mylibrary.utils.StringUtils; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class NodeAdapter extends BaseQuickAdapter { + + public NodeAdapter(int layoutResId, @Nullable List data) { + super(R.layout.item_node_select, data); + } + + @Override + protected void convert(@NotNull BaseViewHolder helper, NodeBean item) { + helper.setText(R.id.tv_title, item.getNode()) + .setText(R.id.tv_lxr, StringUtils.isEmpty(item.getDocking())?"":item.getDocking() + " " + (StringUtils.isEmpty(item.getDockingPhone())?"":item.getDockingPhone())) + .setText(R.id.tv_addres, item.getFreighter()); + CheckBox cb = helper.getView(R.id.cb); + cb.setChecked("1".equals(item.isSelect())?true:false); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/SelectDicAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/SelectDicAdapter.java new file mode 100644 index 0000000..fa6d46e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/SelectDicAdapter.java @@ -0,0 +1,37 @@ +package com.dahe.mylibrary.adapter; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.bean.StateBean; + +import java.util.List; + + +public class SelectDicAdapter extends BaseQuickAdapter { + private int selectPos = -1; + + + public SelectDicAdapter(int layoutResId, @Nullable List data, int selectPos) { + super(R.layout.item_dic_select, data); + this.selectPos = selectPos; + } + + @Override + protected void convert(BaseViewHolder helper, StateBean item) { + helper.setText(R.id.tv_content,item.getDictLabel()); +// TextView tv = helper.getView(R.id.tv_content); +// if (item.equals(selectString)){ +// tv.setSelected(true); +// }else{ +// tv.setSelected(false); +// } + + } + + public void setSelect(int selectString){ + this.selectPos = selectString; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseActivity.java b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseActivity.java new file mode 100644 index 0000000..4407faf --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseActivity.java @@ -0,0 +1,307 @@ +package com.dahe.mylibrary.base; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +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 android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.ContextCompat; +import androidx.viewbinding.ViewBinding; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.callback.RefreshCallBack; +import com.dahe.mylibrary.utils.BarUtils; +import com.dahe.mylibrary.utils.ConvertUtils; +import com.dahe.mylibrary.utils.StatusBar; +import com.dahe.mylibrary.utils.ToastUtils; +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.constant.RefreshState; +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener; + +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; + +import qiu.niorgai.StatusBarCompat; + + +public abstract class BaseActivity extends AppCompatActivity { + protected Context mContext; + protected final int DEFAULT_STATUS_BAR_ALPHA = 0; + private static final String TAG = "BaseActivity"; + protected Toolbar mToolbar; + protected int mRefreshPage = 1; + protected int mRefreshCount = 15; + + public VB binding; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = createBinding(); + if (binding==null) + return; + setContentView(binding.getRoot()); + mContext = this; + setStatusBarColorToLight(); + initView(savedInstanceState); + initDate(); + } + + + private VB createBinding() { + try { + Class vbClass = getVBClass(); + Method inflateMethod = vbClass.getMethod("inflate", LayoutInflater.class); + inflateMethod.setAccessible(true); + return (VB) inflateMethod.invoke(null, getLayoutInflater()); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private Class getVBClass() { + ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); + Class vbClass = (Class) type.getActualTypeArguments()[0]; + + return vbClass; + } + +// protected abstract VB getViewBinding(); + + /** + * 标题栏的颜色 文字白色 + */ + public void setStatusBarCancelLightColor() { + StatusBar.cancelLightStatusBar(this); + } + + + /** + * 设置沉浸式标题栏 标题栏的颜色 + */ + public void setStatusBarColor(int color) { + StatusBarCompat.setStatusBarColor(this, ContextCompat.getColor(mContext, color), DEFAULT_STATUS_BAR_ALPHA); + StatusBar.changeToLightStatusBar(this); //黑色 下边白色 +// StatusBar.cancelLightStatusBar(this); + } + + /** + * 设置沉浸式标题栏 标题栏的颜色 + */ + public void setStatusBarColor() { +// StatusBarCompat.setStatusBarColor(this, ContextCompat.getColor(mContext, color), DEFAULT_STATUS_BAR_ALPHA); +// StatusBar.changeToLightStatusBar(this); //黑色 下边白色 + StatusBar.cancelLightStatusBar(this); + } + + /** + * 设置沉浸式标题栏 里面是Fragment + */ + public void setStatusBarColorInFragment() { + StatusBarCompat.translucentStatusBar(this); + } + + /** + * 设置透明沉浸式标题栏 + * * true标题栏无背景,false标题栏有背景 + */ + public void setStatusBarColorToLight() { + StatusBar.translucentStatusBar(this, true); + StatusBar.changeToLightStatusBar(this); + } + + /** + * 设置透明沉浸式标题栏 + * true标题栏无背景,false标题栏有背景 + */ + public void setStatusBarColorToLight(boolean isHide) { + StatusBar.translucentStatusBar(this, isHide); + StatusBar.changeToLightStatusBar(this); + + } + + /** + * 设置标题 + */ + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + protected void setTitleBar(String title, View.OnClickListener listener) { + mToolbar = (Toolbar) findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) findViewById(R.id.common_toolBar_title)).setText(title); + mToolbar.setNavigationIcon(R.drawable.left_black); + mToolbar.setNavigationOnClickListener(listener); + } + + /** + * 设置标题 + */ + protected void setTitleBar(String title) { + mToolbar = (Toolbar) findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) findViewById(R.id.common_toolBar_title)).setText(title); + } + /** + * 设置标题 + */ + protected void setTitleBar(String title,boolean isBack) { + mToolbar = (Toolbar) findViewById(R.id.common_toolbar); + mToolbar.setBackgroundColor(Color.TRANSPARENT); + if (isBack){ + mToolbar.setNavigationIcon(R.drawable.left_black); + mToolbar.setNavigationOnClickListener(view -> finish()); + } + if (!TextUtils.isEmpty(title)) + ((TextView) findViewById(R.id.common_toolBar_title)).setText(title); + } + + /** + * 显示右边标题 + * + * @param title + * @param listener + * @param isVisible + * @param right + */ + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + protected void setTitleBar(String title, View.OnClickListener listener, boolean isVisible, String right, View.OnClickListener rightListener) { + mToolbar = (Toolbar) findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) findViewById(R.id.common_toolBar_title)).setText(title); + TextView mTextRight = (TextView) findViewById(R.id.common_toolBar_text_right); + if (isVisible) { + mTextRight.setVisibility(View.VISIBLE); + mTextRight.setText(right); + mTextRight.setOnClickListener(rightListener); + } + mToolbar.setNavigationIcon(R.drawable.left_black); + mToolbar.setNavigationOnClickListener(listener); + } + + /** + * 设置距离顶部距离 + */ + protected void setStatusHeightParams(View llContent) { + RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + closeLayoutParams.topMargin = ConvertUtils.dp2px(8) + BarUtils.getStatusBarHeight(); +// closeLayoutParams.topMargin = BarUtils.getStatusBarHeight(); + llContent.setLayoutParams(closeLayoutParams); + } + + protected abstract void initView(Bundle savedInstanceState); + + protected abstract void initDate(); + + protected void showToast(Object message) { + ToastUtils.showToast(this, message instanceof String ? message + "" : getResources().getString((int) message)); + } + + protected void canCelToast() { + ToastUtils.cancelToast(); + } + + +// protected void showToast(Object message,int time) { +// ToastUtils.showToast(this, message instanceof String ? message + "" : getResources().getString((int) message),time); +// } + + @Override + protected void onDestroy() { + super.onDestroy(); + //释放持有,防止泄露 + binding = null; + } + + + /** + * 设置刷新控件 + * + * @param refreshLayout + * @param callBack 访问网络回调 + */ + protected void setRefresh(final SmartRefreshLayout refreshLayout, final RefreshCallBack callBack) { + refreshLayout.setEnableOverScrollDrag(true) + .setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + mRefreshPage++; + callBack.getRefreshDate(2, mRefreshPage, mRefreshCount); + } + + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + mRefreshPage = 1; + callBack.getRefreshDate(1, mRefreshPage, mRefreshCount); + } + }); + } + + /** + * 网络访问完成 刷新控件 + * + * @param refreshLayout + * @param isLoadMore false禁用下拉加载更多 + */ + protected void setFinishRefresh(final SmartRefreshLayout refreshLayout, boolean isLoadMore) { + if (refreshLayout != null && refreshLayout.getState() == RefreshState.Refreshing) + refreshLayout.finishRefresh(); + else if (refreshLayout != null && refreshLayout.getState() == RefreshState.Loading) + refreshLayout.finishLoadMore(); + if (!isLoadMore) { + refreshLayout.finishLoadMore(); //加载完成 + refreshLayout.finishLoadMoreWithNoMoreData(); //全部加载完成,没有数据了调用此方法 + } +// refreshLayout.setEnableLoadMore(isLoadMore); + } + + public void onClick(View view) { + + } + + + /** + * 获取Drawable + * + * @param id + * @return + */ + protected Drawable getDrawableV4(@DrawableRes int id) { + return ContextCompat.getDrawable(this, id); + } + + /** + * 获取Color + * + * @param id + * @return + */ + protected int getColorV4(@ColorRes int id) { + return ContextCompat.getColor(this, id); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + } + + +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseFragment.java b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseFragment.java new file mode 100644 index 0000000..499fbce --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseFragment.java @@ -0,0 +1,341 @@ +package com.dahe.mylibrary.base; + + +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; +import androidx.viewbinding.ViewBinding; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.callback.RefreshCallBack; +import com.dahe.mylibrary.utils.StatusBar; +import com.dahe.mylibrary.utils.ToastUtils; +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.constant.RefreshState; +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; + +import qiu.niorgai.StatusBarCompat; + +/** + *

+ * Fragment基类,封装了懒加载的实现 + *

+ * 1、Viewpager + Fragment情况下,fragment的生命周期因Viewpager的缓存机制而失去了具体意义 + * 该抽象类自定义一个新的回调方法,当fragment可见状态改变时会触发的回调方法 + * + * @see #onFragmentVisibleChange(boolean) + * @see #onFragmentFirstVisible() + */ +public abstract class BaseFragment extends Fragment { + private boolean isFragmentVisible; + private boolean isReuseView; + private boolean isFirstVisible; + private boolean isPause; + private View rootView; + private static final String TAG = "BaseFragment"; + protected Context mContext; + protected int mRefreshPage = 1; + protected int mRefreshCount = 20; + protected Toolbar mToolbar; + protected final int DEFAULT_STATUS_BAR_ALPHA = 0; + + public VB binding; + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + Log.i(TAG, "onViewCreated: " + (rootView == null) + "---getUserVisibleHint()" + getUserVisibleHint() + "---isFirstVisible" + isFirstVisible); + //如果setUserVisibleHint()在rootView创建前调用时,那么 + //就等到rootView创建完后才回调onFragmentVisibleChange(true) + //保证onFragmentVisibleChange()的回调发生在rootView创建完成之后,以便支持ui操作 + if (rootView == null) { + rootView = view; + if (getUserVisibleHint()) { + if (isFirstVisible) { + onFragmentFirstVisible(); + isFirstVisible = false; + } + + onFragmentVisibleChange(isFirstVisible); + isFragmentVisible = true; + } + } + super.onViewCreated(isReuseView && rootView != null ? rootView : view, savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass(); + try { + Class cls = (Class) superClass.getActualTypeArguments()[0]; + Method method = cls.getMethod("inflate", LayoutInflater.class, ViewGroup.class, Boolean.TYPE); + method.setAccessible(true); + binding = (VB) method.invoke(null, inflater,container, Boolean.FALSE); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + if (binding!=null&&binding.getRoot()!=null) { + mContext = getActivity(); + return binding.getRoot(); + } else { + return super.onCreateView(inflater, container, savedInstanceState); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + binding = null; + } + + /** + * 标题栏的颜色 文字白色 + */ + public void setStatusBarCancelLightColor() { + StatusBar.cancelLightStatusBar(getActivity()); + } + + /** + * 设置沉浸式标题栏 标题栏的颜色 + */ + public void setStatusBarColor(int color) { + StatusBarCompat.setStatusBarColor(getActivity(), ContextCompat.getColor(mContext, color), DEFAULT_STATUS_BAR_ALPHA); + StatusBar.changeToLightStatusBar(getActivity()); + } + + /** + * 设置沉浸式标题栏 里面是Fragment + */ + public void setStatusBarColorInFragment() { + StatusBarCompat.translucentStatusBar(getActivity()); + } + + public void setStatusBarColorToLight() { + StatusBar.translucentStatusBar(getActivity(), true); + StatusBar.changeToLightStatusBar(getActivity()); + } + + @Override + public void onDestroy() { + initVariable(); + super.onDestroy(); + } + + + protected void showToast(Object message) { + ToastUtils.showToast(mContext, message instanceof String ? message + "" : getResources().getString((int) message)); + } + + /** + * 设置刷新控件 + * + * @param refreshLayout + * @param callBack 访问网络回调 + */ + protected void setRefresh(final SmartRefreshLayout refreshLayout, final RefreshCallBack callBack) { + refreshLayout.setEnableOverScrollDrag(true) + .setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + mRefreshPage++; + callBack.getRefreshDate(2, mRefreshPage, mRefreshCount); + } + + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + mRefreshPage = 1; + callBack.getRefreshDate(1, mRefreshPage, mRefreshCount); + } + }); + } + + /** + * 网络访问完成 刷新控件 + * + * @param refreshLayout + * @param isLoadMore false禁用下拉加载更多 + */ + protected void setFinishRefresh(final SmartRefreshLayout refreshLayout, boolean isLoadMore) { + if (refreshLayout.getState() == RefreshState.Refreshing) + refreshLayout.finishRefresh(); + else if (refreshLayout.getState() == RefreshState.Loading) + refreshLayout.finishLoadMore(); + if (!isLoadMore){ + refreshLayout.finishLoadMore(); //加载完成 + refreshLayout.finishLoadMoreWithNoMoreData(); //全部加载完成,没有数据了调用此方法 + } +// refreshLayout.setEnableLoadMore(isLoadMore); + } + + /** + * 设置标题 + */ + + protected void setTitleBar(String title, View.OnClickListener listener) { + mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title); + mToolbar.setNavigationIcon(R.drawable.black_back); + mToolbar.setNavigationOnClickListener(listener); + } + + /** + * 设置标题 + */ + + protected void setTitleBar(String title) { + mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title); + } + + /** + * 设置标题 + */ + + protected void setTitleBar(String title, boolean isRight, View.OnClickListener listener) { + mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) { + ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title); + ((RelativeLayout) rootView.findViewById(R.id.rlMessage)).setVisibility(isRight ? View.VISIBLE : View.GONE); + (rootView.findViewById(R.id.rlMessage)).setOnClickListener(listener); + } + } + + /** + * 设置标题 + */ + + protected void setTitleBar(String title, boolean isRight,String message, View.OnClickListener listener) { + mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) { + ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title); + ((RelativeLayout) rootView.findViewById(R.id.rlMessage)).setVisibility(isRight ? View.VISIBLE : View.GONE); + ((TextView) rootView.findViewById(R.id.tvMessage)).setText(message); + (rootView.findViewById(R.id.rlMessage)).setOnClickListener(listener); + } + } + + /** + * 设置标题 + */ + + protected void setBadView(boolean isRight) { + if (null != ((TextView) rootView.findViewById(R.id.tvCount))) { + ((TextView) rootView.findViewById(R.id.tvCount)).setVisibility(isRight ? View.VISIBLE : View.GONE); + } + } + + protected void setCount(int count) { + if (count > 100) { + ((TextView) rootView.findViewById(R.id.tvCount)).setText("99··"); + } else { + ((TextView) rootView.findViewById(R.id.tvCount)).setText(count + ""); + } + + } + + + //setUserVisibleHint()在Fragment创建时会先被调用一次,传入isVisibleToUser = false + //如果当前Fragment可见,那么setUserVisibleHint()会再次被调用一次,传入isVisibleToUser = true + //如果Fragment从可见->不可见,那么setUserVisibleHint()也会被调用,传入isVisibleToUser = false + //总结:setUserVisibleHint()除了Fragment的可见状态发生变化时会被回调外,在new Fragment()时也会被回调 + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + Log.i(TAG, "isFirstVisible: " + isFirstVisible + "--isVisibleToUser" + isVisibleToUser + "--rootView == null" + (rootView == null)); + super.setUserVisibleHint(isVisibleToUser); + //setUserVisibleHint()有可能在fragment的生命周期外被调用 + if (rootView == null) { + return; + } + if (isFirstVisible && isVisibleToUser) { + onFragmentFirstVisible(); + isFirstVisible = false; + isFragmentVisible = true; + return; + } + if (isVisibleToUser) { + onFragmentVisibleChange(true); + isFragmentVisible = true; + return; + } + if (isFragmentVisible) { + isFragmentVisible = false; + onFragmentVisibleChange(false); + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initVariable(); + } + + + private void initVariable() { + isFirstVisible = true; + isFragmentVisible = false; + isPause = false; + rootView = null; + isReuseView = true; + } + + @Override + public void onPause() { + isPause = true; + super.onPause(); + } + + @Override + public void onResume() { + if (isPause && getUserVisibleHint()) + onFragmentVisibleChange(true); + super.onResume(); + } + + /** + * @param isReuse + */ + protected void reuseView(boolean isReuse) { + isReuseView = isReuse; + } + + /** + * 去除setUserVisibleHint()多余的回调场景,保证只有当fragment可见状态发生变化时才回调 + * 回调时机在view创建完后,所以支持ui操作,解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题 + *

+ * 可在该回调方法里进行一些ui显示与隐藏 + * + * @param isVisible true 不可见 -> 可见 + * false 可见 -> 不可见 + */ + protected abstract void onFragmentVisibleChange(boolean isVisible); + + /** + * 在fragment首次可见时回调,可用于加载数据,防止每次进入都重复加载数据 + */ + protected abstract void onFragmentFirstVisible(); + + protected boolean isFragmentVisible() { + return isFragmentVisible; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/CarBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/CarBean.java new file mode 100644 index 0000000..1691809 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/CarBean.java @@ -0,0 +1,100 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class CarBean implements Serializable { + + +// private String approved_load; +// private String driver_name; +// private String current_load; +// private String car_number; +// private String outline_wide; +// private String outline_long; +// private String driver_phone; +// private Integer car_id; +// private String outline_high; + private boolean isSelect; + + private String vehicle; + private String carId; + private String outlineWide; + private String outlineHigh; + private String outlineLong; + private String approvedLoad; + private String driverName; + private String driverPhone; + + public String getVehicle() { + return vehicle; + } + + public void setVehicle(String vehicle) { + this.vehicle = vehicle; + } + + public String getCarId() { + return carId; + } + + public void setCarId(String carId) { + this.carId = carId; + } + + public String getOutlineWide() { + return outlineWide; + } + + public void setOutlineWide(String outlineWide) { + this.outlineWide = outlineWide; + } + + public String getOutlineHigh() { + return outlineHigh; + } + + public void setOutlineHigh(String outlineHigh) { + this.outlineHigh = outlineHigh; + } + + public String getOutlineLong() { + return outlineLong; + } + + public void setOutlineLong(String outlineLong) { + this.outlineLong = outlineLong; + } + + public String getApprovedLoad() { + return approvedLoad; + } + + public void setApprovedLoad(String approvedLoad) { + this.approvedLoad = approvedLoad; + } + + public String getDriverName() { + return driverName; + } + + public void setDriverName(String driverName) { + this.driverName = driverName; + } + + public String getDriverPhone() { + return driverPhone; + } + + public void setDriverPhone(String driverPhone) { + this.driverPhone = driverPhone; + } + + public boolean isSelect() { + return isSelect; + } + + public void setSelect(boolean select) { + isSelect = select; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/DictBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/DictBean.java new file mode 100644 index 0000000..f8e9983 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/DictBean.java @@ -0,0 +1,154 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class DictBean implements Serializable { + + + private String searchValue; + private String createBy; + private String createTime; + private String updateBy; + private String updateTime; + private String remark; + private String dictCode; + private String dictSort; + private String dictLabel; + private String dictValue; + private String dictType; + private String cssClass; + private String listClass; + private String isDefault; + private String status; + + public DictBean() { + + } + + public DictBean(String dictValue, String dictLabel) { + this.dictValue = dictValue; + this.dictLabel = dictLabel; + } + + public String getSearchValue() { + return searchValue; + } + + public void setSearchValue(String searchValue) { + this.searchValue = searchValue; + } + + public String getCreateBy() { + return createBy; + } + + public void setCreateBy(String createBy) { + this.createBy = createBy; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getUpdateBy() { + return updateBy; + } + + public void setUpdateBy(String updateBy) { + this.updateBy = updateBy; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + + public String getDictCode() { + return dictCode; + } + + public void setDictCode(String dictCode) { + this.dictCode = dictCode; + } + + public String getDictSort() { + return dictSort; + } + + public void setDictSort(String dictSort) { + this.dictSort = dictSort; + } + + public String getDictLabel() { + return dictLabel; + } + + public void setDictLabel(String dictLabel) { + this.dictLabel = dictLabel; + } + + public String getDictValue() { + return dictValue; + } + + public void setDictValue(String dictValue) { + this.dictValue = dictValue; + } + + public String getDictType() { + return dictType; + } + + public void setDictType(String dictType) { + this.dictType = dictType; + } + + public String getCssClass() { + return cssClass; + } + + public void setCssClass(String cssClass) { + this.cssClass = cssClass; + } + + public String getListClass() { + return listClass; + } + + public void setListClass(String listClass) { + this.listClass = listClass; + } + + public String getIsDefault() { + return isDefault; + } + + public void setIsDefault(String isDefault) { + this.isDefault = isDefault; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/NodeBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/NodeBean.java new file mode 100644 index 0000000..7da5641 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/NodeBean.java @@ -0,0 +1,354 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class NodeBean implements Serializable { + + + private String searchValue; + private String createBy; + private String createTime; + private String updateBy; + private String updateTime; + private String remark; + private String planId; + private String nodeId; + private String nodeType; + private String orderId; + private String nodeName; + private String address; + private String contacts; + private String contactsPhone; + private String contacts_phone; + private String provinceId; + private String provinceName; + private String cityId; + private String cityName; + private String countyId; + private String countyName; + private String planIndex; + private String remarks; + private String node_name; + private String warehouseId; + private String warehouseName; + private String isSelect; + private String w_child_id; + private String firstNameCode; + + + private String wChildId; + private String waybillId; + private String freighter; + private String freighterId; + private String node; + private String state; + private String isSelectOld; + private String dockingPhone; + private String docking; + + public String getwChildId() { + return wChildId; + } + + public void setwChildId(String wChildId) { + this.wChildId = wChildId; + } + + public String getWaybillId() { + return waybillId; + } + + public void setWaybillId(String waybillId) { + this.waybillId = waybillId; + } + + public String getFreighter() { + return freighter; + } + + public void setFreighter(String freighter) { + this.freighter = freighter; + } + + public String getFreighterId() { + return freighterId; + } + + public void setFreighterId(String freighterId) { + this.freighterId = freighterId; + } + + public String getNode() { + return node; + } + + public void setNode(String node) { + this.node = node; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getIsSelectOld() { + return isSelectOld; + } + + public void setIsSelectOld(String isSelectOld) { + this.isSelectOld = isSelectOld; + } + + public String getDockingPhone() { + return dockingPhone; + } + + public void setDockingPhone(String dockingPhone) { + this.dockingPhone = dockingPhone; + } + + public String getDocking() { + return docking; + } + + public void setDocking(String docking) { + this.docking = docking; + } + + public String getWarehouseId() { + return warehouseId; + } + + public void setWarehouseId(String warehouseId) { + this.warehouseId = warehouseId; + } + + public String getWarehouseName() { + return warehouseName; + } + + public void setWarehouseName(String warehouseName) { + this.warehouseName = warehouseName; + } + + public String getFirstNameCode() { + return firstNameCode; + } + + public void setFirstNameCode(String firstNameCode) { + this.firstNameCode = firstNameCode; + } + + public String getW_child_id() { + return w_child_id; + } + + public void setW_child_id(String w_child_id) { + this.w_child_id = w_child_id; + } + + public String isSelect() { + return isSelect; + } + + public void setSelect(String select) { + isSelect = select; + } + + public String getNode_name() { + return node_name; + } + + public void setNode_name(String node_name) { + this.node_name = node_name; + } + + public String getContacts_phone() { + return contacts_phone; + } + + public void setContacts_phone(String contacts_phone) { + this.contacts_phone = contacts_phone; + } + + public String getSearchValue() { + return searchValue; + } + + public void setSearchValue(String searchValue) { + this.searchValue = searchValue; + } + + public String getCreateBy() { + return createBy; + } + + public void setCreateBy(String createBy) { + this.createBy = createBy; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getUpdateBy() { + return updateBy; + } + + public void setUpdateBy(String updateBy) { + this.updateBy = updateBy; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + + public String getPlanId() { + return planId; + } + + public void setPlanId(String planId) { + this.planId = planId; + } + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + public String getNodeType() { + return nodeType; + } + + public void setNodeType(String nodeType) { + this.nodeType = nodeType; + } + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public String getNodeName() { + return nodeName; + } + + public void setNodeName(String nodeName) { + this.nodeName = nodeName; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getContacts() { + return contacts; + } + + public void setContacts(String contacts) { + this.contacts = contacts; + } + + public String getContactsPhone() { + return contactsPhone; + } + + public void setContactsPhone(String contactsPhone) { + this.contactsPhone = contactsPhone; + } + + public String getProvinceId() { + return provinceId; + } + + public void setProvinceId(String provinceId) { + this.provinceId = provinceId; + } + + public String getProvinceName() { + return provinceName; + } + + public void setProvinceName(String provinceName) { + this.provinceName = provinceName; + } + + public String getCityId() { + return cityId; + } + + public void setCityId(String cityId) { + this.cityId = cityId; + } + + public String getCityName() { + return cityName; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } + + public String getCountyId() { + return countyId; + } + + public void setCountyId(String countyId) { + this.countyId = countyId; + } + + public String getCountyName() { + return countyName; + } + + public void setCountyName(String countyName) { + this.countyName = countyName; + } + + public String getPlanIndex() { + return planIndex; + } + + public void setPlanIndex(String planIndex) { + this.planIndex = planIndex; + } + + public String getRemarks() { + return remarks; + } + + public void setRemarks(String remarks) { + this.remarks = remarks; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/StateBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/StateBean.java new file mode 100644 index 0000000..83f9b59 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/StateBean.java @@ -0,0 +1,151 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class StateBean implements Serializable { + + + private String searchValue; + private String createBy; + private String createTime; + private String updateBy; + private String updateTime; + private String remark; + private String dictCode; + private String dictSort; + private String dictLabel; + private String dictValue; + private String dictType; + private String cssClass; + private String listClass; + private String isDefault; + private String status; + + public StateBean(String dictLabel, String dictValue) { + this.dictLabel = dictLabel; + this.dictValue = dictValue; + } + + public String getSearchValue() { + return searchValue; + } + + public void setSearchValue(String searchValue) { + this.searchValue = searchValue; + } + + public String getCreateBy() { + return createBy; + } + + public void setCreateBy(String createBy) { + this.createBy = createBy; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getUpdateBy() { + return updateBy; + } + + public void setUpdateBy(String updateBy) { + this.updateBy = updateBy; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getDictCode() { + return dictCode; + } + + public void setDictCode(String dictCode) { + this.dictCode = dictCode; + } + + public String getDictSort() { + return dictSort; + } + + public void setDictSort(String dictSort) { + this.dictSort = dictSort; + } + + public String getDictLabel() { + return dictLabel; + } + + public void setDictLabel(String dictLabel) { + this.dictLabel = dictLabel; + } + + public String getDictValue() { + return dictValue; + } + + public void setDictValue(String dictValue) { + this.dictValue = dictValue; + } + + public String getDictType() { + return dictType; + } + + public void setDictType(String dictType) { + this.dictType = dictType; + } + + public String getCssClass() { + return cssClass; + } + + public void setCssClass(String cssClass) { + this.cssClass = cssClass; + } + + public String getListClass() { + return listClass; + } + + public void setListClass(String listClass) { + this.listClass = listClass; + } + + public String getIsDefault() { + return isDefault; + } + + public void setIsDefault(String isDefault) { + this.isDefault = isDefault; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public static class ParamsDTO { + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/TipsBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/TipsBean.java new file mode 100644 index 0000000..1b989cc --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/TipsBean.java @@ -0,0 +1,29 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class TipsBean implements Serializable { + private String title; + private String content; + + public TipsBean(String title, String content) { + this.title = title; + this.content = content; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/VersionBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/VersionBean.java new file mode 100644 index 0000000..55f51f7 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/VersionBean.java @@ -0,0 +1,93 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class VersionBean implements Serializable { + + + + private ParamsDao data; + + public ParamsDao getData() { + return data; + } + + public void setData(ParamsDao data) { + this.data = data; + } + + public static class ParamsDao implements Serializable{ + private int versionId; + private int version; + private String versionName; + private String introduce; + private String updateType; + private String createTime; + private String remark; + private String apkUrl; + + public String getApkUrl() { + return apkUrl; + } + + public void setApkUrl(String apkUrl) { + this.apkUrl = apkUrl; + } + + public int getVersionId() { + return versionId; + } + + public void setVersionId(int versionId) { + this.versionId = versionId; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public String getVersionName() { + return versionName; + } + + public void setVersionName(String versionName) { + this.versionName = versionName; + } + + public String getIntroduce() { + return introduce; + } + + public void setIntroduce(String introduce) { + this.introduce = introduce; + } + + public String getUpdateType() { + return updateType; + } + + public void setUpdateType(String updateType) { + this.updateType = updateType; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/callback/OnItemLongClickListener.java b/mylibrary/src/main/java/com/dahe/mylibrary/callback/OnItemLongClickListener.java new file mode 100644 index 0000000..9e949df --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/callback/OnItemLongClickListener.java @@ -0,0 +1,14 @@ +package com.dahe.mylibrary.callback; + +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +/** + * @author:luck + * @date:2020-01-13 17:58 + * @describe:长按事件 + */ +public interface OnItemLongClickListener { + void onItemLongClick(RecyclerView.ViewHolder holder, int position, View v); +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/callback/RefreshCallBack.java b/mylibrary/src/main/java/com/dahe/mylibrary/callback/RefreshCallBack.java new file mode 100644 index 0000000..adc89c3 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/callback/RefreshCallBack.java @@ -0,0 +1,14 @@ +package com.dahe.mylibrary.callback; + +/** + * 刷新的回调 + */ + +public interface RefreshCallBack { + /** + * @param stat 1刷新 2加载更多 + * @param page 当前页数 + * @param count 当前count + */ + void getRefreshDate(int stat, int page, int count); +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CarSelPopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CarSelPopupView.java new file mode 100644 index 0000000..2493733 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CarSelPopupView.java @@ -0,0 +1,102 @@ +package com.dahe.mylibrary.cuspop; + +import android.content.Context; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.listener.OnItemClickListener; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.CarAdapter; +import com.dahe.mylibrary.bean.CarBean; +import com.dahe.mylibrary.net.JsonUtils; +import com.lxj.xpopup.core.CenterPopupView; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class CarSelPopupView extends CenterPopupView { + + + private Context context; + private List data; + public CarSelPopupView(Context context, String data) { + super(context); + this.context = context; + ArrayList nodeBeans = JsonUtils.getInstance().jsonToList(data, CarBean.class); + this.data = nodeBeans; + } + + @Override + protected int getImplLayoutId() { + return R.layout.view_node; + } + + @Override + protected void onCreate() { + super.onCreate(); + TextView tvTitle = (TextView) findViewById(R.id.tvTitle); + ImageView ivCha = (ImageView) findViewById(R.id.ivCha); + LinearLayout llCha = (LinearLayout) findViewById(R.id.llCha); + Button btnOK = (Button) findViewById(R.id.btnOK); + RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); + recyclerView.setLayoutManager(new LinearLayoutManager(context,RecyclerView.VERTICAL,false)); + recyclerView.setHasFixedSize(true); + CarAdapter nodeAdapter = new CarAdapter(-1,data); + recyclerView.setAdapter(nodeAdapter); + + tvTitle.setText("关联司机"); + nodeAdapter.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(@NonNull BaseQuickAdapter adapter, @NonNull View view, int position) { + CarBean nodeSelectBean = data.get(position); + nodeSelectBean.setSelect(!nodeSelectBean.isSelect()); + nodeAdapter.notifyItemChanged(position); + } + }); + + btnOK.setOnClickListener(v -> { + if (listener!=null){ +// ArrayList temp = new ArrayList<>(); +// for (int i = 0; i < data.size(); i++) { +// CarBean nodeSelectBean = data.get(i); +// if ("1".equals(nodeSelectBean.isSelect())){ +// temp.add(nodeSelectBean); +// } +// +// } +// if (temp.size()<=0){ +// ToastUtils.showToast(context,"至少存在一个节点"); +// return; +// } + listener.okClick(JsonUtils.getInstance().toJson(nodeAdapter.getData())); +// temp = null; + dismiss(); + } + }); + llCha.setOnClickListener(v -> { + dismiss(); + }); + } + + + private OnOkListener listener; + + public CarSelPopupView setOnOkListener(OnOkListener listener) { + this.listener = listener; + return this; + } + + public interface OnOkListener { + void okClick(String data); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CenterPopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CenterPopupView.java new file mode 100644 index 0000000..1bda565 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CenterPopupView.java @@ -0,0 +1,91 @@ +package com.dahe.mylibrary.cuspop; + +import android.app.Activity; +import android.content.Context; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.listener.OnItemClickListener; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.CenterSimAdapter; +import com.dahe.mylibrary.bean.StateBean; +import com.dahe.mylibrary.wapper.SelectSimAdapter; +import com.luck.picture.lib.decoration.GridSpacingItemDecoration; +import com.lxj.xpopup.impl.PartShadowPopupView; + +import java.util.List; + +/** + * Description: 自定义局部阴影弹窗 + * Create by dance, at 2018/12/21 + */ +public class CenterPopupView extends PartShadowPopupView { + private Context ctx; + private RecyclerView recyclerView; + private List wordList; + private CenterSimAdapter adapter; + private StateBean selectString; + + public CenterPopupView(@NonNull Activity context, List wordList, StateBean selectString) { + super(context); + this.wordList= wordList; + this.selectString = selectString; + } + + @Override + protected int getImplLayoutId() { + return R.layout.custom_part_shadow_popup; + } + + + @Override + protected void onCreate() { + super.onCreate(); + recyclerView = findViewById(R.id.recyclerView); + GridLayoutManager gridLayoutManager = new GridLayoutManager(ctx, 4); + recyclerView.addItemDecoration(new GridSpacingItemDecoration(4, 20, false)); + recyclerView.setLayoutManager(gridLayoutManager); + adapter = new CenterSimAdapter(-1, wordList,selectString); + recyclerView.setAdapter(adapter); + + adapter.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(@NonNull BaseQuickAdapter adapter, @NonNull View view, int position) { + if (listener!=null){ + listener.selectChange(wordList.get(position),position); + } + ((CenterSimAdapter)adapter).setSelect(wordList.get(position)); + adapter.notifyDataSetChanged(); + dismiss(); + } + }); + + } + + @Override + protected void onShow() { + super.onShow(); + Log.e("tag", "CustomPartShadowPopupView onShow"); + } + + @Override + protected void onDismiss() { + super.onDismiss(); + Log.e("tag", "CustomPartShadowPopupView onDismiss"); + } + + + private OnSelectChangeListener listener; + public CenterPopupView setOnSelectChangeListener(OnSelectChangeListener listener){ + this.listener = listener; + return this; + } + public interface OnSelectChangeListener{ + void selectChange(StateBean item ,int postion); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CustomDicPopView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CustomDicPopView.java new file mode 100644 index 0000000..7b84f67 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CustomDicPopView.java @@ -0,0 +1,90 @@ +package com.dahe.mylibrary.cuspop; + +import android.content.Context; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.listener.OnItemClickListener; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.SelectDicAdapter; +import com.dahe.mylibrary.bean.DictBean; +import com.dahe.mylibrary.bean.StateBean; +import com.lxj.xpopup.core.AttachPopupView; + +import java.util.List; + +/** + * Description: 自定义局部阴影弹窗 + * Create by dance, at 2018/12/21 + */ +public class CustomDicPopView extends AttachPopupView { + private Context ctx; + private RecyclerView recyclerView; + private List wordList; + private SelectDicAdapter adapter; + private int selectPos; + + public CustomDicPopView(@NonNull Context context, List wordList, int selectPos) { + super(context); + this.ctx = context; + this.wordList= wordList; + this.selectPos = selectPos; + } + + @Override + protected int getImplLayoutId() { + return R.layout.custom_dic_popup; + } + + + @Override + protected void onCreate() { + super.onCreate(); + recyclerView = findViewById(R.id.recyclerView); + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx, RecyclerView.VERTICAL, false); +// recyclerView.addItemDecoration(new RecycleViewDivider(ctx,RecyclerView.VERTICAL)); + recyclerView.setLayoutManager(linearLayoutManager); + adapter = new SelectDicAdapter(-1, wordList,selectPos); + recyclerView.setAdapter(adapter); + + adapter.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(@NonNull BaseQuickAdapter adapter, @NonNull View view, int position) { + if (listener!=null){ + listener.selectChange(wordList.get(position),position); + } + ((SelectDicAdapter)adapter).setSelect(position); + adapter.notifyDataSetChanged(); + dismiss(); + } + }); + + } + + @Override + protected void onShow() { + super.onShow(); + Log.e("tag", "CustomPartShadowPopupView onShow"); + } + + @Override + protected void onDismiss() { + super.onDismiss(); + Log.e("tag", "CustomPartShadowPopupView onDismiss"); + } + + + private OnSelectChangeListener listener; + public CustomDicPopView setOnSelectChangeListener(OnSelectChangeListener listener){ + this.listener = listener; + return this; + } + public interface OnSelectChangeListener{ + void selectChange(StateBean item ,int postion); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CustomPartShadowPopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CustomPartShadowPopupView.java new file mode 100644 index 0000000..d42f762 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CustomPartShadowPopupView.java @@ -0,0 +1,90 @@ +package com.dahe.mylibrary.cuspop; + +import android.app.Activity; +import android.content.Context; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.listener.OnItemClickListener; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.wapper.SelectSimAdapter; +import com.luck.picture.lib.decoration.GridSpacingItemDecoration; +import com.lxj.xpopup.impl.PartShadowPopupView; + +import java.util.List; + +/** + * Description: 自定义局部阴影弹窗 + * Create by dance, at 2018/12/21 + */ +public class CustomPartShadowPopupView extends PartShadowPopupView { + private Context ctx; + private RecyclerView recyclerView; + private List wordList; + private SelectSimAdapter adapter; + private String selectString; + + public CustomPartShadowPopupView(@NonNull Activity context, List wordList, String selectString) { + super(context); + this.wordList= wordList; + this.selectString = selectString; + } + + @Override + protected int getImplLayoutId() { + return R.layout.custom_part_shadow_popup; + } + + + @Override + protected void onCreate() { + super.onCreate(); + recyclerView = findViewById(R.id.recyclerView); + GridLayoutManager gridLayoutManager = new GridLayoutManager(ctx, 4); + recyclerView.addItemDecoration(new GridSpacingItemDecoration(4, 20, false)); + recyclerView.setLayoutManager(gridLayoutManager); + adapter = new SelectSimAdapter(-1, wordList,selectString); + recyclerView.setAdapter(adapter); + + adapter.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(@NonNull BaseQuickAdapter adapter, @NonNull View view, int position) { + if (listener!=null){ + listener.selectChange(wordList.get(position),position); + } + ((SelectSimAdapter)adapter).setSelect(wordList.get(position)); + adapter.notifyDataSetChanged(); + dismiss(); + } + }); + + } + + @Override + protected void onShow() { + super.onShow(); + Log.e("tag", "CustomPartShadowPopupView onShow"); + } + + @Override + protected void onDismiss() { + super.onDismiss(); + Log.e("tag", "CustomPartShadowPopupView onDismiss"); + } + + + private OnSelectChangeListener listener; + public CustomPartShadowPopupView setOnSelectChangeListener(OnSelectChangeListener listener){ + this.listener = listener; + return this; + } + public interface OnSelectChangeListener{ + void selectChange(String item ,int postion); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/InputPopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/InputPopupView.java new file mode 100644 index 0000000..e8e8529 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/InputPopupView.java @@ -0,0 +1,80 @@ +package com.dahe.mylibrary.cuspop; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; +import android.widget.EditText; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.utils.ToastUtils; +import com.lxj.xpopup.core.CenterPopupView; +import com.lxj.xpopup.util.KeyboardUtils; + +/** + * Description: 自定义局部阴影弹窗 + * Create by dance, at 2018/12/21 + */ +public class InputPopupView extends CenterPopupView { + private Context ctx; + + + public InputPopupView(@NonNull Context context) { + super(context); + this.ctx = context; + } + + @Override + protected int getImplLayoutId() { + return R.layout.my_confim_popup_input; + } + + + @Override + protected void onCreate() { + super.onCreate(); + EditText etInput = findViewById(R.id.et_input); + TextView tvCancel = findViewById(R.id.tv_cancel); + TextView tvConfirm = findViewById(R.id.tv_confirm); + if (listener != null) { + tvConfirm.setOnClickListener(view -> { + if (TextUtils.isEmpty(etInput.getText().toString().trim())){ + KeyboardUtils.hideSoftInput(tvConfirm); + ToastUtils.showToast(ctx,"请填写取消原因"); + return; + } + listener.okClick(etInput.getText().toString()); + dismiss(); + }); + } + + tvCancel.setOnClickListener(v -> dismiss()); + + } + + @Override + protected void onShow() { + super.onShow(); + Log.e("tag", "CustomPartShadowPopupView onShow"); + } + + @Override + protected void onDismiss() { + super.onDismiss(); + Log.e("tag", "CustomPartShadowPopupView onDismiss"); + } + + + private OnOkListener listener; + + public InputPopupView setOnOkListener(OnOkListener listener) { + this.listener = listener; + return this; + } + + public interface OnOkListener { + void okClick(String item); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/NodePopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/NodePopupView.java new file mode 100644 index 0000000..b376d25 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/NodePopupView.java @@ -0,0 +1,107 @@ +package com.dahe.mylibrary.cuspop; + +import android.content.Context; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.listener.OnItemClickListener; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.NodeAdapter; +import com.dahe.mylibrary.bean.NodeBean; +import com.dahe.mylibrary.net.JsonUtils; +import com.dahe.mylibrary.utils.ToastUtils; +import com.lxj.xpopup.core.CenterPopupView; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class NodePopupView extends CenterPopupView { + + + private Context context; + private List data; + public NodePopupView(Context context,String data) { + super(context); + this.context = context; + ArrayList nodeBeans = JsonUtils.getInstance().jsonToList(data, NodeBean.class); + this.data = nodeBeans; + } + + @Override + protected int getImplLayoutId() { + return R.layout.view_node; + } + + @Override + protected void onCreate() { + super.onCreate(); + TextView tvTitle = (TextView) findViewById(R.id.tvTitle); + ImageView ivCha = (ImageView) findViewById(R.id.ivCha); + LinearLayout llCha = (LinearLayout) findViewById(R.id.llCha); + Button btnOK = (Button) findViewById(R.id.btnOK); + RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); + recyclerView.setLayoutManager(new LinearLayoutManager(context,RecyclerView.VERTICAL,false)); + recyclerView.setHasFixedSize(true); + NodeAdapter nodeAdapter = new NodeAdapter(-1,data); + recyclerView.setAdapter(nodeAdapter); + + + nodeAdapter.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(@NonNull @NotNull BaseQuickAdapter adapter, @NonNull @NotNull View view, int position) { + NodeBean nodeSelectBean = data.get(position); + if (!"0".equals(nodeSelectBean.getState())){ + ToastUtils.showToast(context,"该节点不可操作"); + return; + } + nodeSelectBean.setSelect("1".equals(nodeSelectBean.isSelect())?"0":"1"); + nodeAdapter.notifyItemChanged(position); + } + }); + + btnOK.setOnClickListener(v -> { + if (listener!=null){ + ArrayList temp = new ArrayList<>(); + for (int i = 0; i < data.size(); i++) { + NodeBean nodeSelectBean = data.get(i); + if ("1".equals(nodeSelectBean.isSelect())){ + temp.add(nodeSelectBean); + } + + } + if (temp.size()<=0){ + ToastUtils.showToast(context,"至少存在一个节点"); + return; + } + listener.okClick(JsonUtils.getInstance().toJson(data)); + temp = null; + dismiss(); + } + }); + llCha.setOnClickListener(v -> { + dismiss(); + }); + } + + + private OnOkListener listener; + + public NodePopupView setOnOkListener(OnOkListener listener) { + this.listener = listener; + return this; + } + + public interface OnOkListener { + void okClick(String data); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/TextPopupTipsView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/TextPopupTipsView.java new file mode 100644 index 0000000..4f08bd1 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/TextPopupTipsView.java @@ -0,0 +1,77 @@ +package com.dahe.mylibrary.cuspop; + +import android.content.Context; +import android.util.Log; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.bean.TipsBean; +import com.lxj.xpopup.core.CenterPopupView; + +/** + * Description: 自定义局部阴影弹窗 + * Create by dance, at 2018/12/21 + */ +public class TextPopupTipsView extends CenterPopupView { + private TipsBean data; + private Context ctx; + + + public TextPopupTipsView(@NonNull Context context, TipsBean data) { + super(context); + this.data = data; + + } + + @Override + protected int getImplLayoutId() { + return R.layout.my_confim_popup_tip; + } + + + @Override + protected void onCreate() { + super.onCreate(); + TextView etInput = findViewById(R.id.tv_input); + TextView tvTitle = findViewById(R.id.tv_title); + TextView tvCancel = findViewById(R.id.tv_cancel); + TextView tvConfirm = findViewById(R.id.tv_confirm); + tvTitle.setText(data.getTitle()); + etInput.setText(data.getContent()); + if (listener != null) { + tvConfirm.setOnClickListener(view -> { + listener.okClick(); + dismiss(); + }); + } + + tvCancel.setOnClickListener(v -> dismiss()); + + } + + @Override + protected void onShow() { + super.onShow(); + Log.e("tag", "CustomPartShadowPopupView onShow"); + } + + @Override + protected void onDismiss() { + super.onDismiss(); + Log.e("tag", "CustomPartShadowPopupView onDismiss"); + } + + + private OnOkListener listener; + + public TextPopupTipsView setOnOkListener(OnOkListener listener) { + this.listener = listener; + return this; + } + + public interface OnOkListener { + void okClick(); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/TextPopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/TextPopupView.java new file mode 100644 index 0000000..798a3b9 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/TextPopupView.java @@ -0,0 +1,74 @@ +package com.dahe.mylibrary.cuspop; + +import android.content.Context; +import android.util.Log; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.dahe.mylibrary.R; +import com.lxj.xpopup.core.CenterPopupView; + +/** + * Description: 自定义局部阴影弹窗 + * Create by dance, at 2018/12/21 + */ +public class TextPopupView extends CenterPopupView { + private String data; + private Context ctx; + + + public TextPopupView(@NonNull Context context,String data) { + super(context); + this.data = data; + + } + + @Override + protected int getImplLayoutId() { + return R.layout.my_confim_popup_unus; + } + + + @Override + protected void onCreate() { + super.onCreate(); + TextView etInput = findViewById(R.id.tv_input); + TextView tvCancel = findViewById(R.id.tv_cancel); + TextView tvConfirm = findViewById(R.id.tv_confirm); + etInput.setText(data); + if (listener != null) { + tvConfirm.setOnClickListener(view -> { + listener.okClick(etInput.getText().toString()); + dismiss(); + }); + } + + tvCancel.setOnClickListener(v -> dismiss()); + + } + + @Override + protected void onShow() { + super.onShow(); + Log.e("tag", "CustomPartShadowPopupView onShow"); + } + + @Override + protected void onDismiss() { + super.onDismiss(); + Log.e("tag", "CustomPartShadowPopupView onDismiss"); + } + + + private OnOkListener listener; + + public TextPopupView setOnOkListener(OnOkListener listener) { + this.listener = listener; + return this; + } + + public interface OnOkListener { + void okClick(String item); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/dialog/DialogPhotoSelect.java b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/DialogPhotoSelect.java new file mode 100644 index 0000000..e06f0e3 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/DialogPhotoSelect.java @@ -0,0 +1,108 @@ +package com.dahe.mylibrary.dialog; + +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.dahe.mylibrary.R; + + +/** + * 头像选择 dialog + * + * @Description: + * @Author: tao + * @CreateDate: 2018/7/26 10:34 + */ +public class DialogPhotoSelect extends MyBaseDialog { + + private TextView take_photo; + private TextView select_photo; + private TextView do_cancel; + + private onSelectClickListener onSelectClickListener; + + public void setOnSelectClickListener(onSelectClickListener onSelectClickListener) { + this.onSelectClickListener = onSelectClickListener; + } + + public DialogPhotoSelect(@NonNull Context context) { + super(context); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_photo_select); + + initView(); + initListener(); + } + + private void initView() { + take_photo = findViewById( R.id.take_photo); + select_photo = findViewById(R.id.select_photo); + do_cancel = findViewById(R.id.do_cancel); + } + + private void initListener() { + + //拍照 + take_photo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismiss(); + onSelectClickListener.onTakePhoto(); + } + }); + + //相册选择 + select_photo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismiss(); + onSelectClickListener.onSelectPhoto(); + } + }); + + do_cancel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismiss(); + } + }); + + + } + + @Override + public void init(@NonNull Context context) { + Window window = getWindow(); + window.setWindowAnimations(R.style.BottomAnim); + window.setGravity( Gravity.BOTTOM); + //默认的Dialog只有5/6左右的宽度,改为全屏宽度,由dialog的布局自己来决定实际显示宽度 + window.getDecorView().setPadding(0, 0, 0, 0); + WindowManager.LayoutParams lp = window.getAttributes(); + lp.width = WindowManager.LayoutParams.MATCH_PARENT; + lp.height = WindowManager.LayoutParams.WRAP_CONTENT; + window.setAttributes(lp); + } + + @Override + public boolean isCancelAble() { + return true; + } + + public interface onSelectClickListener { + + void onTakePhoto(); + + void onSelectPhoto(); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/dialog/MyBaseDialog.java b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/MyBaseDialog.java new file mode 100644 index 0000000..74b915f --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/MyBaseDialog.java @@ -0,0 +1,55 @@ +package com.dahe.mylibrary.dialog; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.NonNull; + +import com.dahe.mylibrary.R; + + +/** + * Dialog 基类 基类 基类 + *

+ * 以后再写Dialog,都要继承这个 + * + * @Description: + * @Author: tao + * @CreateDate: 2018/7/26 10:29 + */ +public class MyBaseDialog extends Dialog { + + + public MyBaseDialog(@NonNull Context context) { + super(context, R.style.MyBaseDialog); + init(context); + } + + public void init(@NonNull Context context) { + Window window = getWindow(); + window.setWindowAnimations(R.style.BottomAnim); + window.setGravity(Gravity.CENTER); + //默认的Dialog只有5/6左右的宽度,改为全屏宽度,由dialog的布局自己来决定实际显示宽度 + window.getDecorView().setPadding(0, 0, 0, 0); + WindowManager.LayoutParams lp = window.getAttributes(); + lp.width = WindowManager.LayoutParams.MATCH_PARENT; + lp.height = WindowManager.LayoutParams.WRAP_CONTENT; + window.setAttributes(lp); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setCancelable(isCancelAble()); + setCanceledOnTouchOutside(isCancelAble()); + } + + public boolean isCancelAble() { + return false; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/dialog/VersionDialog.java b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/VersionDialog.java new file mode 100644 index 0000000..383c55f --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/VersionDialog.java @@ -0,0 +1,21 @@ +package com.dahe.mylibrary.dialog; + +import android.app.Dialog; +import android.content.Context; + +/** + * Created by Allen Liu on 2017/2/23. + */ +public class VersionDialog extends Dialog { + private int res; + + public VersionDialog(Context context, int theme, int res) { + super(context, theme); + getWindow().setBackgroundDrawableResource(android.R.color.transparent); + // TODO 自动生成的构造函数存根 + setContentView(res); + this.res = res; + setCanceledOnTouchOutside(false); + } + +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/glide/GlideEngine.java b/mylibrary/src/main/java/com/dahe/mylibrary/glide/GlideEngine.java new file mode 100644 index 0000000..5fc2ad3 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/glide/GlideEngine.java @@ -0,0 +1,117 @@ +package com.dahe.mylibrary.glide; + +import android.content.Context; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.dahe.mylibrary.R; +import com.luck.picture.lib.engine.ImageEngine; +import com.luck.picture.lib.utils.ActivityCompatHelper; + +/** + * @author:luck + * @date:2019-11-13 17:02 + * @describe:Glide加载引擎 + */ +public class GlideEngine implements ImageEngine { + + /** + * 加载图片 + * + * @param context 上下文 + * @param url 资源url + * @param imageView 图片承载控件 + */ + @Override + public void loadImage(Context context, String url, ImageView imageView) { + if (!ActivityCompatHelper.assertValidRequest(context)) { + return; + } + Glide.with(context) + .load(url) + .into(imageView); + } + + @Override + public void loadImage(Context context, ImageView imageView, String url, int maxWidth, int maxHeight) { + if (!ActivityCompatHelper.assertValidRequest(context)) { + return; + } + Glide.with(context) + .load(url) + .override(maxWidth, maxHeight) + .into(imageView); + } + + /** + * 加载相册目录封面 + * + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView + */ + @Override + public void loadAlbumCover(Context context, String url, ImageView imageView) { + if (!ActivityCompatHelper.assertValidRequest(context)) { + return; + } + Glide.with(context) + .asBitmap() + .load(url) + .override(180, 180) + .sizeMultiplier(0.5f) + .transform(new CenterCrop(), new RoundedCorners(8)) + .placeholder(com.luck.picture.lib.R.drawable.ps_image_placeholder) + .into(imageView); + } + + + /** + * 加载图片列表图片 + * + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView + */ + @Override + public void loadGridImage(Context context, String url, ImageView imageView) { + if (!ActivityCompatHelper.assertValidRequest(context)) { + return; + } + Glide.with(context) + .load(url) + .override(200, 200) + .centerCrop() + .placeholder(com.luck.picture.lib.R.drawable.ps_image_placeholder) + .into(imageView); + } + + @Override + public void pauseRequests(Context context) { + if (!ActivityCompatHelper.assertValidRequest(context)) { + return; + } + Glide.with(context).pauseRequests(); + } + + @Override + public void resumeRequests(Context context) { + if (!ActivityCompatHelper.assertValidRequest(context)) { + return; + } + Glide.with(context).resumeRequests(); + } + + private GlideEngine() { + } + + private static final class InstanceHolder { + static final GlideEngine instance = new GlideEngine(); + } + + public static GlideEngine createGlideEngine() { + return InstanceHolder.instance; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/glide/UnsafeOkHttpClient.java b/mylibrary/src/main/java/com/dahe/mylibrary/glide/UnsafeOkHttpClient.java new file mode 100644 index 0000000..da9e54e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/glide/UnsafeOkHttpClient.java @@ -0,0 +1,67 @@ +package com.dahe.mylibrary.glide; + +import java.security.cert.CertificateException; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import okhttp3.OkHttpClient; + +/** + * @ClassName UnsafeOkHttpClient + * @Author 用户 + * @Date 2021/10/11 10:16 + * @Description TODO + */ +public class UnsafeOkHttpClient { + public static OkHttpClient getUnsafeOkHttpClient() { + try { + // Create a trust manager that does not validate certificate chains + final TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + } + }; + + // Install the all-trusting trust manager + final SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + + // Create an ssl socket factory with our all-trusting manager + final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]); + builder.hostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + + builder.connectTimeout(20, TimeUnit.SECONDS); + builder.readTimeout(20,TimeUnit.SECONDS); + + OkHttpClient okHttpClient = builder.build(); + return okHttpClient; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/CommonResponseBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/CommonResponseBean.java new file mode 100644 index 0000000..8c8bd99 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/CommonResponseBean.java @@ -0,0 +1,82 @@ +package com.dahe.mylibrary.net; + +import java.io.Serializable; + +/** + * 返回通用的实体类 + */ + +public class CommonResponseBean implements Serializable { + private T data; + private int code; + private String info; + private String msg; + private String url; + private int res; + private String fileName; + private boolean success; + + public int getRes() { + return res; + } + + public void setRes(int res) { + this.res = res; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/ErrorResponse.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/ErrorResponse.java new file mode 100644 index 0000000..d2998e9 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/ErrorResponse.java @@ -0,0 +1,22 @@ +package com.dahe.mylibrary.net; + +public class ErrorResponse { + private int code; + private String msg; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/FileInterceptor.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/FileInterceptor.java new file mode 100644 index 0000000..d373b7c --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/FileInterceptor.java @@ -0,0 +1,60 @@ +package com.dahe.mylibrary.net; + +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; + +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.Buffer; +import okio.BufferedSource; + +/** + * 文件上传Interceptor + */ + +public class FileInterceptor implements Interceptor { + private static final String TAG = "FileInterceptor"; + private File mFile; + + public FileInterceptor(File mFile) { + this.mFile = mFile; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + request = request.newBuilder() + .post(RequestBody.create(MediaType.parse("application/file; charset=utf-8"), mFile)) + .build(); + Response response = chain.proceed(request); + Log.i(TAG, "url= " + request.body()); + Log.i(TAG, "method= " + request.method()); + ResponseBody responseBody = response.body(); + //为了不消耗buffer,我们这里使用source先获得buffer对象,然后clone()后使用 + BufferedSource source = responseBody.source(); + source.request(Long.MAX_VALUE); // Buffer the entire body. + //获得返回的数据 + Buffer buffer = source.buffer(); + //使用前clone()下,避免直接消耗 + String responseBodyStr = buffer.clone().readString(Charset.forName("UTF-8")); + Log.i(TAG, "result-body= " + responseBodyStr); + try { + JSONObject jsonObject = new JSONObject(responseBodyStr); + responseBody = ResponseBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.getString("response")); + } catch (JSONException e) { + e.printStackTrace(); + } + response = response.newBuilder().body(responseBody).build(); + return response; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/GsonResponseBodyConverter.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/GsonResponseBodyConverter.java new file mode 100644 index 0000000..5ce33b2 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/GsonResponseBodyConverter.java @@ -0,0 +1,74 @@ +package com.dahe.mylibrary.net; + +import com.google.gson.Gson; + +import org.json.JSONObject; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.charset.Charset; + +import okhttp3.ResponseBody; +import okio.Buffer; +import okio.BufferedSource; +import retrofit2.Converter; + + +public class GsonResponseBodyConverter implements Converter { + private final Gson gson; + private final Type type; + + + public GsonResponseBodyConverter(Gson gson, Type type) { + this.gson = gson; + this.type = type; + } + + @Override + public T convert(ResponseBody value) throws IOException { + + //为了不消耗buffer,我们这里使用source先获得buffer对象,然后clone()后使用 + BufferedSource source = value.source(); + source.request(Long.MAX_VALUE); // Buffer the entire body. + //获得返回的数据 + Buffer buffer = source.buffer(); + //使用前clone()下,避免直接消耗 + String responseBodyStr = buffer.clone().readString(Charset.forName("UTF-8")); + try { + + JSONObject jsonObject = new JSONObject(responseBodyStr); + int code = jsonObject.optInt("code"); + if (-1 == code) { + jsonObject.put("data", new JSONObject()); +// ErrorResponse errorResponse = gson.fromJson(response, ErrorResponse.class); + //抛一个自定义ResultException 传入失败时候的状态码,和信息 + + throw new ResultException(-1, "errorResponse.getMsg()"); + +// return gson.fromJson(responseBodyStr,type); + } + } catch (Exception e) { + e.printStackTrace(); + } + return gson.fromJson(responseBodyStr, type); + + +// String response = value.string(); +// //先将返回的json数据解析到Response中,如果code==200,则解析到我们的实体基类中,否则抛异常 +// Response httpResult = gson.fromJson(response, Response.class); +// if (httpResult.code()==200){ +// //200的时候就直接解析,不可能出现解析异常。因为我们实体基类中传入的泛型,就是数据成功时候的格式 +// return gson.fromJson(response,type); +// }else { +// ErrorResponse errorResponse = gson.fromJson(response,ErrorResponse.class); +// //抛一个自定义ResultException 传入失败时候的状态码,和信息 +// try { +// throw new ResultException(errorResponse.getCode(),errorResponse.getMsg()); +// } catch (ResultException e) { +// e.printStackTrace(); +// } +// return null; +// } + } +} + diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonInterceptor.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonInterceptor.java new file mode 100644 index 0000000..27e7ddc --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonInterceptor.java @@ -0,0 +1,67 @@ +package com.dahe.mylibrary.net; + +import android.text.TextUtils; +import android.util.Log; + + +import com.google.zxing.common.StringUtils; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.IOException; +import java.nio.charset.Charset; + +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.Buffer; +import okio.BufferedSource; + +/** + * json的Interceptor + */ + +public class JsonInterceptor implements Interceptor { + private static final String TAG = "JsonInterceptor"; + + public JsonInterceptor() { + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + Response response = chain.proceed(request); + ResponseBody responseBody = response.body(); + //为了不消耗buffer,我们这里使用source先获得buffer对象,然后clone()后使用 + BufferedSource source = responseBody.source(); + source.request(Long.MAX_VALUE); // Buffer the entire body. + //获得返回的数据 + Buffer buffer = source.buffer(); + //使用前clone()下,避免直接消耗 + String responseBodyStr = buffer.clone().readString(Charset.forName("UTF-8")); + Log.i(TAG, "result-body= " + responseBodyStr); + try { + JSONObject jsonObject = new JSONObject(responseBodyStr); + String str = jsonObject.optString("data"); + int code = jsonObject.optInt("code"); + if (-1 == code) { + jsonObject.put("data", new JSONObject()); + throw new ResultException(); + } else { + if (TextUtils.isEmpty(str)) { + jsonObject.put("data", new JSONObject()); + } + } + + String data = jsonObject.toString(); + responseBody = ResponseBody.create(MediaType.parse("application/json; charset=utf-8"), data); + } catch (Exception e) { + e.printStackTrace(); + } + response = response.newBuilder().body(responseBody).build(); + return response; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonUtils.java new file mode 100644 index 0000000..37d91af --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonUtils.java @@ -0,0 +1,91 @@ +package com.dahe.mylibrary.net; + +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.lang.reflect.Type; +import java.util.ArrayList; + +/** + * 利用Gson反射对象类型,将json转化为对象 + */ +public class JsonUtils { + private Gson mGson = null; + private static JsonUtils mUtils; + + public static JsonUtils getInstance() { + if (mUtils == null) { + return new JsonUtils(); + } else { + return mUtils; + } + } + + public Gson getGson() { + if (null == mGson) { + mGson = new GsonBuilder().serializeNulls().create(); + } + return mGson; + } + + public String toJson(Object o){ + return getGson().toJson(o); + } + + /** + * 将json数组转化为List + * + * @param json json字符串 + * @param classOfT 对应实体类型 + * @return 实体列表 + */ + public ArrayList jsonToList(String json, Class classOfT) { + try { + if (mGson == null) { + // 不要直接new Gson是为了避免放回结果为null的这种情况 + mGson = new GsonBuilder().serializeNulls().create(); + } + Type type = new TypeToken>() { + }.getType(); + ArrayList jsonObjs = mGson.fromJson(json, type); + + ArrayList listOfT = new ArrayList(); + for (JsonObject jsonObj : jsonObjs) { + listOfT.add(mGson.fromJson(jsonObj, classOfT)); + } + return listOfT; + } catch (Exception e) { + return null; + } + } + + public T fromJson(String json, Class type) throws JsonIOException, JsonSyntaxException { + try { + JSONObject object = new JSONObject(json); + json = object.getString("response"); + Log.i("fromJson: ", json); + } catch (JSONException e) { + e.printStackTrace(); + } + return getGson().fromJson(json, type); + } + + public T fromJson(String json, Type type) { + return getGson().fromJson(json, type); + } + + public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { + return getGson().fromJson(reader, typeOfT); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/PagerBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagerBean.java new file mode 100644 index 0000000..5ce514d --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagerBean.java @@ -0,0 +1,47 @@ +package com.dahe.mylibrary.net; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Administrator on 2018\8\26 0026. + */ +public class PagerBean { + private int total; + private int count; + private int more; + + private ArrayList rows; + + public ArrayList getRows() { + return rows; + } + + public void setRows(ArrayList rows) { + this.rows = rows; + } + + public int getTotal() { + return total; + } + + public void setTotal(int total) { + this.total = total; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public int getMore() { + return more; + } + + public void setMore(int more) { + this.more = more; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/PagingBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagingBean.java new file mode 100644 index 0000000..7aa11f5 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagingBean.java @@ -0,0 +1,46 @@ +package com.dahe.mylibrary.net; + +import java.io.Serializable; + +/** + * 返回通用的实体类 + */ + +public class PagingBean implements Serializable { + private T data; + private int code; + private String count; + private String msg; + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getCount() { + return count; + } + + public void setCount(String count) { + this.count = count; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/ResponseConverterFactory.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResponseConverterFactory.java new file mode 100644 index 0000000..7d040ed --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResponseConverterFactory.java @@ -0,0 +1,44 @@ +package com.dahe.mylibrary.net; + +import com.google.gson.Gson; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import okhttp3.RequestBody; +import okhttp3.ResponseBody; +import retrofit2.Converter; +import retrofit2.Retrofit; + +public class ResponseConverterFactory extends Converter.Factory { + + public static ResponseConverterFactory create() { + return create(new Gson()); + } + + + public static ResponseConverterFactory create(Gson gson) { + return new ResponseConverterFactory(gson); + } + + private final Gson gson; + + private ResponseConverterFactory(Gson gson) { + if (gson == null) throw new NullPointerException("gson == null"); + this.gson = gson; + } + + @Override + public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { + //返回我们自定义的Gson响应体变换器 + return new GsonResponseBodyConverter<>(gson, type); + } + + @Override + public Converter requestBodyConverter(Type type, + Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { + //返回我们自定义的Gson响应体变换器 + return new GsonResponseBodyConverter<>(gson,type); + } +} + diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/ResultException.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResultException.java new file mode 100644 index 0000000..31ffeed --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResultException.java @@ -0,0 +1,12 @@ +package com.dahe.mylibrary.net; + +public class ResultException extends Exception { + + public ResultException() { + super(); + // TODO Auto-generated constructor stub + } + + public ResultException(int code, String msg) { + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/GridSpacingItemDecoration.java b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/GridSpacingItemDecoration.java new file mode 100644 index 0000000..017eb0f --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/GridSpacingItemDecoration.java @@ -0,0 +1,43 @@ +package com.dahe.mylibrary.recycleviewswipe; + +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { + + private int spanCount; //列数 + private int spacing; //间隔 + private boolean includeEdge; //是否包含边缘 + + public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) { + this.spanCount = spanCount; + this.spacing = spacing; + this.includeEdge = includeEdge; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + + //这里是关键,需要根据你有几列来判断 + int position = parent.getChildAdapterPosition(view); // item position + int column = position % spanCount; // item column + + if (includeEdge) { + outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing) + outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing) + + if (position < spanCount) { // top edge + outRect.top = spacing; + } + outRect.bottom = spacing; // item bottom + } else { + outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing) + outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing) + if (position >= spanCount) { + outRect.top = spacing; // item top + } + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/RecycleViewDivider.java b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/RecycleViewDivider.java new file mode 100644 index 0000000..77bb594 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/RecycleViewDivider.java @@ -0,0 +1,156 @@ +package com.dahe.mylibrary.recycleviewswipe; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.view.View; + +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +public class RecycleViewDivider extends RecyclerView.ItemDecoration { + + private Paint mPaint; + //分割线 + private Drawable mDivider; + //分割线高度,默认是1px + private int mDividerHeight = 1; + //列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL + private int mOrientation; + + private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; + + /** + * + * 默认分割线:高度为2px,颜色为灰色 + * 获取属性值, + * + * @param context + * @param orientation 列表方向 + */ + + public RecycleViewDivider(Context context, int orientation){ + if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) { + throw new IllegalArgumentException("请输入正确的参数!"); + } + mOrientation = orientation; + final TypedArray array = context.obtainStyledAttributes(ATTRS); + mDivider = array.getDrawable(0); + array.recycle(); + mDividerHeight = mDivider.getIntrinsicHeight(); + } + + /** + * 自定义分割线 + * + * @param context + * @param orientation 列表方向 + * @param drawableId 分割线图片 + */ + public RecycleViewDivider(Context context, int orientation, int drawableId) { + if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) { + throw new IllegalArgumentException("请输入正确的参数!"); + } + mOrientation = orientation; + + mDivider = ContextCompat.getDrawable(context, drawableId); + mDividerHeight = mDivider.getIntrinsicHeight(); + } + + /** + * 自定义分割线 + * + * @param orientation 列表方向 + * @param dividerHeight 分割线高度 + * @param dividerColor 分割线颜色 + */ + public RecycleViewDivider(int orientation, int dividerHeight, int dividerColor) { + + if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) { + throw new IllegalArgumentException("请输入正确的参数!"); + } + mOrientation = orientation; + + mDividerHeight = dividerHeight; + + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setColor(dividerColor); + mPaint.setStyle(Paint.Style.FILL); + + } + + //获取分割线尺寸 + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + + if (mOrientation == LinearLayoutManager.VERTICAL) { + outRect.set(0, 0, 0, mDividerHeight); + } else { + outRect.set(0, 0, mDividerHeight, 0); + } + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + super.onDraw(c, parent, state); + if(mOrientation==LinearLayoutManager.VERTICAL){ + drawVerticalLine(c,parent); + }else{ + drawHorizontalLine(c,parent); + } + } + + //为横方向item, 画分割线 + private void drawHorizontalLine(Canvas canvas, RecyclerView parent) { + + final int top = parent.getPaddingTop(); + final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom(); + final int childSize = parent.getChildCount(); + for (int i = 0; i < childSize - 1; i++) { + if ((i+1) % 3 != 0) { + final View child = parent.getChildAt(i); + RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int left = child.getRight() + layoutParams.rightMargin; + final int right = left + mDividerHeight; + if (mDivider != null) { + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(canvas); + } + if (mPaint != null) { + canvas.drawRect(left, top, right, bottom, mPaint); + } + } + } + } + + //为竖方向item, 画分割线 + private void drawVerticalLine(Canvas canvas, RecyclerView parent) { + + final int left = parent.getPaddingLeft(); + final int right = parent.getMeasuredWidth() - parent.getPaddingRight(); + final int childSize = parent.getChildCount(); + for (int i = 0; i < childSize; i++) { + if (i < childSize -1) { + final View child = parent.getChildAt(i); + RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int top = child.getBottom() + layoutParams.bottomMargin; + final int bottom = top + mDividerHeight; + + if (mDivider != null) { + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(canvas); + } + + if (mPaint != null) { + canvas.drawRect(left, top, right, bottom, mPaint); + } + + } + } + } +} + diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ActivityUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ActivityUtils.java new file mode 100644 index 0000000..af47200 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ActivityUtils.java @@ -0,0 +1,330 @@ +package com.dahe.mylibrary.utils; + + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; + +import androidx.annotation.NonNull; + + +import com.dahe.mylibrary.CommonBaseLibrary; + +import java.util.List; + +/** + *

+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/09/23
+ *     desc  : Activity相关工具类
+ * 
+ */ +public class ActivityUtils { + + public ActivityUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 启动Activity + * + * @param context + * @param clz + * @param bundle + */ + public static void startActivity(@NonNull Context context, @NonNull Class clz, Bundle bundle) { + Intent intent = new Intent(context, clz); + if (null != bundle) intent.putExtras(bundle); + context.startActivity(intent); + } + + /** + * 启动Activity + * + * @param context + * @param clz + * @param bundle + */ + public static void startPushActivity(@NonNull Context context, @NonNull Class clz, Bundle bundle) { + Intent intent = new Intent(context, clz); + if (null != bundle){ + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtras(bundle); + } + context.startActivity(intent); + } + + /** + * 启动Activity + * + * @param context + * @param clz + */ + public static void startActivity(@NonNull Context context, @NonNull Class clz) { + startActivity(context, clz, null); + } + + /** + * 启动Activity + * + * @param activity + * @param clz + * @param bundle + */ + public static void startActivityForResult(@NonNull Activity activity, @NonNull Class clz, Bundle bundle, int requestCode) { + Intent intent = new Intent(activity, clz); + if (null != bundle) intent.putExtras(bundle); + activity.startActivityForResult(intent, requestCode); + } + + /** + * 启动Activity + * + * @param activity + * @param clz + */ + public static void startActivityForResult(@NonNull Activity activity, @NonNull Class clz, int requestCode) { + startActivityForResult(activity, clz, null, requestCode); + } + + +// /** +// * 跳转登录界面 +// * +// * @param context +// * @param finishOthers 是否结束其他的activity true结束 false 不结束 +// */ +// public static void openLoginActivity(@NonNull Context context, boolean finishOthers) { +// Intent intent = new Intent(context, LoginMainActivity.class); +// Bundle bundle = new Bundle(); +// bundle.putBoolean("finishOthers", finishOthers); +// intent.putExtras(bundle); +// context.startActivity(intent); +// } + +// /** +// * 启动前必须登录Activity +// * +// * @param context +// * @param clz +// */ +// public static void startActivityByLogin(@NonNull Context context, @NonNull Class clz) { +// startActivityByLogin(context, clz, null); +// } + + + /** + * 回到桌面 + */ + public static void startHomeActivity(Context context) { + Intent homeIntent = new Intent(Intent.ACTION_MAIN); + homeIntent.addCategory(Intent.CATEGORY_HOME); + context.startActivity(homeIntent); + } + + /** + * 获取Activity栈链表 + * + * @return Activity栈链表 + */ + public static List getActivityList() { + return CommonBaseLibrary.activityList; + } + + /** + * 获取启动项Activity + * + * @param packageName 包名 + * @return 启动项Activity + */ + public static String getLauncherActivity(@NonNull final String packageName) { + Intent intent = new Intent(Intent.ACTION_MAIN, null); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + List info = pm.queryIntentActivities(intent, 0); + for (ResolveInfo aInfo : info) { + if (aInfo.activityInfo.packageName.equals(packageName)) { + return aInfo.activityInfo.name; + } + } + return "no " + packageName; + } + + /** + * 获取栈顶Activity + * + * @return 栈顶Activity + */ + public static Activity getTopActivity() { + if (CommonBaseLibrary.topActivity != null) { + Activity activity = CommonBaseLibrary.topActivity.get(); + if (activity != null) { + return activity; + } + } + List activities = CommonBaseLibrary.activityList; + int size = activities.size(); + return size > 0 ? activities.get(size - 1) : null; + } + + /** + * 判断Activity是否存在栈中 + * + * @param activity activity + * @return {@code true}: 存在
{@code false}: 不存在 + */ + public static boolean isActivityExistsInStack(@NonNull final Activity activity) { + List activities = CommonBaseLibrary.activityList; + for (Activity aActivity : activities) { + if (aActivity.equals(activity)) { + return true; + } + } + return false; + } + + /** + * 判断Activity是否存在栈中 + * + * @param clz activity类 + * @return {@code true}: 存在
{@code false}: 不存在 + */ + public static boolean isActivityExistsInStack(@NonNull final Class clz) { + List activities = CommonBaseLibrary.activityList; + for (Activity aActivity : activities) { + if (aActivity.getClass().equals(clz)) { + return true; + } + } + return false; + } + + /** + * 结束Activity + * + * @param activity activity + */ + public static void finishActivity(@NonNull final Activity activity) { + activity.finish(); + } + + + /** + * 结束Activity + * + * @param clz activity类 + */ + public static void finishActivity(@NonNull final Class clz) { + List activities = CommonBaseLibrary.activityList; + for (Activity activity : activities) { + if (activity.getClass().equals(clz)) { + activity.finish(); + } + } + } + + /** + * 结束到指定Activity + * + * @param activity activity + * @param isIncludeSelf 是否结束该activity自己 + */ + public static boolean finishToActivity(@NonNull final Activity activity, + final boolean isIncludeSelf) { + List activities = CommonBaseLibrary.activityList; + for (int i = activities.size() - 1; i >= 0; --i) { + Activity aActivity = activities.get(i); + if (aActivity.equals(activity)) { + if (isIncludeSelf) { + finishActivity(aActivity); + } + return true; + } + finishActivity(aActivity); + } + return false; + } + + /** + * 结束到指定Activity + * + * @param isIncludeSelf 是否结束该activity自己 + */ + public static boolean finishToActivity(@NonNull final Class clz, + final boolean isIncludeSelf) { + List activities = CommonBaseLibrary.activityList; + for (int i = activities.size() - 1; i >= 0; --i) { + Activity aActivity = activities.get(i); + if (aActivity.getClass().equals(clz)) { + if (isIncludeSelf) { + finishActivity(aActivity); + } + return true; + }else{ + finishActivity(aActivity); + } +// finishActivity(aActivity); + } + return false; + } + + /** + * 结束除最新之外的同类型Activity + *

也就是让栈中最多只剩下一种类型的Activity

+ * + * @param clz activity类 + */ + public static void finishOtherActivitiesExceptNewest(@NonNull final Class clz) { + List activities = CommonBaseLibrary.activityList; + boolean flag = false; + for (int i = activities.size() - 1; i >= 0; i--) { + Activity activity = activities.get(i); + if (activity.getClass().equals(clz)) { + if (flag) { + finishActivity(activity); + } else { + flag = true; + } + } else { + finishActivity(activity); + } + } + } + + /** + * 清除除本activity之外所有的activity + * + * @param clz 本activity的类名 + */ + public static void finishOtherActivities(@NonNull final Class clz) { + List activities = CommonBaseLibrary.activityList; + for (Activity activity : activities) { + if (!activity.getClass().equals(clz)) { + finishActivity(activity); + } + } + } + + /** + * 结束所有activity + */ + public static void finishAllActivities() { + List activityList = CommonBaseLibrary.activityList; + for (int i = activityList.size() - 1; i >= 0; --i) {// 从栈顶开始移除 + Activity activity = activityList.get(i); + activity.finish();// 在onActivityDestroyed发生remove + } + } + + private static Context getActivityOrApp() { + Activity topActivity = getTopActivity(); + return topActivity == null ? CommonBaseLibrary.getApplication() : topActivity; + } + + +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/AppUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/AppUtils.java new file mode 100644 index 0000000..e556926 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/AppUtils.java @@ -0,0 +1,1062 @@ +package com.dahe.mylibrary.utils; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.Signature; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.provider.Settings; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.core.content.FileProvider; + + +import com.dahe.mylibrary.CommonBaseLibrary; + +import java.io.File; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/08/02
+ *     desc  : utils about app
+ * 
+ * registerAppStatusChangedListener : 注册 App 前后台切换监听器 + * unregisterAppStatusChangedListener: 注销 App 前后台切换监听器 + * installApp : 安装 App(支持 8.0) + * installAppSilent : 静默安装 App + * uninstallApp : 卸载 App + * uninstallAppSilent : 静默卸载 App + * isAppInstalled : 判断 App 是否安装 + * isAppRoot : 判断 App 是否有 root 权限 + * isAppDebug : 判断 App 是否是 Debug 版本 + * isAppSystem : 判断 App 是否是系统应用 + * isAppForeground : 判断 App 是否处于前台 + * launchApp : 打开 App + * relaunchApp : 重启 App + * launchAppDetailsSettings : 打开 App 具体设置 + * exitApp : 关闭应用 + * getAppIcon : 获取 App 图标 + * getAppPackageName : 获取 App 包名 + * getAppName : 获取 App 名称 + * getAppPath : 获取 App 路径 + * getAppVersionName : 获取 App 版本号 + * getAppVersionCode : 获取 App 版本码 + * getAppSignature : 获取 App 签名 + * getAppSignatureSHA1 : 获取应用签名的的 SHA1 值 + * getAppSignatureSHA256 : 获取应用签名的的 SHA256 值 + * getAppSignatureMD5 : 获取应用签名的的 MD5 值 + * getAppInfo : 获取 App 信息 + * getAppsInfo : 获取所有已安装 App 信息 + * getApkInfo : 获取 Apk 信息 + */ +public final class AppUtils { + + private AppUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * Install the app. + *

Target APIs greater than 25 must hold + * {@code }

+ * + * @param filePath The path of file. + */ + public static void installApp(final String filePath) { + installApp(getFileByPath(filePath)); + } + + /** + * Install the app. + *

Target APIs greater than 25 must hold + * {@code }

+ * + * @param file The file. + */ + public static void installApp(final File file) { + if (!isFileExists(file)) return; + CommonBaseLibrary.getApplication().startActivity(getInstallAppIntent(file, true)); + } + + /** + * Install the app. + *

Target APIs greater than 25 must hold + * {@code }

+ * + * @param activity The activity. + * @param filePath The path of file. + * @param requestCode If >= 0, this code will be returned in + * onActivityResult() when the activity exits. + */ + public static void installApp(final Activity activity, + final String filePath, + final int requestCode) { + installApp(activity, getFileByPath(filePath), requestCode); + } + + /** + * Install the app. + *

Target APIs greater than 25 must hold + * {@code }

+ * + * @param activity The activity. + * @param file The file. + * @param requestCode If >= 0, this code will be returned in + * onActivityResult() when the activity exits. + */ + public static void installApp(final Activity activity, + final File file, + final int requestCode) { + if (!isFileExists(file)) return; + activity.startActivityForResult(getInstallAppIntent(file), requestCode); + } + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param filePath The path of file. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final String filePath) { + return installAppSilent(getFileByPath(filePath), null); + } + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param file The file. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final File file) { + return installAppSilent(file, null); + } + + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param filePath The path of file. + * @param params The params of installation(e.g.,-r, -s). + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final String filePath, final String params) { + return installAppSilent(getFileByPath(filePath), params); + } + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param file The file. + * @param params The params of installation(e.g.,-r, -s). + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final File file, final String params) { + return installAppSilent(file, params, isDeviceRooted()); + } + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param file The file. + * @param params The params of installation(e.g.,-r, -s). + * @param isRooted True to use root, false otherwise. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final File file, + final String params, + final boolean isRooted) { + if (!isFileExists(file)) return false; + String filePath = '"' + file.getAbsolutePath() + '"'; + String command = "LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm install " + + (params == null ? "" : params + " ") + + filePath; + ShellUtils.CommandResult commandResult = ShellUtils.execCmd(command, isRooted); + if (commandResult.successMsg != null + && commandResult.successMsg.toLowerCase().contains("success")) { + return true; + } else { + Log.e("AppUtils", "installAppSilent successMsg: " + commandResult.successMsg + + ", errorMsg: " + commandResult.errorMsg); + return false; + } + } + + /** + * Uninstall the app. + * + * @param packageName The name of the package. + */ + public static void uninstallApp(final String packageName) { + if (isSpace(packageName)) return; + CommonBaseLibrary.getApplication().startActivity(getUninstallAppIntent(packageName, true)); + } + + /** + * Uninstall the app. + * + * @param activity The activity. + * @param packageName The name of the package. + * @param requestCode If >= 0, this code will be returned in + * onActivityResult() when the activity exits. + */ + public static void uninstallApp(final Activity activity, + final String packageName, + final int requestCode) { + if (isSpace(packageName)) return; + activity.startActivityForResult(getUninstallAppIntent(packageName), requestCode); + } + + /** + * Uninstall the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param packageName The name of the package. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean uninstallAppSilent(final String packageName) { + return uninstallAppSilent(packageName, false); + } + + /** + * Uninstall the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param packageName The name of the package. + * @param isKeepData Is keep the data. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean uninstallAppSilent(final String packageName, final boolean isKeepData) { + return uninstallAppSilent(packageName, isKeepData, isDeviceRooted()); + } + + /** + * Uninstall the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param packageName The name of the package. + * @param isKeepData Is keep the data. + * @param isRooted True to use root, false otherwise. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean uninstallAppSilent(final String packageName, + final boolean isKeepData, + final boolean isRooted) { + if (isSpace(packageName)) return false; + String command = "LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm uninstall " + + (isKeepData ? "-k " : "") + + packageName; + ShellUtils.CommandResult commandResult = ShellUtils.execCmd(command, isRooted); + if (commandResult.successMsg != null + && commandResult.successMsg.toLowerCase().contains("success")) { + return true; + } else { + Log.e("AppUtils", "uninstallAppSilent successMsg: " + commandResult.successMsg + + ", errorMsg: " + commandResult.errorMsg); + return false; + } + } + + /** + * Return whether the app is installed. + * + * @param packageName The name of the package. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppInstalled(@NonNull final String packageName) { + PackageManager packageManager = CommonBaseLibrary.getApplication().getPackageManager(); + try { + return packageManager.getApplicationInfo(packageName, 0) != null; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + /** + * Return whether the application with root permission. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppRoot() { + ShellUtils.CommandResult result = ShellUtils.execCmd("echo root", true); + if (result.result == 0) return true; + if (result.errorMsg != null) { + Log.d("AppUtils", "isAppRoot() called" + result.errorMsg); + } + return false; + } + + /** + * Return whether it is a debug application. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppDebug() { + return isAppDebug(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return whether it is a debug application. + * + * @param packageName The name of the package. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppDebug(final String packageName) { + if (isSpace(packageName)) return false; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); + return ai != null && (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + /** + * Return whether it is a system application. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppSystem() { + return isAppSystem(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return whether it is a system application. + * + * @param packageName The name of the package. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppSystem(final String packageName) { + if (isSpace(packageName)) return false; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); + return ai != null && (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + + /** + * Return whether application is foreground. + *

Target APIs greater than 21 must hold + * {@code }

+ * + * @param packageName The name of the package. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppForeground(@NonNull final String packageName) { + return !isSpace(packageName) && packageName.equals(getForegroundProcessName()); + } + + /** + * Launch the application. + * + * @param packageName The name of the package. + */ + public static void launchApp(final String packageName) { + if (isSpace(packageName)) return; + CommonBaseLibrary.getApplication().startActivity(getLaunchAppIntent(packageName, true)); + } + + /** + * Launch the application. + * + * @param activity The activity. + * @param packageName The name of the package. + * @param requestCode If >= 0, this code will be returned in + * onActivityResult() when the activity exits. + */ + public static void launchApp(final Activity activity, + final String packageName, + final int requestCode) { + if (isSpace(packageName)) return; + activity.startActivityForResult(getLaunchAppIntent(packageName), requestCode); + } + + /** + * Relaunch the application. + */ + public static void relaunchApp() { + relaunchApp(false); + } + + /** + * Relaunch the application. + * + * @param isKillProcess True to kill the process, false otherwise. + */ + public static void relaunchApp(final boolean isKillProcess) { + PackageManager packageManager = CommonBaseLibrary.getApplication().getPackageManager(); + Intent intent = packageManager.getLaunchIntentForPackage(CommonBaseLibrary.getApplication().getPackageName()); + if (intent == null) return; + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + CommonBaseLibrary.getApplication().startActivity(intent); + if (!isKillProcess) return; + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(0); + } + + /** + * Launch the application's details settings. + */ + public static void launchAppDetailsSettings() { + launchAppDetailsSettings(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Launch the application's details settings. + * + * @param packageName The name of the package. + */ + public static void launchAppDetailsSettings(final String packageName) { + if (isSpace(packageName)) return; + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + packageName)); + CommonBaseLibrary.getApplication().startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + + + /** + * Return the application's icon. + * + * @return the application's icon + */ + public static Drawable getAppIcon() { + return getAppIcon(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's icon. + * + * @param packageName The name of the package. + * @return the application's icon + */ + public static Drawable getAppIcon(final String packageName) { + if (isSpace(packageName)) return null; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? null : pi.applicationInfo.loadIcon(pm); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Return the application's package name. + * + * @return the application's package name + */ + public static String getAppPackageName() { + return CommonBaseLibrary.getApplication().getPackageName(); + } + + /** + * Return the application's name. + * + * @return the application's name + */ + public static String getAppName() { + return getAppName(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's name. + * + * @param packageName The name of the package. + * @return the application's name + */ + public static String getAppName(final String packageName) { + if (isSpace(packageName)) return ""; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? null : pi.applicationInfo.loadLabel(pm).toString(); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * Return the application's path. + * + * @return the application's path + */ + public static String getAppPath() { + return getAppPath(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's path. + * + * @param packageName The name of the package. + * @return the application's path + */ + public static String getAppPath(final String packageName) { + if (isSpace(packageName)) return ""; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? null : pi.applicationInfo.sourceDir; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * Return the application's version name. + * + * @return the application's version name + */ + public static String getAppVersionName() { + return getAppVersionName(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's version name. + * + * @param packageName The name of the package. + * @return the application's version name + */ + public static String getAppVersionName(final String packageName) { + if (isSpace(packageName)) return ""; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? null : pi.versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * Return the application's version code. + * + * @return the application's version code + */ + public static int getAppVersionCode() { + return getAppVersionCode(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's version code. + * + * @param packageName The name of the package. + * @return the application's version code + */ + public static int getAppVersionCode(final String packageName) { + if (isSpace(packageName)) return -1; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? -1 : pi.versionCode; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return -1; + } + } + + /** + * Return the application's signature. + * + * @return the application's signature + */ + public static Signature[] getAppSignature() { + return getAppSignature(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's signature. + * + * @param packageName The name of the package. + * @return the application's signature + */ + public static Signature[] getAppSignature(final String packageName) { + if (isSpace(packageName)) return null; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + @SuppressLint("PackageManagerGetSignatures") + PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + return pi == null ? null : pi.signatures; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Return the application's signature for SHA1 value. + * + * @return the application's signature for SHA1 value + */ + public static String getAppSignatureSHA1() { + return getAppSignatureSHA1(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's signature for SHA1 value. + * + * @param packageName The name of the package. + * @return the application's signature for SHA1 value + */ + public static String getAppSignatureSHA1(final String packageName) { + return getAppSignatureHash(packageName, "SHA1"); + } + + /** + * Return the application's signature for SHA256 value. + * + * @return the application's signature for SHA256 value + */ + public static String getAppSignatureSHA256() { + return getAppSignatureSHA256(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's signature for SHA256 value. + * + * @param packageName The name of the package. + * @return the application's signature for SHA256 value + */ + public static String getAppSignatureSHA256(final String packageName) { + return getAppSignatureHash(packageName, "SHA256"); + } + + /** + * Return the application's signature for MD5 value. + * + * @return the application's signature for MD5 value + */ + public static String getAppSignatureMD5() { + return getAppSignatureMD5(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's signature for MD5 value. + * + * @param packageName The name of the package. + * @return the application's signature for MD5 value + */ + public static String getAppSignatureMD5(final String packageName) { + return getAppSignatureHash(packageName, "MD5"); + } + + private static String getAppSignatureHash(final String packageName, final String algorithm) { + if (isSpace(packageName)) return ""; + Signature[] signature = getAppSignature(packageName); + if (signature == null || signature.length <= 0) return ""; + return bytes2HexString(hashTemplate(signature[0].toByteArray(), algorithm)) + .replaceAll("(?<=[0-9A-F]{2})[0-9A-F]{2}", ":$0"); + } + + /** + * Return the application's information. + *
    + *
  • name of package
  • + *
  • icon
  • + *
  • name
  • + *
  • path of package
  • + *
  • version name
  • + *
  • version code
  • + *
  • is system
  • + *
+ * + * @return the application's information + */ + public static AppInfo getAppInfo() { + return getAppInfo(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's information. + *
    + *
  • name of package
  • + *
  • icon
  • + *
  • name
  • + *
  • path of package
  • + *
  • version name
  • + *
  • version code
  • + *
  • is system
  • + *
+ * + * @param packageName The name of the package. + * @return the application's information + */ + public static AppInfo getAppInfo(final String packageName) { + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return getBean(pm, pi); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Return the applications' information. + * + * @return the applications' information + */ + public static List getAppsInfo() { + List list = new ArrayList<>(); + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + List installedPackages = pm.getInstalledPackages(0); + for (PackageInfo pi : installedPackages) { + AppInfo ai = getBean(pm, pi); + if (ai == null) continue; + list.add(ai); + } + return list; + } + + /** + * Return the application's package information. + * + * @return the application's package information + */ + public static AppInfo getApkInfo(final File apkFile) { + if (apkFile == null || !apkFile.isFile() || !apkFile.exists()) return null; + return getApkInfo(apkFile.getAbsolutePath()); + } + + /** + * Return the application's package information. + * + * @return the application's package information + */ + public static AppInfo getApkInfo(final String apkFilePath) { + if (isSpace(apkFilePath)) return null; + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageArchiveInfo(apkFilePath, 0); + ApplicationInfo appInfo = pi.applicationInfo; + appInfo.sourceDir = apkFilePath; + return getBean(pm, pi); + } + + private static AppInfo getBean(final PackageManager pm, final PackageInfo pi) { + if (pm == null || pi == null) return null; + ApplicationInfo ai = pi.applicationInfo; + String packageName = pi.packageName; + String name = ai.loadLabel(pm).toString(); + Drawable icon = ai.loadIcon(pm); + String packagePath = ai.sourceDir; + String versionName = pi.versionName; + int versionCode = pi.versionCode; + boolean isSystem = (ApplicationInfo.FLAG_SYSTEM & ai.flags) != 0; + return new AppInfo(packageName, name, icon, packagePath, versionName, versionCode, isSystem); + } + + /** + * The application's information. + */ + public static class AppInfo { + + private String packageName; + private String name; + private Drawable icon; + private String packagePath; + private String versionName; + private int versionCode; + private boolean isSystem; + + public Drawable getIcon() { + return icon; + } + + public void setIcon(final Drawable icon) { + this.icon = icon; + } + + public boolean isSystem() { + return isSystem; + } + + public void setSystem(final boolean isSystem) { + this.isSystem = isSystem; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(final String packageName) { + this.packageName = packageName; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getPackagePath() { + return packagePath; + } + + public void setPackagePath(final String packagePath) { + this.packagePath = packagePath; + } + + public int getVersionCode() { + return versionCode; + } + + public void setVersionCode(final int versionCode) { + this.versionCode = versionCode; + } + + public String getVersionName() { + return versionName; + } + + public void setVersionName(final String versionName) { + this.versionName = versionName; + } + + public AppInfo(String packageName, String name, Drawable icon, String packagePath, + String versionName, int versionCode, boolean isSystem) { + this.setName(name); + this.setIcon(icon); + this.setPackageName(packageName); + this.setPackagePath(packagePath); + this.setVersionName(versionName); + this.setVersionCode(versionCode); + this.setSystem(isSystem); + } + + @Override + public String toString() { + return "{" + + "\n pkg name: " + getPackageName() + + "\n app icon: " + getIcon() + + "\n app name: " + getName() + + "\n app path: " + getPackagePath() + + "\n app v name: " + getVersionName() + + "\n app v code: " + getVersionCode() + + "\n is system: " + isSystem() + + "}"; + } + } + + /////////////////////////////////////////////////////////////////////////// + // other utils methods + /////////////////////////////////////////////////////////////////////////// + + private static boolean isFileExists(final File file) { + return file != null && file.exists(); + } + + private static File getFileByPath(final String filePath) { + return isSpace(filePath) ? null : new File(filePath); + } + + private static boolean isSpace(final String s) { + if (s == null) return true; + for (int i = 0, len = s.length(); i < len; ++i) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } + + private static boolean isDeviceRooted() { + String su = "su"; + String[] locations = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/", + "/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/", + "/system/sbin/", "/usr/bin/", "/vendor/bin/"}; + for (String location : locations) { + if (new File(location + su).exists()) { + return true; + } + } + return false; + } + + private static final char HEX_DIGITS[] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + private static byte[] hashTemplate(final byte[] data, final String algorithm) { + if (data == null || data.length <= 0) return null; + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + md.update(data); + return md.digest(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return null; + } + } + + private static String bytes2HexString(final byte[] bytes) { + if (bytes == null) return ""; + int len = bytes.length; + if (len <= 0) return ""; + char[] ret = new char[len << 1]; + for (int i = 0, j = 0; i < len; i++) { + ret[j++] = HEX_DIGITS[bytes[i] >> 4 & 0x0f]; + ret[j++] = HEX_DIGITS[bytes[i] & 0x0f]; + } + return new String(ret); + } + + private static Intent getInstallAppIntent(final File file) { + return getInstallAppIntent(file, false); + } + + private static Intent getInstallAppIntent(final File file, final boolean isNewTask) { + Intent intent = new Intent(Intent.ACTION_VIEW); + Uri data; + String type = "application/vnd.android.package-archive"; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + data = Uri.fromFile(file); + } else { + String authority = CommonBaseLibrary.getApplication().getPackageName() + ".utilcode.provider"; + data = FileProvider.getUriForFile(CommonBaseLibrary.getApplication(), authority, file); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + CommonBaseLibrary.getApplication().grantUriPermission(CommonBaseLibrary.getApplication().getPackageName(), data, Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(data, type); + return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent; + } + + private static Intent getUninstallAppIntent(final String packageName) { + return getUninstallAppIntent(packageName, false); + } + + private static Intent getUninstallAppIntent(final String packageName, final boolean isNewTask) { + Intent intent = new Intent(Intent.ACTION_DELETE); + intent.setData(Uri.parse("package:" + packageName)); + return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent; + } + + private static Intent getLaunchAppIntent(final String packageName) { + return getLaunchAppIntent(packageName, false); + } + + private static Intent getLaunchAppIntent(final String packageName, final boolean isNewTask) { + Intent intent = CommonBaseLibrary.getApplication().getPackageManager().getLaunchIntentForPackage(packageName); + if (intent == null) return null; + return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent; + } + + private static String getForegroundProcessName() { + ActivityManager am = + (ActivityManager) CommonBaseLibrary.getApplication().getSystemService(Context.ACTIVITY_SERVICE); + //noinspection ConstantConditions + List pInfo = am.getRunningAppProcesses(); + if (pInfo != null && pInfo.size() > 0) { + for (ActivityManager.RunningAppProcessInfo aInfo : pInfo) { + if (aInfo.importance + == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { + return aInfo.processName; + } + } + } + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); + List list = + pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + Log.i("ProcessUtils", list.toString()); + if (list.size() <= 0) { + Log.i("ProcessUtils", + "getForegroundProcessName: noun of access to usage information."); + return ""; + } + try {// Access to usage information. + ApplicationInfo info = + pm.getApplicationInfo(CommonBaseLibrary.getApplication().getPackageName(), 0); + AppOpsManager aom = + (AppOpsManager) CommonBaseLibrary.getApplication().getSystemService(Context.APP_OPS_SERVICE); + //noinspection ConstantConditions + if (aom.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, + info.uid, + info.packageName) != AppOpsManager.MODE_ALLOWED) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + CommonBaseLibrary.getApplication().startActivity(intent); + } + if (aom.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, + info.uid, + info.packageName) != AppOpsManager.MODE_ALLOWED) { + Log.i("ProcessUtils", + "getForegroundProcessName: refuse to device usage stats."); + return ""; + } + UsageStatsManager usageStatsManager = (UsageStatsManager) CommonBaseLibrary.getApplication() + .getSystemService(Context.USAGE_STATS_SERVICE); + List usageStatsList = null; + if (usageStatsManager != null) { + long endTime = System.currentTimeMillis(); + long beginTime = endTime - 86400000 * 7; + usageStatsList = usageStatsManager + .queryUsageStats(UsageStatsManager.INTERVAL_BEST, + beginTime, endTime); + } + if (usageStatsList == null || usageStatsList.isEmpty()) return null; + UsageStats recentStats = null; + for (UsageStats usageStats : usageStatsList) { + if (recentStats == null + || usageStats.getLastTimeUsed() > recentStats.getLastTimeUsed()) { + recentStats = usageStats; + } + } + return recentStats == null ? null : recentStats.getPackageName(); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + return ""; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/BarUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BarUtils.java new file mode 100644 index 0000000..30ccf39 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BarUtils.java @@ -0,0 +1,678 @@ +package com.dahe.mylibrary.utils; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Point; +import android.os.Build; +import android.util.Log; +import android.util.TypedValue; +import android.view.Display; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewGroup.MarginLayoutParams; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; +import androidx.drawerlayout.widget.DrawerLayout; + + +import com.dahe.mylibrary.CommonBaseLibrary; + +import java.lang.reflect.Method; + +import static android.Manifest.permission.EXPAND_STATUS_BAR; + +/** + * getStatusBarHeight : 获取状态栏高度(px) + * setStatusBarVisibility : 设置状态栏是否可见 + * isStatusBarVisible : 判断状态栏是否可见 + * setStatusBarLightMode : 设置状态栏是否为浅色模式 + * addMarginTopEqualStatusBarHeight : 为 view 增加 MarginTop 为状态栏高度 + * subtractMarginTopEqualStatusBarHeight: 为 view 减少 MarginTop 为状态栏高度 + * setStatusBarColor : 设置状态栏颜色 + * setStatusBarColor4Drawer : 为 DrawerLayout 设置状态栏颜色 + * getActionBarHeight : 获取 ActionBar 高度 + * setNotificationBarVisibility : 设置通知栏是否可见 + * getNavBarHeight : 获取导航栏高度 + * setNavBarVisibility : 设置导航栏是否可见 + * isNavBarVisible : 判断导航栏是否可见 + * setNavBarColor : 设置导航栏颜色 + * getNavBarColor : 获取导航栏颜色 + * isSupportNavBar : 判断是否支持导航栏 + */ +public final class BarUtils { + + /////////////////////////////////////////////////////////////////////////// + // status bar + /////////////////////////////////////////////////////////////////////////// + + private static final String TAG_STATUS_BAR = "TAG_STATUS_BAR"; + private static final String TAG_OFFSET = "TAG_OFFSET"; + private static final int KEY_OFFSET = -123; + + private BarUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * Return the status bar's height. + * + * @return the status bar's height + */ + public static int getStatusBarHeight() { + Resources resources = Resources.getSystem(); + int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); + return resources.getDimensionPixelSize(resourceId); + } + + /** + * Set the status bar's visibility. + * + * @param activity The activity. + * @param isVisible True to set status bar visible, false otherwise. + */ + public static void setStatusBarVisibility(@NonNull final Activity activity, + final boolean isVisible) { + setStatusBarVisibility(activity.getWindow(), isVisible); + } + + /** + * Set the status bar's visibility. + * + * @param window The window. + * @param isVisible True to set status bar visible, false otherwise. + */ + public static void setStatusBarVisibility(@NonNull final Window window, + final boolean isVisible) { + if (isVisible) { + window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + showStatusBarView(window); + addMarginTopEqualStatusBarHeight(window); + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + hideStatusBarView(window); + subtractMarginTopEqualStatusBarHeight(window); + } + } + + /** + * Return whether the status bar is visible. + * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isStatusBarVisible(@NonNull final Activity activity) { + int flags = activity.getWindow().getAttributes().flags; + return (flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0; + } + + /** + * Set the status bar's light mode. + * + * @param activity The activity. + * @param isLightMode True to set status bar light mode, false otherwise. + */ + public static void setStatusBarLightMode(@NonNull final Activity activity, + final boolean isLightMode) { + setStatusBarLightMode(activity.getWindow(), isLightMode); + } + + /** + * Set the status bar's light mode. + * + * @param window The window. + * @param isLightMode True to set status bar light mode, false otherwise. + */ + public static void setStatusBarLightMode(@NonNull final Window window, + final boolean isLightMode) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + View decorView = window.getDecorView(); + if (decorView != null) { + int vis = decorView.getSystemUiVisibility(); + if (isLightMode) { + vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else { + vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } + decorView.setSystemUiVisibility(vis); + } + } + } + + /** + * Is the status bar light mode. + * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isStatusBarLightMode(@NonNull final Activity activity) { + return isStatusBarLightMode(activity.getWindow()); + } + + /** + * Is the status bar light mode. + * + * @param window The window. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isStatusBarLightMode(@NonNull final Window window) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + View decorView = window.getDecorView(); + if (decorView != null) { + int vis = decorView.getSystemUiVisibility(); + return (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0; + } + } + return false; + } + + /** + * Add the top margin size equals status bar's height for view. + * + * @param view The view. + */ + public static void addMarginTopEqualStatusBarHeight(@NonNull View view) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + view.setTag(TAG_OFFSET); + Object haveSetOffset = view.getTag(KEY_OFFSET); + if (haveSetOffset != null && (Boolean) haveSetOffset) return; + MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams(); + layoutParams.setMargins(layoutParams.leftMargin, + layoutParams.topMargin + getStatusBarHeight(), + layoutParams.rightMargin, + layoutParams.bottomMargin); + view.setTag(KEY_OFFSET, true); + } + + /** + * Subtract the top margin size equals status bar's height for view. + * + * @param view The view. + */ + public static void subtractMarginTopEqualStatusBarHeight(@NonNull View view) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Object haveSetOffset = view.getTag(KEY_OFFSET); + if (haveSetOffset == null || !(Boolean) haveSetOffset) return; + MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams(); + layoutParams.setMargins(layoutParams.leftMargin, + layoutParams.topMargin - getStatusBarHeight(), + layoutParams.rightMargin, + layoutParams.bottomMargin); + view.setTag(KEY_OFFSET, false); + } + + private static void addMarginTopEqualStatusBarHeight(final Window window) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET); + if (withTag == null) return; + addMarginTopEqualStatusBarHeight(withTag); + } + + private static void subtractMarginTopEqualStatusBarHeight(final Window window) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET); + if (withTag == null) return; + subtractMarginTopEqualStatusBarHeight(withTag); + } + + /** + * Set the status bar's color. + * + * @param activity The activity. + * @param color The status bar's color. + */ + public static View setStatusBarColor(@NonNull final Activity activity, + @ColorInt final int color) { + return setStatusBarColor(activity, color, false); + } + + /** + * Set the status bar's color. + * + * @param activity The activity. + * @param color The status bar's color. + * @param isDecor True to add fake status bar in DecorView, + * false to add fake status bar in ContentView. + */ + public static View setStatusBarColor(@NonNull final Activity activity, + @ColorInt final int color, + final boolean isDecor) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null; + transparentStatusBar(activity); + return applyStatusBarColor(activity, color, isDecor); + } + + /** + * Set the status bar's color. + * + * @param fakeStatusBar The fake status bar view. + * @param color The status bar's color. + */ + public static void setStatusBarColor(@NonNull final View fakeStatusBar, + @ColorInt final int color) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Activity activity = getActivityByView(fakeStatusBar); + if (activity == null) return; + transparentStatusBar(activity); + fakeStatusBar.setVisibility(View.VISIBLE); + ViewGroup.LayoutParams layoutParams = fakeStatusBar.getLayoutParams(); + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + layoutParams.height = getStatusBarHeight(); + fakeStatusBar.setBackgroundColor(color); + } + + /** + * Set the custom status bar. + * + * @param fakeStatusBar The fake status bar view. + */ + public static void setStatusBarCustom(@NonNull final View fakeStatusBar) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Activity activity = getActivityByView(fakeStatusBar); + if (activity == null) return; + transparentStatusBar(activity); + fakeStatusBar.setVisibility(View.VISIBLE); + ViewGroup.LayoutParams layoutParams = fakeStatusBar.getLayoutParams(); + if (layoutParams == null) { + layoutParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + getStatusBarHeight() + ); + fakeStatusBar.setLayoutParams(layoutParams); + } else { + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + layoutParams.height = getStatusBarHeight(); + } + } + + /** + * Set the status bar's color for DrawerLayout. + *

DrawLayout must add {@code android:fitsSystemWindows="true"}

+ * + * @param drawer The DrawLayout. + * @param fakeStatusBar The fake status bar view. + * @param color The status bar's color. + */ + public static void setStatusBarColor4Drawer(@NonNull final DrawerLayout drawer, + @NonNull final View fakeStatusBar, + @ColorInt final int color) { + setStatusBarColor4Drawer(drawer, fakeStatusBar, color, false); + } + + /** + * Set the status bar's color for DrawerLayout. + *

DrawLayout must add {@code android:fitsSystemWindows="true"}

+ * + * @param drawer The DrawLayout. + * @param fakeStatusBar The fake status bar view. + * @param color The status bar's color. + * @param isTop True to set DrawerLayout at the top layer, false otherwise. + */ + public static void setStatusBarColor4Drawer(@NonNull final DrawerLayout drawer, + @NonNull final View fakeStatusBar, + @ColorInt final int color, + final boolean isTop) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Activity activity = getActivityByView(fakeStatusBar); + if (activity == null) return; + transparentStatusBar(activity); + drawer.setFitsSystemWindows(false); + setStatusBarColor(fakeStatusBar, color); + for (int i = 0, count = drawer.getChildCount(); i < count; i++) { + drawer.getChildAt(i).setFitsSystemWindows(false); + } + if (isTop) { + hideStatusBarView(activity); + } else { + setStatusBarColor(activity, color, false); + } + } + + private static View applyStatusBarColor(final Activity activity, + final int color, + boolean isDecor) { + ViewGroup parent = isDecor ? + (ViewGroup) activity.getWindow().getDecorView() : + (ViewGroup) activity.findViewById(android.R.id.content); + View fakeStatusBarView = parent.findViewWithTag(TAG_STATUS_BAR); + if (fakeStatusBarView != null) { + if (fakeStatusBarView.getVisibility() == View.GONE) { + fakeStatusBarView.setVisibility(View.VISIBLE); + } + fakeStatusBarView.setBackgroundColor(color); + } else { + fakeStatusBarView = createStatusBarView(activity, color); + parent.addView(fakeStatusBarView); + } + return fakeStatusBarView; + } + + private static void hideStatusBarView(final Activity activity) { + hideStatusBarView(activity.getWindow()); + } + + private static void hideStatusBarView(final Window window) { + ViewGroup decorView = (ViewGroup) window.getDecorView(); + View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR); + if (fakeStatusBarView == null) return; + fakeStatusBarView.setVisibility(View.GONE); + } + + private static void showStatusBarView(final Window window) { + ViewGroup decorView = (ViewGroup) window.getDecorView(); + View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR); + if (fakeStatusBarView == null) return; + fakeStatusBarView.setVisibility(View.VISIBLE); + } + + private static View createStatusBarView(final Activity activity, + final int color) { + View statusBarView = new View(activity); + statusBarView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight())); + statusBarView.setBackgroundColor(color); + statusBarView.setTag(TAG_STATUS_BAR); + return statusBarView; + } + + private static void transparentStatusBar(final Activity activity) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Window window = activity.getWindow(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + int option = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + window.getDecorView().setSystemUiVisibility(option); + window.setStatusBarColor(Color.TRANSPARENT); + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + } + } + + /////////////////////////////////////////////////////////////////////////// + // action bar + /////////////////////////////////////////////////////////////////////////// + + /** + * Return the action bar's height. + * + * @return the action bar's height + */ + public static int getActionBarHeight() { + TypedValue tv = new TypedValue(); + if (CommonBaseLibrary.getApplication().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { + return TypedValue.complexToDimensionPixelSize( + tv.data, CommonBaseLibrary.getApplication().getResources().getDisplayMetrics() + ); + } + return 0; + } + + /////////////////////////////////////////////////////////////////////////// + // notification bar + /////////////////////////////////////////////////////////////////////////// + + /** + * Set the notification bar's visibility. + *

Must hold {@code }

+ * + * @param isVisible True to set notification bar visible, false otherwise. + */ + @RequiresPermission(EXPAND_STATUS_BAR) + public static void setNotificationBarVisibility(final boolean isVisible) { + String methodName; + if (isVisible) { + methodName = (Build.VERSION.SDK_INT <= 16) ? "expand" : "expandNotificationsPanel"; + } else { + methodName = (Build.VERSION.SDK_INT <= 16) ? "collapse" : "collapsePanels"; + } + invokePanels(methodName); + } + + private static void invokePanels(final String methodName) { + try { + @SuppressLint("WrongConstant") + Object service = CommonBaseLibrary.getApplication().getSystemService("statusbar"); + @SuppressLint("PrivateApi") + Class statusBarManager = Class.forName("android.app.StatusBarManager"); + Method expand = statusBarManager.getMethod(methodName); + expand.invoke(service); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /////////////////////////////////////////////////////////////////////////// + // navigation bar + /////////////////////////////////////////////////////////////////////////// + + /** + * Return the navigation bar's height. + * + * @return the navigation bar's height + */ + public static int getNavBarHeight() { + Resources res = Resources.getSystem(); + int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android"); + if (resourceId != 0) { + return res.getDimensionPixelSize(resourceId); + } else { + return 0; + } + } + + /** + * Set the navigation bar's visibility. + * + * @param activity The activity. + * @param isVisible True to set navigation bar visible, false otherwise. + */ + public static void setNavBarVisibility(@NonNull final Activity activity, boolean isVisible) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + setNavBarVisibility(activity.getWindow(), isVisible); + + } + + /** + * Set the navigation bar's visibility. + * + * @param window The window. + * @param isVisible True to set navigation bar visible, false otherwise. + */ + public static void setNavBarVisibility(@NonNull final Window window, boolean isVisible) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + final ViewGroup decorView = (ViewGroup) window.getDecorView(); + for (int i = 0, count = decorView.getChildCount(); i < count; i++) { + final View child = decorView.getChildAt(i); + final int id = child.getId(); + if (id != View.NO_ID) { + String resourceEntryName = CommonBaseLibrary.getApplication() + .getResources() + .getResourceEntryName(id); + if ("navigationBarBackground".equals(resourceEntryName)) { + child.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE); + } + } + } + final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + if (isVisible) { + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() & ~uiOptions); + } else { + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | uiOptions); + } + } + + /** + * Return whether the navigation bar visible. + *

Call it in onWindowFocusChanged will get right result.

+ * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isNavBarVisible(@NonNull final Activity activity) { + return isNavBarVisible(activity.getWindow()); + } + + + + /** + * 判断是否显示了导航栏 + * (说明这里的context 一定要是activity的context 否则类型转换失败) + * + * @param context + * @return + */ +// public static boolean isShowNavBar(Context context) { +// if (null == context) { +// node_return false; +// } +// /** +// * 获取应用区域高度 +// */ +// Rect outRect1 = new Rect(); +// try { +// ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect1); +// } catch (ClassCastException e) { +// e.printStackTrace(); +// node_return false; +// } +// int activityHeight = outRect1.height(); +// /** +// * 获取状态栏高度 +// */ +// int statuBarHeight = WindowDispaly.getStatusBarHeight(); +// /** +// * 屏幕物理高度 减去 状态栏高度 +// */ +// int remainHeight = WindowDispaly.getRealHeight() - statuBarHeight; +// /** +// * 剩余高度跟应用区域高度相等 说明导航栏没有显示 否则相反 +// */ +// if (activityHeight == remainHeight) { +// node_return false; +// } else { +// node_return true; +// } +// +// } + + /** + * Return whether the navigation bar visible. + *

Call it in onWindowFocusChanged will get right result.

+ * + * @param window The window. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isNavBarVisible(@NonNull final Window window) { + boolean isVisible = false; + ViewGroup decorView = (ViewGroup) window.getDecorView(); + for (int i = 0, count = decorView.getChildCount(); i < count; i++) { + final View child = decorView.getChildAt(i); + final int id = child.getId(); + if (id != View.NO_ID) { + String resourceEntryName = CommonBaseLibrary.getApplication() + .getResources() + .getResourceEntryName(id); + if ("navigationBarBackground".equals(resourceEntryName) + && child.getVisibility() == View.VISIBLE) { + isVisible = true; + break; + } + } + } + if (isVisible) { + int visibility = decorView.getSystemUiVisibility(); + isVisible = (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; + } + return isVisible; + } + + /** + * Set the navigation bar's color. + * + * @param activity The activity. + * @param color The navigation bar's color. + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static void setNavBarColor(@NonNull final Activity activity, @ColorInt final int color) { + setNavBarColor(activity.getWindow(), color); + } + + /** + * Set the navigation bar's color. + * + * @param window The window. + * @param color The navigation bar's color. + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static void setNavBarColor(@NonNull final Window window, @ColorInt final int color) { + window.setNavigationBarColor(color); + } + + /** + * Return the color of navigation bar. + * + * @param activity The activity. + * @return the color of navigation bar + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static int getNavBarColor(@NonNull final Activity activity) { + return getNavBarColor(activity.getWindow()); + } + + /** + * Return the color of navigation bar. + * + * @param window The window. + * @return the color of navigation bar + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static int getNavBarColor(@NonNull final Window window) { + return window.getNavigationBarColor(); + } + + /** + * Return whether the navigation bar visible. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isSupportNavBar() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + WindowManager wm = (WindowManager) CommonBaseLibrary.getApplication().getSystemService(Context.WINDOW_SERVICE); + if (wm == null) return false; + Display display = wm.getDefaultDisplay(); + Point size = new Point(); + Point realSize = new Point(); + display.getSize(size); + display.getRealSize(realSize); + return realSize.y != size.y || realSize.x != size.x; + } + boolean menu = ViewConfiguration.get(CommonBaseLibrary.getApplication()).hasPermanentMenuKey(); + boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK); + return !menu && !back; + } + + private static Activity getActivityByView(@NonNull final View view) { + Context context = view.getContext(); + while (context instanceof ContextWrapper) { + if (context instanceof Activity) { + return (Activity) context; + } + context = ((ContextWrapper) context).getBaseContext(); + } + Log.e("BarUtils", "the view's Context is not an Activity."); + return null; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/Base64Utils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/Base64Utils.java new file mode 100644 index 0000000..8278fda --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/Base64Utils.java @@ -0,0 +1,13 @@ +package com.dahe.mylibrary.utils; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Base64; + +public class Base64Utils { + + public static Bitmap asdf(String imageBase64){ + byte[] decodedString = Base64.decode(imageBase64, Base64.DEFAULT); + return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseSPUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseSPUtils.java new file mode 100644 index 0000000..9450e59 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseSPUtils.java @@ -0,0 +1,193 @@ +package com.dahe.mylibrary.utils; + +import android.content.Context; +import android.content.SharedPreferences; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; + +/** + * 轻量级数据存储工具类 + * + * @author Administrator + */ +public class BaseSPUtils { + /** + * 保存在手机里面的文件名 + */ + public static final String FILE_NAME = "sp_data"; + public static final String USER_INFO_KEY = "user_info_key"; + public static final String NET_SERVICE_TEST = "net_service_test"; + public static final String SEARRH_CACHE = "search_cache"; + public static final String NAVI_PH_EDIT_CACHE = "navi_ph_edit_cache"; + public static final String FIRST_OPEN = "first_open"; + public static final String KEY_PRIVACY_AGREEMENT = "privacy_agreement"; + + /** + * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法 + * + * @param context + * @param key + * @param object + */ + public static void put(Context context, String key, Object object) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + if (object instanceof String) { + editor.putString(key, (String) object); + } else if (object instanceof Integer) { + editor.putInt(key, (Integer) object); + } else if (object instanceof Boolean) { + editor.putBoolean(key, (Boolean) object); + } else if (object instanceof Float) { + editor.putFloat(key, (Float) object); + } else if (object instanceof Long) { + editor.putLong(key, (Long) object); + } else { + editor.putString(key, object.toString()); + } + + SharedPreferencesCompat.apply(editor); + } + + /** + * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值 + * + * @param context + * @param key + * @param defaultObject + * @return + */ + public static Object get(Context context, String key, Object defaultObject) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + + if (defaultObject instanceof String) { + return sp.getString(key, (String) defaultObject); + } else if (defaultObject instanceof Integer) { + return sp.getInt(key, (Integer) defaultObject); + } else if (defaultObject instanceof Boolean) { + return sp.getBoolean(key, (Boolean) defaultObject); + } else if (defaultObject instanceof Float) { + return sp.getFloat(key, (Float) defaultObject); + } else if (defaultObject instanceof Long) { + return sp.getLong(key, (Long) defaultObject); + } + + return null; + } + + /** + * 移除某个key值已经对应的值 + * + * @param context + * @param key + */ + public static void remove(Context context, String key) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.remove(key); + SharedPreferencesCompat.apply(editor); + } + + /** + * 清除所有数据 + * + * @param context + */ + public static void clear(Context context) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.clear(); + SharedPreferencesCompat.apply(editor); + } + + /** + * 查询某个key是否已经存在 + * + * @param context + * @param key + * @return + */ + public static boolean contains(Context context, String key) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + return sp.contains(key); + } + + /** + * 返回所有的键值对 + * + * @param context + * @return + */ + public static Map getAll(Context context) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + return sp.getAll(); + } + + /** + * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类 + * + * @author zhy + */ + private static class SharedPreferencesCompat { + private static final Method sApplyMethod = findApplyMethod(); + + /** + * 反射查找apply的方法 + * + * @return + */ + @SuppressWarnings( + {"unchecked", "rawtypes"}) + private static Method findApplyMethod() { + try { + Class clz = SharedPreferences.Editor.class; + return clz.getMethod("apply"); + } catch (NoSuchMethodException e) { + } + + return null; + } + + /** + * 如果找到则使用apply执行,否则使用commit + * + * @param editor + */ + public static void apply(SharedPreferences.Editor editor) { + try { + if (sApplyMethod != null) { + sApplyMethod.invoke(editor); + return; + } + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } catch (InvocationTargetException e) { + } + editor.commit(); + } + } + + /*****---------------------------------------------***/ + /** + * 是否含有用户信息 + * + * @param context + * @return + */ + public static boolean hasUserInfo(Context context) { + return contains(context, USER_INFO_KEY); + } + + /** + * 清除用户信息 + * + * @param context + * @return + */ + public static void cleanUserInfo(Context context) { + remove(context, USER_INFO_KEY); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseUtils.java new file mode 100644 index 0000000..da2d6de --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseUtils.java @@ -0,0 +1,243 @@ +package com.dahe.mylibrary.utils; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.provider.ContactsContract; +import android.text.TextUtils; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +import androidx.appcompat.app.AppCompatActivity; + +import com.dahe.mylibrary.R; +import com.shehuan.nicedialog.BaseNiceDialog; +import com.shehuan.nicedialog.NiceDialog; +import com.shehuan.nicedialog.ViewConvertListener; +import com.shehuan.nicedialog.ViewHolder; + +import java.util.Locale; + +public class BaseUtils { + /** + * 验证手机格式 + */ + public static boolean isMobileNO(String mobiles) { + String telRegex = "[1][3456789]\\d{9}"; + // "[1]"代表第1位为数字1,"[358]"代表第二位可以为3、5、8中的一个,"\\d{9}"代表后面是可以是0~9的数字,有9位。 + if (TextUtils.isEmpty(mobiles)) return false; + else return mobiles.matches(telRegex); + } + + + /** + * 获取语言 + * + * @param context + * @return + */ + public static int getLanguage(Context context) { + Locale curLocale = getLocale(context); + String language = curLocale.getLanguage(); + String country = curLocale.getCountry(); + if (language.equals(Locale.CHINA.getLanguage())) { + //0是简体中文,1是繁体中文 + return country.equals(Locale.SIMPLIFIED_CHINESE.getCountry()) ? 0 : 1; + } else if (language.equals(Locale.ENGLISH.getLanguage())) { + //英语 + return 2; + } else if (language.equals("th")) { + //泰文 + return 3; + } else if (language.equals(Locale.KOREAN.getLanguage())) { + //韩文 + return 4; + } else if (language.equals("vi")) { + //越南语 + return 5; + } else if (language.equals(Locale.JAPAN.getLanguage())) { + //日语 + return 6; + } else if (language.equals("in")) { + //印尼语 + return 7; + } else { + return 2; + } + } + + //获取Locale + private static Locale getLocale(Context context) { + Locale locale; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + locale = context.getResources().getConfiguration().getLocales().get(0); + } else { + locale = context.getResources().getConfiguration().locale; + } + return locale; + } + + + /** + * 拨打电话(直接拨打电话) + * @param phoneNum 电话号码 + */ + public static void callPhone(AppCompatActivity context , String phoneNum){ + + NiceDialog.init() + .setLayoutId(R.layout.dialog_phone) + .setConvertListener(new ViewConvertListener() { + @Override + protected void convertView(ViewHolder viewHolder, BaseNiceDialog baseNiceDialog) { + viewHolder.setText(R.id.message, phoneNum); + viewHolder.setOnClickListener(R.id.ok, new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(Intent.ACTION_CALL); + Uri data = Uri.parse("tel:" + phoneNum); + intent.setData(data); + context.startActivity(intent); + baseNiceDialog.dismiss(); + } + }); + viewHolder.setOnClickListener(R.id.cancel, new View.OnClickListener() { + @Override + public void onClick(View v) { + baseNiceDialog.dismiss(); + } + }); + } + }) + .setWidth(260).show(context.getSupportFragmentManager()); + + } + + /** + * 获取VersionCode + * + * @param context + * @return + */ + public static String geVersionCode(Context context) { + try { + PackageInfo packageInfo = context.getPackageManager() + .getPackageInfo(context.getPackageName(), 0); + return packageInfo.versionName; + } catch (Exception e) { + return "1.0.0"; + } + } + + /** + * 跳转qq + * + * @param context + * @return + */ + public static String goToQQ(Context context, String qqNumber) { + try { + context.getPackageManager().getApplicationInfo("com.tencent.mobileqq", + PackageManager.GET_UNINSTALLED_PACKAGES); + context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin=" + qqNumber + "&version=1"))); + } catch (PackageManager.NameNotFoundException e) { + return "客服为qq在线,联系客服请先安装qq"; + } + return ""; + } + + /** + * 跳转手机通讯录 选择联系人 并返回联系人信息 + * + * @param context + * @param uri + * @return + */ + public static String[] getPhoneContacts(Context context, Uri uri) { + String[] contact = new String[2]; + ContentResolver cr = context.getContentResolver(); + Cursor cursor = cr.query(uri, null, null, null, null); + if (cursor != null && cursor.getCount() != 0) { + cursor.moveToFirst(); + int nameFieldColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); + contact[0] = cursor.getString(nameFieldColumnIndex); + String ContactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); + Cursor phone = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, + ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + ContactId, null, null); + if (phone != null && phone.getCount() != 0) { + phone.moveToFirst(); + contact[1] = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)).trim().replace(" ", "").toString(); + } else { + contact[1] = ""; + } + phone.close(); + cursor.close(); + } else { + return null; + } + return contact; + } + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public static int dip2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * 根据手机的分辨率从 px(像素) 的单位 转成为 dp + */ + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + /** + * 将sp值转换为px值,保证文字大小不变 + * + * @param spValue + * @param spValue (DisplayMetrics类中属性scaledDensity) + * @return + */ + public static int sp2px(Context context, float spValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } + + /** + * 强制隐藏输入法键盘 + * + * @param context Context + * @param view EditText + */ + public static void hideInput(Context context, View view) { + InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + + /** + * 隐藏软键盘(只适用于Activity,不适用于Fragment) + */ + public static void hideSoftKeyboard(Activity activity) { + View view = activity.getCurrentFocus(); + if (view != null) { + InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + } + + //view为接受软键盘输入的视图,SHOW_FORCED表示强制显示 + public static void hideSoftKeyboard(Activity activity, View view) { + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(view, InputMethodManager.SHOW_FORCED); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); //强制隐藏键盘 + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CNPinyinIndex.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CNPinyinIndex.java new file mode 100644 index 0000000..d55d146 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CNPinyinIndex.java @@ -0,0 +1,76 @@ +package com.dahe.mylibrary.utils; + +import java.io.UnsupportedEncodingException; + +public class CNPinyinIndex { + + + //自动获取汉子的首字母 + static final int GB_SP_DIFF = 160; + // 存放国标一级汉字不同读音的起始区位码 + static final int[] secPosValueList = {1601, 1637, 1833, 2078, 2274, 2302, + 2433, 2594, 2787, 3106, 3212, 3472, 3635, 3722, 3730, 3858, 4027, + 4086, 4390, 4558, 4684, 4925, 5249, 5600}; + // 存放国标一级汉字不同读音的起始区位码对应读音 + static final char[] firstLetter = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'w', 'x', + 'y', 'z'}; + + + + public static String getSpells(String characters) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < characters.length(); i++) { + + char ch = characters.charAt(i); + if ((ch >> 7) == 0) { + // 判断是否为汉字,如果左移7为为0就不是汉字,否则是汉字 + } else { + char spell = getFirstLetter(ch); + buffer.append(String.valueOf(spell)); + } + } + return buffer.toString(); + } + + // 获取一个汉字的首字母 + public static Character getFirstLetter(char ch) { + + byte[] uniCode = null; + try { + uniCode = String.valueOf(ch).getBytes("GBK"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + if (uniCode[0] < 128 && uniCode[0] > 0) { // 非汉字 + return null; + } else { + return convert(uniCode); + } + } + + /** + * 获取一个汉字的拼音首字母。 GB码两个字节分别减去160,转换成10进制码组合就可以得到区位码 + * 例如汉字“你”的GB码是0xC4/0xE3,分别减去0xA0(160)就是0x24/0x43 + * 0x24转成10进制就是36,0x43是67,那么它的区位码就是3667,在对照表中读音为‘n’ + */ + static char convert(byte[] bytes) { + char result = '-'; + int secPosValue = 0; + int i; + for (i = 0; i < bytes.length; i++) { + bytes[i] -= GB_SP_DIFF; + } + secPosValue = bytes[0] * 100 + bytes[1]; + for (i = 0; i < 23; i++) { + if (secPosValue >= secPosValueList[i] + && secPosValue < secPosValueList[i + 1]) { + result = firstLetter[i]; + break; + } + } + return result; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ConvertUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ConvertUtils.java new file mode 100644 index 0000000..a45c471 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ConvertUtils.java @@ -0,0 +1,645 @@ +package com.dahe.mylibrary.utils; + + +import android.annotation.SuppressLint; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; + + +import com.dahe.mylibrary.CommonBaseLibrary; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +/** + * bytes2Bits, bits2Bytes : bytes 与 bits 互转 + * bytes2Chars, chars2Bytes : bytes 与 chars 互转 + * bytes2HexString, hexString2Bytes : bytes 与 hexString 互转 + * memorySize2Byte, byte2MemorySize : 以 unit 为单位的内存大小与字节数互转 + * byte2FitMemorySize : 字节数转合适内存大小 + * timeSpan2Millis, millis2TimeSpan : 以 unit 为单位的时间长度与毫秒时间戳互转 + * millis2FitTimeSpan : 毫秒时间戳转合适时间长度 + * input2OutputStream, output2InputStream : inputStream 与 outputStream 互转 + * inputStream2Bytes, bytes2InputStream : inputStream 与 bytes 互转 + * outputStream2Bytes, bytes2OutputStream : outputStream 与 bytes 互转 + * inputStream2String, string2InputStream : inputStream 与 string 按编码互转 + * outputStream2String, string2OutputStream: outputStream 与 string 按编码互转 + * bitmap2Bytes, bytes2Bitmap : bitmap 与 bytes 互转 + * drawable2Bitmap, bitmap2Drawable : drawable 与 bitmap 互转 + * drawable2Bytes, bytes2Drawable : drawable 与 bytes 互转 + * view2Bitmap : view 转 Bitmap + * dp2px, px2dp : dp 与 px 互转 + * sp2px, px2sp : sp 与 px 互转 + */ +public final class ConvertUtils { + + private ConvertUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static final char hexDigits[] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + /** + * Bytes to bits. + * + * @param bytes The bytes. + * @return bits + */ + public static String bytes2Bits(final byte[] bytes) { + if (bytes == null || bytes.length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (byte aByte : bytes) { + for (int j = 7; j >= 0; --j) { + sb.append(((aByte >> j) & 0x01) == 0 ? '0' : '1'); + } + } + return sb.toString(); + } + + /** + * Bits to bytes. + * + * @param bits The bits. + * @return bytes + */ + public static byte[] bits2Bytes(String bits) { + int lenMod = bits.length() % 8; + int byteLen = bits.length() / 8; + // add "0" until length to 8 times + if (lenMod != 0) { + for (int i = lenMod; i < 8; i++) { + bits = "0" + bits; + } + byteLen++; + } + byte[] bytes = new byte[byteLen]; + for (int i = 0; i < byteLen; ++i) { + for (int j = 0; j < 8; ++j) { + bytes[i] <<= 1; + bytes[i] |= bits.charAt(i * 8 + j) - '0'; + } + } + return bytes; + } + + /** + * Bytes to chars. + * + * @param bytes The bytes. + * @return chars + */ + public static char[] bytes2Chars(final byte[] bytes) { + if (bytes == null) return null; + int len = bytes.length; + if (len <= 0) return null; + char[] chars = new char[len]; + for (int i = 0; i < len; i++) { + chars[i] = (char) (bytes[i] & 0xff); + } + return chars; + } + + /** + * Chars to bytes. + * + * @param chars The chars. + * @return bytes + */ + public static byte[] chars2Bytes(final char[] chars) { + if (chars == null || chars.length <= 0) return null; + int len = chars.length; + byte[] bytes = new byte[len]; + for (int i = 0; i < len; i++) { + bytes[i] = (byte) (chars[i]); + } + return bytes; + } + + /** + * Bytes to hex string. + *

e.g. bytes2HexString(new byte[] { 0, (byte) 0xa8 }) returns "00A8"

+ * + * @param bytes The bytes. + * @return hex string + */ + public static String bytes2HexString(final byte[] bytes) { + if (bytes == null) return ""; + int len = bytes.length; + if (len <= 0) return ""; + char[] ret = new char[len << 1]; + for (int i = 0, j = 0; i < len; i++) { + ret[j++] = hexDigits[bytes[i] >> 4 & 0x0f]; + ret[j++] = hexDigits[bytes[i] & 0x0f]; + } + return new String(ret); + } + + /** + * Hex string to bytes. + *

e.g. hexString2Bytes("00A8") returns { 0, (byte) 0xA8 }

+ * + * @param hexString The hex string. + * @return the bytes + */ + public static byte[] hexString2Bytes(String hexString) { + if (isSpace(hexString)) return null; + int len = hexString.length(); + if (len % 2 != 0) { + hexString = "0" + hexString; + len = len + 1; + } + char[] hexBytes = hexString.toUpperCase().toCharArray(); + byte[] ret = new byte[len >> 1]; + for (int i = 0; i < len; i += 2) { + ret[i >> 1] = (byte) (hex2Int(hexBytes[i]) << 4 | hex2Int(hexBytes[i + 1])); + } + return ret; + } + + private static int hex2Int(final char hexChar) { + if (hexChar >= '0' && hexChar <= '9') { + return hexChar - '0'; + } else if (hexChar >= 'A' && hexChar <= 'F') { + return hexChar - 'A' + 10; + } else { + throw new IllegalArgumentException(); + } + } + + /** + * Size of memory in unit to size of byte. + * + * @param memorySize Size of memory. + * @param unit The unit of memory size. + *
    + *
  • {@link MemoryConstants#BYTE}
  • + *
  • {@link MemoryConstants#KB}
  • + *
  • {@link MemoryConstants#MB}
  • + *
  • {@link MemoryConstants#GB}
  • + *
+ * @return size of byte + */ + public static long memorySize2Byte(final long memorySize, + @MemoryConstants.Unit final int unit) { + if (memorySize < 0) return -1; + return memorySize * unit; + } + + /** + * Size of byte to size of memory in unit. + * + * @param byteSize Size of byte. + * @param unit The unit of memory size. + *
    + *
  • {@link MemoryConstants#BYTE}
  • + *
  • {@link MemoryConstants#KB}
  • + *
  • {@link MemoryConstants#MB}
  • + *
  • {@link MemoryConstants#GB}
  • + *
+ * @return size of memory in unit + */ + public static double byte2MemorySize(final long byteSize, + @MemoryConstants.Unit final int unit) { + if (byteSize < 0) return -1; + return (double) byteSize / unit; + } + + /** + * Size of byte to fit size of memory. + *

to three decimal places

+ * + * @param byteSize Size of byte. + * @return fit size of memory + */ + @SuppressLint("DefaultLocale") + public static String byte2FitMemorySize(final long byteSize) { + if (byteSize < 0) { + return "shouldn't be less than zero!"; + } else if (byteSize < MemoryConstants.KB) { + return String.format("%.3fB", (double) byteSize); + } else if (byteSize < MemoryConstants.MB) { + return String.format("%.3fKB", (double) byteSize / MemoryConstants.KB); + } else if (byteSize < MemoryConstants.GB) { + return String.format("%.3fMB", (double) byteSize / MemoryConstants.MB); + } else { + return String.format("%.3fGB", (double) byteSize / MemoryConstants.GB); + } + } + + /** + * Time span in unit to milliseconds. + * + * @param timeSpan The time span. + * @param unit The unit of time span. + *
    + *
  • {@link TimeConstants#MSEC}
  • + *
  • {@link TimeConstants#SEC }
  • + *
  • {@link TimeConstants#MIN }
  • + *
  • {@link TimeConstants#HOUR}
  • + *
  • {@link TimeConstants#DAY }
  • + *
+ * @return milliseconds + */ + public static long timeSpan2Millis(final long timeSpan, @TimeConstants.Unit final int unit) { + return timeSpan * unit; + } + + /** + * Milliseconds to time span in unit. + * + * @param millis The milliseconds. + * @param unit The unit of time span. + *
    + *
  • {@link TimeConstants#MSEC}
  • + *
  • {@link TimeConstants#SEC }
  • + *
  • {@link TimeConstants#MIN }
  • + *
  • {@link TimeConstants#HOUR}
  • + *
  • {@link TimeConstants#DAY }
  • + *
+ * @return time span in unit + */ + public static long millis2TimeSpan(final long millis, @TimeConstants.Unit final int unit) { + return millis / unit; + } + + /** + * Milliseconds to fit time span. + * + * @param millis The milliseconds. + *

millis <= 0, node_return null

+ * @param precision The precision of time span. + *
    + *
  • precision = 0, node_return null
  • + *
  • precision = 1, node_return 天
  • + *
  • precision = 2, node_return 天, 小时
  • + *
  • precision = 3, node_return 天, 小时, 分钟
  • + *
  • precision = 4, node_return 天, 小时, 分钟, 秒
  • + *
  • precision >= 5,node_return 天, 小时, 分钟, 秒, 毫秒
  • + *
+ * @return fit time span + */ + @SuppressLint("DefaultLocale") + public static String millis2FitTimeSpan(long millis, int precision) { + if (millis <= 0 || precision <= 0) return null; + StringBuilder sb = new StringBuilder(); + String[] units = {"天", "小时", "分钟", "秒", "毫秒"}; + int[] unitLen = {86400000, 3600000, 60000, 1000, 1}; + precision = Math.min(precision, 5); + for (int i = 0; i < precision; i++) { + if (millis >= unitLen[i]) { + long mode = millis / unitLen[i]; + millis -= mode * unitLen[i]; + sb.append(mode).append(units[i]); + } + } + return sb.toString(); + } + + /** + * Input stream to output stream. + * + * @param is The input stream. + * @return output stream + */ + public static ByteArrayOutputStream input2OutputStream(final InputStream is) { + if (is == null) return null; + try { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + byte[] b = new byte[MemoryConstants.KB]; + int len; + while ((len = is.read(b, 0, MemoryConstants.KB)) != -1) { + os.write(b, 0, len); + } + return os; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * Output stream to input stream. + * + * @param out The output stream. + * @return input stream + */ + public ByteArrayInputStream output2InputStream(final OutputStream out) { + if (out == null) return null; + return new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray()); + } + + /** + * Input stream to bytes. + * + * @param is The input stream. + * @return bytes + */ + public static byte[] inputStream2Bytes(final InputStream is) { + if (is == null) return null; + return input2OutputStream(is).toByteArray(); + } + + /** + * Bytes to input stream. + * + * @param bytes The bytes. + * @return input stream + */ + public static InputStream bytes2InputStream(final byte[] bytes) { + if (bytes == null || bytes.length <= 0) return null; + return new ByteArrayInputStream(bytes); + } + + /** + * Output stream to bytes. + * + * @param out The output stream. + * @return bytes + */ + public static byte[] outputStream2Bytes(final OutputStream out) { + if (out == null) return null; + return ((ByteArrayOutputStream) out).toByteArray(); + } + + /** + * Bytes to output stream. + * + * @param bytes The bytes. + * @return output stream + */ + public static OutputStream bytes2OutputStream(final byte[] bytes) { + if (bytes == null || bytes.length <= 0) return null; + ByteArrayOutputStream os = null; + try { + os = new ByteArrayOutputStream(); + os.write(bytes); + return os; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * Input stream to string. + * + * @param is The input stream. + * @param charsetName The name of charset. + * @return string + */ + public static String inputStream2String(final InputStream is, final String charsetName) { + if (is == null || isSpace(charsetName)) return ""; + try { + return new String(inputStream2Bytes(is), charsetName); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * String to input stream. + * + * @param string The string. + * @param charsetName The name of charset. + * @return input stream + */ + public static InputStream string2InputStream(final String string, final String charsetName) { + if (string == null || isSpace(charsetName)) return null; + try { + return new ByteArrayInputStream(string.getBytes(charsetName)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Output stream to string. + * + * @param out The output stream. + * @param charsetName The name of charset. + * @return string + */ + public static String outputStream2String(final OutputStream out, final String charsetName) { + if (out == null || isSpace(charsetName)) return ""; + try { + return new String(outputStream2Bytes(out), charsetName); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * String to output stream. + * + * @param string The string. + * @param charsetName The name of charset. + * @return output stream + */ + public static OutputStream string2OutputStream(final String string, final String charsetName) { + if (string == null || isSpace(charsetName)) return null; + try { + return bytes2OutputStream(string.getBytes(charsetName)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Bitmap to bytes. + * + * @param bitmap The bitmap. + * @param format The format of bitmap. + * @return bytes + */ + public static byte[] bitmap2Bytes(final Bitmap bitmap, final Bitmap.CompressFormat format) { + if (bitmap == null) return null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bitmap.compress(format, 100, baos); + return baos.toByteArray(); + } + + /** + * Bytes to bitmap. + * + * @param bytes The bytes. + * @return bitmap + */ + public static Bitmap bytes2Bitmap(final byte[] bytes) { + return (bytes == null || bytes.length == 0) + ? null + : BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + } + + /** + * Drawable to bitmap. + * + * @param drawable The drawable. + * @return bitmap + */ + public static Bitmap drawable2Bitmap(final Drawable drawable) { + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + if (bitmapDrawable.getBitmap() != null) { + return bitmapDrawable.getBitmap(); + } + } + Bitmap bitmap; + if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { + bitmap = Bitmap.createBitmap(1, 1, + drawable.getOpacity() != PixelFormat.OPAQUE + ? Bitmap.Config.ARGB_8888 + : Bitmap.Config.RGB_565); + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), + drawable.getOpacity() != PixelFormat.OPAQUE + ? Bitmap.Config.ARGB_8888 + : Bitmap.Config.RGB_565); + } + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } + + /** + * Bitmap to drawable. + * + * @param bitmap The bitmap. + * @return drawable + */ + public static Drawable bitmap2Drawable(final Bitmap bitmap) { + return bitmap == null ? null : new BitmapDrawable(CommonBaseLibrary.getApplication().getResources(), bitmap); + } + + /** + * Drawable to bytes. + * + * @param drawable The drawable. + * @param format The format of bitmap. + * @return bytes + */ + public static byte[] drawable2Bytes(final Drawable drawable, + final Bitmap.CompressFormat format) { + return drawable == null ? null : bitmap2Bytes(drawable2Bitmap(drawable), format); + } + + /** + * Bytes to drawable. + * + * @param bytes The bytes. + * @return drawable + */ + public static Drawable bytes2Drawable(final byte[] bytes) { + return bytes == null ? null : bitmap2Drawable(bytes2Bitmap(bytes)); + } + + /** + * View to bitmap. + * + * @param view The view. + * @return bitmap + */ + public static Bitmap view2Bitmap(final View view) { + if (view == null) return null; + Bitmap ret = + Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(ret); + Drawable bgDrawable = view.getBackground(); + if (bgDrawable != null) { + bgDrawable.draw(canvas); + } else { + canvas.drawColor(Color.WHITE); + } + view.draw(canvas); + return ret; + } + + /** + * Value of dp to value of px. + * + * @param dpValue The value of dp. + * @return value of px + */ + public static int dp2px(final float dpValue) { + final float scale = Resources.getSystem().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * Value of px to value of dp. + * + * @param pxValue The value of px. + * @return value of dp + */ + public static int px2dp(final float pxValue) { + final float scale = Resources.getSystem().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + /** + * Value of sp to value of px. + * + * @param spValue The value of sp. + * @return value of px + */ + public static int sp2px(final float spValue) { + final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } + + /** + * Value of px to value of sp. + * + * @param pxValue The value of px. + * @return value of sp + */ + public static int px2sp(final float pxValue) { + final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; + return (int) (pxValue / fontScale + 0.5f); + } + + /////////////////////////////////////////////////////////////////////////// + // other utils methods + /////////////////////////////////////////////////////////////////////////// + + private static boolean isSpace(final String s) { + if (s == null) return true; + for (int i = 0, len = s.length(); i < len; ++i) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CountDownTimerUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CountDownTimerUtils.java new file mode 100644 index 0000000..faf18ab --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CountDownTimerUtils.java @@ -0,0 +1,38 @@ +package com.dahe.mylibrary.utils; + +import android.os.CountDownTimer; +import android.widget.TextView; + +public class CountDownTimerUtils extends CountDownTimer { + + private TextView mTextView; + /** + * @param millisInFuture The number of millis in the future from the call + * to {@link #start()} until the countdown is done and {@link #onFinish()} + * is called. + * @param countDownInterval The interval along the way to receive + * {@link #onTick(long)} callbacks. + */ + public CountDownTimerUtils(TextView textView, long millisInFuture, long countDownInterval) { + super(millisInFuture, countDownInterval); + this.mTextView = textView; + } + + @Override + public void onTick(long millisUntilFinished) { + mTextView.setClickable(false); //设置不可点击 + mTextView.setText(millisUntilFinished / 1000 + "秒后重新发送"); //设置倒计时时间 +// mTextView.setBackgroundResource(R.drawable.bg_identify_code_press); //设置按钮为灰色,这时是不能点击的 +// SpannableString spannableString = new SpannableString(mTextView.getText().toString()); //获取按钮上的文字 +// ForegroundColorSpan span = new ForegroundColorSpan(Color.RED); +// spannableString.setSpan(span, 0, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//将倒计时的时间设置为红色 +// mTextView.setText(spannableString); + } + + @Override + public void onFinish() { + mTextView.setText("获取验证码"); + mTextView.setClickable(true);//重新获得点击 +// mTextView.setBackgroundResource(R.drawable.bg_identify_code_normal); //还原背景色 + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler.java new file mode 100644 index 0000000..928d308 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler.java @@ -0,0 +1,243 @@ +package com.dahe.mylibrary.utils; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Environment; +import android.os.Looper; +import android.os.SystemClock; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import static android.os.Environment.DIRECTORY_ALARMS; + +/** + *

全局捕获异常

+ *
+ * 当程序发生Uncaught异常的时候,有该类来接管程序,并记录错误日志 + * + */ +@SuppressLint("SimpleDateFormat") +public class CrashHandler implements Thread.UncaughtExceptionHandler { + + public static String TAG = "MyCrash"; + // 系统默认的UncaughtException处理类 + private Thread.UncaughtExceptionHandler mDefaultHandler; + + private static CrashHandler instance = new CrashHandler(); + private Context mContext; + + // 用来存储设备信息和异常信息 + private Map infos = new HashMap(); + + // 用于格式化日期,作为日志文件名的一部分 + private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + /** 保证只有一个CrashHandler实例 */ + private CrashHandler() { + } + + /** 获取CrashHandler实例 ,单例模式 */ + public static CrashHandler getInstance() { + return instance; + } + + /** + * 初始化 + * + * @param context + */ + public void init(Context context) { + mContext = context; + // 获取系统默认的UncaughtException处理器 + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + // 设置该CrashHandler为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + FileUtil.removeFileByTime(getGlobalpath()); +// autoClear(5); + } + + /** + * 当UncaughtException发生时会转入该函数来处理 + */ + @Override + public void uncaughtException(Thread thread, Throwable ex) { + if (!handleException(ex) && mDefaultHandler != null) { + // 如果用户没有处理则让系统默认的异常处理器来处理 + mDefaultHandler.uncaughtException(thread, ex); + } else { + SystemClock.sleep(3000); + // 退出程序 + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(1); + } + } + + /** + * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. + * + * @param ex + * @return true:如果处理了该异常信息; 否则返回false. + */ + private boolean handleException(Throwable ex) { + if (ex == null) + return false; + try { + // 使用Toast来显示异常信息 + new Thread() { + + @Override + public void run() { + Looper.prepare(); + Toast.makeText(mContext, "很抱歉,程序出现异常,即将重启.", + Toast.LENGTH_LONG).show(); + Looper.loop(); + } + }.start(); + // 收集设备参数信息 + collectDeviceInfo(mContext); + // 保存日志文件 + saveCrashInfoFile(ex); + SystemClock.sleep(3000); + } catch (Exception e) { + e.printStackTrace(); + } + + return true; + } + + /** + * 收集设备参数信息 + * + * @param ctx + */ + public void collectDeviceInfo(Context ctx) { + try { + PackageManager pm = ctx.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), + PackageManager.GET_ACTIVITIES); + if (pi != null) { + String versionName = pi.versionName + ""; + String versionCode = pi.versionCode + ""; + infos.put("versionName", versionName); + infos.put("versionCode", versionCode); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "an error occured when collect package info", e); + } + Field[] fields = Build.class.getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + infos.put(field.getName(), field.get(null).toString()); + } catch (Exception e) { + Log.e(TAG, "an error occured when collect crash info", e); + } + } + } + + /** + * 保存错误信息到文件中 + * @param ex + * @return 返回文件名称,便于将文件传送到服务器 + * @throws Exception + */ + private String saveCrashInfoFile(Throwable ex) throws Exception { + StringBuffer sb = new StringBuffer(); + try { + SimpleDateFormat sDateFormat = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + String date = sDateFormat.format(new java.util.Date()); + sb.append("\r\n" + date + "\n"); + for (Map.Entry entry : infos.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key + "=" + value + "\n"); + } + + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); + } + printWriter.flush(); + printWriter.close(); + String result = writer.toString(); + sb.append(result); + + String fileName = writeFile(sb.toString()); + return fileName; + } catch (Exception e) { + Log.e(TAG, "an error occured while writing file...", e); + sb.append("an error occured while writing file...\r\n"); + writeFile(sb.toString()); + } + return null; + } + + private String writeFile(String sb) throws Exception { + String time = formatter.format(new Date()); + String fileName = "crash-" + time + ".log"; +// if (FileUtil.hasSdcard()) { + String path = getGlobalpath(); + File dir = new File(path); + if (!dir.exists()) + dir.mkdirs(); + + String filePath = path + fileName; + File txtFile = new File(filePath); + if (!txtFile.exists()) + txtFile.createNewFile(); + + FileOutputStream fos = new FileOutputStream(txtFile, true); + fos.write(sb.getBytes()); + fos.flush(); + fos.close(); +// } + return fileName; + } + + public static String getGlobalpath() { + return Environment.getExternalStorageDirectory().getAbsolutePath() + + File.separator + "crash" + File.separator; + } + + public static void setTag(String tag) { + TAG = tag; + } + + /** + * 文件删除 + * @param day 文件保存天数 + */ +// public void autoClear(final int autoClearDay) { +// FileUtil.delete(getGlobalpath(), new FilenameFilter() { +// +// @Override +// public boolean accept(File file, String filename) { +// String s = FileUtil.getFileNameWithoutExtension(filename); +// int day = autoClearDay < 0 ? autoClearDay : -1 * autoClearDay; +// String date = "crash-" + DateUtil.getOtherDay(day); +// return date.compareTo(s) >= 0; +// } +// }); +// } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler2.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler2.java new file mode 100644 index 0000000..b0ef708 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler2.java @@ -0,0 +1,218 @@ +package com.dahe.mylibrary.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Environment; +import android.os.Looper; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * @ClassName CrashHandler2 + * @Author 用户 + * @Date 2023/9/27 11:17 + * @Description TODO + */ +public class CrashHandler2 implements Thread.UncaughtExceptionHandler { + // 用于打印日志的 TAG 标识符 + public static final String TAG = "octopus.CrashHandler"; + + // 系统默认的UncaughtException处理类 + private Thread.UncaughtExceptionHandler mDefaultHandler; + // 程序的Context对象 + private Context mContext; + // 用来存储设备信息和异常信息 + private Map mInfos = new HashMap(); + // 用于格式化日期,作为日志文件名的一部分 + private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + + // 单例模式 + private static CrashHandler2 INSTANCE = new CrashHandler2(); + private CrashHandler2() { + } + public static CrashHandler2 getInstance() { + return INSTANCE; + } + + /** + * 初始化该类, 向系统中注册 + * @param context + */ + public void init(Context context) { + mContext = context; + // 获取系统默认的 UncaughtException 处理器 + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + // 设置该 CrashHandler 为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + } + + /* + * 出现未捕获的异常时, 会自动回调该方法 + * (non-Javadoc) + * @see java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java.lang.Thread, java.lang.Throwable) + */ + @Override + public void uncaughtException(Thread thread, Throwable ex) { + /* + * 调用 handleException() 方法处理该线程 + * 如果返回 true 说明处理成功, 如果返回 false 则调用默认的异常处理器来处理 + * 一般情况下该方法都会成功处理 + */ + if (!handleException(ex) && mDefaultHandler != null) { + // 如果用户没有处理则让系统默认的异常处理器来处理 + mDefaultHandler.uncaughtException(thread, ex); + } else { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + Log.e(TAG, "error : ", e); + } + // 退出程序 + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(1); + } + } + + /** + * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. + * @param ex + * 异常信息 + * @return + * true:如果处理了该异常信息;否则返回false. + */ + private boolean handleException(Throwable ex) { + if (ex == null) { + return false; + } + /* + * 使用Toast来显示异常信息, + * 由于在主线程会阻塞, + * 不能实时出现 Toast 信息, + * 这里我们在子线程中处理 Toast 信息 + */ + new Thread() { + @Override + public void run() { + Looper.prepare(); + Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG) + .show(); + Looper.loop(); + } + }.start(); + // 收集设备参数信息 + collectDeviceInfo(mContext); + // 保存日志文件 + saveCrashInfo2File(ex); + return true; + } + + /** + * 收集设备参数信息, 将手机到的信息存储到 + * @param ctx + * 上下文对象 + */ + public void collectDeviceInfo(Context ctx) { + try { + //获取包管理器 + PackageManager pm = ctx.getPackageManager(); + //获取包信息 + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), + PackageManager.GET_ACTIVITIES); + if (pi != null) { + //版本号 + String versionName = pi.versionName == null ? "null" + : pi.versionName; + //版本代码 + String versionCode = pi.versionCode + ""; + //将版本信息存放到 成员变量 Map mInfos 中 + this.mInfos.put("versionName", versionName); + this.mInfos.put("versionCode", versionCode); + } + } catch (Exception e) { + Log.e(TAG, "an error occured when collect package info", e); + } + + //获取 Build 中定义的变量, 使用反射方式获取, 该类中定义了设备相关的变量信息 + Field[] fields = Build.class.getDeclaredFields(); + //遍历获取额变量, 将这些信息存放到成员变量 Map mInfos 中 + for (Field field : fields) { + try { + //设置 Build 成员变量可访问 + field.setAccessible(true); + //将 设备相关的信息存放到 mInfos 成员变量中 + mInfos.put(field.getName(), field.get(null).toString()); + Log.d(TAG, field.getName() + " : " + field.get(null)); + } catch (Exception e) { + Log.e(TAG, "an error occured when collect crash info", e); + } + } + } + + /** + * 保存错误信息到文件中 + * @param ex + * @return 返回文件名称,便于将文件传送到服务器 + */ + private String saveCrashInfo2File(Throwable ex) { + //存储相关的字符串信息 + StringBuffer sb = new StringBuffer(); + //将成员变量 Map mInfos 中的数据 存储到 StringBuffer sb 中 + for (Map.Entry entry : this.mInfos.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key + "=" + value + "\n"); + } + + //将 StringBuffer sb 中的字符串写出到文件中 + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); + } + printWriter.close(); + String result = writer.toString(); + sb.append(result); + try { + long timestamp = System.currentTimeMillis(); + String time = formatter.format(new Date()); + String fileName = "crash-" + time + "-" + timestamp + ".txt"; + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + //获取文件输出路径 + String path = Environment.getExternalStorageDirectory() + + "/crashinfo/"; + //创建文件夹和文件 + File dir = new File(path); + if (!dir.exists()) { + dir.mkdirs(); + } + //创建输出流 + FileOutputStream fos = new FileOutputStream(path + fileName); + //向文件中写出数据 + fos.write(sb.toString().getBytes()); + fos.close(); + } + return fileName; + } catch (Exception e) { + Log.e(TAG, "an error occured while writing file...", e); + } + return null; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtil.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtil.java new file mode 100644 index 0000000..1eda86f --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtil.java @@ -0,0 +1,89 @@ +package com.dahe.mylibrary.utils; + +import android.util.Log; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +import static com.dahe.mylibrary.utils.CrashHandler.TAG; + +public class FileUtil { + + + + + //移除文件,获取文件时间与当前时间对比,我这时间定位5天,删除五天前的文件 + public static void removeFileByTime(String dirPath) { + //获取目录下所有文件 + List allFile = getDirAllFile(new File(dirPath)); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //获取当前时间 + Date end = new Date(System.currentTimeMillis()); + try { + end = dateFormat.parse(dateFormat.format(new Date(System.currentTimeMillis()))); + } catch (Exception e){ + Log.d(TAG, "dataformat exeption e " + e.toString()); + } + Log.d(TAG, "getNeedRemoveFile dirPath = " +dirPath); + for (File file : allFile) {//ComDef + try { + //文件时间减去当前时间 + Date start = dateFormat.parse(dateFormat.format(new Date(file.lastModified()))); + long diff = end.getTime() - start.getTime();//这样得到的差值是微秒级别 + long days = diff / (1000 * 60 * 60 * 24); +// if(ComDef.LOGMAXKEEPTIME <= days){ + if(5 <= days){ + deleteFile(file); + } + + } catch (Exception e){ + Log.d(TAG, "dataformat exeption e " + e.toString()); + } + } + } + + //删除文件夹及文件夹下所有文件 + public static void deleteFile(File file) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + File f = files[i]; + deleteFile(f); + } + file.delete(); + } else if (file.exists()) { + file.delete(); + } + } + + //获取指定目录下一级文件 + public static List getDirAllFile(File file) { + List fileList = new ArrayList<>(); + File[] fileArray = file.listFiles(); + if(fileArray == null) + return fileList; + for (File f : fileArray) { + fileList.add(f); + } + fileSortByTime(fileList); + return fileList; + } + + + //对文件进行时间排序 + public static void fileSortByTime(List fileList) { + Collections.sort(fileList, new Comparator() { + public int compare(File p1, File p2) { + if (p1.lastModified() < p2.lastModified()) { + return -1; + } + return 1; + } + }); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtils.java new file mode 100644 index 0000000..b9f8d67 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtils.java @@ -0,0 +1,1382 @@ +package com.dahe.mylibrary.utils; + +import android.annotation.SuppressLint; +import android.net.Uri; +import android.provider.MediaStore; +import android.text.TextUtils; +import android.util.Log; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @ClassName FileUtils + * @Author 用户 + * @Date 2023/9/27 11:06 + * @Description TODO + */ +public class FileUtils { + + private FileUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static final String LINE_SEP = System.getProperty("line.separator"); + + /** + * 根据文件路径获取文件 + * + * @param filePath 文件路径 + * @return 文件 + */ + public static File getFileByPath(final String filePath) { + return isSpace(filePath) ? null : new File(filePath); + } + + /** + * 根据文件目录路径获取子目录名称(不获取二级子目录) + * + * @param dirPath 文件路径 + * @return 文件目录名称 + */ + public static List getFiledirList(String dirPath) { + if (dirPath == null || !isDir(dirPath)) return null; + List stringList = new ArrayList<>(); + File f = new File(dirPath); + File[] files = f.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.isDirectory()) { + stringList.add(file.getName()); + } + } + } + return stringList; + } + + /** + * 判断文件是否存在 + * + * @param filePath 文件路径 + * @return {@code true}: 存在
{@code false}: 不存在 + */ + public static boolean isFileExists(final String filePath) { + return isFileExists(getFileByPath(filePath)); + } + + /** + * 判断文件是否存在 + * + * @param file 文件 + * @return {@code true}: 存在
{@code false}: 不存在 + */ + public static boolean isFileExists(final File file) { + return file != null && file.exists(); + } + + /** + * 重命名文件 + * + * @param filePath 文件路径 + * @param newName 新名称 + * @return {@code true}: 重命名成功
{@code false}: 重命名失败 + */ + public static boolean rename(final String filePath, final String newName) { + return rename(getFileByPath(filePath), newName); + } + + /** + * 重命名文件 + * + * @param file 文件 + * @param newName 新名称 + * @return {@code true}: 重命名成功 + *
+ * {@code false}: 重命名失败 + */ + public static boolean rename(final File file, final String newName) { + // 文件为空返回false + if (file == null) return false; + // 文件不存在返回false + if (!file.exists()) return false; + // 新的文件名为空返回false + if (isSpace(newName)) return false; + // 如果文件名没有改变返回true + if (newName.equals(file.getName())) return true; + File newFile = new File(file.getParent() + File.separator + newName); + // 如果重命名的文件已存在返回false + return !newFile.exists() + && file.renameTo(newFile); + } + + /** + * 判断是否是目录 + * + * @param dirPath 目录路径 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isDir(final String dirPath) { + return isDir(getFileByPath(dirPath)); + } + + /** + * 判断是否是目录 + * + * @param file 文件 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isDir(final File file) { + return isFileExists(file) && file.isDirectory(); + } + + /** + * 判断是否是文件 + * + * @param filePath 文件路径 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isFile(final String filePath) { + return isFile(getFileByPath(filePath)); + } + + /** + * 判断是否是文件 + * + * @param file 文件 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isFile(final File file) { + return isFileExists(file) && file.isFile(); + } + + /** + * 判断目录是否存在,不存在则判断是否创建成功 + * + * @param dirPath 目录路径 + * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 + */ + public static boolean createOrExistsDir(final String dirPath) { + return createOrExistsDir(getFileByPath(dirPath)); + } + + /** + * 判断目录是否存在,不存在则判断是否创建成功 + * + * @param file 文件 + * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 + */ + public static boolean createOrExistsDir(final File file) { + // 如果存在,是目录则返回true,是文件则返回false,不存在则返回是否创建成功 + return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); + } + + /** + * 判断文件是否存在,不存在则判断是否创建成功 + * + * @param filePath 文件路径 + * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 + */ + public static boolean createOrExistsFile(final String filePath) { + return createOrExistsFile(getFileByPath(filePath)); + } + + /** + * 判断文件是否存在,不存在则判断是否创建成功 + * + * @param file 文件 + * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 + */ + public static boolean createOrExistsFile(final File file) { + if (file == null) return false; + // 如果存在,是文件则返回true,是目录则返回false + if (file.exists()) return file.isFile(); + if (!createOrExistsDir(file.getParentFile())) return false; + try { + return file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 判断文件是否存在,存在则在创建之前删除 + * + * @param file 文件 + * @return {@code true}: 创建成功
{@code false}: 创建失败 + */ + public static boolean createFileByDeleteOldFile(final File file) { + if (file == null) return false; + // 文件存在并且删除失败返回false + if (file.exists() && !file.delete()) return false; + // 创建目录失败返回false + if (!createOrExistsDir(file.getParentFile())) return false; + try { + return file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 复制或移动目录 + * + * @param srcDirPath 源目录路径 + * @param destDirPath 目标目录路径 + * @param isMove 是否移动 + * @return {@code true}: 复制或移动成功
{@code false}: 复制或移动失败 + */ +// private static boolean copyOrMoveDir(final String srcDirPath, final String destDirPath, final boolean isMove) { +// return copyOrMoveDir(getFileByPath(srcDirPath), getFileByPath(destDirPath), isMove); +// } + + /** + * 复制或移动目录 + * + * @param srcDir 源目录 + * @param destDir 目标目录 + * @param isMove 是否移动 + * @return {@code true}: 复制或移动成功
{@code false}: 复制或移动失败 + */ +// private static boolean copyOrMoveDir(final File srcDir, final File destDir, final boolean isMove) { +// if (srcDir == null || destDir == null) return false; +// // 如果目标目录在源目录中则返回false,看不懂的话好好想想递归怎么结束 +// // srcPath : F:\\MyGithub\\AndroidUtilCode\\utilcode\\src\\test\\res +// // destPath: F:\\MyGithub\\AndroidUtilCode\\utilcode\\src\\test\\res1 +// // 为防止以上这种情况出现出现误判,须分别在后面加个路径分隔符 +// String srcPath = srcDir.getPath() + File.separator; +// String destPath = destDir.getPath() + File.separator; +// if (destPath.contains(srcPath)) return false; +// // 源文件不存在或者不是目录则返回false +// if (!srcDir.exists() || !srcDir.isDirectory()) return false; +// // 目标目录不存在返回false +// if (!createOrExistsDir(destDir)) return false; +// File[] files = srcDir.listFiles(); +// for (File file : files) { +// File oneDestFile = new File(destPath + file.getName()); +// if (file.isFile()) { +// // 如果操作失败返回false +// if (!copyOrMoveFile(file, oneDestFile, isMove)) return false; +// } else if (file.isDirectory()) { +// // 如果操作失败返回false +// if (!copyOrMoveDir(file, oneDestFile, isMove)) return false; +// } +// } +// return !isMove || deleteDir(srcDir); +// } + + /** + * 复制或移动文件 + * + * @param srcFilePath 源文件路径 + * @param destFilePath 目标文件路径 + * @param isMove 是否移动 + * @return {@code true}: 复制或移动成功
{@code false}: 复制或移动失败 + */ +// private static boolean copyOrMoveFile(final String srcFilePath, final String destFilePath, final boolean isMove) { +// return copyOrMoveFile(getFileByPath(srcFilePath), getFileByPath(destFilePath), isMove); +// } + + /** + * 复制或移动文件 + * + * @param srcFile 源文件 + * @param destFile 目标文件 + * @param isMove 是否移动 + * @return {@code true}: 复制或移动成功
{@code false}: 复制或移动失败 + */ +// private static boolean copyOrMoveFile(final File srcFile, final File destFile, final boolean isMove) { +// if (srcFile == null || destFile == null) return false; +// // 源文件不存在或者不是文件则返回false +// if (!srcFile.exists() || !srcFile.isFile()) return false; +// // 目标文件存在且是文件则返回false +// if (destFile.exists() && destFile.isFile()) return false; +// // 目标目录不存在返回false +// if (!createOrExistsDir(destFile.getParentFile())) return false; +// try { +// return FileIOUtils.writeFileFromIS(destFile, new FileInputStream(srcFile), false) +// && !(isMove && !deleteFile(srcFile)); +// } catch (FileNotFoundException e) { +// e.printStackTrace(); +// return false; +// } +// } + + /** + * 复制目录 + * + * @param srcDirPath 源目录路径 + * @param destDirPath 目标目录路径 + * @return {@code true}: 复制成功
{@code false}: 复制失败 + */ +// public static boolean copyDir(final String srcDirPath, final String destDirPath) { +// return copyDir(getFileByPath(srcDirPath), getFileByPath(destDirPath)); +// } + + /** + * 复制目录 + * + * @param srcDir 源目录 + * @param destDir 目标目录 + * @return {@code true}: 复制成功
{@code false}: 复制失败 + */ +// public static boolean copyDir(final File srcDir, final File destDir) { +// return copyOrMoveDir(srcDir, destDir, false); +// } + + /** + * 复制文件 + * + * @param srcFilePath 源文件路径 + * @param destFilePath 目标文件路径 + * @return {@code true}: 复制成功
{@code false}: 复制失败 + */ +// public static boolean copyFile(final String srcFilePath, final String destFilePath) { +// return copyFile(getFileByPath(srcFilePath), getFileByPath(destFilePath)); +// } + + /** + * 复制文件 + * + * @param srcFile 源文件 + * @param destFile 目标文件 + * @return {@code true}: 复制成功
{@code false}: 复制失败 + */ +// public static boolean copyFile(final File srcFile, final File destFile) { +// return copyOrMoveFile(srcFile, destFile, false); +// } + + /** + * 移动目录 + * + * @param srcDirPath 源目录路径 + * @param destDirPath 目标目录路径 + * @return {@code true}: 移动成功
{@code false}: 移动失败 + */ +// public static boolean moveDir(final String srcDirPath, final String destDirPath) { +// return moveDir(getFileByPath(srcDirPath), getFileByPath(destDirPath)); +// } + + /** + * 移动目录 + * + * @param srcDir 源目录 + * @param destDir 目标目录 + * @return {@code true}: 移动成功
{@code false}: 移动失败 + */ +// public static boolean moveDir(final File srcDir, final File destDir) { +// return copyOrMoveDir(srcDir, destDir, true); +// } + + /** + * 移动文件 + * + * @param srcFilePath 源文件路径 + * @param destFilePath 目标文件路径 + * @return {@code true}: 移动成功
{@code false}: 移动失败 + */ +// public static boolean moveFile(final String srcFilePath, final String destFilePath) { +// Log.e("xxx", "移动文件" + srcFilePath + "---->" + destFilePath); +// return moveFile(getFileByPath(srcFilePath), getFileByPath(destFilePath)); +// } + + /** + * 移动文件 + * + * @param srcFile 源文件 + * @param destFile 目标文件 + * @return {@code true}: 移动成功
{@code false}: 移动失败 + */ +// public static boolean moveFile(final File srcFile, final File destFile) { +// return copyOrMoveFile(srcFile, destFile, true); +// } + + /** + * 删除目录 + * + * @param dirPath 目录路径 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteDir(final String dirPath) { + return deleteDir(getFileByPath(dirPath)); + } + + /** + * 删除文件或目录 + * + * @param file + * @return + */ + public static boolean deleteDirOrFile(File file) { + if (file == null) return false; + if (!file.exists()) return false; + if (file.isFile()) { + return deleteFile(file); + } else { + return deleteDir(file); + } + } + + /** + * 删除文件或目录 + * + * @param path + * @return + */ + public static boolean deleteDirOrFile(String path) { + return deleteDirOrFile(getFileByPath(path)); + } + + /** + * 删除目录 + * + * @param dir 目录 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteDir(final File dir) { + if (dir == null) return false; + // 目录不存在返回true + if (!dir.exists()) return true; + // 不是目录返回false + if (!dir.isDirectory()) return false; + // 现在文件存在且是文件夹 + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.isFile()) { + if (!file.delete()) return false; + } else if (file.isDirectory()) { + if (!deleteDir(file)) return false; + } + } + } + return dir.delete(); + } + + /** + * 删除Luban文件集合 以“|” 分割 + * + * @param srcFilePaths + */ + public static void deleteFiles(String srcFilePaths) { + if (TextUtils.isEmpty(srcFilePaths)) { return; } + List list = Arrays.asList(srcFilePaths.split("\\|")); + for (String path : list) { + if (path.contains("luban")) { + deleteFile(path); + } + } + } + + /** + * 删除文件 + * + * @param srcFilePath 文件路径 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteFile(final String srcFilePath) { + return deleteFile(getFileByPath(srcFilePath)); + } + + /** + * 删除文件 + * + * @param file 文件 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteFile(final File file) { + return file != null && (!file.exists() || file.isFile() && file.delete()); + } + + /** + * 删除目录下的所有文件 + * + * @param dirPath 目录路径 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteFilesInDir(final String dirPath) { + return deleteFilesInDir(getFileByPath(dirPath)); + } + + /** + * 删除目录下的所有文件 + * + * @param dir 目录 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteFilesInDir(final File dir) { + if (dir == null) return false; + // 目录不存在返回true + if (!dir.exists()) return true; + // 不是目录返回false + if (!dir.isDirectory()) return false; + // 现在文件存在且是文件夹 + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.isFile()) { + if (!file.delete()) return false; + } else if (file.isDirectory()) { + if (!deleteDir(file)) return false; + } + } + } + return true; + } + + /** + * 获取目录下所有文件 + * + * @param dirPath 目录路径 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDir(final String dirPath, final boolean isRecursive) { + return listFilesInDir(getFileByPath(dirPath), isRecursive); + } + + /** + * 获取目录下所有文件 + * + * @param dir 目录 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDir(final File dir, final boolean isRecursive) { + if (!isDir(dir)) return null; + if (isRecursive) return listFilesInDir(dir); + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + Collections.addAll(list, files); + } + return list; + } + + /** + * 获取目录下所有文件包括子目录 + * + * @param dirPath 目录路径 + * @return 文件链表 + */ + public static List listFilesInDir(final String dirPath) { + return listFilesInDir(getFileByPath(dirPath)); + } + + /** + * 获取目录下所有文件包括子目录 + * + * @param dir 目录 + * @return 文件链表 + */ + public static List listFilesInDir(final File dir) { + if (!isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + list.add(file); + if (file.isDirectory()) { + List fileList = listFilesInDir(file); + if (fileList != null) { + list.addAll(fileList); + } + } + } + } + return list; + } + + /** + * 获取目录下所有后缀名为suffix的文件 + *

大小写忽略

+ * + * @param dirPath 目录路径 + * @param suffix 后缀名 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final String dirPath, final String suffix, final boolean isRecursive) { + return listFilesInDirWithFilter(getFileByPath(dirPath), suffix, isRecursive); + } + + /** + * 获取目录下所有后缀名为suffix的文件 + *

大小写忽略

+ * + * @param dir 目录 + * @param suffix 后缀名 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final File dir, final String suffix, final boolean isRecursive) { + if (isRecursive) return listFilesInDirWithFilter(dir, suffix); + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.length() > 10) { + if (file.getName().toUpperCase().endsWith(suffix.toUpperCase())) { + list.add(file); + } + } + } + } + return list; + } + + /** + * 获取目录下所有后缀名为suffix的文件包括子目录 + *

大小写忽略

+ * + * @param dirPath 目录路径 + * @param suffix 后缀名 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final String dirPath, final String suffix) { + return listFilesInDirWithFilter(getFileByPath(dirPath), suffix); + } + + /** + * 获取目录下所有后缀名为suffix的文件包括子目录 + *

大小写忽略

+ * + * @param dir 目录 + * @param suffix 后缀名 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final File dir, final String suffix) { + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.getName().toUpperCase().endsWith(suffix.toUpperCase())) { + list.add(file); + } + if (file.isDirectory()) { + list.addAll(listFilesInDirWithFilter(file, suffix)); + } + } + } + return list; + } + + /** + * 获取目录下所有符合filter的文件 + * + * @param dirPath 目录路径 + * @param filter 过滤器 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final String dirPath, final FilenameFilter filter, final boolean isRecursive) { + return listFilesInDirWithFilter(getFileByPath(dirPath), filter, isRecursive); + } + + /** + * 获取目录下所有符合filter的文件 + * + * @param dir 目录 + * @param filter 过滤器 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final File dir, final FilenameFilter filter, final boolean isRecursive) { + if (isRecursive) return listFilesInDirWithFilter(dir, filter); + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (filter.accept(file.getParentFile(), file.getName())) { + list.add(file); + } + } + } + return list; + } + + /** + * 获取目录下所有符合filter的文件包括子目录 + * + * @param dirPath 目录路径 + * @param filter 过滤器 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final String dirPath, final FilenameFilter filter) { + return listFilesInDirWithFilter(getFileByPath(dirPath), filter); + } + + /** + * 获取目录下所有符合filter的文件包括子目录 + * + * @param dir 目录 + * @param filter 过滤器 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final File dir, final FilenameFilter filter) { + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (filter.accept(file.getParentFile(), file.getName())) { + list.add(file); + } + if (file.isDirectory()) { + list.addAll(listFilesInDirWithFilter(file, filter)); + } + } + } + return list; + } + + /** + * 获取目录下指定文件名的文件包括子目录 + *

大小写忽略

+ * + * @param dirPath 目录路径 + * @param fileName 文件名 + * @return 文件链表 + */ + public static List searchFileInDir(final String dirPath, final String fileName) { + return searchFileInDir(getFileByPath(dirPath), fileName); + } + + /** + * 获取目录下指定文件名的文件包括子目录 + *

大小写忽略

+ * + * @param dir 目录 + * @param fileName 文件名 + * @return 文件链表 + */ + public static List searchFileInDir(final File dir, final String fileName) { + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.getName().toUpperCase().equals(fileName.toUpperCase())) { + list.add(file); + } + if (file.isDirectory()) { + list.addAll(searchFileInDir(file, fileName)); + } + } + } + return list; + } + + /** + * 获取文件最后修改的毫秒时间戳 + * + * @param filePath 文件路径 + * @return 文件最后修改的毫秒时间戳 + */ + public static long getFileLastModified(final String filePath) { + return getFileLastModified(getFileByPath(filePath)); + } + + /** + * 获取文件最后修改的毫秒时间戳 + * + * @param file 文件 + * @return 文件最后修改的毫秒时间戳 + */ + public static long getFileLastModified(final File file) { + if (file == null) return -1; + return file.lastModified(); + } + + /** + * 简单获取文件编码格式 + * + * @param filePath 文件路径 + * @return 文件编码 + */ + public static String getFileCharsetSimple(final String filePath) { + return getFileCharsetSimple(getFileByPath(filePath)); + } + + /** + * 简单获取文件编码格式 + * + * @param file 文件 + * @return 文件编码 + */ + public static String getFileCharsetSimple(final File file) { + int p = 0; + InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + p = (is.read() << 8) + is.read(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + switch (p) { + case 0xefbb: + return "UTF-8"; + case 0xfffe: + return "Unicode"; + case 0xfeff: + return "UTF-16BE"; + default: + return "GBK"; + } + } + + /** + * 获取文件行数 + * + * @param filePath 文件路径 + * @return 文件行数 + */ + public static int getFileLines(final String filePath) { + return getFileLines(getFileByPath(filePath)); + } + + /** + * 获取文件行数 + *

比readLine要快很多

+ * + * @param file 文件 + * @return 文件行数 + */ + public static int getFileLines(final File file) { + int count = 1; + InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + byte[] buffer = new byte[1024]; + int readChars; + if (LINE_SEP.endsWith("\n")) { + while ((readChars = is.read(buffer, 0, 1024)) != -1) { + for (int i = 0; i < readChars; ++i) { + if (buffer[i] == '\n') ++count; + } + } + } else { + while ((readChars = is.read(buffer, 0, 1024)) != -1) { + for (int i = 0; i < readChars; ++i) { + if (buffer[i] == '\r') ++count; + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return count; + } + + /** + * 获取目录大小 + * + * @param dirPath 目录路径 + * @return 文件大小 + */ + public static String getDirSize(final String dirPath) { + return getDirSize(getFileByPath(dirPath)); + } + + /** + * 获取目录大小 + * + * @param dir 目录 + * @return 文件大小 + */ + public static String getDirSize(final File dir) { + long len = getDirLength(dir); + return len == -1 ? "" : byte2FitMemorySize(len); + } + + /** + * 获取文件大小 + * + * @param filePath 文件路径 + * @return 文件大小 + */ + public static String getFileSize(final String filePath) { + return getFileSize(getFileByPath(filePath)); + } + + /** + * 获取文件大小 + * + * @param file 文件 + * @return 文件大小 + */ + public static String getFileSize(final File file) { + long len = getFileLength(file); + return len == -1 ? "" : byte2FitMemorySize(len); + } + + /** + * 获取目录长度 + * + * @param dirPath 目录路径 + * @return 目录长度 + */ + public static long getDirLength(final String dirPath) { + return getDirLength(getFileByPath(dirPath)); + } + + /** + * 获取目录长度 + * + * @param dir 目录 + * @return 目录长度 + */ + public static long getDirLength(final File dir) { + if (!isDir(dir)) return -1; + long len = 0; + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.isDirectory()) { + len += getDirLength(file); + } else { + len += file.length(); + } + } + } + return len; + } + + /** + * 获取文件长度 + * + * @param filePath 文件路径 + * @return 文件长度 + */ + public static long getFileLength(final String filePath) { + return getFileLength(getFileByPath(filePath)); + } + + /** + * 获取文件长度 + * + * @param file 文件 + * @return 文件长度 + */ + public static long getFileLength(final File file) { + if (!isFile(file)) return -1; + return file.length(); + } + + /** + * 获取文件的MD5校验码 + * + * @param filePath 文件路径 + * @return 文件的MD5校验码 + */ + public static String getFileMD5ToString(final String filePath) { + File file = isSpace(filePath) ? null : new File(filePath); + return getFileMD5ToString(file); + } + + /** + * 获取文件的MD5校验码 + * + * @param filePath 文件路径 + * @return 文件的MD5校验码 + */ + public static byte[] getFileMD5(final String filePath) { + File file = isSpace(filePath) ? null : new File(filePath); + return getFileMD5(file); + } + + /** + * 获取文件的MD5校验码 + * + * @param file 文件 + * @return 文件的MD5校验码 + */ + public static String getFileMD5ToString(final File file) { + return bytes2HexString(getFileMD5(file)); + } + + /** + * 获取文件的MD5校验码 + * + * @param file 文件 + * @return 文件的MD5校验码 + */ + public static byte[] getFileMD5(final File file) { + if (file == null) return null; + DigestInputStream dis = null; + try { + FileInputStream fis = new FileInputStream(file); + MessageDigest md = MessageDigest.getInstance("MD5"); + dis = new DigestInputStream(fis, md); + byte[] buffer = new byte[1024 * 256]; + while (true) { + if (!(dis.read(buffer) > 0)) break; + } + md = dis.getMessageDigest(); + return md.digest(); + } catch (NoSuchAlgorithmException | IOException e) { + e.printStackTrace(); + } finally { + try { + dis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + + /** + * 获取全路径中的最长目录 + * + * @param file 文件 + * @return filePath最长目录 + */ + public static String getDirName(final File file) { + if (file == null) return null; + return getDirName(file.getPath()); + } + + /** + * 获取全路径中的最长目录 + * + * @param filePath 文件路径 + * @return filePath最长目录 + */ + public static String getDirName(final String filePath) { + if (isSpace(filePath)) return filePath; + int lastSep = filePath.lastIndexOf(File.separator); + return lastSep == -1 ? "" : filePath.substring(0, lastSep + 1); + } + + /** + * 获取全路径中的文件名 + * + * @param file 文件 + * @return 文件名 + */ + public static String getFileName(final File file) { + if (file == null) return null; + return getFileName(file.getPath()); + } + + /** + * 获取全路径中的文件名 + * + * @param filePath 文件路径 + * @return 文件名 + */ + public static String getFileName(final String filePath) { + if (isSpace(filePath)) return filePath; + int lastSep = filePath.lastIndexOf(File.separator); + return lastSep == -1 ? filePath : filePath.substring(lastSep + 1); + } + + /** + * 获取全路径中的不带拓展名的文件名 + * + * @param file 文件 + * @return 不带拓展名的文件名 + */ + public static String getFileNameNoExtension(final File file) { + if (file == null) return null; + return getFileNameNoExtension(file.getPath()); + } + + /** + * 获取全路径中的不带拓展名的文件名 + * + * @param filePath 文件路径 + * @return 不带拓展名的文件名 + */ + public static String getFileNameNoExtension(final String filePath) { + if (isSpace(filePath)) return filePath; + int lastPoi = filePath.lastIndexOf('.'); + int lastSep = filePath.lastIndexOf(File.separator); + if (lastSep == -1) { + return (lastPoi == -1 ? filePath : filePath.substring(0, lastPoi)); + } + if (lastPoi == -1 || lastSep > lastPoi) { + return filePath.substring(lastSep + 1); + } + return filePath.substring(lastSep + 1, lastPoi); + } + + /** + * 获取全路径中的文件拓展名 + * + * @param file 文件 + * @return 文件拓展名 + */ + public static String getFileExtension(final File file) { + if (file == null) return null; + return getFileExtension(file.getPath()); + } + + /** + * 获取全路径中的文件拓展名 + * + * @param filePath 文件路径 + * @return 文件拓展名 + */ + public static String getFileExtension(final String filePath) { + if (isSpace(filePath)) return filePath; + int lastPoi = filePath.lastIndexOf('.'); + int lastSep = filePath.lastIndexOf(File.separator); + if (lastPoi == -1 || lastSep >= lastPoi) return ""; + return filePath.substring(lastPoi + 1); + } + + /** + * 根据文件类型去删除其在系统中对应的Media数据库 + * + * @param file + * @return -1代表不是媒体文件,0表示在数据库中查找不到,1找到数据库中对应的数据,并且删除 + */ + public static int deleteMedia(File file) { + String name = file.getName(); + String path = file.getAbsolutePath(); + if (name.contains(".jpg") || name.contains(".mp4")) { + Uri MEDIA_URI = null; + if (name.contains(".jpg")) { + if (path.contains("mnt/sdcard/")) { + MEDIA_URI = MediaStore.Images.Media.INTERNAL_CONTENT_URI; + path = path.replace("/mnt/sdcard/", "/storage/sdcard0/"); + } else if (file.getAbsolutePath().contains("mnt/sdcard2/")) { + MEDIA_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + path = path.replace("/mnt/sdcard2/", "/storage/sdcard1/"); + } + } else { + if (path.contains("mnt/sdcard/")) { + MEDIA_URI = MediaStore.Video.Media.INTERNAL_CONTENT_URI; + path = path.replace("/mnt/sdcard1/", "/storage/sdcard0/"); + } else if (file.getAbsolutePath().contains("mnt/sdcard2/")) { + MEDIA_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + path = path.replace("/mnt/sdcard2/", "/storage/sdcard1/"); + } + } + int resultCode = 0; + // resultCode = MyApp.getInstance().getContentResolver().delete(MEDIA_URI, MediaStore.Images.Media.DATA+"="+"'"+path+"'" , null); + return resultCode; + } else { + return -1; + } + } + /// + // copy from ConvertUtils + /// + + private static final char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + /** + * byteArr转hexString + *

例如:

+ * bytes2HexString(new byte[] { 0, (byte) 0xa8 }) returns 00A8 + * + * @param bytes 字节数组 + * @return 16进制大写字符串 + */ + private static String bytes2HexString(final byte[] bytes) { + if (bytes == null) return null; + int len = bytes.length; + if (len <= 0) return null; + char[] ret = new char[len << 1]; + for (int i = 0, j = 0; i < len; i++) { + ret[j++] = hexDigits[bytes[i] >>> 4 & 0x0f]; + ret[j++] = hexDigits[bytes[i] & 0x0f]; + } + return new String(ret); + } + + /** + * 字节数转合适内存大小 + *

保留3位小数

+ * + * @param byteNum 字节数 + * @return 合适内存大小 + */ + @SuppressLint("DefaultLocale") + private static String byte2FitMemorySize(final long byteNum) { + if (byteNum < 0) { + return "shouldn't be less than zero!"; + } else if (byteNum < 1024) { + return String.format("%.3fB", (double) byteNum + 0.0005); + } else if (byteNum < 1048576) { + return String.format("%.3fKB", (double) byteNum / 1024 + 0.0005); + } else if (byteNum < 1073741824) { + return String.format("%.3fMB", (double) byteNum / 1048576 + 0.0005); + } else { + return String.format("%.3fGB", (double) byteNum / 1073741824 + 0.0005); + } + } + + private static boolean isSpace(final String s) { + if (s == null) return true; + for (int i = 0, len = s.length(); i < len; ++i) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } + + // --------------- + + /** + * 在指定的位置创建指定的文件 + * + * @param filePath 完整的文件路径 + * @param mkdir 是否创建相关的文件夹 + * @throws IOException + */ + public static void mkFile(String filePath, boolean mkdir) throws IOException { + File file = new File(filePath); + /** + * mkdirs()创建多层目录,mkdir()创建单层目录 + * writeObject时才创建磁盘文件。 + * 若不创建文件,readObject出错。 + */ + file.getParentFile().mkdirs(); + file.createNewFile(); + file = null; + } + + /** + * 在指定的位置创建文件夹 + * + * @param dirPath 文件夹路径 + * @return 若创建成功,则返回True;反之,则返回False + */ + public static boolean mkDir(String dirPath) { + return new File(dirPath).mkdirs(); + } + + /** + * 删除指定的文件 + * + * @param filePath 文件路径 + * @return 若删除成功,则返回True;反之,则返回False + */ + public static boolean delFile(String filePath) { + return new File(filePath).delete(); + } + + /** + * 删除指定的文件夹 + * + * @param dirPath 文件夹路径 + * @param delFile 文件夹中是否包含文件 + * @return 若删除成功,则返回True;反之,则返回False + */ + public static boolean delDir(String dirPath, boolean delFile) { + if (delFile) { + File file = new File(dirPath); + if (file.isFile()) { + return file.delete(); + } else if (file.isDirectory()) { + if (file.listFiles().length == 0) { + return file.delete(); + } else { + int zFiles = file.listFiles().length; + File[] delfile = file.listFiles(); + for (int i = 0; i < zFiles; i++) { + if (delfile[i].isDirectory()) { + delDir(delfile[i].getAbsolutePath(), true); + } + delfile[i].delete(); + } + return file.delete(); + } + } else { + return false; + } + } else { + return new File(dirPath).delete(); + } + } + + /** + * 复制文件/文件夹 若要进行文件夹复制,请勿将目标文件夹置于源文件夹中 + * + * @param source 源文件(夹) + * @param target 目标文件(夹) + * @param isFolder 若进行文件夹复制,则为True;反之为False + * @throws IOException + */ + public static void copy(String source, String target, boolean isFolder) throws IOException { + if (isFolder) { + new File(target).mkdirs(); + File a = new File(source); + String[] file = a.list(); + File temp = null; + for (int i = 0; i < file.length; i++) { + if (source.endsWith(File.separator)) { + temp = new File(source + file[i]); + } else { + temp = new File(source + File.separator + file[i]); + } + if (temp.isFile()) { + FileInputStream input = new FileInputStream(temp); + FileOutputStream output = new FileOutputStream(target + File.separator + temp.getName().toString()); + byte[] b = new byte[1024]; + int len; + while ((len = input.read(b)) != -1) { + output.write(b, 0, len); + } + output.flush(); + output.close(); + input.close(); + } + if (temp.isDirectory()) { + copy(source + File.separator + file[i], target + File.separator + file[i], true); + } + } + } else { + int byteread = 0; + File oldfile = new File(source); + if (oldfile.exists()) { + InputStream inputStream = new FileInputStream(source); + File file = new File(target); + file.getParentFile().mkdirs(); + file.createNewFile(); + FileOutputStream outputStream = new FileOutputStream(file); + byte[] buffer = new byte[1024]; + while ((byteread = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, byteread); + } + inputStream.close(); + outputStream.close(); + } + } + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ImageLoader.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ImageLoader.java new file mode 100644 index 0000000..1890f38 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ImageLoader.java @@ -0,0 +1,204 @@ +package com.dahe.mylibrary.utils; + +import android.content.Context; +import android.widget.ImageView; + +import androidx.core.content.ContextCompat; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.MultiTransformation; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestOptions; +import com.dahe.mylibrary.weight.GlideCircleWithBorder; + +/** + * Created by Administrator on 2017/11/27 0027. + * 图片加载工具类 + */ + +public class ImageLoader { + public static ImageLoader mInstance = null; + + public static ImageLoader getInstance() { + if (null == mInstance) { + synchronized (ImageLoader.class) { + if (null == mInstance) { + mInstance = new ImageLoader(); + } + } + } + return mInstance; + } + + /** + * 普通的加载图片 带占位图 + * + * @param context + * @param url + * @param imageView + * @param multiTransformation 同时设置scaleType在设置圆角或者圆形 + */ + public void loadingImage(Context context, final Object url, final ImageView imageView, MultiTransformation multiTransformation, int placeholder) { + RequestOptions requestOptions = new RequestOptions(); + if (null != context) { + if (placeholder != -1) + requestOptions = requestOptions.placeholder(placeholder).error(placeholder); + if (null != multiTransformation) + requestOptions = requestOptions.transform(multiTransformation); + Glide.with(context).load(url).apply(requestOptions).into(imageView); + } + } + + /** + * 普通的加载图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadingImage(Context context, final Object url, final ImageView imageView) { + loadingImage(context, url, imageView, null, -1); + } + + /** + * 普通的加载图片 带展位图 + * + * @param context + * @param url + * @param imageView + */ + public void loadImage(Context context, final Object url, final ImageView imageView, RequestOptions requestOptions, int placeholder) { + if (null != context) { + if (placeholder != -1) + requestOptions = requestOptions.placeholder(placeholder).error(placeholder); + Glide.with(context).load(url).centerCrop().apply(requestOptions).into(imageView); + } + } + + /** + * 普通的加载图片 不带占位图的 + * + * @param context + * @param url + * @param imageView + */ + @Deprecated + public void loadImage(Context context, final Object url, final ImageView imageView) { + loadImage(context, url, imageView, -1); + } + + /** + * 普通的加载图片 不带占位图的 + * + * @param context + * @param url + * @param imageView + */ + public void loadImage(Context context, final Object url, final ImageView imageView, int placeholder) { + RequestOptions requestOptions = new RequestOptions(); + loadImage(context, url, imageView, requestOptions, placeholder); + } + + /** + * 加载圆形图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleImage(Context context, Object url, ImageView imageView, int placeholder) { + if (null != context) { + loadImage(context, url, imageView, RequestOptions.circleCropTransform(), placeholder); + } + } + + /** + * 加载圆形图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleImage(Context context, Object url, ImageView imageView) { + if (null != context) { + loadCircleImage(context, url, imageView, -1); + } + } + + /** + * 加载圆角图片 + * + * @param context + * @param url + * @param round + * @param imageView + */ + public void loadRoundImage(Context context, Object url, int round, ImageView imageView, int placeholder) { + if (null != context) { + RequestOptions requestOptions = RequestOptions.fitCenterTransform().transform(new CenterCrop(), new RoundedCorners(round)); +// RequestOptions requestOptions = new RequestOptions(); +// requestOptions.transform(new GlideRoundTransform(context, round)); + loadImage(context, url, imageView, requestOptions, placeholder); + } + } + + /** + * 加载圆角图片 + * + * @param context + * @param url + * @param round + * @param imageView + */ + public void loadRoundImage(Context context, Object url, int round, ImageView imageView) { + if (null != context) { + loadRoundImage(context, url, round, imageView, -1); + } + } + + /** + * 加载圆形带圆环图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleWithBorderImage(Context context, Object url, int borderWidth, int borderColor, ImageView imageView, int placeholder) { + if (null != context) { + RequestOptions requestOptions = new RequestOptions(); + requestOptions.transform(new GlideCircleWithBorder(context, borderWidth, ContextCompat.getColor(context, borderColor))); + loadImage(context, url, imageView, requestOptions, placeholder); + } + } + + + /** + * 加载圆形带圆环图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleWithBorderImage(Context context, Object url,RequestOptions requestOptions, int borderWidth, int borderColor, ImageView imageView, int placeholder) { + if (null != context) { + requestOptions.transform(new GlideCircleWithBorder(context, borderWidth, ContextCompat.getColor(context, borderColor))); + loadImage(context, url, imageView, requestOptions, placeholder); + } + } + + /** + * 加载圆形带圆环图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleWithBorderImage(Context context, Object url, int borderWidth, int borderColor, ImageView imageView) { + if (null != context) { + loadCircleWithBorderImage(context, url, borderWidth, borderColor, imageView, -1); + } + } + + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/MD5Utils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MD5Utils.java new file mode 100644 index 0000000..4c2afac --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MD5Utils.java @@ -0,0 +1,60 @@ +package com.dahe.mylibrary.utils; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.security.MessageDigest; + +public class MD5Utils { + + private static final int BUFFERSIZE = 8196; + private static final String ALGORITHM = "MD5"; + private static final String CHARSET = "UTF-8"; + + public MD5Utils() { + } + + public static String md5(String input) { + return md5(input, CHARSET); + } + + private static String md5(String input, String charsetName) { + try { + MessageDigest md5 = MessageDigest.getInstance(ALGORITHM); + byte md5Bytes[] = md5.digest(input.getBytes(charsetName)); + return StringUtils.byte2hex(md5Bytes); + } catch (Exception e) { + e.printStackTrace(); + } + return input; + } + + public static String md5file(File filename) { + BufferedInputStream bufferedInputStream = null; + MessageDigest md; + try { + bufferedInputStream = new BufferedInputStream(new FileInputStream(filename), BUFFERSIZE); + md = MessageDigest.getInstance(ALGORITHM); + byte[] buffer = new byte[BUFFERSIZE]; + int i = 0; + while ((i = bufferedInputStream.read(buffer)) != -1) { + md.update(buffer, 0, i); + } + return StringUtils.byte2hex(md.digest()); + } catch (Exception e) { + e.printStackTrace(); + return null; + } finally { + try { + bufferedInputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public static String md5reverse(String md5) { + return ""; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/MemoryConstants.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MemoryConstants.java new file mode 100644 index 0000000..7566d70 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MemoryConstants.java @@ -0,0 +1,28 @@ +package com.dahe.mylibrary.utils; + + +import androidx.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2017/03/13
+ *     desc  : constants of memory
+ * 
+ */ +public final class MemoryConstants { + + public static final int BYTE = 1; + public static final int KB = 1024; + public static final int MB = 1048576; + public static final int GB = 1073741824; + + @IntDef({BYTE, KB, MB, GB}) + @Retention(RetentionPolicy.SOURCE) + public @interface Unit { + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/MobileInfoUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MobileInfoUtils.java new file mode 100644 index 0000000..c96854f --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MobileInfoUtils.java @@ -0,0 +1,160 @@ +package com.dahe.mylibrary.utils; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.provider.Settings; +import android.util.Log; + +/** + * @ClassName MobileInfoUtils + * @Author 用户 + * @Date 2022/10/8 10:18 + * @Description TODO + */ +public class MobileInfoUtils { + +// private SettingDialogPermision dialog_per; + + //获取手机类型 + + private static String getMobileType() { + + return Build.MANUFACTURER; + + } + + //跳转至授权页面 + + public void jumpStartInterface(Context context) { + + Intent intent = new Intent(); + + try { + + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + Log.e("HLQ_Struggle", "******************当前手机型号为:" + getMobileType()); + + ComponentName componentName = null; + + if (getMobileType().equals("Xiaomi")) { // 红米Note4测试通过 + + componentName = new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"); + + } else if (getMobileType().equals("Letv")) { // 乐视2测试通过 + + intent.setAction("com.letv.android.permissionautoboot"); + + } else if (getMobileType().equals("samsung")) { // 三星Note5测试通过 + + //componentName = new ComponentName("com.samsung.android.sm_cn", "com.samsung.android.sm.ui.ram.AutoRunActivity"); + + //componentName = ComponentName.unflattenFromString("com.samsung.android.sm/.ui.ram.RamActivity");// Permission Denial not exported from uid 1000,不允许被其他程序调用 + + componentName = ComponentName.unflattenFromString("com.samsung.android.sm/.app.dashboard.SmartManagerDashBoardActivity"); + + } else if (getMobileType().equals("HUAWEI")) { // 华为测试通过 + + componentName = new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity");//锁屏清理 +// componentName = new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity"); +// componentName = ComponentName.unflattenFromString("com.huawei.systemmanager/.startupmgr.ui.StartupNormalAppListActivity");//跳自启动管理 + + //SettingOverlayView.show(context); + + } else if (getMobileType().equals("vivo")) { // VIVO测试通过 + + componentName = ComponentName.unflattenFromString("com.iqoo.secure/.safeguard.PurviewTabActivity"); + + } else if (getMobileType().equals("Meizu")) { //万恶的魅族 + + //componentName = ComponentName.unflattenFromString("com.meizu.safe/.permission.PermissionMainActivity");//跳转到手机管家 + + componentName = ComponentName.unflattenFromString("com.meizu.safe/.permission.SmartBGActivity");//跳转到后台管理页面 + + } else if (getMobileType().equals("OPPO")) { // OPPO R8205测试通过 + + componentName = ComponentName.unflattenFromString("com.oppo.safe/.permission.startup.StartupAppListActivity"); + + } else if (getMobileType().equals("ulong")) { // 360手机 未测试 + + componentName = new ComponentName("com.yulong.android.coolsafe", ".ui.activity.autorun.AutoRunListActivity"); + + } else { + + // 将用户引导到系统设置页面 + + if (Build.VERSION.SDK_INT >= 9) { + + Log.e("HLQ_Struggle", "APPLICATION_DETAILS_SETTINGS"); + + intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS"); + + intent.setData(Uri.fromParts("package", context.getPackageName(), null)); + + } else if (Build.VERSION.SDK_INT <= 8) { + + intent.setAction(Intent.ACTION_VIEW); + + intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails"); + + intent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName()); + + } + + } + + intent.setComponent(componentName); + + context.startActivity(intent); + +// if (getMobileType().equals("Xiaomi")) { +// +// showtip();//显示弹窗(**特别注意**) +// +// } +// +// if (getMobileType().equals("samsung")){ +// +// new SettingOverlayView().show(context);// +// +// } + + } catch (Exception e) {//抛出异常就直接打开设置页面 + + Log.e("HLQ_Struggle", e.getLocalizedMessage()); + + intent = new Intent(Settings.ACTION_SETTINGS); + + context.startActivity(intent); + + } + + } + +//小米手机显示弹窗 + +// private void showtip() { +// +// try { +// +// dialog_per=new SettingDialogPermision(context, R.style.CustomDialog4); +// +// dialog_per.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);//注意这里改成吐司类型 +// +// dialog_per.show(); +// +// Log.e("HLQ_Struggle","显示弹窗"); +// +// } catch (Exception e) { +// +// e.printStackTrace(); +// +// Log.e("HLQ_Struggle", "没有显示弹窗"+e.getMessage()); +// +// } +// +// } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/PatternUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PatternUtils.java new file mode 100644 index 0000000..f3ec6fa --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PatternUtils.java @@ -0,0 +1,28 @@ +package com.dahe.mylibrary.utils; + +import java.util.regex.Pattern; + +public class PatternUtils { + + + /** + * 正则表达式:验证密码(包含大小写,数字,特殊字符,6-12位) + */ +// public static final String REGEX_PASSWORD = "^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*,\\.])[0-9a-zA-Z!@#$%^&*,\\\\.]{6,12}$"; + public static final String REGEX_PASSWORD = "^(?=.*[0-9])(?=.*[a-z])(?=.*[!@#$%^&*,\\.])[0-9a-zA-Z!@#$%^&*,\\\\.]{6,12}$"; + public static final String REGEX_WORD = "^[A-Za-z]+$"; + + /** + * 校验密码 + * + * @param password + * @return 校验通过返回true,否则返回false + */ + public static boolean isPassword(String password) { + return Pattern.matches(REGEX_PASSWORD, password); + } + + public static boolean isLetter(String password){ + return Pattern.matches(REGEX_WORD, password); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/PhoneFormatCheckUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PhoneFormatCheckUtils.java new file mode 100644 index 0000000..2ab5ba1 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PhoneFormatCheckUtils.java @@ -0,0 +1,55 @@ +package com.dahe.mylibrary.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class PhoneFormatCheckUtils { + + /** + * 大陆号码或香港号码均可 + */ + public static boolean isPhoneLegal(String str) throws PatternSyntaxException { + return isChinaPhoneLegal(str) || isHKPhoneLegal(str); + } + + /** + * 大陆手机号码11位数,匹配格式:前三位固定格式+后8位任意数 + * 此方法中前三位格式有: + * 13+任意数 + * 145,147,149 + * 15+除4的任意数(不要写^4,这样的话字母也会被认为是正确的) + * 166 + * 17+3,5,6,7,8 + * 18+任意数 + * 198,199 + */ + public static boolean isChinaPhoneLegal(String str) throws PatternSyntaxException { + // ^ 匹配输入字符串开始的位置 + // \d 匹配一个或多个数字,其中 \ 要转义,所以是 \\d + // $ 匹配输入字符串结尾的位置 + String regExp = "^((13[0-9])|(14[5,7,9])|(15[0-3,5-9])|(166)|(17[3,5,6,7,8])" + + "|(18[0-9])|(19[8,9]))\\d{8}$"; + Pattern p = Pattern.compile(regExp); + Matcher m = p.matcher(str); + return m.matches(); + } + + /** + * 香港手机号码8位数,5|6|8|9开头+7位任意数 + */ + public static boolean isHKPhoneLegal(String str) throws PatternSyntaxException { + // ^ 匹配输入字符串开始的位置 + // \d 匹配一个或多个数字,其中 \ 要转义,所以是 \\d + // $ 匹配输入字符串结尾的位置 + String regExp = "^(5|6|8|9)\\d{7}$"; + Pattern p = Pattern.compile(regExp); + Matcher m = p.matcher(str); + return m.matches(); + } + + public static String hintPhone(String phone){ + return phone.substring(0, 3) + "****" + phone.substring(7, 11); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils6.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils6.java new file mode 100644 index 0000000..d8b146e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils6.java @@ -0,0 +1,247 @@ +package com.dahe.mylibrary.utils; + +import android.app.Activity; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.GridImageAdapter; +import com.dahe.mylibrary.dialog.DialogPhotoSelect; +import com.dahe.mylibrary.glide.GlideEngine; +import com.dahe.mylibrary.weight.FullyGridLayoutManager; +import com.luck.picture.lib.PictureSelectorPreviewFragment; +import com.luck.picture.lib.basic.IBridgeViewLifecycle; +import com.luck.picture.lib.basic.PictureSelector; +import com.luck.picture.lib.config.InjectResourceSource; +import com.luck.picture.lib.config.PictureConfig; +import com.luck.picture.lib.config.PictureMimeType; +import com.luck.picture.lib.config.SelectMimeType; +import com.luck.picture.lib.decoration.GridSpacingItemDecoration; +import com.luck.picture.lib.entity.LocalMedia; +import com.luck.picture.lib.interfaces.OnExternalPreviewEventListener; +import com.luck.picture.lib.interfaces.OnInjectActivityPreviewListener; +import com.luck.picture.lib.interfaces.OnInjectLayoutResourceListener; +import com.luck.picture.lib.interfaces.OnResultCallbackListener; +import com.luck.picture.lib.style.PictureSelectorStyle; +import com.luck.picture.lib.utils.DensityUtil; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +import me.jessyan.autosize.utils.ScreenUtils; + +public class SelectPhotoUtils6 implements View.OnClickListener { + private Activity ctx; + private OnResultCallbackListener listener; + private GridImageAdapter mAdapter; + private Build build; + private final List mData = new ArrayList<>(); + + private SelectPhotoUtils6(Build build, Activity ctx) { + this.build = build; + this.ctx = ctx; + this.listener = build.listener; + if (null == listener) { + ToastUtils.showToast(ctx, "请初始化回调listener"); + return; + } + if (build.isSingle) {//单选 + if (null == build.imageView) { + ToastUtils.showToast(ctx, "请初始化ImageView"); + return; + } + selectSimple(build.imageView); + } else {//多选 + if (null == build.recyclerView || !(build.recyclerView instanceof RecyclerView)) { + ToastUtils.showToast(ctx, "请初始化RecycleView"); + return; + } + selectMul(build.recyclerView); + + } + } + + + public static class Build { + private int maxSelect; + private boolean isSingle; + private boolean isOnlyShow; + private ImageView imageView; + private RecyclerView recyclerView; + private List pics; + private OnResultCallbackListener listener; + + public Build maxSelect(int max) { + this.maxSelect = max; + return this; + } + + public Build isSingle(boolean isSingle) { + this.isSingle = isSingle; + return this; + } + + public Build isOnlyShow(boolean isOnlyShow) { + this.isOnlyShow = isOnlyShow; + return this; + } + + public Build imageview(ImageView imageView) { + this.imageView = imageView; + return this; + } + + public Build recycleview(RecyclerView recyclerView) { + this.recyclerView = recyclerView; + return this; + } + + public Build newPics(List pics) { + this.pics = pics; + return this; + } + + public Build resultListener(OnResultCallbackListener listener) { + this.listener = listener; + return this; + } + + public SelectPhotoUtils6 create(Activity ctx) { + return new SelectPhotoUtils6(this, ctx); + } + } + + public GridImageAdapter getmAdapter() { + return mAdapter; + } + + + public void selectSimple(ImageView imageView) { + imageView.setOnClickListener(this); + } + + + public void selectMul(RecyclerView recyclerView) { + FullyGridLayoutManager manager = new FullyGridLayoutManager(ctx, + 4, GridLayoutManager.VERTICAL, false); + + recyclerView.addItemDecoration(new GridSpacingItemDecoration(40, + DensityUtil.dip2px(ctx, 8), true + )); + recyclerView.setLayoutManager(manager); + mAdapter = new GridImageAdapter(ctx, mData); + mAdapter.setSelectMax(build.maxSelect); +// mAdapter.setIsOnlyShow(build.isOnlyShow); + recyclerView.setAdapter(mAdapter); + + + mAdapter.setOnItemClickListener(new GridImageAdapter.OnItemClickListener() { + @Override + public void onItemClick(View v, int position) { + // 预览图片、视频、音频 + PictureSelector.create(ctx) + .openPreview() + .setImageEngine(GlideEngine.createGlideEngine()) + .setSelectorUIStyle(new PictureSelectorStyle()) +// .isAutoVideoPlay(cb_auto_video.isChecked()) +// .isLoopAutoVideoPlay(cb_auto_video.isChecked()) +// .isPreviewFullScreenMode(cb_preview_full.isChecked()) +// .isVideoPauseResumePlay(cb_video_resume.isChecked()) +// .setCustomLoadingListener(getCustomLoadingListener()) + .isPreviewZoomEffect(true, recyclerView) + .setExternalPreviewEventListener(new MyExternalPreviewEventListener()) + .setAttachViewLifecycle(new IBridgeViewLifecycle() { + @Override + public void onViewCreated(Fragment fragment, View view, Bundle savedInstanceState) { +// PictureSelectorPreviewFragment previewFragment = (PictureSelectorPreviewFragment) fragment; +// MediumBoldTextView tvShare = view.findViewById(R.id.tv_share); +// tvShare.setVisibility(View.VISIBLE) +// previewFragment.addAminViews(tvShare); +// ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) tvShare.getLayoutParams(); +// layoutParams.topMargin = cb_preview_full.isChecked() ? DensityUtil.getStatusBarHeight(getContext()) : 0; +// tvShare.setOnClickListener(new View.OnClickListener() { +// @Override +// public void onClick(View v) { +// PicturePreviewAdapter previewAdapter = previewFragment.getAdapter(); +// ViewPager2 viewPager2 = previewFragment.getViewPager2(); +// LocalMedia media = previewAdapter.getItem(viewPager2.getCurrentItem()); +// ToastUtils.showToast(fragment.getContext(), "自定义分享事件:" + viewPager2.getCurrentItem()); +// } +// }); + } + + @Override + public void onDestroy(Fragment fragment) { +// if (cb_preview_full.isChecked()) { +// // 如果是全屏预览模式且是startFragmentPreview预览,回到自己的界面时需要恢复一下自己的沉浸式状态 +// // 以下提供2种解决方案: +// // 1.通过ImmersiveManager.immersiveAboveAPI23重新设置一下沉浸式 +// int statusBarColor = ContextCompat.getColor(getContext(), R.color.ps_color_grey); +// int navigationBarColor = ContextCompat.getColor(getContext(), R.color.ps_color_grey); +// ImmersiveManager.immersiveAboveAPI23(MainActivity.this, +// true, true, +// statusBarColor, navigationBarColor, false); +// // 2.让自己的titleBar的高度加上一个状态栏高度且内容PaddingTop下沉一个状态栏的高度 +// } + } + }) + .startActivityPreview(position, true, mAdapter.getData()); + } + + @Override + public void openPicture() { + + } + }); + + + } + + + + + + + @Override + public void onClick(View view) { + DialogPhotoSelect dialogPhotoSelect = new DialogPhotoSelect(ctx); + dialogPhotoSelect.show(); + dialogPhotoSelect.setOnSelectClickListener(new DialogPhotoSelect.onSelectClickListener() { + @Override + public void onTakePhoto() { +// doTakePhoto(ctx); + } + + @Override + public void onSelectPhoto() { +// doSelectPhoto(ctx); + } + }); + } + + /** + * 外部预览监听事件 + */ + private class MyExternalPreviewEventListener implements OnExternalPreviewEventListener { + + @Override + public void onPreviewDelete(int position) { + mAdapter.remove(position); + mAdapter.notifyItemRemoved(position); + } + + @Override + public boolean onLongPressDownload(Context context, LocalMedia media) { + return false; + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ShellUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ShellUtils.java new file mode 100644 index 0000000..caf3f45 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ShellUtils.java @@ -0,0 +1,201 @@ +package com.dahe.mylibrary.utils; + + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/08/07
+ *     desc  : utils about shell
+ * 
+ */ +public final class ShellUtils { + + private static final String LINE_SEP = System.getProperty("line.separator"); + + private ShellUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * Execute the command. + * + * @param command The command. + * @param isRooted True to use root, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String command, final boolean isRooted) { + return execCmd(new String[]{command}, isRooted, true); + } + + /** + * Execute the command. + * + * @param commands The commands. + * @param isRooted True to use root, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final List commands, final boolean isRooted) { + return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRooted, true); + } + + /** + * Execute the command. + * + * @param commands The commands. + * @param isRooted True to use root, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String[] commands, final boolean isRooted) { + return execCmd(commands, isRooted, true); + } + + /** + * Execute the command. + * + * @param command The command. + * @param isRooted True to use root, false otherwise. + * @param isNeedResultMsg True to node_return the message of result, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String command, + final boolean isRooted, + final boolean isNeedResultMsg) { + return execCmd(new String[]{command}, isRooted, isNeedResultMsg); + } + + /** + * Execute the command. + * + * @param commands The commands. + * @param isRooted True to use root, false otherwise. + * @param isNeedResultMsg True to node_return the message of result, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final List commands, + final boolean isRooted, + final boolean isNeedResultMsg) { + return execCmd(commands == null ? null : commands.toArray(new String[]{}), + isRooted, + isNeedResultMsg); + } + + /** + * Execute the command. + * + * @param commands The commands. + * @param isRooted True to use root, false otherwise. + * @param isNeedResultMsg True to node_return the message of result, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String[] commands, + final boolean isRooted, + final boolean isNeedResultMsg) { + int result = -1; + if (commands == null || commands.length == 0) { + return new CommandResult(result, "", ""); + } + Process process = null; + BufferedReader successResult = null; + BufferedReader errorResult = null; + StringBuilder successMsg = null; + StringBuilder errorMsg = null; + DataOutputStream os = null; + try { + process = Runtime.getRuntime().exec(isRooted ? "su" : "sh"); + os = new DataOutputStream(process.getOutputStream()); + for (String command : commands) { + if (command == null) continue; + os.write(command.getBytes()); + os.writeBytes(LINE_SEP); + os.flush(); + } + os.writeBytes("exit" + LINE_SEP); + os.flush(); + result = process.waitFor(); + if (isNeedResultMsg) { + successMsg = new StringBuilder(); + errorMsg = new StringBuilder(); + successResult = new BufferedReader( + new InputStreamReader(process.getInputStream(), "UTF-8") + ); + errorResult = new BufferedReader( + new InputStreamReader(process.getErrorStream(), "UTF-8") + ); + String line; + if ((line = successResult.readLine()) != null) { + successMsg.append(line); + while ((line = successResult.readLine()) != null) { + successMsg.append(LINE_SEP).append(line); + } + } + if ((line = errorResult.readLine()) != null) { + errorMsg.append(line); + while ((line = errorResult.readLine()) != null) { + errorMsg.append(LINE_SEP).append(line); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (successResult != null) { + successResult.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (errorResult != null) { + errorResult.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + if (process != null) { + process.destroy(); + } + } + return new CommandResult( + result, + successMsg == null ? "" : successMsg.toString(), + errorMsg == null ? "" : errorMsg.toString() + ); + } + + /** + * The result of command. + */ + public static class CommandResult { + public int result; + public String successMsg; + public String errorMsg; + + public CommandResult(final int result, final String successMsg, final String errorMsg) { + this.result = result; + this.successMsg = successMsg; + this.errorMsg = errorMsg; + } + + @Override + public String toString() { + return "result: " + result + "\n" + + "successMsg: " + successMsg + "\n" + + "errorMsg: " + errorMsg; + } + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SmsTimeUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SmsTimeUtils.java new file mode 100644 index 0000000..61ba406 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SmsTimeUtils.java @@ -0,0 +1,148 @@ +package com.dahe.mylibrary.utils; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.widget.TextView; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * 文件名:SmsTimeUtils + */ +public class SmsTimeUtils { + + /*倒计时时长 单位:秒*/ + private final static int COUNT = 60; + /*当前做*/ + private static int CURR_COUNT = 10; + /*发送验证码*/ + public final static int SETTING_FINANCE_ACCOUNT_TIME = 1; + public final static int WITHDRAW_CASH = 4; + + private static long SETTING_FINANCE_ACCOUNT_TIME_END = 0; + private static long WITHDRAW_CASH_END = 0; + + private static Timer countdownTimer; + private static TextView tvSendCode; + private static Context mContext; + + public static String currPhone;//记录获取验证码的手机号,倒计时结束后清空 + + /** + * 检查是否超过60秒 + * 给当前要从多少开始倒数赋值 + * + * @param first true 表示第一次 false不是 + * @return 是否需要调用startCountdown(TextView textView),主要用于判断在重新打开页,需不需要继续倒计时 + */ + public static boolean check(int type, boolean first) { + long data = System.currentTimeMillis(); + long time = 0; + switch (type) { + case SETTING_FINANCE_ACCOUNT_TIME: + time = SETTING_FINANCE_ACCOUNT_TIME_END; + break; + case WITHDRAW_CASH: + time = WITHDRAW_CASH_END; + break; + } + if (data > time) { + /*主要是区别于是否是第一次进入。第一次进入不需要赋值*/ + if (!first) { + CURR_COUNT = COUNT; + time = data + COUNT * 1000; + switch (type) { + case SETTING_FINANCE_ACCOUNT_TIME: + SETTING_FINANCE_ACCOUNT_TIME_END = time; + break; + case WITHDRAW_CASH: + WITHDRAW_CASH_END = time; + break; + } + } + return false; + } else { + int the_difference = ((int) (time - data)) / 1000; + CURR_COUNT = the_difference; + return true; + } + } + + /** + * 开始倒计时 + * + * @param textView 控制倒计时的view + */ + public static void startCountdown(TextView textView, Context context) { + tvSendCode = textView; + mContext = context; + if (countdownTimer == null) { + countdownTimer = new Timer(); + countdownTimer.schedule(new TimerTask() { + @Override + public void run() { + Message msg = new Message(); + msg.what = CURR_COUNT--; + handler.sendMessage(msg); + } + }, 0, 1000); + } + } + + + /** + * 开始倒计时 + * + * @param textView 控制倒计时的view + */ + public static void startCountdown(TextView textView, Context context,String phone) { + currPhone = phone; + tvSendCode = textView; + mContext = context; + if (countdownTimer == null) { + countdownTimer = new Timer(); + countdownTimer.schedule(new TimerTask() { + @Override + public void run() { + Message msg = new Message(); + msg.what = CURR_COUNT--; + handler.sendMessage(msg); + } + }, 0, 1000); + } + } + + private static Handler handler = new Handler() { + public void handleMessage(Message msg) { + if (msg.what <= 0) { + if (countdownTimer != null) { + countdownTimer.cancel(); + countdownTimer = null; + } + currPhone=""; + tvSendCode.setText("获取验证码"); + tvSendCode.setEnabled(true); + } else { + tvSendCode.setText(msg.what + "s后重新获取"); + tvSendCode.setEnabled(false); + } + super.handleMessage(msg); + } + }; + + + public static void stopCountdown(TextView textView, Context context){ + tvSendCode = textView; + mContext = context; + if (countdownTimer != null) { + countdownTimer.cancel(); + countdownTimer=null; + currPhone=""; + SETTING_FINANCE_ACCOUNT_TIME_END =0; + tvSendCode.setText("获取验证码"); + tvSendCode.setEnabled(true); + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBar.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBar.java new file mode 100644 index 0000000..d7bcaf4 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBar.java @@ -0,0 +1,111 @@ +package com.dahe.mylibrary.utils; + +import android.app.Activity; +import android.os.Build; +import android.view.View; +import android.view.Window; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.Toolbar; + +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.CollapsingToolbarLayout; + + +/** + * Utils for status bar + * Created by qiu on 3/29/16. + */ +public class StatusBar { + + //Get alpha color + static int calculateStatusBarColor(int color, int alpha) { + float a = 1 - alpha / 255f; + int red = color >> 16 & 0xff; + int green = color >> 8 & 0xff; + int blue = color & 0xff; + red = (int) (red * a + 0.5); + green = (int) (green * a + 0.5); + blue = (int) (blue * a + 0.5); + return 0xff << 24 | red << 16 | green << 8 | blue; + } + + /** + * set statusBarColor + * @param statusColor color + * @param alpha 0 - 255 + */ + public static void setStatusBarColor(@NonNull Activity activity, @ColorInt int statusColor, int alpha) { + setStatusBarColor(activity, calculateStatusBarColor(statusColor, alpha)); + } + + public static void setStatusBarColor(@NonNull Activity activity, @ColorInt int statusColor) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + StatusBarCompatLollipop.setStatusBarColor(activity, statusColor); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + StatusBarCompatKitKat.setStatusBarColor(activity, statusColor); + } + } + + public static void translucentStatusBar(@NonNull Activity activity) { + translucentStatusBar(activity, false); + } + + /** + * change to full screen mode + * @param hideStatusBarBackground hide status bar alpha Background when SDK > 21, true if hide it + */ + public static void translucentStatusBar(@NonNull Activity activity, boolean hideStatusBarBackground) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + StatusBarCompatLollipop.translucentStatusBar(activity, hideStatusBarBackground); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + StatusBarCompatKitKat.translucentStatusBar(activity); + } + } + + public static void setStatusBarColorForCollapsingToolbar(@NonNull Activity activity, AppBarLayout appBarLayout, CollapsingToolbarLayout collapsingToolbarLayout, + Toolbar toolbar, @ColorInt int statusColor) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + StatusBarCompatLollipop.setStatusBarColorForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusColor); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + StatusBarCompatKitKat.setStatusBarColorForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusColor); + } + } + + public static void changeToLightStatusBar(@NonNull Activity activity) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return; + } + if (activity == null) { + return; + } + Window window = activity.getWindow(); + if (window == null) { + return; + } + View decorView = window.getDecorView(); + if (decorView == null) { + return; + } + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } + + public static void cancelLightStatusBar(@NonNull Activity activity) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return; + } + if (activity == null) { + return; + } + Window window = activity.getWindow(); + if (window == null) { + return; + } + View decorView = window.getDecorView(); + if (decorView == null) { + return; + } + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatKitKat.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatKitKat.java new file mode 100644 index 0000000..5e9c98e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatKitKat.java @@ -0,0 +1,221 @@ +package com.dahe.mylibrary.utils; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.os.Build; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.view.ViewCompat; + +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.CollapsingToolbarLayout; + + +/** + * After kitkat add fake status bar + * Created by qiu on 8/27/16. + */ +@TargetApi(Build.VERSION_CODES.KITKAT) +class StatusBarCompatKitKat { + + private static final String TAG_FAKE_STATUS_BAR_VIEW = "statusBarView"; + private static final String TAG_MARGIN_ADDED = "marginAdded"; + + /** + * node_return statusBar's Height in pixels + */ + private static int getStatusBarHeight(Context context) { + int result = 0; + int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resId > 0) { + result = context.getResources().getDimensionPixelOffset(resId); + } + return result; + } + + /** + * 1. Add fake statusBarView. + * 2. set tag to statusBarView. + */ + private static View addFakeStatusBarView(Activity activity, int statusBarColor, int statusBarHeight) { + Window window = activity.getWindow(); + ViewGroup mDecorView = (ViewGroup) window.getDecorView(); + + View mStatusBarView = new View(activity); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight); + layoutParams.gravity = Gravity.TOP; + mStatusBarView.setLayoutParams(layoutParams); + mStatusBarView.setBackgroundColor(statusBarColor); + mStatusBarView.setTag(TAG_FAKE_STATUS_BAR_VIEW); + + mDecorView.addView(mStatusBarView); + return mStatusBarView; + } + + /** + * use reserved order to remove is more quickly. + */ + private static void removeFakeStatusBarViewIfExist(Activity activity) { + Window window = activity.getWindow(); + ViewGroup mDecorView = (ViewGroup) window.getDecorView(); + + View fakeView = mDecorView.findViewWithTag(TAG_FAKE_STATUS_BAR_VIEW); + if (fakeView != null) { + mDecorView.removeView(fakeView); + } + } + + /** + * add marginTop to simulate set FitsSystemWindow true + */ + private static void addMarginTopToContentChild(View mContentChild, int statusBarHeight) { + if (mContentChild == null) { + return; + } + if (!TAG_MARGIN_ADDED.equals(mContentChild.getTag())) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentChild.getLayoutParams(); + lp.topMargin += statusBarHeight; + mContentChild.setLayoutParams(lp); + mContentChild.setTag(TAG_MARGIN_ADDED); + } + } + + /** + * remove marginTop to simulate set FitsSystemWindow false + */ + private static void removeMarginTopOfContentChild(View mContentChild, int statusBarHeight) { + if (mContentChild == null) { + return; + } + if (TAG_MARGIN_ADDED.equals(mContentChild.getTag())) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentChild.getLayoutParams(); + lp.topMargin -= statusBarHeight; + mContentChild.setLayoutParams(lp); + mContentChild.setTag(null); + } + } + + /** + * set StatusBarColor + * + * 1. set Window Flag : WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + * 2. removeFakeStatusBarViewIfExist + * 3. addFakeStatusBarView + * 4. addMarginTopToContentChild + * 5. cancel ContentChild's fitsSystemWindow + */ + static void setStatusBarColor(Activity activity, int statusColor) { + Window window = activity.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + View mContentChild = mContentView.getChildAt(0); + int statusBarHeight = getStatusBarHeight(activity); + + removeFakeStatusBarViewIfExist(activity); + addFakeStatusBarView(activity, statusColor, statusBarHeight); + addMarginTopToContentChild(mContentChild, statusBarHeight); + + if (mContentChild != null) { + ViewCompat.setFitsSystemWindows(mContentChild, false); + } + } + + /** + * translucentStatusBar + * + * 1. set Window Flag : WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + * 2. removeFakeStatusBarViewIfExist + * 3. removeMarginTopOfContentChild + * 4. cancel ContentChild's fitsSystemWindow + */ + static void translucentStatusBar(Activity activity) { + Window window = activity.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + + ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT); + View mContentChild = mContentView.getChildAt(0); + + removeFakeStatusBarViewIfExist(activity); + removeMarginTopOfContentChild(mContentChild, getStatusBarHeight(activity)); + if (mContentChild != null) { + ViewCompat.setFitsSystemWindows(mContentChild, false); + } + } + + /** + * compat for CollapsingToolbarLayout + * + * 1. set Window Flag : WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + * 2. set FitsSystemWindows for views. + * 3. add Toolbar's height, let it layout from top, then add paddingTop to layout normal. + * 4. removeFakeStatusBarViewIfExist + * 5. removeMarginTopOfContentChild + * 6. add OnOffsetChangedListener to change statusBarView's alpha + */ + static void setStatusBarColorForCollapsingToolbar(Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout, + Toolbar toolbar, int statusColor) { + Window window = activity.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + + View mContentChild = mContentView.getChildAt(0); + mContentChild.setFitsSystemWindows(false); + ((View) appBarLayout.getParent()).setFitsSystemWindows(false); + appBarLayout.setFitsSystemWindows(false); + collapsingToolbarLayout.setFitsSystemWindows(false); + collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false); + + toolbar.setFitsSystemWindows(false); + if (toolbar.getTag() == null) { + CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams(); + int statusBarHeight = getStatusBarHeight(activity); + lp.height += statusBarHeight; + toolbar.setLayoutParams(lp); + toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom()); + toolbar.setTag(true); + } + + int statusBarHeight = getStatusBarHeight(activity); + removeFakeStatusBarViewIfExist(activity); + removeMarginTopOfContentChild(mContentChild, statusBarHeight); + final View statusView = addFakeStatusBarView(activity, statusColor, statusBarHeight); + + CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams()).getBehavior(); + if (behavior != null && behavior instanceof AppBarLayout.Behavior) { + int verticalOffset = ((AppBarLayout.Behavior) behavior).getTopAndBottomOffset(); + if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { + statusView.setAlpha(1f); + } else { + statusView.setAlpha(0f); + } + } else { + statusView.setAlpha(0f); + } + + appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { + if (statusView.getAlpha() == 0) { + statusView.animate().cancel(); + statusView.animate().alpha(1f).setDuration(collapsingToolbarLayout.getScrimAnimationDuration()).start(); + } + } else { + if (statusView.getAlpha() == 1) { + statusView.animate().cancel(); + statusView.animate().alpha(0f).setDuration(collapsingToolbarLayout.getScrimAnimationDuration()).start(); + } + } + } + }); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatLollipop.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatLollipop.java new file mode 100644 index 0000000..c6e64ae --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatLollipop.java @@ -0,0 +1,193 @@ +package com.dahe.mylibrary.utils; + +import android.animation.ValueAnimator; +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Build; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; + +import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.view.OnApplyWindowInsetsListener; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.CollapsingToolbarLayout; + + +/** + * After Lollipop use system method. + * Created by qiu on 8/27/16. + */ +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +class StatusBarCompatLollipop { + + /** + * node_return statusBar's Height in pixels + */ + private static int getStatusBarHeight(Context context) { + int result = 0; + int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resId > 0) { + result = context.getResources().getDimensionPixelOffset(resId); + } + return result; + } + + /** + * set StatusBarColor + * + * 1. set Flags to call setStatusBarColor + * 2. call setSystemUiVisibility to clear translucentStatusBar's Flag. + * 3. set FitsSystemWindows to false + */ + static void setStatusBarColor(Activity activity, int statusColor) { + Window window = activity.getWindow(); + + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(statusColor); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + ViewCompat.setFitsSystemWindows(mChildView, false); + ViewCompat.requestApplyInsets(mChildView); + } + } + + /** + * translucentStatusBar(full-screen) + * + * 1. set Flags to full-screen + * 2. set FitsSystemWindows to false + * + * @param hideStatusBarBackground hide statusBar's shadow + */ + static void translucentStatusBar(Activity activity, boolean hideStatusBarBackground) { + Window window = activity.getWindow(); + + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + if (hideStatusBarBackground) { + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.setStatusBarColor(Color.TRANSPARENT); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + ViewCompat.setFitsSystemWindows(mChildView, false); + ViewCompat.requestApplyInsets(mChildView); + } + } + + /** + * compat for CollapsingToolbarLayout + * + * 1. change to full-screen mode(like translucentStatusBar). + * 2. cancel CollapsingToolbarLayout's WindowInsets, let it layout as normal(now setStatusBarScrimColor is useless). + * 3. set View's FitsSystemWindow to false. + * 4. add Toolbar's height, let it layout from top, then add paddingTop to layout normal. + * 5. change statusBarColor by AppBarLayout's offset. + * 6. add Listener to change statusBarColor + */ + static void setStatusBarColorForCollapsingToolbar(Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout, + Toolbar toolbar, final int statusColor) { + final Window window = activity.getWindow(); + + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.TRANSPARENT); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + + ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, new OnApplyWindowInsetsListener() { + @Override + public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { + return insets; + } + }); + + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + ViewCompat.setFitsSystemWindows(mChildView, false); + ViewCompat.requestApplyInsets(mChildView); + } + + ((View) appBarLayout.getParent()).setFitsSystemWindows(false); + appBarLayout.setFitsSystemWindows(false); + + toolbar.setFitsSystemWindows(false); + if (toolbar.getTag() == null) { + CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams(); + int statusBarHeight = getStatusBarHeight(activity); + lp.height += statusBarHeight; + toolbar.setLayoutParams(lp); + toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom()); + toolbar.setTag(true); + } + + CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams()).getBehavior(); + if (behavior != null && behavior instanceof AppBarLayout.Behavior) { + int verticalOffset = ((AppBarLayout.Behavior) behavior).getTopAndBottomOffset(); + if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { + window.setStatusBarColor(statusColor); + } else { + window.setStatusBarColor(Color.TRANSPARENT); + } + } else { + window.setStatusBarColor(Color.TRANSPARENT); + } + + collapsingToolbarLayout.setFitsSystemWindows(false); + appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { + if (window.getStatusBarColor() != statusColor) { + startColorAnimation(window.getStatusBarColor(), statusColor, collapsingToolbarLayout.getScrimAnimationDuration(), window); + } + } else { + if (window.getStatusBarColor() != Color.TRANSPARENT) { + startColorAnimation(window.getStatusBarColor(), Color.TRANSPARENT, collapsingToolbarLayout.getScrimAnimationDuration(), window); + } + } + } + }); + collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false); + collapsingToolbarLayout.setStatusBarScrimColor(statusColor); + } + + /** + * use ValueAnimator to change statusBarColor when using collapsingToolbarLayout + */ + static void startColorAnimation(int startColor, int endColor, long duration, final Window window) { + if (sAnimator != null) { + sAnimator.cancel(); + } + sAnimator = ValueAnimator.ofArgb(startColor, endColor) + .setDuration(duration); + sAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + if (window != null) { + window.setStatusBarColor((Integer) valueAnimator.getAnimatedValue()); + } + } + }); + sAnimator.start(); + } + + private static ValueAnimator sAnimator; +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StringUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StringUtils.java new file mode 100644 index 0000000..b71df3a --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StringUtils.java @@ -0,0 +1,99 @@ +package com.dahe.mylibrary.utils; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; + +public class StringUtils { + + public static String byte2hex(byte[] b) { + + String str = ""; + String stmp = ""; + + int length = b.length; + + for (int n = 0; n < length; n++) { + stmp = (Integer.toHexString(b[n] & 0XFF)); + if (stmp.length() == 1) { + str += "0"; + } + str += stmp; + } + + return str.toLowerCase(); + } + + public static String nullToStrTrim(String str) { + + if (str == null) { + str = ""; + } + + return str.trim(); + } + + public static boolean isNotEmpty(String str) { + + return ((str != null) && (str.trim().length() > 0 && !"null".equals(str))); + } + + public static boolean isEmpty(String str) { + + return !isNotEmpty(str); + } + + public static int getRealLength(String str) { + + return getRealLength(str, "utf-8"); + } + + public static int getRealLength(String str, String charsetName) { + + str = nullToStrTrim(str); + + try { + return str.getBytes(charsetName).length; + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return 0; + } + } + public static String encode(String str, String enc) { + + String strEncode = ""; + + try { + if (str != null) + strEncode = URLEncoder.encode(str, enc); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + return strEncode; + } + + public static String decode(String str, String enc) { + + String strDecode = ""; + + try { + if (str != null) + strDecode = URLDecoder.decode(str, enc); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + return strDecode; + } + + public static String encode(String str) { + + return encode(str, "utf-8"); + } + + public static String decode(String str) { + + return decode(str, "utf-8"); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeConstants.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeConstants.java new file mode 100644 index 0000000..d1951da --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeConstants.java @@ -0,0 +1,44 @@ +package com.dahe.mylibrary.utils; + + +import androidx.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2017/03/13
+ *     desc  : 时间相关常量
+ * 
+ */ +public final class TimeConstants { + + /** + * 毫秒与毫秒的倍数 + */ + public static final int MSEC = 1; + /** + * 秒与毫秒的倍数 + */ + public static final int SEC = 1000; + /** + * 分与毫秒的倍数 + */ + public static final int MIN = 60000; + /** + * 时与毫秒的倍数 + */ + public static final int HOUR = 3600000; + /** + * 天与毫秒的倍数 + */ + public static final int DAY = 86400000; + + @IntDef({MSEC, SEC, MIN, HOUR, DAY}) + @Retention(RetentionPolicy.SOURCE) + public @interface Unit { + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeUtil.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeUtil.java new file mode 100644 index 0000000..0cc51bc --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeUtil.java @@ -0,0 +1,1703 @@ +package com.dahe.mylibrary.utils; + +import android.text.TextUtils; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +/** + *
+ *     author: LiJia
+ *     time  : 2021/08/02
+ *     desc  : 时间相关工具类
+ * 
+ */ +public final class TimeUtil { + + /** + *

在工具类中经常使用到工具类的格式化描述,这个主要是一个日期的操作类,所以日志格式主要使用 SimpleDateFormat的定义格式.

+ * 格式的意义如下: 日期和时间模式
+ *

日期和时间格式由日期和时间模式字符串指定。在日期和时间模式字符串中,未加引号的字母 'A' 到 'Z' 和 'a' 到 'z' + * 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (') 引起来,以免进行解释。"''" + * 表示单引号。所有其他字符均不解释;只是在格式化时将它们简单复制到输出字符串,或者在分析时与输入字符串进行匹配。 + *

+ * 定义了以下模式字母(所有其他字符 'A' 到 'Z' 和 'a' 到 'z' 都被保留):
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
字母日期或时间元素表示示例
GEra 标志符TextAD
y Year 1996; 96
M 年中的月份 Month July; Jul; 07
w 年中的周数 Number 27
W 月份中的周数 Number 2
D 年中的天数 Number 189
d 月份中的天数 Number 10
F 月份中的星期 Number 2
E 星期中的天数 Text Tuesday; Tue
a Am/pm 标记 Text PM
H 一天中的小时数(0-23) Number 0
k 一天中的小时数(1-24) Number 24
K am/pm 中的小时数(0-11) Number 0
h am/pm 中的小时数(1-12) Number 12
m 小时中的分钟数 Number 30
s 分钟中的秒数 Number 55
S 毫秒数 Number 978
z 时区 General time zone Pacific Standard Time; PST; GMT-08:00
Z 时区 RFC 822 time zone -0800
+ *
+     *                                             HH:mm    15:44
+     *                                            h:mm a    3:44 下午
+     *                                           HH:mm z    15:44 CST
+     *                                           HH:mm Z    15:44 +0800
+     *                                        HH:mm zzzz    15:44 中国标准时间
+     *                                          HH:mm:ss    15:44:40
+     *                                        yyyy-MM-dd    2016-08-12
+     *                                  yyyy-MM-dd HH:mm    2016-08-12 15:44
+     *                               yyyy-MM-dd HH:mm:ss    2016-08-12 15:44:40
+     *                          yyyy-MM-dd HH:mm:ss zzzz    2016-08-12 15:44:40 中国标准时间
+     *                     EEEE yyyy-MM-dd HH:mm:ss zzzz    星期五 2016-08-12 15:44:40 中国标准时间
+     *                          yyyy-MM-dd HH:mm:ss.SSSZ    2016-08-12 15:44:40.461+0800
+     *                        yyyy-MM-dd'T'HH:mm:ss.SSSZ    2016-08-12T15:44:40.461+0800
+     *                      yyyy.MM.dd G 'at' HH:mm:ss z    2016.08.12 公元 at 15:44:40 CST
+     *                                            K:mm a    3:44 下午
+     *                                  EEE, MMM d, ''yy    星期五, 八月 12, '16
+     *                             hh 'o''clock' a, zzzz    03 o'clock 下午, 中国标准时间
+     *                      yyyyy.MMMMM.dd GGG hh:mm aaa    02016.八月.12 公元 03:44 下午
+     *                        EEE, d MMM yyyy HH:mm:ss Z    星期五, 12 八月 2016 15:44:40 +0800
+     *                                     yyMMddHHmmssZ    160812154440+0800
+     *                        yyyy-MM-dd'T'HH:mm:ss.SSSZ    2016-08-12T15:44:40.461+0800
+     * EEEE 'DATE('yyyy-MM-dd')' 'TIME('HH:mm:ss')' zzzz    星期五 DATE(2016-08-12) TIME(15:44:40) 中国标准时间
+     * 
+ * 注意:SimpleDateFormat不是线程安全的,线程安全需用{@code ThreadLocal} + */ + + private static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + private static final DateFormat DEFAULT_FORMAT2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZSS:SS", Locale.getDefault()); + private static final DateFormat DEFAULT_FORMAT3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault()); + + private TimeUtil() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 将时间戳转为时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param millis 毫秒时间戳 + * @return 时间字符串 + */ + public static String millis2String(final long millis) { + return millis2String(millis, DEFAULT_FORMAT); + } + + /** + * 将时间戳转为时间字符串 + *

格式为format

+ * + * @param millis 毫秒时间戳 + * @param format 时间格式 + * @return 时间字符串 + */ + public static String millis2String(final long millis, final DateFormat format) { + return format.format(new Date(millis)); + } + + /** + * 将时间字符串转为时间戳 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 毫秒时间戳 + */ + public static long string2Millis(final String time) { + if (TextUtils.isEmpty(time)){ + return -1; + } + return string2Millis(time, DEFAULT_FORMAT); + } + + /** + * 将时间字符串转为时间戳 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 毫秒时间戳 + */ + public static long string2Millis(final String time, final DateFormat format) { + try { + return format.parse(time).getTime(); + } catch (ParseException e) { + e.printStackTrace(); + } + return -1; + } + + /** + * 将时间字符串转为时间戳 + *

time格式为format

+ * + * @param time 时间字符串 + * @return 毫秒时间戳 + */ + public static String string2String(final String time,final SimpleDateFormat format) { + try { + return date2String(format.parse(time)); +// return DEFAULT_FORMAT.format(DEFAULT_FORMAT2.parse(time).getTime()); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + /** + * 将时间字符串转为Date类型 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return Date类型 + */ + public static Date string2Date(final String time) { + return string2Date(time, DEFAULT_FORMAT); + } + + /** + * 将时间字符串转为Date类型 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return Date类型 + */ + public static Date string2Date(final String time, final DateFormat format) { + try { + return format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 将Date类型转为时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param date Date类型时间 + * @return 时间字符串 + */ + public static String date2String(final Date date) { + return date2String(date, DEFAULT_FORMAT); + } + + /** + * 将Date类型转为时间字符串 + *

格式为format

+ * + * @param date Date类型时间 + * @param format 时间格式 + * @return 时间字符串 + */ + public static String date2String(final Date date, final DateFormat format) { + return format.format(date); + } + + /** + * 将Date类型转为时间戳 + * + * @param date Date类型时间 + * @return 毫秒时间戳 + */ + public static long date2Millis(final Date date) { + return date.getTime(); + } + + /** + * 将时间戳转为Date类型 + * + * @param millis 毫秒时间戳 + * @return Date类型时间 + */ + public static Date millis2Date(final long millis) { + return new Date(millis); + } + + /** + * 获取两个时间差(单位:unit) + *

time0和time1格式都为yyyy-MM-dd HH:mm:ss

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final String time0, final String time1, @TimeConstants.Unit final int unit) { + return getTimeSpan(time0, time1, DEFAULT_FORMAT, unit); + } + + /** + * 获取两个时间差(单位:unit) + *

time0和time1格式都为format

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param format 时间格式 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final String time0, final String time1, final DateFormat format, @TimeConstants.Unit final int unit) { + return millis2TimeSpan(Math.abs(string2Millis(time0, format) - string2Millis(time1, format)), unit); + } + + /** + * 获取两个时间差(单位:unit) + * + * @param date0 Date类型时间0 + * @param date1 Date类型时间1 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final Date date0, final Date date1, @TimeConstants.Unit final int unit) { + return millis2TimeSpan(Math.abs(date2Millis(date0) - date2Millis(date1)), unit); + } + + /** + * 获取两个时间差(单位:unit) + * + * @param millis0 毫秒时间戳0 + * @param millis1 毫秒时间戳1 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final long millis0, final long millis1, @TimeConstants.Unit final int unit) { + return millis2TimeSpan(Math.abs(millis0 - millis1), unit); + } + + /** + * 获取合适型两个时间差 + *

time0和time1格式都为yyyy-MM-dd HH:mm:ss

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final String time0, final String time1, final int precision) { + if (TextUtils.isEmpty(time0)||TextUtils.isEmpty(time1)){ + return ""; + } + return millis2FitTimeSpan(Math.abs(string2Millis(time0, DEFAULT_FORMAT) - string2Millis(time1, DEFAULT_FORMAT)), precision); + } + + /** + * 获取合适型两个时间差 + *

time0和time1格式都为format

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param format 时间格式 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final String time0, final String time1, final DateFormat format, final int precision) { + return millis2FitTimeSpan(Math.abs(string2Millis(time0, format) - string2Millis(time1, format)), precision); + } + + /** + * 获取合适型两个时间差 + * + * @param date0 Date类型时间0 + * @param date1 Date类型时间1 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final Date date0, final Date date1, final int precision) { + return millis2FitTimeSpan(Math.abs(date2Millis(date0) - date2Millis(date1)), precision); + } + + /** + * 获取合适型两个时间差 + * + * @param millis0 毫秒时间戳1 + * @param millis1 毫秒时间戳2 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final long millis0, final long millis1, final int precision) { + return millis2FitTimeSpan(Math.abs(millis0 - millis1), precision); + } + + /** + * 获取当前毫秒时间戳 + * + * @return 毫秒时间戳 + */ + public static long getNowMills() { + return System.currentTimeMillis(); + } + + /** + * 获取当前时间字符串 + * + * @param pattern 格式化时间的格式 + * @return + */ + public static String getNowString(String pattern) { + return millis2String(System.currentTimeMillis(), TextUtils.isEmpty(pattern) ? DEFAULT_FORMAT : new SimpleDateFormat(pattern, Locale.getDefault())); + } + + /** + * 获取当前时间字符串 + *

格式为format

+ * + * @param format 时间格式 + * @return 时间字符串 + */ + public static String getNowString(final DateFormat format) { + return millis2String(System.currentTimeMillis(), format); + } + + /** + * 获取当前Date + * + * @return Date类型时间 + */ + public static Date getNowDate() { + return new Date(); + } + + /** + * 获取与当前时间的差(单位:unit) + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final String time, @TimeConstants.Unit final int unit) { + return getTimeSpan(getNowString(""), time, DEFAULT_FORMAT, unit); + } + + /** + * 获取与当前时间的差(单位:unit) + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final String time, final DateFormat format, @TimeConstants.Unit final int unit) { + return getTimeSpan(getNowString(format), time, format, unit); + } + + /** + * 获取与当前时间的差(单位:unit) + * + * @param date Date类型时间 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final Date date, @TimeConstants.Unit final int unit) { + return getTimeSpan(new Date(), date, unit); + } + + /** + * 获取与当前时间的差(单位:unit) + * + * @param millis 毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final long millis, @TimeConstants.Unit final int unit) { + return getTimeSpan(System.currentTimeMillis(), millis, unit); + } + + /** + * 获取合适型与当前时间的差 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final String time, final int precision) { + return getFitTimeSpan(getNowString(""), time, DEFAULT_FORMAT, precision); + } + + /** + * 获取合适型与当前时间的差 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final String time, final DateFormat format, final int precision) { + return getFitTimeSpan(getNowString(format), time, format, precision); + } + + /** + * 获取合适型与当前时间的差 + * + * @param date Date类型时间 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final Date date, final int precision) { + return getFitTimeSpan(getNowDate(), date, precision); + } + + /** + * 获取合适型与当前时间的差 + * + * @param millis 毫秒时间戳 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final long millis, final int precision) { + return getFitTimeSpan(System.currentTimeMillis(), millis, precision); + } + + /** + * 获取友好型与当前时间的差 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final String time) { + return getFriendlyTimeSpanByNow(time, DEFAULT_FORMAT); + } + + /** + * 获取友好型与当前时间的差 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final String time, final DateFormat format) { + return getFriendlyTimeSpanByNow(string2Millis(time, format)); + } + + /** + * 获取友好型与当前时间的差 + * + * @param date Date类型时间 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final Date date) { + return getFriendlyTimeSpanByNow(date.getTime()); + } + + /** + * 获取友好型与当前时间的差 + * + * @param millis 毫秒时间戳 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final long millis) { + long now = System.currentTimeMillis(); + long span = now - millis; + if (span < 0) + return String.format("%tc", millis);// U can read http://www.apihome.cn/api/java/Formatter.html to understand it. + if (span < 1000) { + return "刚刚"; + } else if (span < TimeConstants.MIN) { + return String.format(Locale.getDefault(), "%d秒前", span / TimeConstants.SEC); + } else if (span < TimeConstants.HOUR) { + return String.format(Locale.getDefault(), "%d分钟前", span / TimeConstants.MIN); + } + // 获取当天00:00 + long wee = getWeeOfToday(); + if (millis >= wee) { + return String.format("今天%tR", millis); + } else if (millis >= wee - TimeConstants.DAY) { + return String.format("昨天%tR", millis); + } else { + return String.format("%tF", millis); + } + } + + private static long getWeeOfToday() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTimeInMillis(); + } + + /** + * 获取与给定时间等于时间差的时间戳 + * + * @param millis 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis + timeSpan2Millis(timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间戳 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final String time, final long timeSpan, @TimeConstants.Unit final int unit) { + return getMillis(time, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间戳 + *

time格式为format

+ * + * @param time 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return string2Millis(time, format) + timeSpan2Millis(timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间戳 + * + * @param date 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) { + return date2Millis(date) + timeSpan2Millis(timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param millis 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) { + return getString(millis, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为format

+ * + * @param millis 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final long millis, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2String(millis + timeSpan2Millis(timeSpan, unit), format); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final String time, final long timeSpan, @TimeConstants.Unit final int unit) { + return getString(time, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为format

+ * + * @param time 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2String(string2Millis(time, format) + timeSpan2Millis(timeSpan, unit), format); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param date 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) { + return getString(date, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为format

+ * + * @param date 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final Date date, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2String(date2Millis(date) + timeSpan2Millis(timeSpan, unit), format); + } + + /** + * 获取与给定时间等于时间差的Date + * + * @param millis 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2Date(millis + timeSpan2Millis(timeSpan, unit)); + } + + /** + * 获取与给定时间等于时间差的Date + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final String time, final long timeSpan, @TimeConstants.Unit final int unit) { + return getDate(time, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的Date + *

格式为format

+ * + * @param time 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2Date(string2Millis(time, format) + timeSpan2Millis(timeSpan, unit)); + } + + /** + * 获取与给定时间等于时间差的Date + * + * @param date 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2Date(date2Millis(date) + timeSpan2Millis(timeSpan, unit)); + } + + /** + * 获取与当前时间等于时间差的时间戳 + * + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的时间戳 + */ + public static long getMillisByNow(final long timeSpan, @TimeConstants.Unit final int unit) { + return getMillis(getNowMills(), timeSpan, unit); + } + + /** + * 获取与当前时间等于时间差的时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的时间字符串 + */ + public static String getStringByNow(final long timeSpan, @TimeConstants.Unit final int unit) { + return getStringByNow(timeSpan, DEFAULT_FORMAT, unit); + } + + /** + * 获取与当前时间等于时间差的时间字符串 + *

格式为format

+ * + * @param timeSpan 时间差的毫秒时间戳 + * @param format 时间格式 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的时间字符串 + */ + public static String getStringByNow(final long timeSpan, final DateFormat format, @TimeConstants.Unit final int unit) { + return getString(getNowMills(), format, timeSpan, unit); + } + + /** + * 获取与当前时间等于时间差的Date + * + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的Date + */ + public static Date getDateByNow(final long timeSpan, @TimeConstants.Unit final int unit) { + return getDate(getNowMills(), timeSpan, unit); + } + + /** + * 判断是否今天 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final String time) { + return isToday(string2Millis(time, DEFAULT_FORMAT)); + } + + /** + * 判断是否今天 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final String time, final DateFormat format) { + return isToday(string2Millis(time, format)); + } + + /** + * 判断是否今天 + * + * @param date Date类型时间 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final Date date) { + return isToday(date.getTime()); + } + + /** + * 判断是否今天 + * + * @param millis 毫秒时间戳 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final long millis) { + long wee = getWeeOfToday(); + return millis >= wee && millis < wee + TimeConstants.DAY; + } + + /** + * 判断是否闰年 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final String time) { + return isLeapYear(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 判断是否闰年 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final String time, final DateFormat format) { + return isLeapYear(string2Date(time, format)); + } + + /** + * 判断是否闰年 + * + * @param date Date类型时间 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int year = cal.get(Calendar.YEAR); + return isLeapYear(year); + } + + /** + * 判断是否闰年 + * + * @param millis 毫秒时间戳 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final long millis) { + return isLeapYear(millis2Date(millis)); + } + + /** + * 判断是否闰年 + * + * @param year 年份 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final int year) { + return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; + } + + /** + * 获取中式星期 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 中式星期 + */ + public static String getChineseWeek(final String time) { + return getChineseWeek(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取当前中式时间 + * + * @return + */ + public static String getChineseNowWeek() { + return getChineseWeek(string2Date(getNowString(""), DEFAULT_FORMAT)); + } + + /** + * 获取中式星期 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 中式星期 + */ + public static String getChineseWeek(final String time, final DateFormat format) { + return getChineseWeek(string2Date(time, format)); + } + + /** + * 获取中式星期 + * + * @param date Date类型时间 + * @return 中式星期 + */ + public static String getChineseWeek(final Date date) { + return new SimpleDateFormat("E", Locale.CHINA).format(date); + } + + /** + * 获取中式星期 + * + * @param millis 毫秒时间戳 + * @return 中式星期 + */ + public static String getChineseWeek(final long millis) { + return getChineseWeek(new Date(millis)); + } + + /** + * 获取美式星期 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 美式星期 + */ + public static String getUSWeek(final String time) { + return getUSWeek(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取美式星期 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 美式星期 + */ + public static String getUSWeek(final String time, final DateFormat format) { + return getUSWeek(string2Date(time, format)); + } + + /** + * 获取美式星期 + * + * @param date Date类型时间 + * @return 美式星期 + */ + public static String getUSWeek(final Date date) { + return new SimpleDateFormat("EEEE", Locale.US).format(date); + } + + /** + * 获取美式星期 + * + * @param millis 毫秒时间戳 + * @return 美式星期 + */ + public static String getUSWeek(final long millis) { + return getUSWeek(new Date(millis)); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final String time) { + return getWeekIndex(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final String time, final DateFormat format) { + return getWeekIndex(string2Date(time, format)); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ * + * @param date Date类型时间 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.DAY_OF_WEEK); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ * + * @param millis 毫秒时间戳 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final long millis) { + return getWeekIndex(millis2Date(millis)); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 1...5 + */ + public static int getWeekOfMonth(final String time) { + return getWeekOfMonth(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 1...5 + */ + public static int getWeekOfMonth(final String time, final DateFormat format) { + return getWeekOfMonth(string2Date(time, format)); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param date Date类型时间 + * @return 1...5 + */ + public static int getWeekOfMonth(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.WEEK_OF_MONTH); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param millis 毫秒时间戳 + * @return 1...5 + */ + public static int getWeekOfMonth(final long millis) { + return getWeekOfMonth(millis2Date(millis)); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 1...54 + */ + public static int getWeekOfYear(final String time) { + return getWeekOfYear(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 1...54 + */ + public static int getWeekOfYear(final String time, final DateFormat format) { + return getWeekOfYear(string2Date(time, format)); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param date Date类型时间 + * @return 1...54 + */ + public static int getWeekOfYear(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.WEEK_OF_YEAR); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param millis 毫秒时间戳 + * @return 1...54 + */ + public static int getWeekOfYear(final long millis) { + return getWeekOfYear(millis2Date(millis)); + } + + private static final String[] CHINESE_ZODIAC = {"猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"}; + + /** + * 获取生肖 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 生肖 + */ + public static String getChineseZodiac(final String time) { + return getChineseZodiac(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取生肖 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 生肖 + */ + public static String getChineseZodiac(final String time, final DateFormat format) { + return getChineseZodiac(string2Date(time, format)); + } + + /** + * 获取生肖 + * + * @param date Date类型时间 + * @return 生肖 + */ + public static String getChineseZodiac(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return CHINESE_ZODIAC[cal.get(Calendar.YEAR) % 12]; + } + + /** + * 获取生肖 + * + * @param millis 毫秒时间戳 + * @return 生肖 + */ + public static String getChineseZodiac(final long millis) { + return getChineseZodiac(millis2Date(millis)); + } + + /** + * 获取生肖 + * + * @param year 年 + * @return 生肖 + */ + public static String getChineseZodiac(final int year) { + return CHINESE_ZODIAC[year % 12]; + } + + private static final String[] ZODIAC = {"水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "魔羯座"}; + private static final int[] ZODIAC_FLAGS = {20, 19, 21, 21, 21, 22, 23, 23, 23, 24, 23, 22}; + + /** + * 获取星座 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 生肖 + */ + public static String getZodiac(final String time) { + return getZodiac(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取星座 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 生肖 + */ + public static String getZodiac(final String time, final DateFormat format) { + return getZodiac(string2Date(time, format)); + } + + /** + * 获取星座 + * + * @param date Date类型时间 + * @return 星座 + */ + public static String getZodiac(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int month = cal.get(Calendar.MONTH) + 1; + int day = cal.get(Calendar.DAY_OF_MONTH); + return getZodiac(month, day); + } + + /** + * 获取星座 + * + * @param millis 毫秒时间戳 + * @return 星座 + */ + public static String getZodiac(final long millis) { + return getZodiac(millis2Date(millis)); + } + + /** + * 获取星座 + * + * @param month 月 + * @param day 日 + * @return 星座 + */ + public static String getZodiac(final int month, final int day) { + return ZODIAC[day >= ZODIAC_FLAGS[month - 1] + ? month - 1 + : (month + 10) % 12]; + } + + private static long timeSpan2Millis(final long timeSpan, @TimeConstants.Unit final int unit) { + return timeSpan * unit; + } + + private static long millis2TimeSpan(final long millis, @TimeConstants.Unit final int unit) { + return millis / unit; + } + + public static String millis2FitTimeSpan(long millis, int precision) { + if (millis < 0 || precision <= 0) return null; + precision = Math.min(precision, 5); + String[] units = {"天", "时", "分", "秒", "毫秒"}; + if (millis == 0) return 0 + units[precision - 1]; + StringBuilder sb = new StringBuilder(); + int[] unitLen = {86400000, 3600000, 60000, 1000, 1}; + for (int i = 0; i < precision; i++) { + if (millis >= unitLen[i]) { + long mode = millis / unitLen[i]; + millis -= mode * unitLen[i]; + sb.append(mode).append(units[i]); + } + } + return sb.toString(); + } + + + /** + * 比较时间大小 + * + * @param nowDate + * @param compareDate + * @return + */ + public static boolean compareDate(String nowDate, String compareDate) { + DateFormat df = DEFAULT_FORMAT; + try { + Date now = df.parse(nowDate); + Date compare = df.parse(compareDate); + if (now.after(compare)) { + return true; + } else { + return false; + } + } catch (ParseException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 比较时间大小 + * + * @param nowDate + * @param compareDate + * @return + */ + public static boolean compareDate(String nowDate, String compareDate,DateFormat format) { + DateFormat df = format; + try { + Date now = df.parse(nowDate); + Date compare = df.parse(compareDate); + if (now.after(compare)) { + return true; + } else { + return false; + } + } catch (ParseException e) { + e.printStackTrace(); + return false; + } + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimingX.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimingX.java new file mode 100644 index 0000000..df631dc --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimingX.java @@ -0,0 +1,145 @@ +package com.dahe.mylibrary.utils; + +import android.os.Handler; +import android.os.Message; +import android.widget.TextView; + +import java.util.ArrayList; + +import io.reactivex.rxjava3.annotations.NonNull; + +public class TimingX { + + private volatile static TimingX sTimingX; + + private static int sSecond = 0, sStatus = TimingEnum.STOP.val; + + private static final Handler sHandler = new TimingXHandler(); + + private static final ArrayList timingViews = new ArrayList<>(8); + + private static String time = ""; + + private TimingX() { + } + + public static TimingX builder(){ + if(sTimingX == null){ + synchronized (TimingX.class){ + if(sTimingX == null){ + sTimingX = new TimingX(); + } + } + } + return sTimingX; + } + + private static class TimingXHandler extends Handler { + @Override + public void handleMessage(@NonNull Message msg) { + int status = msg.what; + if (status == TimingEnum.START.val) { + sSecond += 1; + time = format(sSecond); + sHandler.sendEmptyMessageDelayed(status, 1000); + } else if (status == TimingEnum.STOP.val) { + time = format(sSecond); + } + showTime(); + } + } + + private static void showTime(){ + for (TextView timingView : timingViews) { + timingView.setText(time); + } + } + + public int getStatus(){ + return sStatus; + } + + enum TimingEnum { + STOP(0), // 停止计时 + START(1), // 开始计时 + CLEAR(-1); // 清除计时 + int val; + TimingEnum(int val){ + this.val = val; + } + } + + /** + * 添加需要计时的 view + * @param view + * @return + */ + public TimingX add(TextView view){ + if(!timingViews.contains(view)){ + timingViews.add(view); + } + return sTimingX; + } + + /** + * 移除不需要计时的 view + * @param view + * @return + */ + public TimingX remove(TextView view){ + timingViews.remove(view); + return sTimingX; + } + + /** + * 开始计时 + */ + public void start(){ + if(sStatus == TimingEnum.STOP.val){ + sStatus = TimingEnum.START.val; + sHandler.sendEmptyMessageDelayed(sStatus, 1000); + } + } + + /** + * 停止计时 + */ + public void stop(){ + if(sStatus == TimingEnum.START.val){ + sStatus = TimingEnum.STOP.val; + sHandler.removeMessages(TimingEnum.START.val); + sHandler.sendEmptyMessage(sStatus); + } + } + + /** + * 销毁 handler + */ + public void destroy(){ + sStatus = TimingEnum.STOP.val; + sSecond = 0; + sHandler.removeMessages(TimingEnum.START.val); + timingViews.clear(); + } + + /** + * 将秒转化为分秒的形式(00:00) + * @param second + * @return + */ + public static String format(int second) { + StringBuilder sb = new StringBuilder(); + int minutes = second / 60; + int sec = second % 60; + if(minutes < 10){ + sb.append(0); + } + sb.append(minutes); + sb.append(":"); + if(sec < 10){ + sb.append(0); + } + sb.append(sec); + return sb.toString(); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ToastUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ToastUtils.java new file mode 100644 index 0000000..5b03d72 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ToastUtils.java @@ -0,0 +1,37 @@ +package com.dahe.mylibrary.utils; + +import android.content.Context; +import android.text.TextUtils; +import android.widget.Toast; + +/** + * Created by Administrator on 2017/11/28 0028. + */ + +public class ToastUtils { + public static Toast mToast = null; + + public static void showToast(Context mContext, String message) { + if (!TextUtils.isEmpty(message)) { + +// if ( mToast != null) { +// mToast.cancel(); +// } +// mToast = Toast.makeText(mContext, message, Toast.LENGTH_SHORT); +// mToast.show(); + + if (mToast == null) { + mToast = Toast.makeText(mContext, message, Toast.LENGTH_SHORT); + } else { + mToast.setText(message); + } + mToast.show(); + } + } + + public static void cancelToast(){ + if (mToast!=null) + mToast.cancel(); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/wapper/SelectSimAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/wapper/SelectSimAdapter.java new file mode 100644 index 0000000..6302e3e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/wapper/SelectSimAdapter.java @@ -0,0 +1,37 @@ +package com.dahe.mylibrary.wapper; + +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; + +import java.util.List; + +public class SelectSimAdapter extends BaseQuickAdapter { + private String selectString = ""; + + + public SelectSimAdapter(int layoutResId, @Nullable List data, String selectString) { + super(R.layout.item_select, data); + this.selectString = selectString; + } + + @Override + protected void convert(BaseViewHolder helper, String item) { + helper.setText(R.id.tv_content,item); + TextView tv = helper.getView(R.id.tv_content); + if (item.equals(selectString)){ + tv.setSelected(true); + }else{ + tv.setSelected(false); + } + + } + + public void setSelect(String selectString){ + this.selectString = selectString; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/AttachButton.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/AttachButton.java new file mode 100644 index 0000000..6051134 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/AttachButton.java @@ -0,0 +1,157 @@ +package com.dahe.mylibrary.weight; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.BounceInterpolator; + +import androidx.annotation.Nullable; + +import com.dahe.mylibrary.R; +/** + * 自定义View实现拖动并自动吸边效果 + *

+ * 处理滑动和贴边 {@link #onTouchEvent(MotionEvent)} + * 处理事件分发 {@link #dispatchTouchEvent(MotionEvent)} + *

+ * + * @attr customIsAttach //是否需要自动吸边 + * @attr customIsDrag //是否可拖曳 + */ +public class AttachButton extends View { + private float mLastRawX; + private float mLastRawY; + private final String TAG = "AttachButton"; + private boolean isDrug = false; + private int mRootMeasuredWidth = 0; + private int mRootMeasuredHeight = 0; + private int mRootTopY = 0; + private boolean customIsAttach; + private boolean customIsDrag; + + public AttachButton(Context context) { + this(context, null); + } + + public AttachButton(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public AttachButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initAttrs(context, attrs); + } + + /** + * 初始化自定义属性 + */ + private void initAttrs(Context context, AttributeSet attrs) { + TypedArray mTypedAttay = context.obtainStyledAttributes(attrs, R.styleable.AttachButton); + customIsAttach = mTypedAttay.getBoolean(R.styleable.AttachButton_customIsAttach, true); + customIsDrag = mTypedAttay.getBoolean(R.styleable.AttachButton_customIsDrag, true); + mTypedAttay.recycle(); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + super.dispatchTouchEvent(event); + return true; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + //判断是否需要滑动 + if (customIsDrag) { + //当前手指的坐标 + float mRawX = ev.getRawX(); + float mRawY = ev.getRawY(); + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN://手指按下 + isDrug = false; + //记录按下的位置 + mLastRawX = mRawX; + mLastRawY = mRawY; + ViewGroup mViewGroup = (ViewGroup) getParent(); + if (mViewGroup != null) { + int[] location = new int[2]; + mViewGroup.getLocationInWindow(location); + //获取父布局的高度 + mRootMeasuredHeight = mViewGroup.getMeasuredHeight(); + mRootMeasuredWidth = mViewGroup.getMeasuredWidth(); + //获取父布局顶点的坐标 + mRootTopY = location[1]; + } + break; + case MotionEvent.ACTION_MOVE://手指滑动 + if (mRawX >= 0 && mRawX <= mRootMeasuredWidth && mRawY >= mRootTopY && mRawY <= (mRootMeasuredHeight + mRootTopY)) { + //手指X轴滑动距离 + float differenceValueX = mRawX - mLastRawX; + //手指Y轴滑动距离 + float differenceValueY = mRawY - mLastRawY; + //判断是否为拖动操作 + if (!isDrug) { + if (Math.sqrt(differenceValueX * differenceValueX + differenceValueY * differenceValueY) < 2) { + isDrug = false; + } else { + isDrug = true; + } + } + //获取手指按下的距离与控件本身X轴的距离 + float ownX = getX(); + //获取手指按下的距离与控件本身Y轴的距离 + float ownY = getY(); + //理论中X轴拖动的距离 + float endX = ownX + differenceValueX; + //理论中Y轴拖动的距离 + float endY = ownY + differenceValueY; + //X轴可以拖动的最大距离 + float maxX = mRootMeasuredWidth - getWidth(); + //Y轴可以拖动的最大距离 + float maxY = mRootMeasuredHeight - getHeight(); + //X轴边界限制 + endX = endX < 0 ? 0 : endX > maxX ? maxX : endX; + //Y轴边界限制 + endY = endY < 0 ? 0 : endY > maxY ? maxY : endY; + //开始移动 + setX(endX); + setY(endY); + //记录位置 + mLastRawX = mRawX; + mLastRawY = mRawY; + } + + break; + case MotionEvent.ACTION_UP://手指离开 + //根据自定义属性判断是否需要贴边 + if (customIsAttach) { + //判断是否为点击事件 + if (isDrug) { + float center = mRootMeasuredWidth / 2; + //自动贴边 + if (mLastRawX <= center) { + //向左贴边 + AttachButton.this.animate() + .setInterpolator(new BounceInterpolator()) + .setDuration(500) + .x(0) + .start(); + } else { + //向右贴边 + AttachButton.this.animate() + .setInterpolator(new BounceInterpolator()) + .setDuration(500) + .x(mRootMeasuredWidth - getWidth()) + .start(); + } + } + } + break; + } + } + //是否拦截事件 + return isDrug ? isDrug : super.onTouchEvent(ev); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/FullyGridLayoutManager.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/FullyGridLayoutManager.java new file mode 100644 index 0000000..ed6da0e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/FullyGridLayoutManager.java @@ -0,0 +1,104 @@ +package com.dahe.mylibrary.weight; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +/** + * author:luck + * project:PictureSelector + * package:com.luck.picture.ui + * email:893855882@qq.com + * data:16/12/31 + */ + +public class FullyGridLayoutManager extends GridLayoutManager { + public FullyGridLayoutManager(Context context, int spanCount) { + super(context, spanCount); + } + + public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { + super(context, spanCount, orientation, reverseLayout); + } + + private int[] mMeasuredDimension = new int[2]; + + @Override + public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { + final int widthMode = View.MeasureSpec.getMode(widthSpec); + final int heightMode = View.MeasureSpec.getMode(heightSpec); + final int widthSize = View.MeasureSpec.getSize(widthSpec); + final int heightSize = View.MeasureSpec.getSize(heightSpec); + + int width = 0; + int height = 0; + int count = getItemCount(); + int span = getSpanCount(); + for (int i = 0; i < count; i++) { + measureScrapChild(recycler, i, + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), + mMeasuredDimension); + + if (getOrientation() == HORIZONTAL) { + if (i % span == 0) { + width = width + mMeasuredDimension[0]; + } + if (i == 0) { + height = mMeasuredDimension[1]; + } + } else { + if (i % span == 0) { + height = height + mMeasuredDimension[1]; + } + if (i == 0) { + width = mMeasuredDimension[0]; + } + } + } + + switch (widthMode) { + case View.MeasureSpec.EXACTLY: + width = widthSize; + case View.MeasureSpec.AT_MOST: + case View.MeasureSpec.UNSPECIFIED: + } + + switch (heightMode) { + case View.MeasureSpec.EXACTLY: + height = heightSize; + case View.MeasureSpec.AT_MOST: + case View.MeasureSpec.UNSPECIFIED: + } + + setMeasuredDimension(width, height); + } + + final RecyclerView.State mState = new RecyclerView.State(); + + private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, + int heightSpec, int[] measuredDimension) { + int itemCount = mState.getItemCount(); + if (position < itemCount) { + try { + View view = recycler.getViewForPosition(0); + if (view != null) { + RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); + int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, + getPaddingLeft() + getPaddingRight(), p.width); + int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, + getPaddingTop() + getPaddingBottom(), p.height); + view.measure(childWidthSpec, childHeightSpec); + measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; + measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; + recycler.recycleView(view); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideCircleWithBorder.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideCircleWithBorder.java new file mode 100644 index 0000000..24f7cf3 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideCircleWithBorder.java @@ -0,0 +1,67 @@ +package com.dahe.mylibrary.weight; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; + +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; + +import java.security.MessageDigest; + +/** + * 加载圆形头像带白色边框 + */ +public class GlideCircleWithBorder extends BitmapTransformation { + private Paint mBorderPaint; + private float mBorderWidth; + + public GlideCircleWithBorder(Context context, int borderWidth, int borderColor) { + mBorderWidth = Resources.getSystem().getDisplayMetrics().density * borderWidth; + mBorderPaint = new Paint(); + mBorderPaint.setDither(true); + mBorderPaint.setAntiAlias(true); + mBorderPaint.setColor(borderColor); + mBorderPaint.setStyle(Paint.Style.STROKE); + mBorderPaint.setStrokeWidth(mBorderWidth); + } + + protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { + return circleCrop(pool, toTransform); + } + + private Bitmap circleCrop(BitmapPool pool, Bitmap source) { + if (source == null) { + return null; + } + int size = (int) (Math.min(source.getWidth(), source.getHeight()) - (mBorderWidth / 2)); + int x = (source.getWidth() - size) / 2; + int y = (source.getHeight() - size) / 2; + Bitmap squared = Bitmap.createBitmap(source, x, y, size, size); + Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888); + if (result == null) { + result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); + } + //创建画笔 画布 手动描绘边框 + Canvas canvas = new Canvas(result); + Paint paint = new Paint(); + paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); + paint.setAntiAlias(true); + float r = size / 2f; + canvas.drawCircle(r, r, r, paint); + if (mBorderPaint != null) { + float borderRadius = r - mBorderWidth / 2; + canvas.drawCircle(r, r, borderRadius, mBorderPaint); + } + return result; + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) { + + } + +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/MovedImageButton.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MovedImageButton.java new file mode 100644 index 0000000..114c7f2 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MovedImageButton.java @@ -0,0 +1,91 @@ +package com.dahe.mylibrary.weight; + +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.MotionEvent; +import android.view.animation.OvershootInterpolator; + + +public class MovedImageButton extends androidx.appcompat.widget.AppCompatImageButton { + private int lastX; + private int lastY; + private float screenWidth; + + public MovedImageButton(Context context) { + super(context); + } + + public MovedImageButton(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public MovedImageButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + DisplayMetrics dm = getResources().getDisplayMetrics(); + screenWidth = dm.widthPixels; + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + int x = (int) event.getX(); + int y = (int) event.getY(); + switch (event.getAction()){ + case MotionEvent.ACTION_DOWN: + lastX = x; + lastY = y; + break; + case MotionEvent.ACTION_MOVE: + int offsetX = x-lastX; + int offsetY = y-lastY; + //第一种方法 +// layout(getLeft()+offsetX, +// getTop()+offsetY, +// getRight()+offsetX, +// getBottom()+offsetY); + //第二种方法 + offsetLeftAndRight(offsetX); + offsetTopAndBottom(offsetY); + break; + case MotionEvent.ACTION_UP: + adsorbAnim(event.getRawX(), event.getRawY()); + break; + } + return super.onTouchEvent(event); + } + + private void adsorbAnim(float rawX, float rawY){ + //靠顶吸附 +// if (rawY <= BaseUtils.dip2px(getContext(),200)){//注意rawY包含了标题栏的高 +// animate().setDuration(400) +// .setInterpolator(new OvershootInterpolator()) +// .yBy(-getY()-getHeight()/2.0f) +// .start(); +// }else + + if (rawX >= screenWidth/2){//靠右吸附 + animate().setDuration(400) + .setInterpolator(new OvershootInterpolator()) + .xBy(screenWidth - getX() - getWidth()) + .start(); + }else {//靠左吸附 + ObjectAnimator animator = ObjectAnimator.ofFloat(this, "x", getX(), 0); + animator.setInterpolator(new OvershootInterpolator()); + animator.setDuration(400); + animator.start(); + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/MySlideBar.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MySlideBar.java new file mode 100644 index 0000000..7bd8b59 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MySlideBar.java @@ -0,0 +1,191 @@ +package com.dahe.mylibrary.weight; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.utils.ToastUtils; + +public class MySlideBar extends RelativeLayout implements View.OnClickListener { + + private boolean canSelect; + private TextView tvT1; + private TextView tvT2; + private TextView tvT3; + private TextView tvT4; + private TextView tvC1; + private TextView tvC2; + private TextView tvC3; + private TextView tvC4; + private View view1; + private View view2; + + public MySlideBar(Context context) { + this(context, null); + } + + public MySlideBar(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public MySlideBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + this(context, attrs, 0, 0); + } + + public MySlideBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context, attrs); + + + } + + private void init(Context context, AttributeSet attrs) { + View inflate = View.inflate(context, R.layout.view_slide_bar, this); + tvT1 = (TextView) findViewById(R.id.tv_title1); + tvT2 = (TextView) findViewById(R.id.tv_title2); + tvT3 = (TextView) findViewById(R.id.tv_title3); + tvT4 = (TextView) findViewById(R.id.tv_title4); + tvC1 = (TextView) findViewById(R.id.tv_conten1); + tvC2 = (TextView) findViewById(R.id.tv_content2); + tvC3 = (TextView) findViewById(R.id.tv_content3); + tvC4 = (TextView) findViewById(R.id.tv_content4); + view1 = (View) findViewById(R.id.view1); + view2 = (View) findViewById(R.id.view2); + LinearLayout ll1 = (LinearLayout) findViewById(R.id.ll1); + LinearLayout ll2 = (LinearLayout) findViewById(R.id.ll2); + LinearLayout ll3 = (LinearLayout) findViewById(R.id.ll3); + LinearLayout ll4 = (LinearLayout) findViewById(R.id.ll4); + ll1.setOnClickListener(this); + ll2.setOnClickListener(this); + ll3.setOnClickListener(this); + ll4.setOnClickListener(this); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MySlideBar); + int integer = a.getInteger(R.styleable.MySlideBar_proress, -1); + canSelect = a.getBoolean(R.styleable.MySlideBar_canSelect, false); + changeProress(integer,true); + + a.recycle(); + } + + @Override + public void onClick(View v) { + if (canSelect) { + int id = v.getId(); + if (id == R.id.ll1) { + changeProress(0,canSelect); + } else if (id == R.id.ll2) { + changeProress(1,canSelect); + } else if (id == R.id.ll3) { + changeProress(2,canSelect); + } else if (id == R.id.ll4) { + changeProress(3,canSelect); + } + } + + } + + public void setProress(int proress){ + changeProress(proress,canSelect); + } + + private void changeProress(int integer,boolean canSelect){ + if (listener!=null&&canSelect){ + listener.onChange(integer); + } + if (0 == integer) { + tvT1.setBackgroundResource(R.drawable.select_slide_title); + tvT2.setBackgroundResource(R.drawable.select_slide_title); + tvT3.setBackgroundResource(R.drawable.select_slide_title); + tvT4.setBackgroundResource(R.drawable.select_slide_title); + tvT1.setText("1"); + tvT2.setText("2"); + tvT3.setText("3"); + tvT4.setText("4"); + tvT1.setSelected(true); + tvT2.setSelected(false); + tvT3.setSelected(false); + tvT4.setSelected(false); + + view1.setBackgroundResource(R.color.color_d5); + view2.setBackgroundResource(R.color.color_d5); + + tvC1.setTextColor(getResources().getColor(R.color.mine_top_bg)); + tvC2.setTextColor(getResources().getColor(R.color.color_9)); + tvC3.setTextColor(getResources().getColor(R.color.color_9)); + tvC4.setTextColor(getResources().getColor(R.color.color_9)); + } else if (1 == integer) { + tvT1.setBackgroundResource(R.drawable.ok); + tvT2.setBackgroundResource(R.drawable.select_slide_title); + tvT3.setBackgroundResource(R.drawable.select_slide_title); + tvT4.setBackgroundResource(R.drawable.select_slide_title); + tvT1.setText(""); + tvT2.setText("2"); + tvT3.setText("3"); + tvT4.setText("4"); + tvT2.setSelected(true); + tvT3.setSelected(false); + tvT4.setSelected(false); + + view1.setBackgroundResource(R.color.mine_top_bg); + view2.setBackgroundResource(R.color.color_d5); + + tvC1.setTextColor(getResources().getColor(R.color.black)); + tvC2.setTextColor(getResources().getColor(R.color.mine_top_bg)); + tvC3.setTextColor(getResources().getColor(R.color.color_9)); + tvC4.setTextColor(getResources().getColor(R.color.color_9)); + } else if (2 == integer) { + tvT1.setBackgroundResource(R.drawable.ok); + tvT2.setBackgroundResource(R.drawable.ok); + tvT3.setBackgroundResource(R.drawable.select_slide_title); + tvT4.setBackgroundResource(R.drawable.select_slide_title); + tvT1.setText(""); + tvT2.setText(""); + tvT3.setText("3"); + tvT4.setText("4"); + tvT3.setSelected(true); + tvT4.setSelected(false); + + view1.setBackgroundResource(R.color.mine_top_bg); + view2.setBackgroundResource(R.color.mine_top_bg); + + tvC1.setTextColor(getResources().getColor(R.color.black)); + tvC2.setTextColor(getResources().getColor(R.color.black)); + tvC3.setTextColor(getResources().getColor(R.color.mine_top_bg)); + tvC4.setTextColor(getResources().getColor(R.color.color_9)); + } else if (3 == integer) { + tvT1.setBackgroundResource(R.drawable.ok); + tvT2.setBackgroundResource(R.drawable.ok); + tvT3.setBackgroundResource(R.drawable.ok); + tvT4.setBackgroundResource(R.drawable.select_slide_title); + tvT1.setText(""); + tvT2.setText(""); + tvT3.setText(""); + tvT4.setText("4"); + tvT4.setSelected(true); + + tvC1.setTextColor(getResources().getColor(R.color.black)); + tvC2.setTextColor(getResources().getColor(R.color.black)); + tvC3.setTextColor(getResources().getColor(R.color.black)); + tvC4.setTextColor(getResources().getColor(R.color.mine_top_bg)); + } + } + + + public interface OnChangeListener{ + void onChange(int progress); + } + + private OnChangeListener listener; + public void setOnChangeListener(OnChangeListener listener){ + this.listener = listener; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/SideBar.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SideBar.java new file mode 100644 index 0000000..1b1e471 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SideBar.java @@ -0,0 +1,130 @@ +package com.dahe.mylibrary.weight; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.graphics.drawable.ColorDrawable; +import android.os.Vibrator; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.TextView; + +import com.dahe.mylibrary.R; + +public class SideBar extends View { + // 触摸事件 + private OnTouchingLetterChangedListener onTouchingLetterChangedListener; + public static String[] b = { "A", "B", "C", "D", "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "#" }; + private int choose = -1; + private Paint paint = new Paint(); + + private TextView mTextDialog; + + /** + * 为SideBar设置显示字母的TextView + * @param textDialog + */ + public void setTextView(TextView textDialog) { + this.mTextDialog = textDialog; + } + + + public SideBar(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public SideBar(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SideBar(Context context) { + super(context); + } + + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + int height = getHeight(); + int width = getWidth(); + int singleHeight = height / b.length;// 获取每一个字母的高度 + + for (int i = 0; i < b.length; i++) { + paint.setColor(Color.rgb(33, 65, 98)); + // paint.setColor(Color.WHITE); + paint.setTypeface(Typeface.DEFAULT_BOLD); + paint.setAntiAlias(true); + paint.setTextSize(20); + if (i == choose) {// 选中的状态 + paint.setColor(Color.parseColor("#999999")); + paint.setFakeBoldText(true); + } + // x坐标等于中间-字符串宽度的一半 + float xPos = width / 2 - paint.measureText(b[i]) / 2; + float yPos = singleHeight * i + singleHeight; + canvas.drawText(b[i], xPos, yPos, paint); + paint.reset(); + } + + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + final int action = event.getAction(); + final float y = event.getY(); + final int oldChoose = choose; + final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener; + final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数 + + switch (action) { + case MotionEvent.ACTION_UP: + setBackground(new ColorDrawable(0x00000000)); + choose = -1;// + invalidate(); + if (mTextDialog != null) { + mTextDialog.setVisibility(View.INVISIBLE); + } + break; + + default: +// setBackgroundResource(R.drawable.sidebar_background); + if (oldChoose != c) { + if (c >= 0 && c < b.length) { + if (listener != null) { + listener.onTouchingLetterChanged(b[c]); + } + if (mTextDialog != null) { + mTextDialog.setText(b[c]); + mTextDialog.setVisibility(View.VISIBLE); + } + + choose = c; + invalidate(); + } + } + + break; + } + return true; + } + + /** + * 触摸事件 + * @param onTouchingLetterChangedListener + */ + public void setOnTouchingLetterChangedListener( + OnTouchingLetterChangedListener onTouchingLetterChangedListener) { + this.onTouchingLetterChangedListener = onTouchingLetterChangedListener; + } + + /** + * 回调接口 + */ + public interface OnTouchingLetterChangedListener { + void onTouchingLetterChanged(String s); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/SwitchView.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SwitchView.java new file mode 100644 index 0000000..93fbb50 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SwitchView.java @@ -0,0 +1,508 @@ +package com.dahe.mylibrary.weight; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RadialGradient; +import android.graphics.RectF; +import android.graphics.Shader; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AccelerateInterpolator; + +import com.dahe.mylibrary.R; + + +/** + * hei hei hei + */ +public class SwitchView extends View { + + private static final int STATE_SWITCH_ON = 4; + private static final int STATE_SWITCH_ON2 = 3; + private static final int STATE_SWITCH_OFF2 = 2; + private static final int STATE_SWITCH_OFF = 1; + + private final AccelerateInterpolator interpolator = new AccelerateInterpolator(2); + private final Paint paint = new Paint(); + private final Path sPath = new Path(); + private final Path bPath = new Path(); + private final RectF bRectF = new RectF(); + private float sAnim, bAnim; + private RadialGradient shadowGradient; + + protected float ratioAspect = 0.68f; // (0,1] + protected float animationSpeed = 0.1f; // (0,1] + + private int state; + private int lastState; + private boolean isCanVisibleDrawing = false; + private OnClickListener mOnClickListener; + protected int colorPrimary; + protected int colorPrimaryDark; + protected int colorOff; + protected int colorOffDark; + protected int colorShadow; + protected boolean hasShadow; + protected boolean isOpened; + protected boolean canEnable; + + private float sRight; + private float sCenterX, sCenterY; + private float sScale; + + private float bOffset; + private float bRadius, bStrokeWidth; + private float bWidth; + private float bLeft; + private float bRight; + private float bOnLeftX, bOn2LeftX, bOff2LeftX, bOffLeftX; + + private float shadowReservedHeight; + + public SwitchView(Context context) { + this(context, null); + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public SwitchView(Context context, AttributeSet attrs) { + super(context, attrs); + setLayerType(LAYER_TYPE_SOFTWARE, null); + + final int DEFAULT_COLOR_PRIMARY = 0xFF4BD763; + final int DEFAULT_COLOR_PRIMARY_DARK = 0xFF3AC652; + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwitchView); + colorPrimary = a.getColor(R.styleable.SwitchView_primaryColor, DEFAULT_COLOR_PRIMARY); + colorPrimaryDark = a.getColor(R.styleable.SwitchView_primaryColorDark, DEFAULT_COLOR_PRIMARY_DARK); + colorOff = a.getColor(R.styleable.SwitchView_offColor, 0xFFE3E3E3); + colorOffDark = a.getColor(R.styleable.SwitchView_offColorDark, 0xFFBFBFBF); + colorShadow = a.getColor(R.styleable.SwitchView_shadowColor, 0xFF333333); + ratioAspect = a.getFloat(R.styleable.SwitchView_ratioAspect, 0.68f); + hasShadow = a.getBoolean(R.styleable.SwitchView_hasShadow, true); + isOpened = a.getBoolean(R.styleable.SwitchView_isOpened, false); + canEnable = a.getBoolean(R.styleable.SwitchView_canEnable, true); + state = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + lastState = state; + a.recycle(); + + if (colorPrimary == DEFAULT_COLOR_PRIMARY && colorPrimaryDark == DEFAULT_COLOR_PRIMARY_DARK) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + TypedValue primaryColorTypedValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.colorPrimary, primaryColorTypedValue, true); + if (primaryColorTypedValue.data > 0) colorPrimary = primaryColorTypedValue.data; + TypedValue primaryColorDarkTypedValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.colorPrimaryDark, primaryColorDarkTypedValue, true); + if (primaryColorDarkTypedValue.data > 0) + colorPrimaryDark = primaryColorDarkTypedValue.data; + } + } catch (Exception ignore) { + } + } + } + + public void setColor(int newColorPrimary, int newColorPrimaryDark) { + setColor(newColorPrimary, newColorPrimaryDark, colorOff, colorOffDark); + } + + public void setColor(int newColorPrimary, int newColorPrimaryDark, int newColorOff, int newColorOffDark) { + setColor(newColorPrimary, newColorPrimaryDark, newColorOff, newColorOffDark, colorShadow); + } + + public void setColor(int newColorPrimary, int newColorPrimaryDark, int newColorOff, int newColorOffDark, int newColorShadow) { + colorPrimary = newColorPrimary; + colorPrimaryDark = newColorPrimaryDark; + colorOff = newColorOff; + colorOffDark = newColorOffDark; + colorShadow = newColorShadow; + invalidate(); + } + + public void setCanEnable(boolean canEnable){ + this.canEnable = canEnable; + invalidate(); + } + + public void setShadow(boolean shadow) { + hasShadow = shadow; + invalidate(); + } + + public boolean isOpened() { + return isOpened; + } + + public void setOpened(boolean isOpened) { + int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + if (wishState == state) { + return; + } + refreshState(wishState); + } + + public void toggleSwitch(boolean isOpened) { + int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + if (wishState == state) { + return; + } + if ((wishState == STATE_SWITCH_ON && (state == STATE_SWITCH_OFF || state == STATE_SWITCH_OFF2)) + || (wishState == STATE_SWITCH_OFF && (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2))) { + sAnim = 1; + } + bAnim = 1; + refreshState(wishState); + } + + private void refreshState(int newState) { + if (!isOpened && newState == STATE_SWITCH_ON) { + isOpened = true; + } else if (isOpened && newState == STATE_SWITCH_OFF) { + isOpened = false; + } + lastState = state; + state = newState; + postInvalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int resultWidth; + if (widthMode == MeasureSpec.EXACTLY) { + resultWidth = widthSize; + } else { + resultWidth = (int) (56 * getResources().getDisplayMetrics().density + 0.5f) + + getPaddingLeft() + getPaddingRight(); + if (widthMode == MeasureSpec.AT_MOST) { + resultWidth = Math.min(resultWidth, widthSize); + } + } + + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int resultHeight; + if (heightMode == MeasureSpec.EXACTLY) { + resultHeight = heightSize; + } else { + resultHeight = (int) (resultWidth * ratioAspect) + getPaddingTop() + getPaddingBottom(); + if (heightMode == MeasureSpec.AT_MOST) { + resultHeight = Math.min(resultHeight, heightSize); + } + } + setMeasuredDimension(resultWidth, resultHeight); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + isCanVisibleDrawing = w > getPaddingLeft() + getPaddingRight() && h > getPaddingTop() + getPaddingBottom(); + + if (isCanVisibleDrawing) { + int actuallyDrawingAreaWidth = w - getPaddingLeft() - getPaddingRight(); + int actuallyDrawingAreaHeight = h - getPaddingTop() - getPaddingBottom(); + + int actuallyDrawingAreaLeft; + int actuallyDrawingAreaRight; + int actuallyDrawingAreaTop; + int actuallyDrawingAreaBottom; + if (actuallyDrawingAreaWidth * ratioAspect < actuallyDrawingAreaHeight) { + actuallyDrawingAreaLeft = getPaddingLeft(); + actuallyDrawingAreaRight = w - getPaddingRight(); + int heightExtraSize = (int) (actuallyDrawingAreaHeight - actuallyDrawingAreaWidth * ratioAspect); + actuallyDrawingAreaTop = getPaddingTop() + heightExtraSize / 2; + actuallyDrawingAreaBottom = getHeight() - getPaddingBottom() - heightExtraSize / 2; + } else { + int widthExtraSize = (int) (actuallyDrawingAreaWidth - actuallyDrawingAreaHeight / ratioAspect); + actuallyDrawingAreaLeft = getPaddingLeft() + widthExtraSize / 2; + actuallyDrawingAreaRight = getWidth() - getPaddingRight() - widthExtraSize / 2; + actuallyDrawingAreaTop = getPaddingTop(); + actuallyDrawingAreaBottom = getHeight() - getPaddingBottom(); + } + + shadowReservedHeight = (int) ((actuallyDrawingAreaBottom - actuallyDrawingAreaTop) * 0.07f); + float sLeft = actuallyDrawingAreaLeft; + float sTop = actuallyDrawingAreaTop + shadowReservedHeight; + sRight = actuallyDrawingAreaRight; + float sBottom = actuallyDrawingAreaBottom - shadowReservedHeight; + + float sHeight = sBottom - sTop; + sCenterX = (sRight + sLeft) / 2; + sCenterY = (sBottom + sTop) / 2; + + bLeft = sLeft; + bWidth = sBottom - sTop; + bRight = sLeft + bWidth; + final float halfHeightOfS = bWidth / 2; // OfB + bRadius = halfHeightOfS * 0.95f; + bOffset = bRadius * 0.2f; // offset of switching + bStrokeWidth = (halfHeightOfS - bRadius) * 2; + bOnLeftX = sRight - bWidth; + bOn2LeftX = bOnLeftX - bOffset; + bOffLeftX = sLeft; + bOff2LeftX = bOffLeftX + bOffset; + sScale = 1 - bStrokeWidth / sHeight; + + sPath.reset(); + RectF sRectF = new RectF(); + sRectF.top = sTop; + sRectF.bottom = sBottom; + sRectF.left = sLeft; + sRectF.right = sLeft + sHeight; + sPath.arcTo(sRectF, 90, 180); + sRectF.left = sRight - sHeight; + sRectF.right = sRight; + sPath.arcTo(sRectF, 270, 180); + sPath.close(); + + bRectF.left = bLeft; + bRectF.right = bRight; + bRectF.top = sTop + bStrokeWidth / 2; // bTop = sTop + bRectF.bottom = sBottom - bStrokeWidth / 2; // bBottom = sBottom + float bCenterX = (bRight + bLeft) / 2; + float bCenterY = (sBottom + sTop) / 2; + + int red = colorShadow >> 16 & 0xFF; + int green = colorShadow >> 8 & 0xFF; + int blue = colorShadow & 0xFF; + shadowGradient = new RadialGradient(bCenterX, bCenterY, bRadius, Color.argb(200, red, green, blue), + Color.argb(25, red, green, blue), Shader.TileMode.CLAMP); + } + } + + private void calcBPath(float percent) { + bPath.reset(); + bRectF.left = bLeft + bStrokeWidth / 2; + bRectF.right = bRight - bStrokeWidth / 2; + bPath.arcTo(bRectF, 90, 180); + bRectF.left = bLeft + percent * bOffset + bStrokeWidth / 2; + bRectF.right = bRight + percent * bOffset - bStrokeWidth / 2; + bPath.arcTo(bRectF, 270, 180); + bPath.close(); + } + + private float calcBTranslate(float percent) { + float result = 0; + switch (state - lastState) { + case 1: + if (state == STATE_SWITCH_OFF2) { + result = bOffLeftX; // off -> off2 + } else if (state == STATE_SWITCH_ON) { + result = bOnLeftX - (bOnLeftX - bOn2LeftX) * percent; // on2 -> on + } + break; + case 2: + if (state == STATE_SWITCH_ON) { + result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off2 -> on + } else if (state == STATE_SWITCH_ON2) { + result = bOn2LeftX - (bOn2LeftX - bOffLeftX) * percent; // off -> on2 + } + break; + case 3: + result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off -> on + break; + case -1: + if (state == STATE_SWITCH_ON2) { + result = bOn2LeftX + (bOnLeftX - bOn2LeftX) * percent; // on -> on2 + } else if (state == STATE_SWITCH_OFF) { + result = bOffLeftX; // off2 -> off + } + break; + case -2: + if (state == STATE_SWITCH_OFF) { + result = bOffLeftX + (bOn2LeftX - bOffLeftX) * percent; // on2 -> off + } else if (state == STATE_SWITCH_OFF2) { + result = bOff2LeftX + (bOnLeftX - bOff2LeftX) * percent; // on -> off2 + } + break; + case -3: + result = bOffLeftX + (bOnLeftX - bOffLeftX) * percent; // on -> off + break; + default: // init + case 0: + if (state == STATE_SWITCH_OFF) { + result = bOffLeftX; // off -> off + } else if (state == STATE_SWITCH_ON) { + result = bOnLeftX; // on -> on + } + break; + } + return result - bOffLeftX; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (!isCanVisibleDrawing) return; + + paint.setAntiAlias(true); + final boolean isOn = (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2); + // Draw background + paint.setStyle(Paint.Style.FILL); + paint.setColor(isOn ? colorPrimary : colorOff); + canvas.drawPath(sPath, paint); + + sAnim = sAnim - animationSpeed > 0 ? sAnim - animationSpeed : 0; + bAnim = bAnim - animationSpeed > 0 ? bAnim - animationSpeed : 0; + + final float dsAnim = interpolator.getInterpolation(sAnim); + final float dbAnim = interpolator.getInterpolation(bAnim); + // Draw background animation + final float scale = sScale * (isOn ? dsAnim : 1 - dsAnim); + final float scaleOffset = (sRight - sCenterX - bRadius) * (isOn ? 1 - dsAnim : dsAnim); + canvas.save(); + canvas.scale(scale, scale, sCenterX + scaleOffset, sCenterY); + paint.setColor(0xFFFFFFFF); + canvas.drawPath(sPath, paint); + canvas.restore(); + // To prepare center bar path + canvas.save(); + canvas.translate(calcBTranslate(dbAnim), shadowReservedHeight); + final boolean isState2 = (state == STATE_SWITCH_ON2 || state == STATE_SWITCH_OFF2); + calcBPath(isState2 ? 1 - dbAnim : dbAnim); + // Use center bar path to draw shadow + if (hasShadow) { + paint.setStyle(Paint.Style.FILL); + paint.setShader(shadowGradient); + canvas.drawPath(bPath, paint); + paint.setShader(null); + } + canvas.translate(0, -shadowReservedHeight); + // draw bar + canvas.scale(0.98f, 0.98f, bWidth / 2, bWidth / 2); + paint.setStyle(Paint.Style.FILL); + paint.setColor(0xffffffff); + canvas.drawPath(bPath, paint); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(bStrokeWidth * 0.5f); + paint.setColor(isOn ? colorPrimaryDark : colorOffDark); + canvas.drawPath(bPath, paint); + canvas.restore(); + + paint.reset(); + if (sAnim > 0 || bAnim > 0) invalidate(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (!canEnable) + return super.onTouchEvent(event); + if ((state == STATE_SWITCH_ON || state == STATE_SWITCH_OFF) && (sAnim * bAnim == 0)) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + return true; + case MotionEvent.ACTION_UP: + lastState = state; + + bAnim = 1; + if (state == STATE_SWITCH_OFF) { + refreshState(STATE_SWITCH_OFF2); + listener.toggleToOn(this); + } else if (state == STATE_SWITCH_ON) { + refreshState(STATE_SWITCH_ON2); + listener.toggleToOff(this); + } + + if (mOnClickListener != null) { + mOnClickListener.onClick(this); + } + break; + } + } + return super.onTouchEvent(event); + } + + @Override + public void setOnClickListener(OnClickListener l) { + super.setOnClickListener(l); + mOnClickListener = l; + } + + public interface OnStateChangedListener { + void toggleToOn(SwitchView view); + + void toggleToOff(SwitchView view); + } + + private OnStateChangedListener listener = new OnStateChangedListener() { + @Override + public void toggleToOn(SwitchView view) { + toggleSwitch(true); + } + + @Override + public void toggleToOff(SwitchView view) { + toggleSwitch(false); + } + }; + + public void setOnStateChangedListener(OnStateChangedListener listener) { + if (listener == null) throw new IllegalArgumentException("empty listener"); + this.listener = listener; + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.isOpened = isOpened; + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + this.isOpened = ss.isOpened; + this.state = this.isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + invalidate(); + } + + private static final class SavedState extends BaseSavedState { + private boolean isOpened; + + SavedState(Parcelable superState) { + super(superState); + } + + private SavedState(Parcel in) { + super(in); + isOpened = 1 == in.readInt(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(isOpened ? 1 : 0); + } + + // fixed by Night99 https://github.com/g19980115 + @Override + public int describeContents() { + return 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/RadiusDrawable.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/RadiusDrawable.java new file mode 100644 index 0000000..2569625 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/RadiusDrawable.java @@ -0,0 +1,139 @@ +package com.dahe.mylibrary.weight.segmentcontrol; + + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; + +// 圆角 Drawable 每个角的圆半径可以不同 (使用不同半径圆角图形的时候 使用这个类 以防止 系统提供的用 xml 实现的圆角 Drawable 在2.3 上 出现各个角位置错乱) + +/** + * Created by caifangmao on 15/4/22. + */ +public class RadiusDrawable extends Drawable { + + private int topLeftRadius; + private int topRightRadius; + private int bottomLeftRadius; + private int bottomRightRadius; + + private int left; + private int top; + private int right; + private int bottom; + + private final Paint paint; + private final boolean isStroke; + private int strokeWidth = 0; + private int strokeColor = Color.CYAN; + private int fillColor; + + private Path path; + + public RadiusDrawable(boolean isStroke) { + this(0, isStroke); + } + + public RadiusDrawable(int radius, boolean isStroke) { + setRadius(radius); + + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + this.isStroke = isStroke; + } + + public void setStrokeWidth(int width) { + strokeWidth = width; + setBounds(left, top, right, bottom); + } + + public void setStrokeColor(int strokeColor) { + this.strokeColor = strokeColor; + } + + public void setFillColor(int fillColor) { + this.fillColor = fillColor; + } + + public void setRadius(int radius) { + this.topLeftRadius = this.topRightRadius = this.bottomLeftRadius = this.bottomRightRadius = radius; + } + + public void setRadius(int topLeftRadius, int topRightRadius, int bottomLeftRadius, int bottomRightRadius) { + this.topLeftRadius = topLeftRadius; + this.topRightRadius = topRightRadius; + this.bottomLeftRadius = bottomLeftRadius; + this.bottomRightRadius = bottomRightRadius; + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + super.setBounds(left, top, right, bottom); + + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + + if (isStroke) { + int halfStrokeWidth = strokeWidth / 2; + left += halfStrokeWidth; + top += halfStrokeWidth; + right -= halfStrokeWidth; + bottom -= halfStrokeWidth; + } + + path = new Path(); + path.moveTo(left + topLeftRadius, top); + path.lineTo(right - topRightRadius, top); + path.arcTo(new RectF(right - topRightRadius * 2, top, right, top + topRightRadius * 2), + -90, 90); + // path.quadTo(right, top, right, top + topRightRadius); + path.lineTo(right, bottom - bottomRightRadius); + path.arcTo(new RectF(right - bottomRightRadius * 2, bottom - bottomRightRadius * 2, right, + bottom), 0, 90); + // path.quadTo(right, bottom, right - bottomRightRadius, bottom); + path.lineTo(left + bottomLeftRadius, bottom); + path.arcTo(new RectF(left, bottom - bottomLeftRadius * 2, left + bottomLeftRadius * 2, + bottom), 90, 90); + // path.quadTo(left, bottom, left, bottom - bottomLeftRadius); + path.lineTo(left, top + topLeftRadius); + path.arcTo(new RectF(left, top, left + topLeftRadius * 2, top + topLeftRadius * 2), 180, 90); + // path.quadTo(left, top, left + topLeftRadius, top); + path.close(); + } + + @Override + public void draw(Canvas canvas) { + if (fillColor != 0) { + paint.setColor(fillColor); + paint.setStyle(Paint.Style.FILL); + canvas.drawPath(path, paint); + } + + if (strokeWidth > 0) { + paint.setColor(strokeColor); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeJoin(Paint.Join.MITER); + paint.setStrokeWidth(strokeWidth); + canvas.drawPath(path, paint); + } + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(ColorFilter cf) { + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/SegmentControl.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/SegmentControl.java new file mode 100644 index 0000000..a5bf65d --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/SegmentControl.java @@ -0,0 +1,526 @@ +package com.dahe.mylibrary.weight.segmentcontrol; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.Build; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +import com.dahe.mylibrary.R; + + +/** + * Created by 7heaven on 15/4/22. + */ +public class SegmentControl extends View { + + private String[] mTexts; + private Rect[] mCacheBounds; + private Rect[] mTextBounds; + + private RadiusDrawable mBackgroundDrawable; + private RadiusDrawable mSelectedDrawable; + + private int mCurrentIndex; + + private int mTouchSlop; + private boolean inTapRegion; + private float mStartX; + private float mStartY; + private float mCurrentX; + private float mCurrentY; + + private int mHorizonGap; + private int mVerticalGap; + + /** 外边框的width */ + private int mBoundWidth = 4; + /** 内边框的width */ + private int mSeparatorWidth = mBoundWidth / 2; + + private int mSingleChildWidth; + private int mSingleChildHeight; + + private Paint mPaint; + + private int mTextSize; + private ColorStateList mBackgroundColors; + private ColorStateList mTextColors; + private int mCornerRadius; + + private int DEFAULT_SELECTED_COLOR = 0xFF32ADFF; + private int DEFAULT_NORMAL_COLOR = 0xFFFFFFFF; + + private Paint.FontMetrics mCachedFM; + + public enum Direction { + HORIZONTAL(0), VERTICAL(1); + + int value; + + Direction(int v) { + value = v; + } + } + + private Direction mDirection; + + public SegmentControl(Context context) { + this(context, null); + } + + public SegmentControl(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SegmentControl(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SegmentControl); + + String textArray = ta.getString(R.styleable.SegmentControl_texts); + if (textArray != null) { + mTexts = textArray.split("\\|"); + } + + mTextSize = ta.getDimensionPixelSize(R.styleable.SegmentControl_android_textSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics())); + mCornerRadius = ta.getDimensionPixelSize(R.styleable.SegmentControl_cornerRadius, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, context.getResources().getDisplayMetrics())); + mDirection = Direction.values()[ta.getInt(R.styleable.SegmentControl_android_orientation, 0)]; + + mHorizonGap = ta.getDimensionPixelSize(R.styleable.SegmentControl_horizonGap, 0); + mVerticalGap = ta.getDimensionPixelSize(R.styleable.SegmentControl_verticalGap, 0); + + int gap = ta.getDimensionPixelSize(R.styleable.SegmentControl_gaps, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics())); + + if(mHorizonGap == 0) { + mHorizonGap = gap; + } + if(mVerticalGap == 0) { + mVerticalGap = gap; + } + + mBackgroundDrawable = new RadiusDrawable(mCornerRadius, true); + mBackgroundDrawable.setStrokeWidth(2); + + DEFAULT_NORMAL_COLOR = ta.getColor(R.styleable.SegmentControl_normalColor, DEFAULT_NORMAL_COLOR); + DEFAULT_SELECTED_COLOR = ta.getColor(R.styleable.SegmentControl_selectedColor, DEFAULT_SELECTED_COLOR); + + mBackgroundColors = ta.getColorStateList(R.styleable.SegmentControl_backgroundColors); + mTextColors = ta.getColorStateList(R.styleable.SegmentControl_textColors); + if (mBackgroundColors == null) { + mBackgroundColors = new ColorStateList(new int[][]{{android.R.attr.state_selected}, {-android.R.attr.state_selected}}, new int[]{DEFAULT_SELECTED_COLOR, DEFAULT_NORMAL_COLOR}); + } + + if(mTextColors == null){ + mTextColors = new ColorStateList(new int[][]{{android.R.attr.state_selected}, {-android.R.attr.state_selected}}, new int[]{DEFAULT_NORMAL_COLOR, DEFAULT_SELECTED_COLOR}); + } + + mBoundWidth = ta.getDimensionPixelSize(R.styleable.SegmentControl_boundWidth, mBoundWidth); + mSeparatorWidth = ta.getDimensionPixelSize(R.styleable.SegmentControl_separatorWidth, mSeparatorWidth); + + ta.recycle(); + + mBackgroundDrawable = new RadiusDrawable(mCornerRadius, true); + mBackgroundDrawable.setStrokeWidth(mBoundWidth); + mBackgroundDrawable.setStrokeColor(getSelectedBGColor()); + mBackgroundDrawable.setFillColor(getNormalBGColor()); + + if (Build.VERSION.SDK_INT < 16) { + setBackgroundDrawable(mBackgroundDrawable); + } else { + setBackground(mBackgroundDrawable); + } + + mSelectedDrawable = new RadiusDrawable(false); + mSelectedDrawable.setFillColor(getSelectedBGColor()); + + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setTextSize(mTextSize); + mCachedFM = mPaint.getFontMetrics(); + + int touchSlop = 0; + if (context == null) { + touchSlop = ViewConfiguration.getTouchSlop(); + } else { + final ViewConfiguration config = ViewConfiguration.get(context); + touchSlop = config.getScaledTouchSlop(); + } + mTouchSlop = touchSlop * touchSlop; + inTapRegion = false; + } + + public void setText(String... texts) { + mTexts = texts; + if (mTexts != null) { + requestLayout(); + } + } + + /** + * 设置文字颜色 + * + * @param color 需要设置的颜色 + */ + public void setSelectedTextColors(ColorStateList color) { + mTextColors = color; + invalidate(); + } + + /** + * 设置背景颜色 + * + * @param colors 颜色 + */ + public void setColors(ColorStateList colors) { + mBackgroundColors = colors; + + if (mBackgroundDrawable != null) { + mBackgroundDrawable.setStrokeColor(getSelectedBGColor()); + mBackgroundDrawable.setFillColor(getNormalBGColor()); + } + + if (mSelectedDrawable != null) { + mSelectedDrawable.setFillColor(getSelectedBGColor()); + } + + invalidate(); + } + + public void setCornerRadius(int cornerRadius) { + mCornerRadius = cornerRadius; + + if (mBackgroundDrawable != null) { + mBackgroundDrawable.setRadius(cornerRadius); + } + + invalidate(); + } + + public void setDirection(Direction direction) { + Direction tDirection = mDirection; + + mDirection = direction; + + if (tDirection != direction) { + requestLayout(); + invalidate(); + } + } + + public void setTextSize(int textSize_sp) { + setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize_sp); + } + + public void setTextSize(int unit, int textSize) { + mPaint.setTextSize((int) (TypedValue.applyDimension(unit, textSize, getContext().getResources().getDisplayMetrics()))); + + if (textSize != mTextSize) { + mTextSize = textSize; + mCachedFM = mPaint.getFontMetrics(); + + requestLayout(); + } + } + + public void setSelectedIndex(int index) { + mCurrentIndex = index; + + if(mOnSegmentControlClickListener != null) { + mOnSegmentControlClickListener.onSegmentControlClick(index); + } + + invalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + int width = 0; + int height = 0; + + if (mTexts != null && mTexts.length > 0) { + + mSingleChildHeight = 0; + mSingleChildWidth = 0; + + if (mCacheBounds == null || mCacheBounds.length != mTexts.length) { + mCacheBounds = new Rect[mTexts.length]; + } + + if (mTextBounds == null || mTextBounds.length != mTexts.length) { + mTextBounds = new Rect[mTexts.length]; + } + + for (int i = 0; i < mTexts.length; i++) { + String text = mTexts[i]; + + if(text != null){ + + if(mTextBounds[i] == null) { + mTextBounds[i] = new Rect(); + } + + mPaint.getTextBounds(text, 0, text.length(), mTextBounds[i]); + + if(mSingleChildWidth < mTextBounds[i].width() + mHorizonGap * 2) { + mSingleChildWidth = mTextBounds[i].width() + mHorizonGap * 2; + } + if(mSingleChildHeight < mTextBounds[i].height() + mVerticalGap * 2) { + mSingleChildHeight = mTextBounds[i].height() + mVerticalGap * 2; + } + } + } + + switch (widthMode) { + case MeasureSpec.AT_MOST: + if (mDirection == Direction.HORIZONTAL) { + if (widthSize <= mSingleChildWidth * mTexts.length) { + mSingleChildWidth = widthSize / mTexts.length; + width = widthSize; + } else { + width = mSingleChildWidth * mTexts.length; + } + } else { + width = widthSize <= mSingleChildWidth ? widthSize : mSingleChildWidth; + } + break; + case MeasureSpec.EXACTLY: + width = widthSize; + break; + case MeasureSpec.UNSPECIFIED: + default: + if (mDirection == Direction.HORIZONTAL) { + width = mSingleChildWidth * mTexts.length; + } else { + width = mSingleChildWidth; + } + break; + } + + switch (heightMode) { + case MeasureSpec.AT_MOST: + if (mDirection == Direction.VERTICAL) { + if (heightSize <= mSingleChildHeight * mTexts.length) { + mSingleChildHeight = heightSize / mTexts.length; + height = heightSize; + } else { + height = mSingleChildHeight * mTexts.length; + } + } else { + height = heightSize <= mSingleChildHeight ? heightSize : mSingleChildHeight; + } + break; + case MeasureSpec.EXACTLY: + height = heightSize; + break; + case MeasureSpec.UNSPECIFIED: + default: + if (mDirection == Direction.VERTICAL) { + height = mSingleChildHeight * mTexts.length; + } else { + height = mSingleChildHeight; + } + + break; + } + + switch (mDirection) { + case HORIZONTAL: + if (mSingleChildWidth != width / mTexts.length) { + mSingleChildWidth = width / mTexts.length; + } + mSingleChildHeight = height; + break; + case VERTICAL: + if(mSingleChildHeight != height / mTexts.length) { + mSingleChildHeight = height / mTexts.length; + } + mSingleChildWidth = width; + break; + default: + break; + } + + for (int i = 0; i < mTexts.length; i++) { + + if (mCacheBounds[i] == null) { + mCacheBounds[i] = new Rect(); + } + + if (mDirection == Direction.HORIZONTAL) { + mCacheBounds[i].left = i * mSingleChildWidth; + mCacheBounds[i].top = 0; + } else { + mCacheBounds[i].left = 0; + mCacheBounds[i].top = i * mSingleChildHeight; + } + + mCacheBounds[i].right = mCacheBounds[i].left + mSingleChildWidth; + mCacheBounds[i].bottom = mCacheBounds[i].top + mSingleChildHeight; + } + } else { + width = widthMode == MeasureSpec.UNSPECIFIED ? 0 : widthSize; + height = heightMode == MeasureSpec.UNSPECIFIED ? 0 : heightSize; + } + + setMeasuredDimension(width, height); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction() & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: + inTapRegion = true; + + mStartX = event.getX(); + mStartY = event.getY(); + break; + + case MotionEvent.ACTION_MOVE: + mCurrentX = event.getX(); + mCurrentY = event.getY(); + + int dx = (int) (mCurrentX - mStartX); + int dy = (int) (mCurrentY - mStartY); + + int distance = dx * dx + dy * dy; + + if (distance > mTouchSlop) { + inTapRegion = false; + } + break; + + case MotionEvent.ACTION_UP: + if (inTapRegion) { + int index = 0; + if (mDirection == Direction.HORIZONTAL) { + index = (int) (mStartX / mSingleChildWidth); + } else { + index = (int) (mStartY / mSingleChildHeight); + } + + setSelectedIndex(index); + } + break; + default: + break; + } + return true; + } + + private int getSelectedTextColor(){ + return mTextColors.getColorForState(new int[]{android.R.attr.state_selected}, DEFAULT_NORMAL_COLOR); + } + + private int getNormalTextColor(){ + return mTextColors.getColorForState(new int[]{-android.R.attr.state_selected}, DEFAULT_SELECTED_COLOR); + } + + private int getSelectedBGColor(){ + return mBackgroundColors.getColorForState(new int[]{android.R.attr.state_selected}, DEFAULT_SELECTED_COLOR); + } + + private int getNormalBGColor(){ + return mBackgroundColors.getColorForState(new int[]{-android.R.attr.state_selected}, DEFAULT_NORMAL_COLOR); + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (mTexts != null && mTexts.length > 0) { + + for (int i = 0; i < mTexts.length; i++) { + + //draw separate lines + if (i < mTexts.length - 1) { + mPaint.setColor(getSelectedBGColor()); + mPaint.setStrokeWidth(mSeparatorWidth); + if (mDirection == Direction.HORIZONTAL) { + canvas.drawLine(mCacheBounds[i].right, 0, mCacheBounds[i].right, getHeight(), mPaint); + } else { + canvas.drawLine(mCacheBounds[i].left, mSingleChildHeight * (i + 1), mCacheBounds[i].right, mSingleChildHeight * (i + 1), mPaint); + } + } + + //draw selected drawable + if (i == mCurrentIndex && mSelectedDrawable != null) { + int topLeftRadius = 0; + int topRightRadius = 0; + int bottomLeftRadius = 0; + int bottomRightRadius = 0; + + if(mTexts.length == 1){ + topLeftRadius = mCornerRadius; + bottomLeftRadius = mCornerRadius; + topRightRadius = mCornerRadius; + bottomRightRadius = mCornerRadius; + }else{ + if (mDirection == Direction.HORIZONTAL) { + if (i == 0) { + topLeftRadius = mCornerRadius; + bottomLeftRadius = mCornerRadius; + } else if (i == mTexts.length - 1) { + topRightRadius = mCornerRadius; + bottomRightRadius = mCornerRadius; + } + } else { + if (i == 0) { + topLeftRadius = mCornerRadius; + topRightRadius = mCornerRadius; + } else if (i == mTexts.length - 1) { + bottomLeftRadius = mCornerRadius; + bottomRightRadius = mCornerRadius; + } + } + } + + mSelectedDrawable.setRadius(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + mSelectedDrawable.setBounds(mCacheBounds[i]); + mSelectedDrawable.draw(canvas); + + mPaint.setColor(getSelectedTextColor()); + } else { + mPaint.setColor(getNormalTextColor()); + } + + //draw texts + + float baseline = mCacheBounds[i].top + ((mSingleChildHeight - mCachedFM.ascent + mCachedFM.descent) / 2) - mCachedFM.descent; + canvas.drawText(mTexts[i], mCacheBounds[i].left + (mSingleChildWidth - mTextBounds[i].width()) / 2, baseline, mPaint); + + } + } + } + + // ========================================================= + // OnSegmentControlClickListener + // ========================================================= + private OnSegmentControlClickListener mOnSegmentControlClickListener; + + public void setOnSegmentControlClickListener(OnSegmentControlClickListener listener) { + mOnSegmentControlClickListener = listener; + } + + public OnSegmentControlClickListener getOnSegmentControlClicklistener() { + return mOnSegmentControlClickListener; + } + + public interface OnSegmentControlClickListener { + void onSegmentControlClick(int index); + } +} diff --git a/mylibrary/src/main/res/anim/anim_bottom_in.xml b/mylibrary/src/main/res/anim/anim_bottom_in.xml new file mode 100644 index 0000000..e1191a5 --- /dev/null +++ b/mylibrary/src/main/res/anim/anim_bottom_in.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/anim/anim_bottom_out.xml b/mylibrary/src/main/res/anim/anim_bottom_out.xml new file mode 100644 index 0000000..2c2299b --- /dev/null +++ b/mylibrary/src/main/res/anim/anim_bottom_out.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/color/select_text_color.xml b/mylibrary/src/main/res/color/select_text_color.xml new file mode 100644 index 0000000..e3e3992 --- /dev/null +++ b/mylibrary/src/main/res/color/select_text_color.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable-hdpi/left.png b/mylibrary/src/main/res/drawable-hdpi/left.png new file mode 100644 index 0000000..6a9e644 Binary files /dev/null and b/mylibrary/src/main/res/drawable-hdpi/left.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/black_back.png b/mylibrary/src/main/res/drawable-xhdpi/black_back.png new file mode 100644 index 0000000..c12c77f Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/black_back.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/fab_add.png b/mylibrary/src/main/res/drawable-xhdpi/fab_add.png new file mode 100644 index 0000000..c118072 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/fab_add.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/ic_add_image.png b/mylibrary/src/main/res/drawable-xhdpi/ic_add_image.png new file mode 100644 index 0000000..38e38da Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/ic_add_image.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/icon_upload.png b/mylibrary/src/main/res/drawable-xhdpi/icon_upload.png new file mode 100644 index 0000000..d8ff158 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/icon_upload.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/left.png b/mylibrary/src/main/res/drawable-xhdpi/left.png new file mode 100644 index 0000000..fa0ec3d Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/left.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/cars.png b/mylibrary/src/main/res/drawable-xxhdpi/cars.png new file mode 100644 index 0000000..c0959a8 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/cars.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/cha.png b/mylibrary/src/main/res/drawable-xxhdpi/cha.png new file mode 100644 index 0000000..7b2ce05 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/cha.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/check_nor.png b/mylibrary/src/main/res/drawable-xxhdpi/check_nor.png new file mode 100644 index 0000000..7b92670 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/check_nor.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/check_sel.png b/mylibrary/src/main/res/drawable-xxhdpi/check_sel.png new file mode 100644 index 0000000..b88f5e3 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/check_sel.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/diss.png b/mylibrary/src/main/res/drawable-xxhdpi/diss.png new file mode 100644 index 0000000..eae77a0 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/diss.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/empty.png b/mylibrary/src/main/res/drawable-xxhdpi/empty.png new file mode 100644 index 0000000..2bc4195 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/empty.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/error.png b/mylibrary/src/main/res/drawable-xxhdpi/error.png new file mode 100644 index 0000000..771f025 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/error.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/fab_add.png b/mylibrary/src/main/res/drawable-xxhdpi/fab_add.png new file mode 100644 index 0000000..07af313 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/fab_add.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/ic_item_delete.png b/mylibrary/src/main/res/drawable-xxhdpi/ic_item_delete.png new file mode 100644 index 0000000..2025f26 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/ic_item_delete.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/icon_refuse.png b/mylibrary/src/main/res/drawable-xxhdpi/icon_refuse.png new file mode 100644 index 0000000..78a9c52 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/icon_refuse.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/id_select.png b/mylibrary/src/main/res/drawable-xxhdpi/id_select.png new file mode 100644 index 0000000..c2f3394 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/id_select.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/id_select_loading.png b/mylibrary/src/main/res/drawable-xxhdpi/id_select_loading.png new file mode 100644 index 0000000..fa1a413 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/id_select_loading.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/id_select_z.png b/mylibrary/src/main/res/drawable-xxhdpi/id_select_z.png new file mode 100644 index 0000000..629b84d Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/id_select_z.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/left.png b/mylibrary/src/main/res/drawable-xxhdpi/left.png new file mode 100644 index 0000000..78dfb14 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/left.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/left_black.png b/mylibrary/src/main/res/drawable-xxhdpi/left_black.png new file mode 100644 index 0000000..61a9703 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/left_black.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/message.png b/mylibrary/src/main/res/drawable-xxhdpi/message.png new file mode 100644 index 0000000..b976b4e Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/message.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/ok.png b/mylibrary/src/main/res/drawable-xxhdpi/ok.png new file mode 100644 index 0000000..e64bc5b Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/ok.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/ps_ic_audio.png b/mylibrary/src/main/res/drawable-xxhdpi/ps_ic_audio.png new file mode 100644 index 0000000..3b33f07 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/ps_ic_audio.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/ps_ic_video.png b/mylibrary/src/main/res/drawable-xxhdpi/ps_ic_video.png new file mode 100644 index 0000000..9faaf32 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/ps_ic_video.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/update_head.png b/mylibrary/src/main/res/drawable-xxhdpi/update_head.png new file mode 100644 index 0000000..97ac15d Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/update_head.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/version_top_bg.png b/mylibrary/src/main/res/drawable-xxhdpi/version_top_bg.png new file mode 100644 index 0000000..8312c7c Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/version_top_bg.png differ diff --git a/mylibrary/src/main/res/drawable-xxxhdpi/left.png b/mylibrary/src/main/res/drawable-xxxhdpi/left.png new file mode 100644 index 0000000..7e9f9c5 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxxhdpi/left.png differ diff --git a/mylibrary/src/main/res/drawable-xxxhdpi/version_top_bg.png b/mylibrary/src/main/res/drawable-xxxhdpi/version_top_bg.png new file mode 100644 index 0000000..e462198 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxxhdpi/version_top_bg.png differ diff --git a/mylibrary/src/main/res/drawable/bnav_shape_du.xml b/mylibrary/src/main/res/drawable/bnav_shape_du.xml new file mode 100644 index 0000000..28f5f8d --- /dev/null +++ b/mylibrary/src/main/res/drawable/bnav_shape_du.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/bnav_tab_background.xml b/mylibrary/src/main/res/drawable/bnav_tab_background.xml new file mode 100644 index 0000000..270a701 --- /dev/null +++ b/mylibrary/src/main/res/drawable/bnav_tab_background.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/loading.xml b/mylibrary/src/main/res/drawable/loading.xml new file mode 100644 index 0000000..0ab50a0 --- /dev/null +++ b/mylibrary/src/main/res/drawable/loading.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/ps_audio_placeholder.xml b/mylibrary/src/main/res/drawable/ps_audio_placeholder.xml new file mode 100644 index 0000000..4f5960a --- /dev/null +++ b/mylibrary/src/main/res/drawable/ps_audio_placeholder.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/select_check_node.xml b/mylibrary/src/main/res/drawable/select_check_node.xml new file mode 100644 index 0000000..1cec8b6 --- /dev/null +++ b/mylibrary/src/main/res/drawable/select_check_node.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/select_sim_text.xml b/mylibrary/src/main/res/drawable/select_sim_text.xml new file mode 100644 index 0000000..d16b429 --- /dev/null +++ b/mylibrary/src/main/res/drawable/select_sim_text.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/select_slide_title.xml b/mylibrary/src/main/res/drawable/select_slide_title.xml new file mode 100644 index 0000000..bf8e084 --- /dev/null +++ b/mylibrary/src/main/res/drawable/select_slide_title.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/select_text_c.xml b/mylibrary/src/main/res/drawable/select_text_c.xml new file mode 100644 index 0000000..5a4b510 --- /dev/null +++ b/mylibrary/src/main/res/drawable/select_text_c.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shadow_bg.9.png b/mylibrary/src/main/res/drawable/shadow_bg.9.png new file mode 100644 index 0000000..6dd4442 Binary files /dev/null and b/mylibrary/src/main/res/drawable/shadow_bg.9.png differ diff --git a/mylibrary/src/main/res/drawable/shape_bg8.xml b/mylibrary/src/main/res/drawable/shape_bg8.xml new file mode 100644 index 0000000..ba34bfb --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_bg8.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_bind_phone_background.xml b/mylibrary/src/main/res/drawable/shape_bind_phone_background.xml new file mode 100644 index 0000000..270e9f0 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_bind_phone_background.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg10.xml b/mylibrary/src/main/res/drawable/shape_blue_bg10.xml new file mode 100644 index 0000000..a9bae1b --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_blue_bg10.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg25.xml b/mylibrary/src/main/res/drawable/shape_blue_bg25.xml new file mode 100644 index 0000000..cdccedf --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_blue_bg25.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg4.xml b/mylibrary/src/main/res/drawable/shape_blue_bg4.xml new file mode 100644 index 0000000..dd388ad --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_blue_bg4.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg8.xml b/mylibrary/src/main/res/drawable/shape_blue_bg8.xml new file mode 100644 index 0000000..6e7e086 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_blue_bg8.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_bottom_bgw16.xml b/mylibrary/src/main/res/drawable/shape_bottom_bgw16.xml new file mode 100644 index 0000000..ad939cf --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_bottom_bgw16.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_gray_bg10.xml b/mylibrary/src/main/res/drawable/shape_gray_bg10.xml new file mode 100644 index 0000000..4a9a9e5 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_gray_bg10.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_gray_bg25.xml b/mylibrary/src/main/res/drawable/shape_gray_bg25.xml new file mode 100644 index 0000000..bb01f39 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_gray_bg25.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_gray_bg4.xml b/mylibrary/src/main/res/drawable/shape_gray_bg4.xml new file mode 100644 index 0000000..7ed2a61 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_gray_bg4.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_log_btn_bg22.xml b/mylibrary/src/main/res/drawable/shape_log_btn_bg22.xml new file mode 100644 index 0000000..6a526c2 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_log_btn_bg22.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_message.xml b/mylibrary/src/main/res/drawable/shape_message.xml new file mode 100644 index 0000000..f70d586 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_message.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_text_4_blue.xml b/mylibrary/src/main/res/drawable/shape_text_4_blue.xml new file mode 100644 index 0000000..9d7ac38 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_text_4_blue.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_text_4_nor.xml b/mylibrary/src/main/res/drawable/shape_text_4_nor.xml new file mode 100644 index 0000000..9389c1b --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_text_4_nor.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_view_v.xml b/mylibrary/src/main/res/drawable/shape_view_v.xml new file mode 100644 index 0000000..d59ee95 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_view_v.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/white_round_corner_bg.xml b/mylibrary/src/main/res/drawable/white_round_corner_bg.xml new file mode 100644 index 0000000..d330d5b --- /dev/null +++ b/mylibrary/src/main/res/drawable/white_round_corner_bg.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/common_toolbar.xml b/mylibrary/src/main/res/layout/common_toolbar.xml new file mode 100644 index 0000000..f4870a6 --- /dev/null +++ b/mylibrary/src/main/res/layout/common_toolbar.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/layout/custom_dialog_two_layout.xml b/mylibrary/src/main/res/layout/custom_dialog_two_layout.xml new file mode 100644 index 0000000..bb372d4 --- /dev/null +++ b/mylibrary/src/main/res/layout/custom_dialog_two_layout.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/layout/empty_pic.xml b/mylibrary/src/main/res/layout/empty_pic.xml new file mode 100644 index 0000000..52b216b --- /dev/null +++ b/mylibrary/src/main/res/layout/empty_pic.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/layout/gv_filter_image.xml b/mylibrary/src/main/res/layout/gv_filter_image.xml new file mode 100644 index 0000000..1ff5a64 --- /dev/null +++ b/mylibrary/src/main/res/layout/gv_filter_image.xml @@ -0,0 +1,44 @@ + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/item_car_select.xml b/mylibrary/src/main/res/layout/item_car_select.xml new file mode 100644 index 0000000..414e97c --- /dev/null +++ b/mylibrary/src/main/res/layout/item_car_select.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/item_dic_select.xml b/mylibrary/src/main/res/layout/item_dic_select.xml new file mode 100644 index 0000000..9e94d4c --- /dev/null +++ b/mylibrary/src/main/res/layout/item_dic_select.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/item_node_select.xml b/mylibrary/src/main/res/layout/item_node_select.xml new file mode 100644 index 0000000..396acb0 --- /dev/null +++ b/mylibrary/src/main/res/layout/item_node_select.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/item_select.xml b/mylibrary/src/main/res/layout/item_select.xml new file mode 100644 index 0000000..56a9f34 --- /dev/null +++ b/mylibrary/src/main/res/layout/item_select.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/my_confim_popup_input.xml b/mylibrary/src/main/res/layout/my_confim_popup_input.xml new file mode 100644 index 0000000..db788f2 --- /dev/null +++ b/mylibrary/src/main/res/layout/my_confim_popup_input.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/my_confim_popup_tip.xml b/mylibrary/src/main/res/layout/my_confim_popup_tip.xml new file mode 100644 index 0000000..366f7cf --- /dev/null +++ b/mylibrary/src/main/res/layout/my_confim_popup_tip.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/layout/view_slide_bar.xml b/mylibrary/src/main/res/layout/view_slide_bar.xml new file mode 100644 index 0000000..80483e7 --- /dev/null +++ b/mylibrary/src/main/res/layout/view_slide_bar.xml @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/values/attrs.xml b/mylibrary/src/main/res/values/attrs.xml new file mode 100644 index 0000000..6af9f09 --- /dev/null +++ b/mylibrary/src/main/res/values/attrs.xml @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/values/colors.xml b/mylibrary/src/main/res/values/colors.xml new file mode 100644 index 0000000..9fce5cc --- /dev/null +++ b/mylibrary/src/main/res/values/colors.xml @@ -0,0 +1,32 @@ + + + #28B950 + #28B950 + #D81B60 + + #FFFFFFFF + #333333 + #666666 + #FE0606 + #FFFFFF + #3C6FC6 + #88888888 + #000000 + + + + + #F5F5F5 + #000000 + #E6E6E6 + #F7F7F7 + #999999 + #cccccc + #f6f6f6 + #D5D9DB + #f6f6f6 + + + + + diff --git a/mylibrary/src/main/res/values/dimens.xml b/mylibrary/src/main/res/values/dimens.xml new file mode 100644 index 0000000..003e401 --- /dev/null +++ b/mylibrary/src/main/res/values/dimens.xml @@ -0,0 +1,26 @@ + + + 8sp + 9sp + 10sp + 11sp + 12sp + 13sp + 14sp + 15sp + 16sp + 17sp + 18sp + 19sp + 20sp + 21sp + 22sp + 23sp + 24sp + 26sp + 28sp + 30sp + 40sp + 56dp + 40dp + diff --git a/mylibrary/src/main/res/values/ids.xml b/mylibrary/src/main/res/values/ids.xml new file mode 100644 index 0000000..efaf17b --- /dev/null +++ b/mylibrary/src/main/res/values/ids.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/values/strings.xml b/mylibrary/src/main/res/values/strings.xml new file mode 100644 index 0000000..6e289c9 --- /dev/null +++ b/mylibrary/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ + + CommonBaseLibrary + + 拍照 + 从相册中选择 + 取消 + %d/100 + diff --git a/mylibrary/src/main/res/values/styles.xml b/mylibrary/src/main/res/values/styles.xml new file mode 100644 index 0000000..6c47106 --- /dev/null +++ b/mylibrary/src/main/res/values/styles.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/test/java/com/dahe/mylibrary/ExampleUnitTest.kt b/mylibrary/src/test/java/com/dahe/mylibrary/ExampleUnitTest.kt new file mode 100644 index 0000000..0e4dd1d --- /dev/null +++ b/mylibrary/src/test/java/com/dahe/mylibrary/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.dahe.mylibrary + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..649748d --- /dev/null +++ b/settings.gradle @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' } + maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' } + maven { url "https://jitpack.io" } + gradlePluginPortal() + google() + mavenCentral() + + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' } + maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' } + maven { url "https://jitpack.io" } + google() + mavenCentral() + } +} +rootProject.name = "GLDriver" +include ':app' +include ':mylibrary'