初始代码
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.zmkg.coaloperation">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET " />
|
||||
|
||||
<application
|
||||
android:name=".MyApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/app_icon"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.AppTheme"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
tools:replace="android:allowBackup">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.login.activity.LoginActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ui.user.activity.NetworkConfigActivity" />
|
||||
<activity android:name=".ui.user.activity.CacheManageActivity" />
|
||||
<activity android:name=".ui.user.activity.AboutUsActivity" />
|
||||
<activity android:name=".ui.home.activity.GeologicalActivity" />
|
||||
<activity android:name=".ui.tunneling.activity.WorkingFaceDetailActivity" />
|
||||
<activity android:name=".ui.tunneling.activity.WorkingPointActivity" />
|
||||
<activity android:name=".ui.tunneling.activity.WorkingFaceDetail2Activity" />
|
||||
<activity android:name=".ui.tunneling.activity.AddWorkingPointActivity"
|
||||
android:windowSoftInputMode="adjustPan"/>
|
||||
<activity android:name=".ui.tunneling.activity.TunnelingActivity" />
|
||||
<activity android:name=".ui.tunneling.activity.WorkFaceActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"textColorNormal": "#A4A3A3",
|
||||
"textColorSelected": "#21BEBD",
|
||||
"textSizeNormal": 9,
|
||||
"textSizeSelected": 9,
|
||||
"backgroundColor": "#e9e9e9",
|
||||
"isNameResId": false,
|
||||
"isTitleVisible": true,
|
||||
"tabs": [
|
||||
{
|
||||
"tabName": "首页",
|
||||
"tabTag": "key_index_fragment",
|
||||
"iconNormal": "home_tab",
|
||||
"iconSelected": "home_select_tab"
|
||||
},
|
||||
{
|
||||
"tabName": "记录",
|
||||
"tabTag": "key_record_fragment",
|
||||
"iconNormal": "record_tab",
|
||||
"iconSelected": "record_select_tab"
|
||||
},
|
||||
{
|
||||
"tabName": "上报",
|
||||
"tabTag": "key_report_fragment",
|
||||
"iconNormal": "report_tab",
|
||||
"iconSelected": "report_select_tab"
|
||||
},
|
||||
{
|
||||
"tabName": "消息",
|
||||
"tabTag": "key_message_fragment",
|
||||
"iconNormal": "message_tab",
|
||||
"iconSelected": "message_select_tab"
|
||||
},
|
||||
{
|
||||
"tabName": "我的",
|
||||
"tabTag": "key_my_fragment",
|
||||
"iconNormal": "self_tab",
|
||||
"iconSelected": "self_select_tab"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.zmkg.coaloperation
|
||||
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel
|
||||
|
||||
class AppViewModel: BaseViewModel() {
|
||||
override fun init() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.zmkg.coaloperation
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.tencent.qcloud.tuikit.tuiconversation.classicui.page.TUIConversationFragmentContainer
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.bottomtab.HomeBottomTabLayout
|
||||
import com.zmkg.coaloperation.databinding.ActivityMainBinding
|
||||
import com.zmkg.coaloperation.ui.home.fragment.HomeFragment
|
||||
import com.zmkg.coaloperation.ui.record.fragment.RecordFragment
|
||||
import com.zmkg.coaloperation.ui.report.fragment.ReportFragment
|
||||
import com.zmkg.coaloperation.ui.user.fragment.UserFragment
|
||||
|
||||
class MainActivity : BaseVMBActivity<TestViewModel, ActivityMainBinding>(R.layout.activity_main),
|
||||
HomeBottomTabLayout.HomeBottomTabLayoutCallback {
|
||||
|
||||
//每个tab对应的tag,和json配置文件中保持一致
|
||||
val TAG_INDEX = "key_index_fragment"
|
||||
val TAG_RECORD = "key_record_fragment"
|
||||
val TAG_REPORT = "key_report_fragment"
|
||||
val TAG_MESSAGE = "key_message_fragment"
|
||||
val TAG_MY = "key_my_fragment"
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
mBinding.apply {
|
||||
//设置回调
|
||||
mainTabLayout.setHomeBottomTabLayoutCallback(this@MainActivity)
|
||||
//初始化,参数为默认展示第几个tab
|
||||
mainTabLayout.initFirstTab(0)
|
||||
//如果需要展示未读消息,通过该方法展示
|
||||
// main_tab_layout.setUnreadTip(TAG_USER, "12")
|
||||
// main_tab_layout.setUnreadTip(TAG_INDEX, "99+")
|
||||
// main_tab_layout.setUnreadTip(TAG_COLLECT, null, false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
}
|
||||
|
||||
override fun getFragmentByTag(tabTag: String): Fragment? {
|
||||
when (tabTag) {
|
||||
TAG_INDEX -> {
|
||||
return HomeFragment()
|
||||
}
|
||||
|
||||
TAG_RECORD -> {
|
||||
return RecordFragment()
|
||||
}
|
||||
|
||||
TAG_REPORT -> {
|
||||
return ReportFragment()
|
||||
}
|
||||
|
||||
TAG_MESSAGE -> {
|
||||
return TUIConversationFragmentContainer()
|
||||
}
|
||||
|
||||
TAG_MY -> {
|
||||
return UserFragment()
|
||||
}
|
||||
}
|
||||
return Fragment()
|
||||
|
||||
}
|
||||
|
||||
override fun onClickChangeTab(selectedIndex: Int, selectedTag: String?) {
|
||||
}
|
||||
|
||||
override fun transparentStatusBar(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.zmkg.coaloperation
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.StrictMode
|
||||
import android.text.TextUtils
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelStore
|
||||
import androidx.lifecycle.ViewModelStoreOwner
|
||||
import androidx.multidex.MultiDex
|
||||
import com.orhanobut.logger.AndroidLogAdapter
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.tencent.qcloud.tuicore.TUILogin
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUILoginListener
|
||||
import com.zmkg.coaloperation.local.DataStoreManager
|
||||
import com.zmkg.coaloperation.retorfit.UrlConfig
|
||||
import com.zmkg.coaloperation.superfuntion.loginIm
|
||||
import com.zmkg.coaloperation.superfuntion.startLoginActivity
|
||||
import com.zmkg.coaloperation.utils.CustomActivityManager
|
||||
import org.json.JSONObject
|
||||
import org.lzh.framework.updatepluginlib.UpdateConfig
|
||||
import org.lzh.framework.updatepluginlib.base.UpdateParser
|
||||
import org.lzh.framework.updatepluginlib.model.Update
|
||||
import retrofit2.HttpException
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
class MyApplication : Application(), ViewModelStoreOwner {
|
||||
private var mAppViewModelStore: ViewModelStore? = null
|
||||
private var mFactory: ViewModelProvider.Factory? = null
|
||||
companion object {
|
||||
@JvmStatic
|
||||
var appContext: MyApplication by Delegates.notNull()
|
||||
@JvmStatic
|
||||
lateinit var appViewModel: AppViewModel
|
||||
val TAG = MyApplication::class.java.simpleName
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
super.attachBaseContext(base)
|
||||
MultiDex.install(this);
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
Logger.addLogAdapter(AndroidLogAdapter())
|
||||
appContext = this
|
||||
mAppViewModelStore = ViewModelStore()
|
||||
appViewModel = getAppViewModelProvider()[AppViewModel::class.java]
|
||||
appViewModel.init()
|
||||
createObserve()
|
||||
createNewConfig()
|
||||
//禁止网络相关安全检查
|
||||
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
|
||||
StrictMode.setThreadPolicy(policy) //这两句设置禁止所有检查
|
||||
registerActivityLifecycleCallbacks(AdjustLifecycleCallbacks())
|
||||
DataStoreManager.initialize(this)
|
||||
initLoginStatusListener()
|
||||
|
||||
}
|
||||
|
||||
fun initLoginStatusListener() {
|
||||
TUILogin.addLoginListener(loginStatusListener)
|
||||
}
|
||||
|
||||
private val loginStatusListener: TUILoginListener = object : TUILoginListener() {
|
||||
override fun onKickedOffline() {
|
||||
if (UrlConfig.isOpenIm){
|
||||
startLoginActivity(CustomActivityManager.getInstance().currentActivity())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUserSigExpired() {
|
||||
if (TextUtils.isEmpty(DataStoreManager.getUserName())) {
|
||||
startLoginActivity(appContext)
|
||||
} else {
|
||||
loginIm(DataStoreManager.getUserName()){ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** 获取一个全局的ViewModel */
|
||||
private fun getAppViewModelProvider(): ViewModelProvider {
|
||||
return ViewModelProvider(this, getAppFactory())
|
||||
}
|
||||
private fun getAppFactory(): ViewModelProvider.Factory {
|
||||
if (mFactory == null) {
|
||||
mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(this)
|
||||
}
|
||||
return mFactory as ViewModelProvider.Factory
|
||||
}
|
||||
|
||||
private fun createNewConfig(): UpdateConfig {
|
||||
return UpdateConfig.createConfig()
|
||||
.setUrl("http://o1wh05aeh.qnssl.com/image/view/app_icons")
|
||||
.setUpdateParser(object : UpdateParser() {
|
||||
@Throws(Exception::class)
|
||||
override fun parse(httpResponse: String): Update {
|
||||
val `object` = JSONObject(httpResponse)
|
||||
val update = Update()
|
||||
// 此apk包的下载地址
|
||||
update.updateUrl = `object`.optString("update_url")
|
||||
// 此apk包的版本号
|
||||
update.versionCode = `object`.optInt("update_ver_code")
|
||||
// 此apk包的版本名称
|
||||
update.versionName = `object`.optString("update_ver_name")
|
||||
// 此apk包的更新内容
|
||||
update.updateContent = `object`.optString("update_content")
|
||||
// 此apk包是否为强制更新
|
||||
update.isForced = true
|
||||
// 是否显示忽略此次版本更新按钮
|
||||
update.isIgnore = `object`.optBoolean("ignore_able", false)
|
||||
update.md5 = `object`.optString("md5")
|
||||
return update
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
fun createObserve() {
|
||||
appViewModel.exception.observeForever { e: Exception? ->
|
||||
if (e is HttpException) {
|
||||
if (e.code() == 401) {
|
||||
// val activity = CustomActivityManager.getInstance().currentActivity()
|
||||
// startLoginActivity(activity)
|
||||
// activity.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private inner class AdjustLifecycleCallbacks : ActivityLifecycleCallbacks {
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||
println("路径" + activity.javaClass.name)
|
||||
CustomActivityManager.getInstance().addActivity(activity)
|
||||
}
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {}
|
||||
override fun onActivityResumed(activity: Activity) {}
|
||||
override fun onActivityPaused(activity: Activity) {}
|
||||
override fun onActivityStopped(activity: Activity) {}
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
|
||||
override fun onActivityDestroyed(activity: Activity) {
|
||||
CustomActivityManager.getInstance().removeActivity(activity)
|
||||
}
|
||||
}
|
||||
|
||||
// private fun initUpdateApp(){
|
||||
// UpdateConfig.getConfig()
|
||||
// .setCheckWorker(CheckUpdateAppVersion::class.java)
|
||||
// //为了通过原检查更新库的检查随便传入的地址,实际请求参考CheckUpdateAppVersion.class
|
||||
// .setCheckEntity(CheckEntity().setUrl("https://www.baidu.com"))
|
||||
// .setCheckNotifier(CustomUpdateNotifier())
|
||||
// .setInstallNotifier(CustomInstallNotifier())
|
||||
// .setDownloadNotifier(CustomDownloadNotifier())
|
||||
// .setUpdateParser(object : UpdateParser() {
|
||||
// override fun parse(response: String?): Update {
|
||||
// val resultBean: AppUpdateBean? = response.jsonToBean(AppUpdateBean::class.java)
|
||||
// val update = Update()
|
||||
// if(resultBean == null){
|
||||
// return update
|
||||
// }
|
||||
// // 此apk包的下载地址
|
||||
// update.updateUrl = UrlConfig.IMAGE_BASE_URL+resultBean.appUrl
|
||||
// // 此apk包的版本号(因接口只有在有更新时才会返回数据,而且没有返回云端APP版本号,故将当前APP版本号+1,传给更新框架用作判断有新版本)
|
||||
// update.versionCode = resultBean.versionNo ?: 0
|
||||
// // 此apk包的版本名称
|
||||
// update.versionName = resultBean.versionName
|
||||
// // 此apk包的更新内容
|
||||
// update.updateContent = resultBean.updateContent
|
||||
// // 此apk包是否为强制更新
|
||||
// if (resultBean != null) {
|
||||
// update.isForced = 1 == resultBean.forced
|
||||
// }else{
|
||||
// update.isForced = false
|
||||
// }
|
||||
// // 是否显示忽略此次版本更新按钮
|
||||
// update.isIgnore = 1 == resultBean.ignoreFlag
|
||||
// return update
|
||||
// }
|
||||
// }).updateStrategy = object : UpdateStrategy() {
|
||||
// override fun isShowUpdateDialog(update: Update): Boolean {
|
||||
// // 是否在检查到有新版本更新时展示Dialog。
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
// override fun isAutoInstall(): Boolean {
|
||||
// // 是否自动更新.当为自动更新时。代表下载成功后不通知用户。直接调起安装。
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
// override fun isShowDownloadDialog(): Boolean {
|
||||
// // 在APK下载时。是否显示下载进度的Dialog
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
override fun getViewModelStore(): ViewModelStore {
|
||||
return mAppViewModelStore!!
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.zmkg.coaloperation.adapter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.viewholder.BaseViewHolder
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.bean.RockItem
|
||||
import com.zmkg.coaloperation.bean.WorkingFaceItem
|
||||
import com.zmkg.coaloperation.databinding.ListItemRockBinding
|
||||
import com.zmkg.coaloperation.databinding.ListItemWorkingFaceBinding
|
||||
import com.zmkg.coaloperation.utils.ScreenUtil
|
||||
|
||||
class WorkingItemAdapter(data: MutableList<WorkingFaceItem>) :
|
||||
BaseQuickAdapter<WorkingFaceItem, WorkingItemAdapter.VH>(
|
||||
R.layout.list_item_working_face,
|
||||
data
|
||||
) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
|
||||
val binding = ListItemWorkingFaceBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return VH(binding)
|
||||
}
|
||||
|
||||
override fun convert(
|
||||
holder: VH,
|
||||
item: WorkingFaceItem
|
||||
) {
|
||||
if (item.pageType == 0) {
|
||||
loadFaceData(holder.binding, item)
|
||||
} else if (item.pageType == 1) {
|
||||
loadPointData(holder.binding, item)
|
||||
}
|
||||
val position = holder.layoutPosition
|
||||
holder.binding.divider.let {
|
||||
if (position == data.size - 1) {
|
||||
it.visibility = View.GONE
|
||||
} else {
|
||||
it.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadPointData(binding: ListItemWorkingFaceBinding, item: WorkingFaceItem) {
|
||||
binding.run {
|
||||
tvItemName.text = item.name
|
||||
if (item.items.isNullOrEmpty()) {
|
||||
tvItemName.updateLayoutParams { height = ScreenUtil.dp2px(50f) }
|
||||
tvItemValue.let {
|
||||
it.visibility = View.VISIBLE
|
||||
it.text = item.value
|
||||
}
|
||||
llContainer.visibility = View.GONE
|
||||
} else {
|
||||
tvItemName.updateLayoutParams { height = ScreenUtil.dp2px(60f) }
|
||||
tvItemValue.visibility = View.GONE
|
||||
llContainer.let {
|
||||
it.visibility = View.VISIBLE
|
||||
it.removeAllViews()
|
||||
addChildToContainer(it, item.items)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun loadFaceData(binding: ListItemWorkingFaceBinding, item: WorkingFaceItem) {
|
||||
binding.tvItemName.let {
|
||||
it.updateLayoutParams { height = ScreenUtil.dp2px(50f) }
|
||||
it.text = item.name
|
||||
}
|
||||
binding.tvItemValue.let {
|
||||
it.visibility = View.VISIBLE
|
||||
it.text = item.value
|
||||
}
|
||||
binding.llContainer.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun addChildToContainer(container: LinearLayout, list: MutableList<RockItem>?) {
|
||||
list?.forEach { item ->
|
||||
val itemBinding = ListItemRockBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
container,
|
||||
false
|
||||
)
|
||||
itemBinding.run {
|
||||
tvRockStartLen.let {
|
||||
it.focusable = EditText.NOT_FOCUSABLE
|
||||
it.setOnKeyListener(null)
|
||||
it.setText("${item.startLen}")
|
||||
}
|
||||
tvRockEndLen.let {
|
||||
it.focusable = EditText.NOT_FOCUSABLE
|
||||
it.setOnKeyListener(null)
|
||||
it.setText("${item.endLen}")
|
||||
}
|
||||
tvRockType.let {
|
||||
it.focusable = EditText.NOT_FOCUSABLE
|
||||
it.setOnKeyListener(null)
|
||||
it.setText(item.rockType)
|
||||
}
|
||||
container.addView(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inner class VH(var binding: ListItemWorkingFaceBinding) : BaseViewHolder(binding.root)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.zmkg.coaloperation.adapter.common
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.util.getItemView
|
||||
import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
|
||||
|
||||
/**
|
||||
* 基于第三方库BaseRecyclerViewAdapterHelper拓展使用DataBinding的Adapter
|
||||
*/
|
||||
abstract class BaseDataBindingAdapter<T, BD : ViewDataBinding>
|
||||
@JvmOverloads constructor(@LayoutRes private val layoutResId: Int, data: MutableList<T>? = null
|
||||
) : BaseQuickAdapter<T, BaseDataBindingHolder<BD>>(layoutResId, data) {
|
||||
override fun onCreateDefViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): BaseDataBindingHolder<BD> {
|
||||
return BaseDataBindingHolder(parent.getItemView(layoutResId))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.zmkg.coaloperation.adapter.common
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
|
||||
class ViewPagerAdapter :
|
||||
FragmentStateAdapter {
|
||||
private var tabs: Array<out Any>
|
||||
private var onCreateFragmentListener: OnCreateFragmentListener
|
||||
|
||||
constructor(
|
||||
fa: FragmentActivity,
|
||||
tabs: Array<out Any>,
|
||||
onCreateFragmentListener: OnCreateFragmentListener
|
||||
) : super(fa) {
|
||||
this.tabs = tabs
|
||||
this.onCreateFragmentListener = onCreateFragmentListener
|
||||
}
|
||||
constructor(
|
||||
fa: Fragment,
|
||||
tabs: Array<out Any>,
|
||||
onCreateFragmentListener: OnCreateFragmentListener
|
||||
) : super(fa) {
|
||||
this.tabs = tabs
|
||||
this.onCreateFragmentListener = onCreateFragmentListener
|
||||
}
|
||||
constructor(
|
||||
fragmentManager: FragmentManager,
|
||||
lifecycle: Lifecycle,
|
||||
tabs: Array<out Any>,
|
||||
onCreateFragmentListener: OnCreateFragmentListener
|
||||
) : super(fragmentManager, lifecycle) {
|
||||
this.tabs = tabs
|
||||
this.onCreateFragmentListener = onCreateFragmentListener
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return tabs.size
|
||||
}
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return onCreateFragmentListener.createFragment(position)
|
||||
}
|
||||
|
||||
interface OnCreateFragmentListener {
|
||||
fun createFragment(position: Int): Fragment
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,435 @@
|
||||
package com.zmkg.coaloperation.base
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.ImageView
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.OnRebindCallback
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.gyf.immersionbar.ktx.immersionBar
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.zmkg.coaloperation.BR
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel.Companion.LOADING_STATE_HIDE
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel.Companion.LOADING_STATE_SHOW
|
||||
import com.zmkg.coaloperation.superfuntion.hideLoading
|
||||
import com.zmkg.coaloperation.superfuntion.showLoading
|
||||
import com.zmkg.coaloperation.utils.StatusbarUtil
|
||||
import com.zmkg.coaloperation.view.CustomToast
|
||||
import com.zmkg.coaloperation.view.LoadingDialog
|
||||
import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.net.ConnectException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import java.sql.SQLException
|
||||
|
||||
|
||||
/**
|
||||
* 封装了ViewModel和DataBinding的Activity基类
|
||||
*/
|
||||
abstract class BaseVMBActivity<VM : BaseViewModel, B : ViewDataBinding>(private val contentViewResId: Int) :
|
||||
AppCompatActivity(), View.OnClickListener {
|
||||
var mContext: Context? = null
|
||||
var mActivity: Activity? = null
|
||||
lateinit var mViewModel: VM
|
||||
lateinit var mBinding: B
|
||||
var dialog: LoadingDialog? = null
|
||||
var mEmpty: View?=null
|
||||
var mRootView:RelativeLayout?=null
|
||||
|
||||
/**
|
||||
* 重写getResources()方法,让APP的字体不受系统设置字体大小影响
|
||||
*/
|
||||
override fun getResources(): Resources? {
|
||||
val config = Configuration()
|
||||
config.setToDefaults()
|
||||
createConfigurationContext(config)
|
||||
return super.getResources()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
EventBus.getDefault().register(this)
|
||||
mContext = this
|
||||
mActivity = this
|
||||
initViewModel()
|
||||
initDataBinding()
|
||||
initImmersionBar()
|
||||
createObserve()
|
||||
createDialog()
|
||||
initView(savedInstanceState)
|
||||
initData()
|
||||
bindEvent()
|
||||
mBinding.addOnRebindCallback(object : OnRebindCallback<B>(){
|
||||
override fun onPreBind(binding: B): Boolean {//数据绑定之前
|
||||
return super.onPreBind(binding)
|
||||
}
|
||||
override fun onBound(binding: B) {//数据绑定之后
|
||||
super.onBound(binding)
|
||||
setTransparentStatusBar(transparentStatusBar(), statusBarDarkFont())
|
||||
dataBindingFinish()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
open fun initImmersionBar() {
|
||||
initToolBar()
|
||||
}
|
||||
|
||||
|
||||
open fun dataBindingFinish(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param isTransparent
|
||||
* @param isStatusBarDarkFont
|
||||
*/
|
||||
open fun setTransparentStatusBar(isTransparent: Boolean, isStatusBarDarkFont: Boolean) {
|
||||
immersionBar {
|
||||
// reset()
|
||||
titleBar(getToolBar())
|
||||
var bgColor: Int = ContextCompat.getColor(this@BaseVMBActivity, R.color.colorAccent)
|
||||
if (isTransparent) {
|
||||
statusBarColorInt(ContextCompat.getColor(this@BaseVMBActivity, R.color.transparent))
|
||||
.fitsSystemWindows(false) //解决状态栏和布局重叠问题
|
||||
//如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度
|
||||
statusBarDarkFont(isStatusBarDarkFont,0.2f)
|
||||
} else {
|
||||
var relativeLayout: RelativeLayout? = findViewById(R.id.toolbar_lay)
|
||||
var background = relativeLayout?.background
|
||||
if (relativeLayout != null && background is ColorDrawable) {
|
||||
bgColor = background.color
|
||||
}
|
||||
statusBarColorInt(bgColor)
|
||||
.fitsSystemWindows(false) //解决状态栏和布局重叠问题
|
||||
//如果为亮色则状态栏字体为黑色,否则为白色
|
||||
statusBarDarkFont(isLightColor(bgColor), 0.2f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个颜色是否是亮色
|
||||
*/
|
||||
fun isLightColor(color: Int): Boolean {
|
||||
val darkness = ColorUtils.calculateLuminance(color)
|
||||
return darkness >= 0.5
|
||||
}
|
||||
private fun initToolBar() {
|
||||
// if (transparentStatusBar()) {
|
||||
var titleLay: View? = findViewById(R.id.rl_title_lay)
|
||||
if (titleLay == null){
|
||||
titleLay = findViewById(R.id.toolbar_lay)
|
||||
}
|
||||
if (titleLay == null){
|
||||
titleLay = getToolBar()
|
||||
}
|
||||
fitTransparentStatusBar(titleLay)
|
||||
|
||||
// }
|
||||
findViewById<ImageView>(R.id.title_iv_back)?.setOnClickListener {
|
||||
onBackEvent()
|
||||
}
|
||||
}
|
||||
|
||||
fun fitTransparentStatusBar(view: View?) {
|
||||
view?.let {
|
||||
var statusHeight = StatusbarUtil.getStatusBarHeight(this@BaseVMBActivity)
|
||||
it.setPadding(
|
||||
0, statusHeight,
|
||||
0, 0
|
||||
)
|
||||
var height: Int = it.layoutParams?.height ?: 0
|
||||
it.layoutParams.height = height + statusHeight
|
||||
}
|
||||
}
|
||||
|
||||
fun addClickViews(vararg views: View) {
|
||||
for (view in views) {
|
||||
view.setOnClickListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
onBackEvent()
|
||||
}
|
||||
|
||||
open fun onBackEvent() {
|
||||
super.onBackPressed()
|
||||
// finish()
|
||||
}
|
||||
|
||||
override fun onClick(view: View) {
|
||||
processClick(view)
|
||||
}
|
||||
|
||||
open fun getToolBar(): View? {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是透明状态栏
|
||||
*/
|
||||
open fun transparentStatusBar(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
/** 状态栏是否是深色*/
|
||||
open fun statusBarDarkFont(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
/** ViewModel初始化 */
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
open fun initViewModel() {
|
||||
// 这里利用反射获取泛型中第一个参数ViewModel
|
||||
val type: Class<VM> =
|
||||
(this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<VM>
|
||||
mViewModel = ViewModelProvider(this)[type]
|
||||
mViewModel.init()
|
||||
}
|
||||
|
||||
/** DataBinding初始化 */
|
||||
private fun initDataBinding() {
|
||||
mBinding = DataBindingUtil.setContentView(this, contentViewResId)
|
||||
mBinding.apply {
|
||||
// 需绑定lifecycleOwner到activity,xml绑定的数据才会随着liveData数据源的改变而改变
|
||||
lifecycleOwner = this@BaseVMBActivity
|
||||
setVariable(BR.viewModel, mViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
/** View相关初始化 */
|
||||
abstract fun initView(savedInstanceState: Bundle?)
|
||||
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
abstract fun initData()
|
||||
|
||||
/**
|
||||
* 事件监听
|
||||
*/
|
||||
protected abstract fun bindEvent()
|
||||
|
||||
/**
|
||||
* 点击事件处理
|
||||
*
|
||||
* @param paramView
|
||||
*/
|
||||
abstract fun processClick(v: View?)
|
||||
fun showLongToast(message: String?) {
|
||||
CustomToast.makeText(mContext, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
fun showToast(message: String?, drawable: Drawable?) {
|
||||
CustomToast.makeText(mContext, message, Toast.LENGTH_SHORT, drawable).show()
|
||||
}
|
||||
|
||||
fun showToast(message: String?) {
|
||||
if (message != null && message.isNotEmpty()) {
|
||||
CustomToast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
/** 提供编写LiveData监听逻辑的方法 */
|
||||
open fun createObserve() {
|
||||
// 全局服务器请求错误监听
|
||||
mViewModel.apply {
|
||||
loadingDialog.observe(this@BaseVMBActivity) {
|
||||
when (it) {
|
||||
LOADING_STATE_SHOW -> {
|
||||
showLoading()
|
||||
}
|
||||
|
||||
LOADING_STATE_HIDE -> {
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
toastMessage.collect { message ->
|
||||
message?.let {
|
||||
CustomToast.makeText(
|
||||
this@BaseVMBActivity, message, Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exception.observe(this@BaseVMBActivity) {
|
||||
requestError(it.message)
|
||||
Logger.e("Network error:${it.message}")
|
||||
when (it) {
|
||||
is HttpException -> {
|
||||
if (it.code() == 401) {
|
||||
// val activity = CustomActivityManager.getInstance().currentActivity()
|
||||
// if (activity !is LoginActivity) {
|
||||
// startLoginActivity(this@BaseVMBActivity)
|
||||
// finish()
|
||||
// }
|
||||
// }else if (it.code() == 404) {
|
||||
// CustomToast.makeText(
|
||||
// this@BaseVMBActivity,
|
||||
// "服务器走丢了,请稍后重试",
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
}
|
||||
}
|
||||
is SocketTimeoutException -> CustomToast.makeText(
|
||||
this@BaseVMBActivity,
|
||||
getString(R.string.request_time_out), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
|
||||
is ConnectException, is UnknownHostException ->
|
||||
CustomToast.makeText(
|
||||
this@BaseVMBActivity,
|
||||
getString(R.string.network_error), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
is IOException, is SQLException ->
|
||||
CustomToast.makeText(
|
||||
this@BaseVMBActivity,
|
||||
getString(R.string.response_error), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
// else ->
|
||||
// CustomToast.makeText(
|
||||
// this@BaseVMBActivity,
|
||||
// it.message ?: getString(R.string.response_error),
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 全局服务器返回的错误信息监听
|
||||
errorResponse.observe(this@BaseVMBActivity) {
|
||||
requestError(it?.msg)
|
||||
when (it) {
|
||||
is HttpException -> {
|
||||
if (it.code() == 401) {
|
||||
// startLoginActivity(this@BaseVMBActivity)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
it?.msg?.run {
|
||||
CustomToast.makeText(
|
||||
this@BaseVMBActivity,
|
||||
this ?: getString(R.string.response_error),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
it?.msg?.run {
|
||||
CustomToast.makeText(
|
||||
this@BaseVMBActivity,
|
||||
this ?: getString(R.string.response_error),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 提供一个请求错误的方法,用于像关闭加载框,显示错误布局之类的 */
|
||||
open fun requestError(msg: String?) {
|
||||
mViewModel.loadingDialog.value = LOADING_STATE_HIDE
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mViewModel.loadingDialog.value = LOADING_STATE_HIDE
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
open fun onMessageEvent(event: Any?) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录状态发生变化
|
||||
*/
|
||||
open fun loginStateChange(isLogin: Boolean) {
|
||||
|
||||
}
|
||||
|
||||
fun toActivity(clazz: Class<*>?) {
|
||||
val intent = Intent(mActivity, clazz)
|
||||
mActivity?.startActivity(intent)
|
||||
}
|
||||
|
||||
fun toActivityForResult(clazz: Class<*>?, code: Int) {
|
||||
val intent = Intent(mActivity, clazz)
|
||||
mActivity?.startActivityForResult(intent, code)
|
||||
}
|
||||
|
||||
fun toActivityForResult(clazz: Class<*>?, bundle: Bundle?, code: Int) {
|
||||
val intent = Intent(mActivity, clazz)
|
||||
if (bundle != null) {
|
||||
intent.putExtras(bundle)
|
||||
}
|
||||
mActivity?.startActivityForResult(intent, code)
|
||||
}
|
||||
|
||||
fun toActivity(clazz: Class<*>?, bundle: Bundle?) {
|
||||
val intent = Intent(mActivity, clazz)
|
||||
if (bundle != null) {
|
||||
intent.putExtras(bundle)
|
||||
}
|
||||
mActivity?.startActivity(intent)
|
||||
}
|
||||
|
||||
private fun createDialog() {
|
||||
dialog = LoadingDialog(
|
||||
mContext,
|
||||
ProgressDialog.STYLE_SPINNER, "数据加载中"
|
||||
)
|
||||
dialog!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
dialog!!.setCanceledOnTouchOutside(false)
|
||||
dialog!!.setCancelable(false)
|
||||
dialog!!.setMessage("请稍后...")
|
||||
}
|
||||
|
||||
// 字体大小不跟随系统
|
||||
override fun attachBaseContext(newBase: Context) {
|
||||
super.attachBaseContext(getConfigurationContext(newBase))
|
||||
}
|
||||
|
||||
private fun getConfigurationContext(context: Context): Context {
|
||||
val configuration = context.resources.configuration
|
||||
configuration.fontScale = 1f
|
||||
return context.createConfigurationContext(configuration)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
package com.zmkg.coaloperation.base
|
||||
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.zmkg.coaloperation.BR
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel.Companion.LOADING_STATE_HIDE
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel.Companion.LOADING_STATE_SHOW
|
||||
import com.zmkg.coaloperation.superfuntion.hideLoading
|
||||
import com.zmkg.coaloperation.superfuntion.showLoading
|
||||
import com.zmkg.coaloperation.utils.StatusbarUtil
|
||||
import com.zmkg.coaloperation.view.CustomToast
|
||||
import com.zmkg.coaloperation.view.LoadingDialog
|
||||
import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.net.ConnectException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import java.sql.SQLException
|
||||
|
||||
/**
|
||||
* 封装了ViewModel和DataBinding的Fragment基类
|
||||
* 未默认实现onClick方法主要为了让使用者看到而不是另外实现接口
|
||||
*/
|
||||
abstract class BaseVMBFragment<VM : BaseViewModel, B : ViewDataBinding>(private val contentViewResId: Int) :
|
||||
Fragment(), View.OnClickListener {
|
||||
var mRootView: RelativeLayout?=null
|
||||
/** 是否第一次加载 */
|
||||
private var mIsFirstLoading = true
|
||||
var dialog: LoadingDialog? = null
|
||||
protected lateinit var mViewModel: VM
|
||||
lateinit var mBinding: B
|
||||
var mEmpty: View?=null
|
||||
var mIsVisible: Boolean=false
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
mBinding = DataBindingUtil.inflate(inflater, contentViewResId, container, false)
|
||||
return mBinding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (!EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
createDialog()
|
||||
mIsFirstLoading = true
|
||||
initViewModel()
|
||||
onDrawFinish()
|
||||
initView(view, savedInstanceState)
|
||||
initData()
|
||||
setupDataBinding()
|
||||
createObserve()
|
||||
initToolBar()
|
||||
bindEvent()
|
||||
}
|
||||
|
||||
/** ViewModel初始化 */
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
open fun initViewModel() {
|
||||
// 这里利用反射获取泛型中第一个参数ViewModel
|
||||
val type: Class<VM> =
|
||||
(this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<VM>
|
||||
mViewModel = ViewModelProvider(this)[type]
|
||||
mViewModel.init()
|
||||
}
|
||||
|
||||
/** DataBinding相关设置 */
|
||||
private fun setupDataBinding() {
|
||||
mBinding.apply {
|
||||
// 需绑定lifecycleOwner到Fragment,xml绑定的数据才会随着liveData数据源的改变而改变
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
setVariable(BR.viewModel, mViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
/** View相关初始化 */
|
||||
abstract fun initView(root: View?, savedInstanceState: Bundle?)
|
||||
private fun initToolBar() {
|
||||
if (transparentStatusBar()) {
|
||||
var titleLay: View? = mBinding.root.findViewById(R.id.rl_title_lay)
|
||||
if (titleLay == null) {
|
||||
titleLay = mBinding.root.findViewById(R.id.toolbar_lay)
|
||||
}
|
||||
fitTransparentStatusBar(titleLay)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun fitTransparentStatusBar(view: View?) {
|
||||
view?.let {
|
||||
var statusHeight = StatusbarUtil.getStatusBarHeight(requireContext())
|
||||
it.setPadding(
|
||||
0, statusHeight,
|
||||
0, 0
|
||||
)
|
||||
var height: Int = it.layoutParams?.height ?: 0
|
||||
it.layoutParams.height = height + statusHeight
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
open fun onDrawFinish(){
|
||||
mRootView=mBinding.root.findViewById<RelativeLayout>(R.id.rl_empty_root_view)
|
||||
mRootView?.let{
|
||||
mEmpty=LayoutInflater.from(context)
|
||||
.inflate(R.layout.layout_empty, it, false).apply {
|
||||
findViewById<TextView>(R.id.tv_empty).text = "暂无数据"
|
||||
}
|
||||
var layoutParams =
|
||||
RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
|
||||
layoutParams.addRule(RelativeLayout.BELOW, R.id.toolbar_lay)
|
||||
mEmpty?.layoutParams = layoutParams
|
||||
}
|
||||
}
|
||||
|
||||
fun showEmpty(emptyMessage:String="暂无数据",color: Int=0){
|
||||
try {
|
||||
if(color!=0){
|
||||
mEmpty?.setBackgroundColor(color)
|
||||
}
|
||||
mEmpty?.findViewById<TextView>(R.id.tv_empty)?.setText(emptyMessage)
|
||||
|
||||
if (mEmpty?.parent==null) {
|
||||
mRootView?.addView(mEmpty)
|
||||
}else{
|
||||
mRootView?.removeView(mEmpty)
|
||||
mRootView?.addView(mEmpty)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun hindEmpty(emptyMessage:String="暂无数据"){
|
||||
try {
|
||||
mRootView?.removeView(mEmpty)
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 是否是透明状态栏
|
||||
*/
|
||||
open fun transparentStatusBar(): Boolean {
|
||||
return false
|
||||
}
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mIsVisible=isVisible()
|
||||
if (lifecycle.currentState == Lifecycle.State.STARTED && mIsFirstLoading) {
|
||||
lazyLoadData()
|
||||
mIsFirstLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHiddenChanged(hidden: Boolean) {
|
||||
super.onHiddenChanged(hidden)
|
||||
mIsVisible=!hidden
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
mIsVisible=false
|
||||
}
|
||||
|
||||
fun addClickViews(vararg views: View) {
|
||||
for (view in views) {
|
||||
view.setOnClickListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
/** 数据懒加载 */
|
||||
open fun lazyLoadData() {}
|
||||
|
||||
/** 提供编写LiveData监听逻辑的方法 */
|
||||
open fun createObserve() { // 全局服务器请求错误监听
|
||||
mViewModel.apply {
|
||||
loadingDialog.observe(viewLifecycleOwner) {
|
||||
when (it) {
|
||||
LOADING_STATE_SHOW -> {
|
||||
showLoading()
|
||||
}
|
||||
|
||||
LOADING_STATE_HIDE -> {
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
toastMessage.collect { message ->
|
||||
message?.let {
|
||||
CustomToast.makeText(
|
||||
requireContext(), message, Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exception.observe(viewLifecycleOwner) {
|
||||
requestError(it.message)
|
||||
Logger.e("Network error:${it.message}")
|
||||
when (it) {
|
||||
is HttpException -> {
|
||||
if (it.code() == 401) {
|
||||
// startLoginActivity(requireContext())
|
||||
// requireActivity().finish()
|
||||
// }else if (it.code() == 404) {
|
||||
// CustomToast.makeText(
|
||||
// requireContext(),
|
||||
// "服务器走丢了,请稍后重试",
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
}
|
||||
}
|
||||
|
||||
is SocketTimeoutException -> CustomToast.makeText(
|
||||
requireContext(),
|
||||
getString(R.string.request_time_out), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
|
||||
is ConnectException, is UnknownHostException ->
|
||||
CustomToast.makeText(
|
||||
requireContext(),
|
||||
getString(R.string.network_error), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
is IOException, is SQLException ->
|
||||
CustomToast.makeText(
|
||||
requireContext(),
|
||||
getString(R.string.response_error), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
is WindowManager.BadTokenException ->{
|
||||
|
||||
}
|
||||
// else ->
|
||||
// CustomToast.makeText(
|
||||
// requireContext(),
|
||||
// it.message ?: getString(R.string.response_error),
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
}
|
||||
}
|
||||
|
||||
// 全局服务器返回的错误信息监听
|
||||
errorResponse.observe(viewLifecycleOwner) {
|
||||
requestError(it?.msg)
|
||||
when (it) {
|
||||
is HttpException -> {
|
||||
if (it.code() == 401) {
|
||||
// startLoginActivity(requireContext())
|
||||
// requireActivity().finish()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
it?.msg?.run {
|
||||
if (mIsVisible) {
|
||||
CustomToast.makeText(
|
||||
requireContext(),
|
||||
this ?: getString(R.string.response_error),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
}
|
||||
it?.msg?.run {
|
||||
if (mIsVisible) {
|
||||
CustomToast.makeText(
|
||||
requireContext(),
|
||||
this ?: getString(R.string.response_error),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 提供一个请求错误的方法,用于像关闭加载框之类的 */
|
||||
open fun requestError(msg: String? = null) {
|
||||
mViewModel.loadingDialog.value = LOADING_STATE_HIDE
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
mBinding == null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
if (!EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
open fun onMessageEvent(event: Any?) {
|
||||
}
|
||||
|
||||
open fun loginStateChange(isLogin: Boolean) {
|
||||
|
||||
}
|
||||
|
||||
protected open fun initData() {}
|
||||
protected abstract fun bindEvent()
|
||||
fun showToast(message: String?) {
|
||||
if (message != null && message.isNotEmpty()) {
|
||||
if (this.mIsVisible) {
|
||||
try {
|
||||
CustomToast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toActivity(clazz: Class<*>?) {
|
||||
val intent = Intent(activity, clazz)
|
||||
activity?.startActivity(intent)
|
||||
}
|
||||
|
||||
fun toActivity(clazz: Class<*>?, bundle: Bundle?) {
|
||||
val intent = Intent(activity, clazz)
|
||||
if (bundle != null) {
|
||||
intent.putExtras(bundle)
|
||||
}
|
||||
activity?.startActivity(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* 历史遗留方法,懒得改以前的了,新页面无视即可
|
||||
*/
|
||||
open fun getStatusbarStyle(): Int{
|
||||
return 0
|
||||
} // 0 主题色+白字 1白底黑字
|
||||
|
||||
private fun createDialog() {
|
||||
dialog = LoadingDialog(
|
||||
activity,
|
||||
ProgressDialog.STYLE_SPINNER, "数据加载中"
|
||||
)
|
||||
dialog!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
dialog!!.setCanceledOnTouchOutside(false)
|
||||
dialog!!.setCancelable(false)
|
||||
dialog!!.setMessage("请稍后")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.zmkg.coaloperation.base.repository
|
||||
|
||||
import com.zmkg.coaloperation.data.bean.ApiResponse
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* Repository数据仓库基类,主要用于协程的调用
|
||||
*/
|
||||
open class BaseRepository {
|
||||
|
||||
suspend fun <T> apiCall(api: suspend () -> ApiResponse<T>): ApiResponse<T> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
api.invoke() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zmkg.coaloperation.base.viewmodel
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.zmkg.coaloperation.data.bean.ApiResponse
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
/**
|
||||
* ViewModel基类
|
||||
*/
|
||||
abstract class BaseViewModel : ViewModel() {
|
||||
companion object{
|
||||
const val LOADING_STATE_SHOW = 1
|
||||
const val LOADING_STATE_HIDE = 2
|
||||
}
|
||||
/** 加载框控制 */
|
||||
var loadingDialog = MutableLiveData<Int>()
|
||||
/** 请求异常(服务器请求失败,譬如:服务器连接超时等) */
|
||||
val exception = MutableLiveData<Exception>()
|
||||
|
||||
/** 请求服务器返回错误(服务器请求成功但status错误,譬如:登录过期等) */
|
||||
val errorResponse = MutableLiveData<ApiResponse<*>?>()
|
||||
/** Toast文本 */
|
||||
var toastMessage = MutableStateFlow<String?>(null)
|
||||
/** 界面启动时要进行的初始化逻辑,如网络请求,数据初始化等 */
|
||||
abstract fun init()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.zmkg.coaloperation.base.viewmodel
|
||||
|
||||
class TestViewModel: BaseViewModel() {
|
||||
override fun init() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.zmkg.coaloperation.bean
|
||||
|
||||
/**
|
||||
* 类似九宫格图集使用
|
||||
*/
|
||||
data class ImageBean(var imageUrl: String = "", var isFilePath: Boolean = false, var isAddButton: Boolean = false)
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.zmkg.coaloperation.bean
|
||||
|
||||
data class WorkingFaceItem(
|
||||
var name: String = "",
|
||||
var value: String = "",
|
||||
var items: MutableList<RockItem>? = null,
|
||||
var pageType:Int = 0
|
||||
)
|
||||
|
||||
data class RockItem(
|
||||
var startLen: Int = 0,
|
||||
var endLen: Int = 0,
|
||||
val rockType: String = ""
|
||||
)
|
||||
@@ -0,0 +1,319 @@
|
||||
package com.zmkg.coaloperation.bottomtab
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.TypedArray
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.zmkg.coaloperation.R
|
||||
import java.io.IOException
|
||||
class HomeBottomTabLayout(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs),
|
||||
View.OnClickListener {
|
||||
|
||||
private lateinit var mTabConfig: TabConfig
|
||||
|
||||
private var mFragmentList = ArrayList<Fragment?>()
|
||||
private var mTabContainerList: ArrayList<ViewGroup>? = null
|
||||
|
||||
private var mOverSideTab = ArrayList<View>(1)
|
||||
private var mCurrentSelectedIndex = 0
|
||||
private var mViewPager: ViewPager? = null
|
||||
private var mFragmentManager: FragmentManager? = null
|
||||
private var mCallback: HomeBottomTabLayoutCallback? = null
|
||||
private var mFragmentContainerId = -1
|
||||
private var mViewPagerId = -1
|
||||
private var isCurrentViewPager = false
|
||||
private var mIsCanClickTab = true
|
||||
|
||||
init {
|
||||
val array: TypedArray =
|
||||
context.obtainStyledAttributes(attrs, R.styleable.HomeBottomTabLayout)
|
||||
mFragmentContainerId = array.getResourceId(R.styleable.HomeBottomTabLayout_container_id, -1)
|
||||
mViewPagerId = array.getResourceId(R.styleable.HomeBottomTabLayout_viewPager_id, -1)
|
||||
val configFile = array.getString(R.styleable.HomeBottomTabLayout_config_file_name)
|
||||
isCurrentViewPager = mViewPagerId != -1
|
||||
array.recycle()
|
||||
|
||||
this.orientation = HORIZONTAL
|
||||
this.clipChildren = false
|
||||
mFragmentManager = (context as FragmentActivity).supportFragmentManager
|
||||
configFile?.let {
|
||||
try {
|
||||
val tabConfigFileInputStream = context.assets.open(it)
|
||||
mTabConfig =
|
||||
TabUtils.parseJsonToConfig(tabConfigFileInputStream)
|
||||
?: throw IllegalArgumentException("配置文件错误,请检查")
|
||||
} catch (e: IOException) {
|
||||
throw IllegalArgumentException("请检查${it}是否存在于assets中!")
|
||||
}
|
||||
} ?: let {
|
||||
throw IllegalArgumentException("请使用config_file_name设置配置文件名称!")
|
||||
}
|
||||
initTabs()
|
||||
}
|
||||
|
||||
fun getFragmentSize():Int{
|
||||
return mFragmentList.size
|
||||
}
|
||||
|
||||
private fun initTabs() {
|
||||
if (mTabConfig.tabs.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
mTabContainerList = ArrayList(mTabConfig.tabs.size)
|
||||
mTabConfig.tabs.forEach { tab ->
|
||||
generateItemView(tab)
|
||||
mFragmentList.add(null)
|
||||
}
|
||||
mOverSideTab.forEach {
|
||||
viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
val layoutParams = it.layoutParams as MarginLayoutParams
|
||||
val height = (it.height * 2.5f).toInt()
|
||||
layoutParams.height = height
|
||||
layoutParams.width = height
|
||||
if (!mTabConfig.isTitleVisible) {
|
||||
layoutParams.setMargins(0, 0, 0, (it.height * 1.5f).toInt())
|
||||
}
|
||||
it.layoutParams = layoutParams
|
||||
viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
mOverSideTab.remove(it)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun initFirstTab(index: Int) {
|
||||
if (index < 0 || index > mTabContainerList?.size ?: 0) {
|
||||
throw IndexOutOfBoundsException("没有这么多tab,index值:$index")
|
||||
}
|
||||
if (mCallback == null) {
|
||||
throw IllegalStateException("需要先设置callback获取对应的Fragment")
|
||||
}
|
||||
if (isCurrentViewPager) {
|
||||
setupViewPager(index)
|
||||
} else {
|
||||
changeTab(index)
|
||||
}
|
||||
}
|
||||
|
||||
fun hideTab(index: Int) {
|
||||
if (index < 0 || index > mTabContainerList?.size ?: 0) {
|
||||
throw IndexOutOfBoundsException("没有这么多tab,index值:$index")
|
||||
}
|
||||
mTabContainerList?.get(index)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun selectByTag(tabTag: String) {
|
||||
mTabConfig.tabs.forEachIndexed { index, tabConfig ->
|
||||
if (tabTag == tabConfig.tabTag) {
|
||||
changeTab(index)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentSelectedTag(): String {
|
||||
return mTabConfig.tabs[mCurrentSelectedIndex].tabTag
|
||||
}
|
||||
|
||||
fun getCurrentSelectedIndex(): Int {
|
||||
return mCurrentSelectedIndex
|
||||
}
|
||||
|
||||
fun getCurrentSelectedFragment(): Fragment? {
|
||||
return mFragmentList[mCurrentSelectedIndex]
|
||||
}
|
||||
|
||||
fun getFragmentByTag(tabTag: String): Fragment? {
|
||||
return mFragmentManager?.findFragmentByTag(tabTag)
|
||||
}
|
||||
|
||||
fun getFragmentList(): List<Fragment?>? {
|
||||
return mFragmentList
|
||||
}
|
||||
|
||||
fun setIsCanClickTab(isCanClick: Boolean) {
|
||||
this.mIsCanClickTab = isCanClick
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun setupViewPager(selectedIndex: Int) {
|
||||
mViewPager = rootView.findViewById(mViewPagerId)
|
||||
mTabConfig.tabs.forEachIndexed { index, itemConfig ->
|
||||
mFragmentList[index] = mCallback!!.getFragmentByTag(itemConfig.tabTag)
|
||||
}
|
||||
val map = mFragmentList.map { it!! }
|
||||
mFragmentManager?.let {
|
||||
mViewPager?.adapter = TabFragmentPageAdapter(it, map)
|
||||
}
|
||||
mViewPager?.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onPageScrolled(
|
||||
position: Int,
|
||||
positionOffset: Float,
|
||||
positionOffsetPixels: Int
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
setTabSelected(position)
|
||||
}
|
||||
})
|
||||
mViewPager?.currentItem = selectedIndex
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
if (!mIsCanClickTab) {
|
||||
return
|
||||
}
|
||||
var tempIndex = 0
|
||||
val tag = v?.tag as String
|
||||
mTabContainerList?.forEachIndexed { index, viewGroup ->
|
||||
if ((viewGroup.tag as String) == tag) {
|
||||
tempIndex = index
|
||||
return@forEachIndexed
|
||||
}
|
||||
}
|
||||
changeTab(tempIndex)
|
||||
mCallback?.onClickChangeTab(tempIndex, tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换tab操作,分两步
|
||||
* 1、切换按钮状态
|
||||
* 2、切换fragment
|
||||
*/
|
||||
public fun changeTab(selectedIndex: Int) {
|
||||
if (isCurrentViewPager) {
|
||||
mViewPager?.currentItem = selectedIndex
|
||||
} else {
|
||||
//tab状态改变
|
||||
setTabSelected(selectedIndex)
|
||||
//fragment改变
|
||||
setFragmentSelected(selectedIndex)
|
||||
}
|
||||
//更改当前下标
|
||||
mCurrentSelectedIndex = selectedIndex
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换按钮状态
|
||||
*/
|
||||
private fun setTabSelected(selectedIndex: Int) {
|
||||
mTabContainerList?.forEachIndexed { index, viewGroup ->
|
||||
val ivIcon = viewGroup.findViewById<ImageView>(R.id.tabItem_ivIcon)
|
||||
val tvName = viewGroup.findViewById<TextView>(R.id.tabItem_tvTitle)
|
||||
val itemConfig = mTabConfig.tabs[index]
|
||||
val textColor: Int
|
||||
val iconResource: Int
|
||||
val textSize: Float
|
||||
if (index == selectedIndex) {
|
||||
textColor = mTabConfig.tabSelectedColor
|
||||
textSize = mTabConfig.tabSelectedTextSize.toFloat()
|
||||
iconResource = TabUtils.getResourceDrawableId(context, itemConfig.iconSelected)
|
||||
viewGroup.isEnabled = false
|
||||
} else {
|
||||
textColor = mTabConfig.tabNormalColor
|
||||
textSize = mTabConfig.tabNormalTextSize.toFloat()
|
||||
iconResource = TabUtils.getResourceDrawableId(context, itemConfig.iconNormal)
|
||||
viewGroup.isEnabled = true
|
||||
}
|
||||
ivIcon.setImageResource(iconResource)
|
||||
tvName.setTextColor(textColor)
|
||||
tvName.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换fragment
|
||||
*/
|
||||
private fun setFragmentSelected(selectedIndex: Int) {
|
||||
val beginTransaction = mFragmentManager?.beginTransaction()
|
||||
val itemConfig = mTabConfig.tabs[selectedIndex]
|
||||
var fragmentByTag = mFragmentManager?.findFragmentByTag(itemConfig.tabTag)
|
||||
val isFirstInit: Boolean
|
||||
if (fragmentByTag == null) {
|
||||
fragmentByTag = mCallback?.getFragmentByTag(itemConfig.tabTag)
|
||||
mFragmentList[selectedIndex] = fragmentByTag
|
||||
isFirstInit = true
|
||||
} else {
|
||||
isFirstInit = false
|
||||
}
|
||||
mFragmentList.forEach { fragment ->
|
||||
if (fragment != null && fragment.isAdded) {
|
||||
beginTransaction?.hide(fragment)
|
||||
}
|
||||
}
|
||||
fragmentByTag?.let {
|
||||
if (isFirstInit) {
|
||||
beginTransaction?.add(mFragmentContainerId, fragmentByTag, itemConfig.tabTag)
|
||||
} else {
|
||||
beginTransaction?.show(fragmentByTag)
|
||||
}
|
||||
}
|
||||
beginTransaction?.commitAllowingStateLoss()
|
||||
}
|
||||
|
||||
private fun generateItemView(itemConfig: ItemConfig) {
|
||||
val view: ViewGroup =
|
||||
View.inflate(context, R.layout.bottom_tab_item_layout, null) as ViewGroup
|
||||
val tvName = view.findViewById<TextView>(R.id.tabItem_tvTitle)
|
||||
val ivIcon = view.findViewById<ImageView>(R.id.tabItem_ivIcon)
|
||||
//tabTitle
|
||||
if (mTabConfig.isTabNameResId) {
|
||||
tvName.text = TabUtils.getStringByResId(context, itemConfig.tabName)
|
||||
} else {
|
||||
tvName.text = itemConfig.tabName
|
||||
}
|
||||
tvName.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mTabConfig.tabNormalTextSize.toFloat())
|
||||
tvName.setTextColor(mTabConfig.tabNormalColor)
|
||||
//tabIcon
|
||||
ivIcon.setImageResource(TabUtils.getResourceDrawableId(context, itemConfig.iconNormal))
|
||||
//bg
|
||||
itemConfig.itemBg.apply {
|
||||
if (!TextUtils.isEmpty(this)) {
|
||||
ivIcon.setBackgroundResource(TabUtils.getResourceDrawableId(context, this!!))
|
||||
}
|
||||
}
|
||||
if (itemConfig.isOverSide) {
|
||||
mOverSideTab.add(ivIcon)
|
||||
}
|
||||
if (!mTabConfig.isTitleVisible) {
|
||||
tvName.visibility = View.GONE
|
||||
}
|
||||
val weight = if (itemConfig.isOverSide) 1.1f else 1f
|
||||
val params = LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, weight)
|
||||
|
||||
view.setOnClickListener(this)
|
||||
view.tag = itemConfig.tabTag
|
||||
this.addView(view, params)
|
||||
mTabContainerList?.add(view)
|
||||
}
|
||||
|
||||
fun setHomeBottomTabLayoutCallback(homeBottomTabLayoutCallback: HomeBottomTabLayoutCallback?) {
|
||||
this.mCallback = homeBottomTabLayoutCallback
|
||||
}
|
||||
|
||||
interface HomeBottomTabLayoutCallback {
|
||||
fun getFragmentByTag(tabTag: String): Fragment?
|
||||
|
||||
fun onClickChangeTab(selectedIndex: Int, selectedTag: String?)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.zmkg.coaloperation.bottomtab
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class TabConfig(
|
||||
var tabNormalColor: Int,
|
||||
var tabSelectedColor: Int,
|
||||
var tabNormalTextSize: Int,
|
||||
var tabSelectedTextSize: Int,
|
||||
var isTabNameResId: Boolean = true,
|
||||
var isTitleVisible: Boolean = true,
|
||||
var tabs: List<ItemConfig>
|
||||
) : Serializable
|
||||
|
||||
data class ItemConfig(
|
||||
var tabName: String,
|
||||
var tabTag: String,
|
||||
var iconNormal: String,
|
||||
var iconSelected: String,
|
||||
var isOverSide: Boolean = false,
|
||||
var itemBg: String? = null
|
||||
) : Serializable
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.zmkg.coaloperation.bottomtab
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentPagerAdapter
|
||||
|
||||
class TabFragmentPageAdapter(
|
||||
fragmentManager: FragmentManager, private val fragments: List<Fragment>
|
||||
) : FragmentPagerAdapter(
|
||||
fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
|
||||
) {
|
||||
|
||||
override fun getItem(position: Int): Fragment {
|
||||
return fragments[position]
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
return fragments.size
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.zmkg.coaloperation.bottomtab
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.text.TextUtils
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
import java.util.regex.Pattern
|
||||
|
||||
object TabUtils {
|
||||
/**
|
||||
* 检查颜色是否合法
|
||||
*/
|
||||
fun isColorLegal(color: String): Boolean {
|
||||
if (TextUtils.isEmpty(color)) {
|
||||
return false
|
||||
}
|
||||
//#aabbcc
|
||||
val matchRegix1 = "^#[0-9a-fA-F]{6}"
|
||||
//#00aabbcc
|
||||
val matchRegix2 = "^#[0-9a-fA-F]{8}"
|
||||
//#ccc
|
||||
val matchRegix3 = "^#[0-9a-fA-F]{3}"
|
||||
//去匹配
|
||||
val compile = Pattern.compile(matchRegix1)
|
||||
if (compile.matcher(color).find()) {
|
||||
return true
|
||||
}
|
||||
val compile1 = Pattern.compile(matchRegix2)
|
||||
if (compile1.matcher(color).find()) {
|
||||
return true
|
||||
}
|
||||
val compile2 = Pattern.compile(matchRegix3)
|
||||
if (compile2.matcher(color).find()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun parseJsonToConfig(inputStream: InputStream): TabConfig? {
|
||||
val resultArray = ByteArrayOutputStream()
|
||||
val temp = ByteArray(256)
|
||||
var read = inputStream.read(temp)
|
||||
while (read != -1) {
|
||||
resultArray.write(temp, 0, read)
|
||||
read = inputStream.read(temp)
|
||||
resultArray.flush()
|
||||
}
|
||||
val readJson = resultArray.toString("utf-8")
|
||||
inputStream.close()
|
||||
resultArray.close()
|
||||
if (readJson.isNotEmpty()) {
|
||||
try {
|
||||
val obj = JSONObject(readJson)
|
||||
//颜色
|
||||
val textColorNormal = obj.optString("textColorNormal")
|
||||
val textColorSelected = obj.optString("textColorSelected")
|
||||
val normalColor = if (isColorLegal(textColorNormal)) {
|
||||
Color.parseColor(textColorNormal)
|
||||
} else {
|
||||
Color.BLACK
|
||||
}
|
||||
val selectedColor = if (isColorLegal(textColorSelected)) {
|
||||
Color.parseColor(textColorSelected)
|
||||
} else {
|
||||
Color.GRAY
|
||||
}
|
||||
val textSizeNormal = obj.optInt("textSizeNormal", 14)
|
||||
val textSizeSelected = obj.optInt("textSizeSelected", 14)
|
||||
val isTabNameResId = obj.optBoolean("isNameResId", true)
|
||||
val isTitleVisible = obj.optBoolean("isTitleVisible", true)
|
||||
//标签
|
||||
val itemList = ArrayList<ItemConfig>()
|
||||
val tabs = obj.optJSONArray("tabs")
|
||||
if (tabs != null && tabs.length() > 0) {
|
||||
for (i in 0 until tabs.length()) {
|
||||
val tabJson = tabs.optJSONObject(i)
|
||||
val tabName = tabJson.optString("tabName")
|
||||
val tabTag = tabJson.optString("tabTag")
|
||||
val tabIconNormal = tabJson.optString("iconNormal")
|
||||
val tabIconSelected = tabJson.optString("iconSelected")
|
||||
val isOverSide = tabJson.optBoolean("isOverSide", false)
|
||||
val tabItemConfig =
|
||||
ItemConfig(tabName, tabTag, tabIconNormal, tabIconSelected, isOverSide)
|
||||
val itemBg = tabJson.optString("itemBg", "")
|
||||
tabItemConfig.itemBg = itemBg
|
||||
itemList.add(tabItemConfig)
|
||||
}
|
||||
}
|
||||
return TabConfig(
|
||||
normalColor,
|
||||
selectedColor,
|
||||
textSizeNormal,
|
||||
textSizeSelected,
|
||||
isTabNameResId,
|
||||
isTitleVisible,
|
||||
itemList
|
||||
)
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun getResourceDrawableId(context: Context, drawableName: String): Int {
|
||||
return context.resources.getIdentifier(drawableName, "drawable", context.packageName)
|
||||
}
|
||||
|
||||
fun getStringByResId(context: Context, strResId: String): String {
|
||||
val resId = context.resources.getIdentifier(strResId, "string", context.packageName)
|
||||
return context.resources.getString(resId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.zmkg.coaloperation.data.api
|
||||
|
||||
import com.zmkg.coaloperation.data.bean.ApiResponse
|
||||
import com.zmkg.coaloperation.retorfit.UrlConfig
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.FaceWorkDetailBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeItemBean
|
||||
import com.zmkg.coaloperation.ui.home.bean.WaterLedgerBean
|
||||
import okhttp3.RequestBody
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
|
||||
/**
|
||||
* 首页
|
||||
*/
|
||||
|
||||
interface HomeApi {
|
||||
|
||||
/**
|
||||
* 涌水量观测
|
||||
*/
|
||||
@GET("${UrlConfig.prefix}/inspection/inflow/getWaterLedgerData")
|
||||
suspend fun getWaterLedgerData(): ApiResponse<MutableList<WaterLedgerBean>>
|
||||
|
||||
/**
|
||||
* 掘进-首页-工作面列表
|
||||
*/
|
||||
@GET("/api/mine/tunnelling/surface/list")
|
||||
suspend fun getTunnelingHomeData(): ApiResponse<MutableList<TunnelingHomeBean>>
|
||||
|
||||
/**
|
||||
* 掘进-首页-工作面记录列表
|
||||
*/
|
||||
@GET("/api/mine/tunnelling/surface/record/{recordId}")
|
||||
suspend fun getTunnelingHomeItemData(@Path("recordId") recordId: String?): ApiResponse<MutableList<TunnelingHomeItemBean>>
|
||||
|
||||
/**
|
||||
* 掘进-工作面详情
|
||||
*/
|
||||
@GET("/api/mine/tunnelling/surface/detail/{surfaceId}")
|
||||
suspend fun getTunnelingSurfaceDetail(@Path("surfaceId") surfaceId: String?): ApiResponse<FaceWorkDetailBean>
|
||||
|
||||
/**
|
||||
* 掘进-新增工作面
|
||||
*/
|
||||
@POST("/api/mine/tunnelling/surface/add")
|
||||
suspend fun postTunnellingSurfaceAdd(@Body requestBody: RequestBody): ApiResponse<String>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.zmkg.coaloperation.data.bean
|
||||
|
||||
/**
|
||||
* 接口返回外层封装实体
|
||||
*/
|
||||
data class ApiResponse<T>(
|
||||
var code: Int,
|
||||
val msg: String?,
|
||||
val data: T?
|
||||
)
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.zmkg.coaloperation.data.repository
|
||||
|
||||
import com.zmkg.coaloperation.base.repository.BaseRepository
|
||||
import com.zmkg.coaloperation.data.api.HomeApi
|
||||
import com.zmkg.coaloperation.data.bean.ApiResponse
|
||||
import com.zmkg.coaloperation.retorfit.RetrofitManager
|
||||
import com.zmkg.coaloperation.retorfit.RetrofitManager.toRequestBody
|
||||
import com.zmkg.coaloperation.superfuntion.toJson
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.FaceWorkDetailBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingFaceAddBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeItemBean
|
||||
import com.zmkg.coaloperation.ui.home.bean.WaterLedgerBean
|
||||
|
||||
|
||||
object HomeRepository : BaseRepository(){
|
||||
|
||||
private val service by lazy { RetrofitManager.getService(HomeApi::class.java) }
|
||||
|
||||
|
||||
/**
|
||||
* 涌水量观测
|
||||
*/
|
||||
suspend fun getWaterLedgerData(): ApiResponse<MutableList<WaterLedgerBean>> {
|
||||
return apiCall {
|
||||
val map = mutableMapOf<String, Any?>()
|
||||
service.getWaterLedgerData()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 掘进-首页-工作面列表
|
||||
*/
|
||||
suspend fun getTunnelingHomeData(): ApiResponse<MutableList<TunnelingHomeBean>> {
|
||||
return apiCall {
|
||||
val map = mutableMapOf<String, Any?>()
|
||||
service.getTunnelingHomeData()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 掘进-首页-工作面记录列表
|
||||
*/
|
||||
suspend fun getTunnelingHomeItemData(surfaceId: String?): ApiResponse<MutableList<TunnelingHomeItemBean>> {
|
||||
return apiCall {
|
||||
val map = mutableMapOf<String, Any?>()
|
||||
service.getTunnelingHomeItemData(surfaceId)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 掘进-工作面详情
|
||||
*/
|
||||
suspend fun getTunnelingSurfaceDetail(surfaceId: String?): ApiResponse<FaceWorkDetailBean> {
|
||||
return apiCall {
|
||||
val map = mutableMapOf<String, Any?>()
|
||||
service.getTunnelingSurfaceDetail(surfaceId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 掘进-新增工作面
|
||||
*/
|
||||
suspend fun postTunnellingSurfaceAdd(tunnelingFaceAddBean: TunnelingFaceAddBean): ApiResponse<String> {
|
||||
return apiCall {
|
||||
service.postTunnellingSurfaceAdd(tunnelingFaceAddBean.toJson().toRequestBody())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.zmkg.coaloperation.event
|
||||
|
||||
/**
|
||||
* 掘进-工作面列表
|
||||
*/
|
||||
class TunnelingWorkFaceRefreshEvent {
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//package com.zmkg.coaloperation.http
|
||||
//
|
||||
//
|
||||
//import android.annotation.SuppressLint
|
||||
//import android.util.Log
|
||||
//import okhttp3.Call
|
||||
//import okhttp3.Interceptor
|
||||
//import okhttp3.OkHttpClient
|
||||
//import okhttp3.Request
|
||||
//import okhttp3.Response
|
||||
//import java.util.concurrent.TimeUnit
|
||||
//
|
||||
//import javax.net.ssl.*
|
||||
//import java.security.SecureRandom
|
||||
//import java.security.cert.X509Certificate
|
||||
//
|
||||
//class HttpClient private constructor() {
|
||||
// private val client: OkHttpClient by lazy {
|
||||
// OkHttpClient.Builder()
|
||||
// .apply {
|
||||
// connectTimeout(15, TimeUnit.SECONDS)
|
||||
// readTimeout(30, TimeUnit.SECONDS)
|
||||
// writeTimeout(15, TimeUnit.SECONDS)
|
||||
// sslSocketFactory(createSSLSocketFactory(), TrustAllCerts())
|
||||
// hostnameVerifier { _, _ -> true }
|
||||
// //if (BuildConfig.Debug) {
|
||||
// addInterceptor(LoggingInterceptor())
|
||||
// // }
|
||||
// }
|
||||
// .build()
|
||||
// }
|
||||
//
|
||||
// companion object {
|
||||
// val instance by lazy { HttpClient() }
|
||||
// }
|
||||
//
|
||||
// fun newCall(request: Request): Call = client.newCall(request)
|
||||
//
|
||||
// inner class LoggingInterceptor : Interceptor {
|
||||
// override fun intercept(chain: Interceptor.Chain): Response {
|
||||
// val request = chain.request()
|
||||
// // 打印请求日志
|
||||
// Log.d("OkHttp", "--> ${request.method} ${request.url}")
|
||||
//
|
||||
// val response = chain.proceed(request)
|
||||
// // 打印响应日志
|
||||
// Log.d("OkHttp", "<-- ${response.code} ${response.request.url}")
|
||||
//
|
||||
// return response
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 信任所有证书的TrustManager实现
|
||||
// @SuppressLint("CustomX509TrustManager")
|
||||
// class TrustAllCerts : X509TrustManager {
|
||||
// @SuppressLint("TrustAllX509TrustManager")
|
||||
// override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
|
||||
// @SuppressLint("TrustAllX509TrustManager")
|
||||
// override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}
|
||||
// override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
|
||||
// }
|
||||
//
|
||||
// // 创建信任所有证书的SSLSocketFactory
|
||||
// fun createSSLSocketFactory(): SSLSocketFactory {
|
||||
// val sslContext = SSLContext.getInstance("TLS").apply {
|
||||
// init(null, arrayOf(TrustAllCerts()), SecureRandom())
|
||||
// }
|
||||
// return sslContext.socketFactory
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -0,0 +1,134 @@
|
||||
//package com.zmkg.coaloperation.http
|
||||
//
|
||||
//import android.os.Handler
|
||||
//import android.os.Looper
|
||||
//import android.util.Log
|
||||
//import com.google.gson.reflect.TypeToken
|
||||
//import com.zmkg.coaloperation.data.bean.ApiResponse
|
||||
//import com.zmkg.coaloperation.http.HttpUtil.runMainThread
|
||||
//import com.zmkg.coaloperation.utils.toType
|
||||
//import okhttp3.Call
|
||||
//import okhttp3.Callback
|
||||
//import okhttp3.HttpUrl
|
||||
//import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
//import okhttp3.Request
|
||||
//import okhttp3.RequestBody.Companion.toRequestBody
|
||||
//import okhttp3.Response
|
||||
//import java.io.IOException
|
||||
//
|
||||
//
|
||||
//object HttpUtil {
|
||||
//
|
||||
// fun runMainThread(action: () -> Unit) {
|
||||
// Handler(Looper.getMainLooper()).post {
|
||||
// action()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // GET请求(HTTPS)
|
||||
// fun get(
|
||||
// url: String,
|
||||
// doSuccess: (data: Any) -> Unit,
|
||||
// doFailure: (code: Int?, msg: String?) -> Unit
|
||||
// ) {
|
||||
//// val token = getToken()
|
||||
// val request = Request.Builder()
|
||||
// .url(url)
|
||||
// .apply {
|
||||
//// if (token.isNotBlank()) {
|
||||
//// addHeader("X-Access-Token", token)
|
||||
//// }
|
||||
// }
|
||||
// .get()
|
||||
// .build()
|
||||
// HttpClient.instance.newCall(request).enqueue(CallbackImpl(doSuccess, doFailure))
|
||||
// }
|
||||
//
|
||||
//// fun get(
|
||||
//// isHttps: Boolean = false,
|
||||
//// host: String = "vip.shuziweidao.com",
|
||||
//// pathSegmentList: List<String>,
|
||||
//// queryParams: Map<String, String>,
|
||||
//// doSuccess: (data: Any) -> Unit,
|
||||
//// doFailure: (code: Int?, msg: String?) -> Unit
|
||||
//// ) {
|
||||
////// val token = getToken()
|
||||
//// val url = HttpUrl.Builder()
|
||||
//// .scheme(if (isHttps) "https" else "http")
|
||||
//// .host(host)
|
||||
//// .apply {
|
||||
//// pathSegmentList.forEach { addPathSegment(it) }
|
||||
//// queryParams.forEach { (key, value) -> addQueryParameter(key, value) }
|
||||
//// }
|
||||
//// .build()
|
||||
//// val request = Request.Builder()
|
||||
//// .url(url)
|
||||
//// .apply {
|
||||
////// if (token.isNotBlank()) {
|
||||
////// addHeader("Authorization", token)
|
||||
////// }
|
||||
//// }
|
||||
//// .get()
|
||||
//// .build()
|
||||
//// HttpClient.instance.newCall(request).enqueue(CallbackImpl(doSuccess, doFailure))
|
||||
//// }
|
||||
//
|
||||
// // POST JSON(HTTPS)
|
||||
// fun postJson(
|
||||
// url: String,
|
||||
// json: String,
|
||||
// doSuccess: (data: Any) -> Unit,
|
||||
// doFailure: (code: Int?, msg: String?) -> Unit
|
||||
// ) {
|
||||
// val body = json
|
||||
// .toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
|
||||
//// val token = getToken()
|
||||
// Request.Builder()
|
||||
// .url(url)
|
||||
// .apply {
|
||||
//// if (token.isNotBlank()) {
|
||||
//// addHeader("X-Access-Token", token)
|
||||
//// }
|
||||
// }
|
||||
// .post(body)
|
||||
// .build()
|
||||
// .let { HttpClient.instance.newCall(it).enqueue(CallbackImpl(doSuccess, doFailure)) }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//
|
||||
//class CallbackImpl(
|
||||
// private val doSuccess: (data: Any) -> Unit,
|
||||
// private val doFailure: (code: Int?, msg: String?) -> Unit
|
||||
//) :
|
||||
// Callback {
|
||||
// override fun onFailure(call: Call, e: IOException) {
|
||||
// runMainThread {
|
||||
// e.printStackTrace()
|
||||
// doFailure(-1, "服务异常,${e.message}")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun onResponse(call: Call, response: Response) {
|
||||
// val respData = response.body?.string()
|
||||
// runMainThread {
|
||||
// Log.d("HttpUtil", respData ?: "")
|
||||
// runCatching {
|
||||
// val typeToken = object : TypeToken<ApiResponse<Any>>() {}
|
||||
// val baseReq = respData?.toType<ApiResponse<Any>>(typeToken = typeToken)
|
||||
// if (baseReq == null) {
|
||||
// doFailure(-1, "查询数据失败")
|
||||
// return@runCatching
|
||||
// }
|
||||
// if (baseReq.code != 200) {
|
||||
// doFailure(baseReq.code, baseReq.msg)
|
||||
// return@runCatching
|
||||
// }
|
||||
// doSuccess(baseReq.data ?: "")
|
||||
// }.onFailure {
|
||||
// it.printStackTrace()
|
||||
// doFailure(-1, "解析异常")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
package com.zmkg.coaloperation.http
|
||||
|
||||
import com.zmkg.coaloperation.retorfit.UrlConfig
|
||||
|
||||
object UrlConst {
|
||||
|
||||
|
||||
|
||||
val FACE_LIST = "${UrlConfig.getDefaultBaseUrl()}/api/mine/tunnelling/surface/list"
|
||||
val RECORD_LIST = "${UrlConfig.getDefaultBaseUrl()}/api/mine/tunnelling/surface/record/"
|
||||
|
||||
}*/
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.zmkg.coaloperation.im.signature;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* Module: GenerateTestUserSig
|
||||
*
|
||||
* Function: Used to generate UserSig for testing. UserSig is a security signature designed by Tencent Cloud for its cloud services.
|
||||
* It is calculated based on SDKAppID, UserID, and EXPIRETIME using the HMAC-SHA256 encryption algorithm.
|
||||
*
|
||||
* Attention: Do not use the code below in your commercial application. This is because:
|
||||
*
|
||||
* The code may be able to calculate UserSig correctly, but it is only for quick testing of the SDK’s basic features, not for commercial applications.
|
||||
* SECRETKEY in client code can be easily decompiled and reversed, especially on web.
|
||||
* Once your key is disclosed, attackers will be able to steal your Tencent Cloud traffic.
|
||||
*
|
||||
* The correct method is to deploy the UserSig calculation code and encryption key on your project server so that your application can request from your server a UserSig that is calculated whenever one is needed.
|
||||
* Given that it is more difficult to hack a server than a client application, server-end calculation can better protect your key.
|
||||
*
|
||||
* Reference: https://intl.cloud.tencent.com/document/product/1047/34385
|
||||
*/
|
||||
public class GenerateTestUserSig {
|
||||
|
||||
/**
|
||||
* Tencent Cloud SDKAppID. Set it to the SDKAppID of your account.
|
||||
* <p>
|
||||
* You can view your SDKAppID after creating an application in the [Tencent Cloud IM console](https://console.intl.cloud.tencent.com/im).
|
||||
* SDKAppID uniquely identifies a Tencent Cloud account.
|
||||
*/
|
||||
public static final int SDKAPPID = 1600100891;
|
||||
|
||||
/**
|
||||
* Signature validity period, which should not be set too short
|
||||
* <p>
|
||||
* Time unit: second
|
||||
* Default value: 604800 (7 days)
|
||||
*/
|
||||
private static final int EXPIRETIME = 604800;
|
||||
|
||||
/**
|
||||
* Follow the steps below to obtain the key required for UserSig calculation.
|
||||
* <p>
|
||||
* Step 1. Log in to the [Tencent Cloud IM console](https://console.intl.cloud.tencent.com/im), and create an application if you don’t have one.
|
||||
* Step 2. Click Application Configuration to go to the basic configuration page and locate Account System Integration.
|
||||
* Step 3. Click View Key to view the encrypted key used for UserSig calculation. Then copy and paste the key to the variable below.
|
||||
* <p>
|
||||
* Note: this method is for testing only. Before commercial launch, please migrate the UserSig calculation code and key to your backend server to prevent key disclosure and traffic stealing.
|
||||
* Reference: https://intl.cloud.tencent.com/document/product/1047/34385
|
||||
*/
|
||||
private static final String SECRETKEY = "296af72bcd9c21dae430492e6ddc784e49a3cac2d28f616fff107bde4344945d";
|
||||
|
||||
/**
|
||||
* Calculate UserSig
|
||||
* <p>
|
||||
* The asymmetric encryption algorithm HMAC-SHA256 is used in the function to calculate UserSig based on SDKAppID, UserID, and EXPIRETIME.
|
||||
*
|
||||
* @note: Do not use the code below in your commercial application. This is because:
|
||||
* <p>
|
||||
* The code may be able to calculate UserSig correctly, but it is only for quick testing of the SDK’s basic features, not for commercial applications.
|
||||
* SECRETKEY in client code can be easily decompiled and reversed, especially on web.
|
||||
* Once your key is disclosed, attackers will be able to steal your Tencent Cloud traffic.
|
||||
* <p>
|
||||
* The correct method is to deploy the UserSig calculation code and encryption key on your project server so that your application can request from your server a UserSig that is calculated whenever one is needed.
|
||||
* Given that it is more difficult to hack a server than a client application, server-end calculation can better protect your key.
|
||||
* <p>
|
||||
* Reference: https://intl.cloud.tencent.com/document/product/1047/34385
|
||||
*/
|
||||
public static String genTestUserSig(String userId) {
|
||||
return GenTLSSignature(SDKAPPID, userId, EXPIRETIME, null, SECRETKEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a TLS ticket
|
||||
*
|
||||
* @param sdkappid AppID of the application
|
||||
* @param userId User ID
|
||||
* @param expire Validity period, in seconds
|
||||
* @param userbuf null by default
|
||||
* @param priKeyContent Private key required for generating a TLS ticket
|
||||
* @return If an error occurs, an empty string will be returned or exceptions printed. If the operation succeeds, a valid ticket will be returned.
|
||||
*/
|
||||
private static String GenTLSSignature(long sdkappid, String userId, long expire, byte[] userbuf, String priKeyContent) {
|
||||
if (TextUtils.isEmpty(priKeyContent)) {
|
||||
return "";
|
||||
}
|
||||
long currTime = System.currentTimeMillis() / 1000;
|
||||
JSONObject sigDoc = new JSONObject();
|
||||
try {
|
||||
sigDoc.put("TLS.ver", "2.0");
|
||||
sigDoc.put("TLS.identifier", userId);
|
||||
sigDoc.put("TLS.sdkappid", sdkappid);
|
||||
sigDoc.put("TLS.expire", expire);
|
||||
sigDoc.put("TLS.time", currTime);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String base64UserBuf = null;
|
||||
if (null != userbuf) {
|
||||
base64UserBuf = Base64.encodeToString(userbuf, Base64.NO_WRAP);
|
||||
try {
|
||||
sigDoc.put("TLS.userbuf", base64UserBuf);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
String sig = hmacsha256(sdkappid, userId, currTime, expire, priKeyContent, base64UserBuf);
|
||||
if (sig.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
sigDoc.put("TLS.sig", sig);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Deflater compressor = new Deflater();
|
||||
compressor.setInput(sigDoc.toString().getBytes(Charset.forName("UTF-8")));
|
||||
compressor.finish();
|
||||
byte[] compressedBytes = new byte[2048];
|
||||
int compressedBytesLength = compressor.deflate(compressedBytes);
|
||||
compressor.end();
|
||||
return new String(base64EncodeUrl(Arrays.copyOfRange(compressedBytes, 0, compressedBytesLength)));
|
||||
}
|
||||
|
||||
|
||||
private static String hmacsha256(long sdkappid, String userId, long currTime, long expire, String priKeyContent, String base64Userbuf) {
|
||||
String contentToBeSigned = "TLS.identifier:" + userId + "\n"
|
||||
+ "TLS.sdkappid:" + sdkappid + "\n"
|
||||
+ "TLS.time:" + currTime + "\n"
|
||||
+ "TLS.expire:" + expire + "\n";
|
||||
if (null != base64Userbuf) {
|
||||
contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
|
||||
}
|
||||
try {
|
||||
byte[] byteKey = priKeyContent.getBytes("UTF-8");
|
||||
Mac hmac = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
|
||||
hmac.init(keySpec);
|
||||
byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes("UTF-8"));
|
||||
return new String(Base64.encode(byteSig, Base64.NO_WRAP));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return "";
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return "";
|
||||
} catch (InvalidKeyException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] base64EncodeUrl(byte[] input) {
|
||||
byte[] base64 = new String(Base64.encode(input, Base64.NO_WRAP)).getBytes();
|
||||
for (int i = 0; i < base64.length; ++i)
|
||||
switch (base64[i]) {
|
||||
case '+':
|
||||
base64[i] = '*';
|
||||
break;
|
||||
case '/':
|
||||
base64[i] = '-';
|
||||
break;
|
||||
case '=':
|
||||
base64[i] = '_';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return base64;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.zmkg.coaloperation.local
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object DataStoreManager {
|
||||
|
||||
private const val TAG = "CommonSPUtils"
|
||||
private const val KEY_USER_NAME = "user_name"
|
||||
private const val KEY_HOME_DATA = "home_data"
|
||||
|
||||
|
||||
private lateinit var dataStore: DataStoreUtils
|
||||
|
||||
fun initialize(context: Context?) {
|
||||
if (context == null) {
|
||||
Log.w(TAG, "initialize: context is null")
|
||||
return
|
||||
}
|
||||
|
||||
context?.apply {
|
||||
dataStore = DataStoreUtils.init(context)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
fun setUserName(userName: String) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
dataStore?.putData(KEY_USER_NAME, userName)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
fun getUserName(): String {
|
||||
return if (DataStoreManager::dataStore.isInitialized) {
|
||||
dataStore.getSyncData(KEY_USER_NAME, "")
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 首页tab数据
|
||||
*/
|
||||
fun getHomeData(): String {
|
||||
return if (DataStoreManager::dataStore.isInitialized) {
|
||||
dataStore.getSyncData(KEY_HOME_DATA, "")
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 首页tab数据
|
||||
*/
|
||||
fun setHomeData(homeData:String) {
|
||||
|
||||
dataStore?.putSyncData(KEY_HOME_DATA, homeData)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
package com.zmkg.coaloperation.local
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.*
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.IOException
|
||||
/**
|
||||
*
|
||||
* 异步获取数据
|
||||
* [getData] [readBooleanFlow] [readFloatFlow] [readIntFlow] [readLongFlow] [readStringFlow]
|
||||
* 同步获取数据
|
||||
* [getSyncData] [readBooleanData] [readFloatData] [readIntData] [readLongData] [readStringData]
|
||||
*
|
||||
* 异步写入数据
|
||||
* [putData] [saveBooleanData] [saveFloatData] [saveIntData] [saveLongData] [saveStringData]
|
||||
* 同步写入数据
|
||||
* [putSyncData] [saveSyncBooleanData] [saveSyncFloatData] [saveSyncIntData] [saveSyncLongData] [saveSyncStringData]
|
||||
*
|
||||
* 异步清除数据
|
||||
* [clear]
|
||||
* 同步清除数据
|
||||
* [clearSync]
|
||||
*
|
||||
* 描述:DataStore 工具类
|
||||
*
|
||||
*/
|
||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "CoalOperation")
|
||||
|
||||
object DataStoreUtils {
|
||||
|
||||
private lateinit var dataStore: DataStore<Preferences>
|
||||
|
||||
/**
|
||||
* init Context
|
||||
* @param context Context
|
||||
*/
|
||||
fun init(context: Context): DataStoreUtils {
|
||||
dataStore = context.dataStore
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <U> getSyncData(key: String, default: U): U {
|
||||
val res = when (default) {
|
||||
is Long -> readLongData(key, default)
|
||||
is String -> readStringData(key, default)
|
||||
is Int -> readIntData(key, default)
|
||||
is Boolean -> readBooleanData(key, default)
|
||||
is Float -> readFloatData(key, default)
|
||||
else -> throw IllegalArgumentException("This type can be saved into DataStore")
|
||||
}
|
||||
return res as U
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <U> getData(key: String, default: U): Flow<U> {
|
||||
val data = when (default) {
|
||||
is Long -> readLongFlow(key, default)
|
||||
is String -> readStringFlow(key, default)
|
||||
is Int -> readIntFlow(key, default)
|
||||
is Boolean -> readBooleanFlow(key, default)
|
||||
is Float -> readFloatFlow(key, default)
|
||||
else -> throw IllegalArgumentException("This type can be saved into DataStore")
|
||||
}
|
||||
return data as Flow<U>
|
||||
}
|
||||
|
||||
suspend fun <U> putData(key: String, value: U) {
|
||||
when (value) {
|
||||
is Long -> saveLongData(key, value)
|
||||
is String -> saveStringData(key, value)
|
||||
is Int -> saveIntData(key, value)
|
||||
is Boolean -> saveBooleanData(key, value)
|
||||
is Float -> saveFloatData(key, value)
|
||||
else -> throw IllegalArgumentException("This type can be saved into DataStore")
|
||||
}
|
||||
}
|
||||
|
||||
fun <U> putSyncData(key: String, value: U) {
|
||||
when (value) {
|
||||
is Long -> saveSyncLongData(key, value)
|
||||
is String -> saveSyncStringData(key, value)
|
||||
is Int -> saveSyncIntData(key, value)
|
||||
is Boolean -> saveSyncBooleanData(key, value)
|
||||
is Float -> saveSyncFloatData(key, value)
|
||||
else -> throw IllegalArgumentException("This type can be saved into DataStore")
|
||||
}
|
||||
}
|
||||
|
||||
private fun readBooleanFlow(key: String, default: Boolean = false): Flow<Boolean> =
|
||||
dataStore.data
|
||||
.catch {
|
||||
//当读取数据遇到错误时,如果是 `IOException` 异常,发送一个 emptyPreferences 来重新使用
|
||||
//但是如果是其他的异常,最好将它抛出去,不要隐藏问题
|
||||
if (it is IOException) {
|
||||
it.printStackTrace()
|
||||
emit(emptyPreferences())
|
||||
} else {
|
||||
throw it
|
||||
}
|
||||
}.map {
|
||||
it[booleanPreferencesKey(key)] ?: default
|
||||
}
|
||||
|
||||
private fun readBooleanData(key: String, default: Boolean = false): Boolean {
|
||||
var value = false
|
||||
runBlocking {
|
||||
dataStore.data.first {
|
||||
value = it[booleanPreferencesKey(key)] ?: default
|
||||
true
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
private fun readIntFlow(key: String, default: Int = 0): Flow<Int> =
|
||||
dataStore.data
|
||||
.catch {
|
||||
if (it is IOException) {
|
||||
it.printStackTrace()
|
||||
emit(emptyPreferences())
|
||||
} else {
|
||||
throw it
|
||||
}
|
||||
}.map {
|
||||
it[intPreferencesKey(key)] ?: default
|
||||
}
|
||||
|
||||
fun readIntData(key: String, default: Int = 0): Int {
|
||||
var value = 0
|
||||
runBlocking {
|
||||
dataStore.data.first {
|
||||
value = it[intPreferencesKey(key)] ?: default
|
||||
true
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
private fun readStringFlow(key: String, default: String = ""): Flow<String> =
|
||||
dataStore.data
|
||||
.catch {
|
||||
if (it is IOException) {
|
||||
it.printStackTrace()
|
||||
emit(emptyPreferences())
|
||||
} else {
|
||||
throw it
|
||||
}
|
||||
}.map {
|
||||
it[stringPreferencesKey(key)] ?: default
|
||||
}
|
||||
|
||||
private fun readStringData(key: String, default: String = ""): String {
|
||||
var value = ""
|
||||
runBlocking {
|
||||
dataStore.data.first {
|
||||
value = it[stringPreferencesKey(key)] ?: default
|
||||
true
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
private fun readFloatFlow(key: String, default: Float = 0f): Flow<Float> =
|
||||
dataStore.data
|
||||
.catch {
|
||||
if (it is IOException) {
|
||||
it.printStackTrace()
|
||||
emit(emptyPreferences())
|
||||
} else {
|
||||
throw it
|
||||
}
|
||||
}.map {
|
||||
it[floatPreferencesKey(key)] ?: default
|
||||
}
|
||||
|
||||
private fun readFloatData(key: String, default: Float = 0f): Float {
|
||||
var value = 0f
|
||||
runBlocking {
|
||||
dataStore.data.first {
|
||||
value = it[floatPreferencesKey(key)] ?: default
|
||||
true
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
private fun readLongFlow(key: String, default: Long = 0L): Flow<Long> =
|
||||
dataStore.data
|
||||
.catch {
|
||||
if (it is IOException) {
|
||||
it.printStackTrace()
|
||||
emit(emptyPreferences())
|
||||
} else {
|
||||
throw it
|
||||
}
|
||||
}.map {
|
||||
it[longPreferencesKey(key)] ?: default
|
||||
}
|
||||
|
||||
private fun readLongData(key: String, default: Long = 0L): Long {
|
||||
var value = 0L
|
||||
runBlocking {
|
||||
dataStore.data.first {
|
||||
value = it[longPreferencesKey(key)] ?: default
|
||||
true
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
suspend fun saveBooleanData(key: String, value: Boolean) {
|
||||
dataStore.edit { mutablePreferences ->
|
||||
mutablePreferences[booleanPreferencesKey(key)] = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveSyncBooleanData(key: String, value: Boolean) =
|
||||
runBlocking { saveBooleanData(key, value) }
|
||||
|
||||
private suspend fun saveIntData(key: String, value: Int) {
|
||||
dataStore.edit { mutablePreferences ->
|
||||
mutablePreferences[intPreferencesKey(key)] = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveSyncIntData(key: String, value: Int) = runBlocking { saveIntData(key, value) }
|
||||
|
||||
private suspend fun saveStringData(key: String, value: String) {
|
||||
dataStore.edit { mutablePreferences ->
|
||||
mutablePreferences[stringPreferencesKey(key)] = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveSyncStringData(key: String, value: String) = runBlocking { saveStringData(key, value) }
|
||||
|
||||
private suspend fun saveFloatData(key: String, value: Float) {
|
||||
dataStore.edit { mutablePreferences ->
|
||||
mutablePreferences[floatPreferencesKey(key)] = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveSyncFloatData(key: String, value: Float) = runBlocking { saveFloatData(key, value) }
|
||||
|
||||
private suspend fun saveLongData(key: String, value: Long) {
|
||||
dataStore.edit { mutablePreferences ->
|
||||
mutablePreferences[longPreferencesKey(key)] = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveSyncLongData(key: String, value: Long) = runBlocking { saveLongData(key, value) }
|
||||
|
||||
suspend fun clear() {
|
||||
dataStore.edit {
|
||||
it.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun clearSync() {
|
||||
runBlocking {
|
||||
dataStore.edit {
|
||||
it.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.zmkg.coaloperation.retorfit
|
||||
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.zmkg.coaloperation.retorfit.UrlConfig.getDefaultBaseUrl
|
||||
import com.zmkg.coaloperation.retorfit.gson.GsonConverterFactory
|
||||
import com.zmkg.coaloperation.retorfit.interceptor.logInterceptor
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import retrofit2.Retrofit
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Retrofit管理类
|
||||
*
|
||||
*/
|
||||
object RetrofitManager {
|
||||
/** 请求超时时间 */
|
||||
private const val TIME_OUT_SECONDS = 30
|
||||
|
||||
/** 请求cookie */
|
||||
// val cookieJar: PersistentCookieJar by lazy {
|
||||
// PersistentCookieJar(
|
||||
// SetCookieCache(),
|
||||
// SharedPrefsCookiePersistor(appContext)
|
||||
// )
|
||||
// }
|
||||
|
||||
/** 请求根地址 */
|
||||
private val BASE_URL: String get() =
|
||||
getDefaultBaseUrl()
|
||||
|
||||
|
||||
/** OkHttpClient相关配置 */
|
||||
private val client: OkHttpClient
|
||||
get() = OkHttpClient.Builder()
|
||||
// .addInterceptor(CustomSignInterceptor())
|
||||
// 请求过滤器
|
||||
.addInterceptor(logInterceptor)
|
||||
// .dns(ApiDns())
|
||||
//设置缓存配置,缓存最大10M,设置了缓存之后可缓存请求的数据到data/data/包名/cache/net_cache目录中
|
||||
// .cache(Cache(File(appContext.cacheDir, "net_cache"), 10 * 1024 * 1024))
|
||||
//添加缓存拦截器 可传入缓存天数
|
||||
// .addInterceptor(CacheInterceptor(30))
|
||||
// 请求超时时间
|
||||
.connectTimeout(TIME_OUT_SECONDS.toLong(), TimeUnit.SECONDS)
|
||||
.readTimeout(TIME_OUT_SECONDS.toLong(), TimeUnit.SECONDS)
|
||||
.writeTimeout(TIME_OUT_SECONDS.toLong(), TimeUnit.SECONDS)
|
||||
// .cookieJar(cookieJar)
|
||||
.build()
|
||||
/**
|
||||
* Retrofit相关配置
|
||||
*/
|
||||
private fun initRetrofit(client: OkHttpClient, baseUrl: String?): Retrofit{
|
||||
return Retrofit.Builder()
|
||||
.client(client)
|
||||
// 使用Moshi更适合Kotlin
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.baseUrl(baseUrl ?: BASE_URL)
|
||||
.build()
|
||||
}
|
||||
|
||||
private val retrofit: Retrofit by lazy {
|
||||
initRetrofit(client, BASE_URL)
|
||||
}
|
||||
|
||||
public fun getRetrofits():Retrofit{
|
||||
return retrofit
|
||||
}
|
||||
|
||||
fun <T> getService(serviceClass: Class<T>, baseUrl: String? = null): T {
|
||||
Logger.e(BASE_URL)
|
||||
if(retrofit != null && baseUrl.isNullOrEmpty()){
|
||||
return retrofit.create(serviceClass)
|
||||
}
|
||||
return initRetrofit(client, baseUrl).create(serviceClass)
|
||||
}
|
||||
|
||||
fun String.toRequestBody(): RequestBody {
|
||||
return toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.zmkg.coaloperation.retorfit
|
||||
|
||||
object UrlConfig {
|
||||
const val DEBUG_DEFAULT_IP_ADDRESS_REMOTE = "http://12hy52961ur4.vicp.fun"
|
||||
// "http://152.136.21.220:9003" // 开发环境
|
||||
const val TEST_DEFAULT_IP_ADDRESS_REMOTE = "" // 测试环境
|
||||
const val PRODUCT_DEFAULT_IP_ADDRESS_REMOTE = "" // 线上环境
|
||||
|
||||
const val prefix="/app-lsd-api"
|
||||
|
||||
var baseUrlType: BaseUrlType = BaseUrlType.DEBUG
|
||||
var isOpenIm: Boolean = true
|
||||
|
||||
|
||||
enum class BaseUrlType(val type: Int) {
|
||||
DEBUG(1),
|
||||
TEST(2),
|
||||
PRODUCT(3)
|
||||
}
|
||||
|
||||
private fun getBaseUrl(baseUrlType: BaseUrlType = BaseUrlType.DEBUG): String {
|
||||
return when (baseUrlType) {
|
||||
BaseUrlType.DEBUG -> {
|
||||
DEBUG_DEFAULT_IP_ADDRESS_REMOTE
|
||||
}
|
||||
|
||||
BaseUrlType.TEST -> {
|
||||
TEST_DEFAULT_IP_ADDRESS_REMOTE
|
||||
}
|
||||
|
||||
BaseUrlType.PRODUCT -> {
|
||||
PRODUCT_DEFAULT_IP_ADDRESS_REMOTE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 方便后续加一些其他逻辑
|
||||
*/
|
||||
fun getDefaultBaseUrl(): String {
|
||||
return getBaseUrl(baseUrlType)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Square, Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package com.zmkg.coaloperation.retorfit.gson;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Converter;
|
||||
import retrofit2.Retrofit;
|
||||
|
||||
/**
|
||||
* A {@linkplain Converter.Factory converter} which uses Gson for JSON.
|
||||
*
|
||||
* <p>Because Gson is so flexible in the types it supports, this converter assumes that it can
|
||||
* handle all types. If you are mixing JSON serialization with something else (such as protocol
|
||||
* buffers), you must {@linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this
|
||||
* instance} last to allow the other converters a chance to see their types.
|
||||
*/
|
||||
public final class GsonConverterFactory extends Converter.Factory {
|
||||
public static GsonConverterFactory create() {
|
||||
return create(new Gson());
|
||||
}
|
||||
|
||||
public static GsonConverterFactory create(Gson gson) {
|
||||
return new GsonConverterFactory(gson);
|
||||
}
|
||||
|
||||
private final Gson gson;
|
||||
|
||||
private GsonConverterFactory(Gson gson) {
|
||||
if (gson == null) throw new NullPointerException("gson == null");
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
|
||||
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
|
||||
|
||||
return new GsonResponseBodyConverter<>(gson, adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
|
||||
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
|
||||
return new GsonRequestBodyConverter<>(gson, adapter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.zmkg.coaloperation.retorfit.gson;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okio.Buffer;
|
||||
import retrofit2.Converter;
|
||||
|
||||
public final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
|
||||
private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
|
||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
|
||||
private final Gson gson;
|
||||
private final TypeAdapter<T> adapter;
|
||||
|
||||
public GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
|
||||
this.gson = gson;
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBody convert(T value) throws IOException {
|
||||
Buffer buffer = new Buffer();
|
||||
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
|
||||
JsonWriter jsonWriter = gson.newJsonWriter(writer);
|
||||
adapter.write(jsonWriter, value);
|
||||
jsonWriter.close();
|
||||
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.zmkg.coaloperation.retorfit.gson;
|
||||
|
||||
import static com.google.common.base.Charsets.UTF_8;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Converter;
|
||||
|
||||
public final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
|
||||
private final Gson gson;
|
||||
private final TypeAdapter<T> adapter;
|
||||
|
||||
public GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
|
||||
this.gson = gson;
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T convert(ResponseBody value) throws IOException {
|
||||
try {
|
||||
String response = value.string();
|
||||
JSONObject jsonObject= null;
|
||||
try {
|
||||
jsonObject = new JSONObject(response);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
boolean success = jsonObject.optBoolean("success");
|
||||
boolean ok = jsonObject.optBoolean("ok");
|
||||
String message = jsonObject.optString("message");
|
||||
JsonReader jsonReader =null;
|
||||
MediaType mediaType = value.contentType();
|
||||
Charset charset=mediaType!=null?mediaType.charset(UTF_8):UTF_8;
|
||||
InputStream inputStream=new ByteArrayInputStream(response.getBytes());
|
||||
jsonReader=gson.newJsonReader(new InputStreamReader(inputStream,charset));
|
||||
if (success||ok) {
|
||||
int code=jsonObject.optInt("code");
|
||||
if(code==0){
|
||||
return adapter.read(jsonReader);
|
||||
}else if(code!=200){
|
||||
value.close();
|
||||
// throw new JsonIOException(message);
|
||||
try {
|
||||
jsonObject.put("result", JSONObject.NULL);
|
||||
jsonObject.put("data", JSONObject.NULL);
|
||||
JsonReader jsonReader2=gson.newJsonReader(new InputStreamReader(new ByteArrayInputStream(jsonObject.toString().getBytes()),charset));
|
||||
return adapter.read(jsonReader2);
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}else{
|
||||
return adapter.read(jsonReader);
|
||||
}
|
||||
}else{
|
||||
int code=jsonObject.optInt("code");
|
||||
if(code!=200){
|
||||
value.close();
|
||||
// throw new JsonIOException(message);
|
||||
try {
|
||||
jsonObject.put("result", JSONObject.NULL);
|
||||
jsonObject.put("data", JSONObject.NULL);
|
||||
JsonReader jsonReader2=gson.newJsonReader(new InputStreamReader(new ByteArrayInputStream(jsonObject.toString().getBytes()),charset));
|
||||
return adapter.read(jsonReader2);
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}else{
|
||||
return adapter.read(jsonReader);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
value.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.zmkg.coaloperation.retorfit.interceptor
|
||||
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.zmkg.coaloperation.BuildConfig
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
|
||||
/**
|
||||
* okhttp 日志拦截器
|
||||
*/
|
||||
val logInterceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
|
||||
override fun log(message: String) {
|
||||
// 使用自己的日志工具接管
|
||||
Logger.d(message)
|
||||
}
|
||||
}).setLevel(if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.BASIC)
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.zmkg.coaloperation.superfuntion
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.tencent.imsdk.BaseConstants
|
||||
import com.tencent.qcloud.tuicore.TUILogin
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUICallback
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUILoginConfig
|
||||
import com.zmkg.coaloperation.MyApplication
|
||||
import com.zmkg.coaloperation.im.signature.GenerateTestUserSig
|
||||
import com.zmkg.coaloperation.local.DataStoreManager
|
||||
import com.zmkg.coaloperation.retorfit.UrlConfig
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 腾讯im登录方法
|
||||
*/
|
||||
|
||||
fun Context.loginIm(userId: String,successCall: () -> Unit = {}) {
|
||||
val userSig = GenerateTestUserSig.genTestUserSig(userId)
|
||||
|
||||
if (!UrlConfig.isOpenIm){
|
||||
// successCall.invoke()
|
||||
return
|
||||
}
|
||||
if (TUILogin.isUserLogined() && userId == TUILogin.getUserId()) {
|
||||
// successCall.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
TUILogin.login(
|
||||
this,
|
||||
GenerateTestUserSig.SDKAPPID,
|
||||
userId,
|
||||
userSig,
|
||||
TUILoginConfig(),
|
||||
object : TUICallback() {
|
||||
override fun onError(code: Int, desc: String) {
|
||||
// successCall.invoke()
|
||||
when (code) {
|
||||
BaseConstants.ERR_SVR_ACCOUNT_USERSIG_EXPIRED,
|
||||
BaseConstants.ERR_USER_SIG_EXPIRED -> {//UserSig过期
|
||||
// CustomToast.makeText(this@loginIm,"im登录失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
Log.i(MyApplication.TAG, "imLogin errorCode = $code, errorInfo = $desc")
|
||||
}
|
||||
|
||||
override fun onSuccess() {
|
||||
// successCall.invoke()
|
||||
Log.i(MyApplication.TAG, "imLogin onSuccess ")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fun logout(successCall: () -> Unit = {}){
|
||||
if (!TUILogin.isUserLogined()){
|
||||
return
|
||||
}
|
||||
CoroutineScope(Dispatchers.Main).launch{
|
||||
DataStoreManager.setUserName("")
|
||||
}
|
||||
TUILogin.logout(object : TUICallback(){
|
||||
override fun onSuccess() {
|
||||
successCall.invoke()
|
||||
}
|
||||
|
||||
override fun onError(errorCode: Int, errorMessage: String?) {
|
||||
Log.i("","IM logout errorCode = $errorCode, errorInfo = $errorMessage")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.zmkg.coaloperation.superfuntion
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.gson.JsonSyntaxException
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel.Companion.LOADING_STATE_HIDE
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel.Companion.LOADING_STATE_SHOW
|
||||
import com.zmkg.coaloperation.data.bean.ApiResponse
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.json.JSONException
|
||||
|
||||
/**
|
||||
* BaseViewModel的一些扩展方法
|
||||
*/
|
||||
|
||||
/**
|
||||
* 启动协程,封装了viewModelScope.launch
|
||||
*
|
||||
* @param showDialog 是否显示加载框
|
||||
* @param tryBlock try语句运行的函数
|
||||
* @param catchBlock catch语句运行的函数,可以用来做一些网络异常等的处理,默认空实现
|
||||
* @param finallyBlock finally语句运行的函数,可以用来做一些资源回收等,默认空实现
|
||||
*/
|
||||
fun BaseViewModel.launch(
|
||||
showDialog: Boolean,
|
||||
tryBlock: suspend CoroutineScope.() -> Unit,
|
||||
catchBlock: suspend CoroutineScope.() -> Unit = {},
|
||||
finallyBlock: suspend CoroutineScope.() -> Unit = {}
|
||||
) {
|
||||
// 默认是执行在主线程,相当于launch(Dispatchers.Main)
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
if (showDialog) {
|
||||
loadingDialog.value = LOADING_STATE_SHOW
|
||||
}
|
||||
tryBlock()
|
||||
} catch (e: Exception) {
|
||||
if (e is JsonSyntaxException) {
|
||||
var exceptionClassInfo = this@launch.javaClass.simpleName
|
||||
Logger.e("json解析异常:${exceptionClassInfo}----${e.toString()}")
|
||||
|
||||
exception.value = JSONException("数据解析异常")
|
||||
} else {
|
||||
exception.value = e
|
||||
}
|
||||
catchBlock()
|
||||
} finally {
|
||||
finallyBlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseViewModel.launch(
|
||||
tryBlock: suspend CoroutineScope.() -> Unit,
|
||||
catchBlock: suspend CoroutineScope.() -> Unit = {},
|
||||
finallyBlock: suspend CoroutineScope.() -> Unit = {},
|
||||
) {
|
||||
launch(true, tryBlock, catchBlock, finallyBlock)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 请求结果处理
|
||||
*
|
||||
* @param response ApiResponse
|
||||
* @param successBlock 服务器请求成功返回成功码的执行回调,默认空实现
|
||||
* @param errorBlock 服务器请求成功返回错误码的执行回调,默认返回false的空实现,函数返回值true:拦截统一错误处理,false:不拦截
|
||||
*/
|
||||
suspend fun <T> BaseViewModel.handleRequest(
|
||||
response: ApiResponse<T>,
|
||||
successBlock: suspend CoroutineScope.(response: ApiResponse<T>) -> Unit = {},
|
||||
errorBlock: suspend CoroutineScope.(response: ApiResponse<T>) -> Boolean = { false }
|
||||
) {
|
||||
coroutineScope {
|
||||
if (200 == response.code || 0 == response.code) {
|
||||
if (loadingDialog.value == LOADING_STATE_SHOW) {
|
||||
loadingDialog.value = LOADING_STATE_HIDE
|
||||
}
|
||||
if (response.data == null) {
|
||||
exception.value = Exception("data = null")
|
||||
} else if (response.data is List<*>) {
|
||||
if (response.data.size == 0) {
|
||||
exception.value = Exception("data list = null")
|
||||
}
|
||||
}
|
||||
successBlock(response)
|
||||
} else if (500 == response.code) {
|
||||
errorResponse.value = response
|
||||
// } else if (602 == response.code||702 == response.code) {
|
||||
// if (!errorBlock(response)) {
|
||||
// // 只有errorBlock返回false不拦截处理时,才去统一提醒错误提示
|
||||
// errorResponse.value = response
|
||||
//// errorBlock(response)
|
||||
// }
|
||||
} else {//其他返回码拦截处理
|
||||
if (!errorBlock(response)) {
|
||||
// 只有errorBlock返回false不拦截处理时,才去统一提醒错误提示
|
||||
errorResponse.value = response
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.zmkg.coaloperation.superfuntion
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.core.view.ContentInfoCompat
|
||||
import com.zmkg.coaloperation.ui.login.activity.LoginActivity
|
||||
|
||||
fun startActivity(
|
||||
context: Context, @ContentInfoCompat.Flags flags: MutableList<Int>? = null,
|
||||
bundle: Bundle? = null, targetClass: Class<*>
|
||||
) {
|
||||
var intent = Intent(context, targetClass)
|
||||
if (!flags.isNullOrEmpty()) {
|
||||
for (flag in flags) {
|
||||
intent.flags = flag
|
||||
}
|
||||
}
|
||||
if (bundle != null) {
|
||||
intent.putExtras(bundle)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录
|
||||
*/
|
||||
fun startLoginActivity(context: Context) {
|
||||
startActivity(context, targetClass = LoginActivity::class.java)
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
package com.zmkg.coaloperation.superfuntion
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.Html
|
||||
import android.text.Spanned
|
||||
import android.text.TextUtils
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* String扩展类
|
||||
*/
|
||||
fun String.toHtml(@SuppressLint("InlinedApi") flag: Int = Html.FROM_HTML_MODE_LEGACY): Spanned {
|
||||
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
Html.fromHtml(this, flag)
|
||||
} else {
|
||||
Html.fromHtml(this)
|
||||
}
|
||||
}
|
||||
|
||||
//fun String.toHtml(view:TextView,conetxt:Context,@SuppressLint("InlinedApi") flag: Int = Html.FROM_HTML_MODE_LEGACY): Spanned {
|
||||
// return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
// Html.fromHtml(this, flag,ImageGetterUtils.MyImageGetter(conetxt,view),null)
|
||||
// } else {
|
||||
// Html.fromHtml(this,ImageGetterUtils.MyImageGetter(conetxt,view),null)
|
||||
// }
|
||||
//}
|
||||
|
||||
/** 将对象转为JSON字符串 */
|
||||
fun Any?.toJson(): String {
|
||||
return Gson().toJson(this)
|
||||
}
|
||||
/** 将对象转为key加密之后的字符串 */
|
||||
fun Any?.toEncryptJson(): String{
|
||||
return GsonBuilder()
|
||||
.create().toJson(this)
|
||||
}
|
||||
fun <T> String?.jsonToBean(clazz: Class<T>): T {
|
||||
return GsonBuilder()
|
||||
.create().fromJson(this, clazz)
|
||||
}
|
||||
|
||||
|
||||
fun String.formatToPassWord(): String = this.replace("[^a-zA-Z0-9]*".toRegex(), "")
|
||||
fun String.formatCheck(): Boolean {
|
||||
var pattern=Pattern.compile("(?=.*[A-Z])(?=.*\\d)(?=.*[a-z])(?=.*\\d)[0-9A-Za-z]{8,16}")
|
||||
return pattern.matcher(this).matches()
|
||||
}
|
||||
|
||||
fun String.phoneCheck(): Boolean {
|
||||
var pattern=Pattern.compile("^1[3-9]\\d{9}\$")
|
||||
return pattern.matcher(this).matches()
|
||||
}
|
||||
|
||||
fun String.lenghtFormat(): String {
|
||||
var value=""
|
||||
if(this.length>10){
|
||||
value=this.substring(0,10)
|
||||
}
|
||||
return value
|
||||
}
|
||||
inline fun String?.orEmptyDefault2(): String {
|
||||
if (this.equals("null")||this.equals("Null")||this==null||this.equals("")){
|
||||
return "--"
|
||||
}else{
|
||||
return this
|
||||
}
|
||||
}
|
||||
fun String?.orEmptyDefault(str:String="--"): String {
|
||||
if (this==null) {
|
||||
return str
|
||||
}else if (this=="null") {
|
||||
return str
|
||||
}else if (this=="") {
|
||||
return str
|
||||
}else{
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
fun Int?.orEmptyDefaultInt(str:String="--"): String {
|
||||
if (this==null) {
|
||||
return str
|
||||
}else{
|
||||
return this.toString()
|
||||
}
|
||||
}
|
||||
|
||||
fun String?.toZeroDefault(f: Float = 0.0F): Float {
|
||||
|
||||
return if (TextUtils.isEmpty(this)) {
|
||||
f
|
||||
} else if (this == "null") {
|
||||
f
|
||||
} else {
|
||||
this!!.toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
fun String?.floatToInt(i: Int = 0): Int {
|
||||
|
||||
return if (TextUtils.isEmpty(this)) {
|
||||
i
|
||||
} else if (this == "null") {
|
||||
i
|
||||
} else {
|
||||
if (this!!.toFloatOrNull() != null) {
|
||||
this.toFloatOrNull()!!.toInt()
|
||||
} else {
|
||||
i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun String?.orEmptyDefaultValue(): String = this ?: ""
|
||||
|
||||
fun Float?.orEmptyDefault(): String {
|
||||
return if (this == null || this == 0.0F) {
|
||||
"--"
|
||||
} else {
|
||||
this.toString()
|
||||
}
|
||||
}
|
||||
fun String.toFormatDouble(): String{
|
||||
var mStr="0"
|
||||
try {
|
||||
var dou=this.toDouble()
|
||||
// if ((dou-dou.toInt())>0){
|
||||
mStr=String.format("%.2f",dou)
|
||||
// }else{
|
||||
// mStr=dou.toInt().toString()
|
||||
// }
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
return mStr
|
||||
}
|
||||
|
||||
fun String.toFormatInt(): Int{
|
||||
var value=0
|
||||
try {
|
||||
if (this!=null&&this.length>0){
|
||||
value=this.toDouble().toInt()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
return value
|
||||
}
|
||||
fun String.toFormatDoubleCounting(): String{
|
||||
var mStr="0"
|
||||
try {
|
||||
var dou=this.toDouble()
|
||||
if(dou>10000){
|
||||
mStr=String.format("%.2f",(dou/10000.00))+"万"
|
||||
}else{
|
||||
mStr=dou.toInt().toString()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
return mStr
|
||||
}
|
||||
fun String.toFormatDouble0(): String{
|
||||
var mStr="0"
|
||||
try {
|
||||
var dou=this.toDouble()
|
||||
mStr=dou.toInt().toString()
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
return mStr
|
||||
}
|
||||
|
||||
fun String.isEmptyStrValue(): Boolean{
|
||||
if (this==null||this==""||this=="0"||this=="0.00") {
|
||||
return true
|
||||
}else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun String.toDateFormat1() : String {
|
||||
val pattern = "yyyy年MM月dd日"
|
||||
val simpleDateFormat = SimpleDateFormat(pattern)
|
||||
val date = simpleDateFormat.parse(this)
|
||||
val timeStamp = date.time
|
||||
return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(timeStamp)
|
||||
}
|
||||
|
||||
fun String.toDateFormat2() : String {
|
||||
val pattern = "yyyy-MM-dd"
|
||||
val simpleDateFormat = SimpleDateFormat(pattern)
|
||||
val date = simpleDateFormat.parse(this)
|
||||
val timeStamp = date.time
|
||||
return SimpleDateFormat("MM.dd", Locale.getDefault()).format(timeStamp)
|
||||
}
|
||||
|
||||
fun String.toDateFormat3() : String {
|
||||
val pattern = "yyyy-MM-dd"
|
||||
val simpleDateFormat = SimpleDateFormat(pattern)
|
||||
val date = simpleDateFormat.parse(this)
|
||||
val timeStamp = date.time
|
||||
return SimpleDateFormat("yyyy.MM", Locale.getDefault()).format(timeStamp)
|
||||
}
|
||||
|
||||
fun String.toDateFormatYear() : String {
|
||||
val pattern = "yyyy-MM-dd"
|
||||
val simpleDateFormat = SimpleDateFormat(pattern)
|
||||
val date = simpleDateFormat.parse(this)
|
||||
val timeStamp = date.time
|
||||
return SimpleDateFormat("yyyy", Locale.getDefault()).format(timeStamp)
|
||||
}
|
||||
|
||||
fun String.toDateFormatMonth() : String {
|
||||
val pattern = "yyyy-MM-dd"
|
||||
val simpleDateFormat = SimpleDateFormat(pattern)
|
||||
val date = simpleDateFormat.parse(this)
|
||||
val timeStamp = date.time
|
||||
return SimpleDateFormat("MM", Locale.getDefault()).format(timeStamp)
|
||||
}
|
||||
|
||||
fun String.toDateFormatDay() : String {
|
||||
val pattern = "yyyy-MM-dd"
|
||||
val simpleDateFormat = SimpleDateFormat(pattern)
|
||||
val date = simpleDateFormat.parse(this)
|
||||
val timeStamp = date.time
|
||||
return SimpleDateFormat("dd", Locale.getDefault()).format(timeStamp)
|
||||
}
|
||||
@@ -0,0 +1,580 @@
|
||||
package com.zmkg.coaloperation.superfuntion
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Window
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.MultiTransformation
|
||||
import com.bumptech.glide.load.engine.GlideException
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop
|
||||
import com.bumptech.glide.load.resource.bitmap.CircleCrop
|
||||
import com.bumptech.glide.load.resource.bitmap.FitCenter
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import com.bumptech.glide.request.RequestListener
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.adapter.common.ViewPagerAdapter
|
||||
import com.zmkg.coaloperation.retorfit.UrlConfig
|
||||
import com.zmkg.coaloperation.ui.home.adapter.HomeMenuAdapter
|
||||
import com.zmkg.coaloperation.utils.ScreenUtil.dp2px
|
||||
import com.zmkg.coaloperation.view.CircleView
|
||||
import com.zmkg.coaloperation.view.LoadingDialog
|
||||
import java.io.File
|
||||
import java.util.Collections
|
||||
|
||||
fun addImageBaseUrl(url: String?): String? {
|
||||
if (url != null) {
|
||||
if (url.startsWith("http")) {
|
||||
return url
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
return UrlConfig.getDefaultBaseUrl() + url.replace("\\","/")
|
||||
}
|
||||
|
||||
/**
|
||||
* ImageView利用Glide加载图片
|
||||
* @param url 图片url(可远程可本地)
|
||||
* @param showPlaceholder 是否展示placeholder,默认为true
|
||||
*/
|
||||
fun ImageView.load(
|
||||
url: String?,
|
||||
showPlaceholder: Boolean = true,
|
||||
@DrawableRes defaultResId: Int = 0
|
||||
) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
if (defaultResId != 0) {
|
||||
setImageResource(defaultResId)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (showPlaceholder) {
|
||||
val options = RequestOptions().transform()
|
||||
if (defaultResId == 0) {
|
||||
options.placeholder(R.drawable.ic_default)
|
||||
.error(R.drawable.ic_default)
|
||||
} else {
|
||||
options.placeholder(defaultResId)
|
||||
.error(defaultResId)
|
||||
}
|
||||
Glide.with(context).load(addImageBaseUrl(url))
|
||||
.apply(options)
|
||||
.into(this)
|
||||
} else {
|
||||
Glide.with(context).load(addImageBaseUrl(url))
|
||||
.into(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun ImageView.loadGif(
|
||||
url: String?,
|
||||
showPlaceholder: Boolean = true,
|
||||
@DrawableRes defaultResId: Int = 0
|
||||
) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
if (defaultResId != 0) {
|
||||
setImageResource(defaultResId)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (showPlaceholder) {
|
||||
val options = RequestOptions().transform()
|
||||
if (defaultResId == 0) {
|
||||
options.placeholder(R.drawable.ic_default)
|
||||
.error(R.drawable.ic_default)
|
||||
} else {
|
||||
options.placeholder(defaultResId)
|
||||
.error(defaultResId)
|
||||
}
|
||||
Glide.with(context).asGif().load(addImageBaseUrl(url)).timeout(10*1000)
|
||||
.apply(options)
|
||||
.into(this)
|
||||
} else {
|
||||
Glide.with(context).asGif().load(addImageBaseUrl(url)).timeout(10*1000)
|
||||
.into(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ImageView利用Glide加载图片
|
||||
* @param url 图片url(可远程可本地)
|
||||
* @param showPlaceholder 是否展示placeholder,默认为true
|
||||
*/
|
||||
fun ImageView.load(
|
||||
file: File,
|
||||
showPlaceholder: Boolean = true,
|
||||
@DrawableRes defaultResId: Int = 0
|
||||
) {
|
||||
Glide.with(context).load(file)
|
||||
.into(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* ImageView利用Glide加载图片
|
||||
* @param resourceId 本地图片资源Id
|
||||
* @param showPlaceholder 是否展示placeholder,默认为false
|
||||
*/
|
||||
fun ImageView.load(
|
||||
@DrawableRes resourceId: Int,
|
||||
showPlaceholder: Boolean = false,
|
||||
@DrawableRes defaultResId: Int = 0
|
||||
) {
|
||||
Glide.with(context).load(resourceId)
|
||||
.into(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* ImageView利用Glide加载圆形图片
|
||||
* @param url 图片url(可远程可本地)
|
||||
*/
|
||||
fun ImageView.loadCircle(url: String?, @DrawableRes defaultResId: Int = 0) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
if (defaultResId != 0) {
|
||||
setImageResource(defaultResId)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val options = RequestOptions
|
||||
.bitmapTransform(CircleCrop())
|
||||
if (defaultResId == 0) {
|
||||
options.placeholder(R.drawable.ic_default)
|
||||
.error(R.drawable.ic_default)
|
||||
} else {
|
||||
options.placeholder(defaultResId)
|
||||
.error(defaultResId)
|
||||
}
|
||||
Glide.with(context).load(addImageBaseUrl(url))
|
||||
.apply(options)
|
||||
.into(this)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ImageView利用Glide加载圆形图片
|
||||
* @param url 图片url(可远程可本地)
|
||||
*/
|
||||
fun ImageView.loadCircle(file: File, @DrawableRes defaultResId: Int = 0) {
|
||||
val options = RequestOptions
|
||||
.bitmapTransform(CircleCrop())
|
||||
if (defaultResId == 0) {
|
||||
options.placeholder(R.drawable.ic_default)
|
||||
.error(R.drawable.ic_default)
|
||||
}
|
||||
Glide.with(context).load(file)
|
||||
.apply(options)
|
||||
.into(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* ImageView利用Glide加载圆形图片
|
||||
* @param resourceId 本地图片资源Id
|
||||
*/
|
||||
fun ImageView.loadCircle(@DrawableRes resourceId: Int) {
|
||||
Glide.with(context).load(resourceId)
|
||||
// .placeholder(R.drawable.ic_default_img)
|
||||
.apply(RequestOptions.bitmapTransform(CircleCrop()))
|
||||
.into(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载图片到ImageView
|
||||
* @param imageUrl 图片地址
|
||||
* @param imageView View
|
||||
* @param placeholder 占位图
|
||||
*/
|
||||
fun ImageView.loadRoundedImage(
|
||||
url: String?,
|
||||
roundingRadius: Float,
|
||||
@DrawableRes defaultResId: Int = 0,
|
||||
isCenterCrop:Boolean = true//是否中心裁剪
|
||||
) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
if (defaultResId != 0) {
|
||||
setImageResource(defaultResId)
|
||||
}
|
||||
return
|
||||
}
|
||||
//设置图片圆角角度
|
||||
val roundedCorners = RoundedCorners(dp2px(roundingRadius))
|
||||
val multiTransformation: MultiTransformation<Bitmap> = MultiTransformation(
|
||||
if (isCenterCrop) CenterCrop() else FitCenter(), roundedCorners
|
||||
)
|
||||
val options = RequestOptions
|
||||
.bitmapTransform(multiTransformation)
|
||||
if (defaultResId == 0) {
|
||||
options.placeholder(R.drawable.ic_default)
|
||||
.error(R.drawable.ic_default)
|
||||
} else {
|
||||
options.placeholder(defaultResId)
|
||||
.error(defaultResId)
|
||||
}
|
||||
Glide.with(context)
|
||||
.load(addImageBaseUrl(url))
|
||||
.apply(options)
|
||||
.into(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载图片到ImageView
|
||||
* @param imageUrl 图片地址
|
||||
* @param imageView View
|
||||
* @param placeholder 占位图
|
||||
*/
|
||||
fun ImageView.loadRoundedImage(
|
||||
url: String?,
|
||||
roundingRadius: Float,
|
||||
@DrawableRes defaultResId: Int = 0,
|
||||
method:(Boolean)->Unit
|
||||
) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
if (defaultResId != 0) {
|
||||
setImageResource(defaultResId)
|
||||
}
|
||||
return
|
||||
}
|
||||
//设置图片圆角角度
|
||||
val roundedCorners = RoundedCorners(dp2px(roundingRadius))
|
||||
val multiTransformation: MultiTransformation<Bitmap> = MultiTransformation(
|
||||
CenterCrop(), roundedCorners
|
||||
)
|
||||
val options = RequestOptions
|
||||
.bitmapTransform(multiTransformation)
|
||||
if (defaultResId == 0) {
|
||||
options.placeholder(R.drawable.ic_default)
|
||||
.error(R.drawable.ic_default)
|
||||
} else {
|
||||
options.placeholder(defaultResId)
|
||||
.error(defaultResId)
|
||||
}
|
||||
Glide.with(context)
|
||||
.load(addImageBaseUrl(url))
|
||||
.listener(object :RequestListener<Drawable>{
|
||||
override fun onLoadFailed(
|
||||
p0: GlideException?,
|
||||
p1: Any?,
|
||||
p2: Target<Drawable>?,
|
||||
p3: Boolean,
|
||||
): Boolean {
|
||||
method(false)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onResourceReady(
|
||||
p0: Drawable?,
|
||||
p1: Any?,
|
||||
p2: Target<Drawable>?,
|
||||
p3: DataSource?,
|
||||
p4: Boolean,
|
||||
): Boolean {
|
||||
method(true)
|
||||
return false
|
||||
}
|
||||
})
|
||||
.apply(options)
|
||||
.into(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载图片到ImageView
|
||||
* @param imageUrl 图片地址
|
||||
* @param imageView View
|
||||
* @param placeholder 占位图
|
||||
*/
|
||||
fun ImageView.loadRoundedImage(
|
||||
file: File,
|
||||
roundingRadius: Float
|
||||
) {
|
||||
|
||||
//设置图片圆角角度
|
||||
val roundedCorners = RoundedCorners(dp2px(roundingRadius))
|
||||
val multiTransformation: MultiTransformation<Bitmap> = MultiTransformation(
|
||||
CenterCrop(), roundedCorners
|
||||
)
|
||||
val options = RequestOptions
|
||||
.bitmapTransform(multiTransformation)
|
||||
Glide.with(context)
|
||||
.load(file)
|
||||
.apply(options)
|
||||
.into(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载图片到ImageView
|
||||
* @param imageUrl 图片地址
|
||||
* @param imageView View
|
||||
* @param placeholder 占位图
|
||||
*/
|
||||
fun ImageView.loadRoundedImage(
|
||||
imageRes: Int,
|
||||
roundingRadius: Float
|
||||
) {
|
||||
//设置图片圆角角度
|
||||
val roundedCorners = RoundedCorners(dp2px(roundingRadius))
|
||||
val multiTransformation: MultiTransformation<Bitmap> = MultiTransformation(
|
||||
CenterCrop(), roundedCorners
|
||||
)
|
||||
val options = RequestOptions
|
||||
.bitmapTransform(multiTransformation)
|
||||
if (imageRes != 0) {
|
||||
Glide.with(context)
|
||||
.load(imageRes)
|
||||
.apply(options)
|
||||
.into(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SwipeRefreshLayout设置加载主题颜色
|
||||
*/
|
||||
fun SwipeRefreshLayout.initColors() {
|
||||
setColorSchemeResources(
|
||||
R.color.theme_color
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 加载框 */
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private var mLoadingDialog: LoadingDialog? = null
|
||||
|
||||
/** 打开加载框 */
|
||||
fun AppCompatActivity.showLoading(message: String = "请稍后") {
|
||||
if (!this.isFinishing&&!this.isDestroyed) {
|
||||
if (mLoadingDialog == null) {
|
||||
mLoadingDialog = LoadingDialog(
|
||||
this,
|
||||
ProgressDialog.STYLE_SPINNER, "请稍后"
|
||||
)
|
||||
mLoadingDialog!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
mLoadingDialog!!.setCanceledOnTouchOutside(false)
|
||||
mLoadingDialog!!.setCancelable(false)
|
||||
mLoadingDialog!!.setMessage(if (message.isNullOrEmpty()) "请稍后" else message)
|
||||
}
|
||||
if (!this.isDestroyed) {
|
||||
mLoadingDialog?.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 打开加载框 */
|
||||
fun Fragment.showLoading(message: String = "请稍后") {
|
||||
if (!this.isRemoving) {
|
||||
if (mLoadingDialog == null) {
|
||||
mLoadingDialog = LoadingDialog(
|
||||
this.activity,
|
||||
ProgressDialog.STYLE_SPINNER, "请稍后"
|
||||
)
|
||||
mLoadingDialog!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
mLoadingDialog!!.setCanceledOnTouchOutside(false)
|
||||
mLoadingDialog!!.setCancelable(false)
|
||||
mLoadingDialog!!.setMessage(if (message.isNullOrEmpty()) "请稍后" else message)
|
||||
}
|
||||
if (this.activity?.isFinishing == false) {
|
||||
mLoadingDialog?.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 隐藏Loading加载框 */
|
||||
fun hideLoading() {
|
||||
mLoadingDialog?.dismiss()
|
||||
mLoadingDialog = null
|
||||
}
|
||||
|
||||
fun ViewPager2.init(
|
||||
fa: FragmentActivity,
|
||||
tabs: Array<String>,
|
||||
onCreateFragmentListener: ViewPagerAdapter.OnCreateFragmentListener,
|
||||
offscreenPageLimit: Int = ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT
|
||||
) {
|
||||
if (tabs.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
this.offscreenPageLimit = offscreenPageLimit
|
||||
this.adapter = ViewPagerAdapter(fa, tabs, onCreateFragmentListener)
|
||||
}
|
||||
fun TabLayout.attachViewPager(
|
||||
viewpager: ViewPager2,
|
||||
tabs: Array<String>,
|
||||
isCustomStyle: Boolean = false,
|
||||
tabStyle: Int = 1
|
||||
){
|
||||
if (tabs.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
var mediator = TabLayoutMediator(
|
||||
this, viewpager
|
||||
) { tab, position -> //这里可以自定义TabView
|
||||
if (isCustomStyle){
|
||||
val tabView = LayoutInflater.from(this.context)
|
||||
.inflate(getTabStyle(tabStyle), null) as TextView
|
||||
tabView.text = tabs[position]
|
||||
tab.customView = tabView
|
||||
}else{
|
||||
tab.text = tabs[position]
|
||||
}
|
||||
}
|
||||
//要执行这一句才是真正将两者绑定起来
|
||||
mediator.attach()
|
||||
}
|
||||
|
||||
fun ViewPager2.onPageChangeCallback(viewList: MutableList<CircleView>) {
|
||||
this.registerOnPageChangeCallback(object :
|
||||
ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
super.onPageSelected(position)
|
||||
|
||||
viewList.forEachIndexed {index, view->
|
||||
if (index == position) {
|
||||
view.setContextColor(Color.parseColor("#A3FEA6"))
|
||||
} else {
|
||||
view.setContextColor(Color.parseColor("#80FFFFFF"))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 白色按钮,灰色背景的TabLayout
|
||||
*/
|
||||
fun TabLayout.onCreateTab(tabList: Array<String>, tabStyle: Int = 2,listener: (TabLayout.Tab?) -> Unit) {
|
||||
for (tabTitle in tabList) {
|
||||
val tab = newTab()
|
||||
onConfigureTab(context, tab, tabTitle,tabStyle)
|
||||
addTab(tab, false)
|
||||
}
|
||||
selectTab(getTabAt(0))
|
||||
addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
listener.invoke(tab)
|
||||
}
|
||||
|
||||
override fun onTabUnselected(p0: TabLayout.Tab?) {
|
||||
}
|
||||
|
||||
override fun onTabReselected(p0: TabLayout.Tab?) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
private fun onConfigureTab(context: Context, tab: TabLayout.Tab, tabTitle: String, tabStyle: Int) {
|
||||
val textView = LayoutInflater.from(context)
|
||||
.inflate(getTabStyle(tabStyle), null) as TextView
|
||||
textView.text = tabTitle
|
||||
tab.customView = textView
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* tab 样式
|
||||
* 1:通用样式 2:癌症结论tab样式
|
||||
*/
|
||||
fun getTabStyle(i: Int): Int {
|
||||
return when (i) {
|
||||
1 -> R.layout.item_tablayout_group_title
|
||||
else -> R.layout.item_tablayout_group_title
|
||||
}
|
||||
}
|
||||
|
||||
fun TabLayout.init(tabs: Array<String>){
|
||||
this.removeAllTabs()
|
||||
tabs.forEach {
|
||||
this.addTab(this.newTab().setText(it))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun RecyclerView.addItemTouchCallback(refreshData:()->Unit){
|
||||
val callback = object : ItemTouchHelper.Callback() {
|
||||
|
||||
override fun getMovementFlags(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder
|
||||
): Int {
|
||||
val dragFlags = ItemTouchHelper.UP or
|
||||
ItemTouchHelper.DOWN or
|
||||
ItemTouchHelper.LEFT or
|
||||
ItemTouchHelper.RIGHT
|
||||
return makeMovementFlags(dragFlags, 0)
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
source: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
val from = source.bindingAdapterPosition
|
||||
val to = target.bindingAdapterPosition
|
||||
if (from == RecyclerView.NO_POSITION || to == RecyclerView.NO_POSITION) return false
|
||||
val adapter = recyclerView.adapter as HomeMenuAdapter
|
||||
|
||||
Collections.swap(adapter!!.data,from,to)
|
||||
|
||||
// adapter!!.data.swap(from, to)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
// 不处理滑动
|
||||
}
|
||||
|
||||
override fun isLongPressDragEnabled(): Boolean = true
|
||||
|
||||
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
super.clearView(recyclerView, viewHolder)
|
||||
|
||||
recyclerView.post {
|
||||
refreshData.invoke()
|
||||
// resetItemTypes(adapter.data)
|
||||
// adapter.notifyDataSetChanged()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val itemTouchHelper = ItemTouchHelper(callback)
|
||||
itemTouchHelper.attachToRecyclerView(this)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
|
||||
// val tmp = this[index1]
|
||||
// this[index1] = this[index2]
|
||||
// this[index2] = tmp
|
||||
//}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zmkg.coaloperation.ui.home.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.ActivityGeologicalBinding
|
||||
|
||||
/**
|
||||
* 地质编录
|
||||
*/
|
||||
class GeologicalActivity : BaseVMBActivity<TestViewModel, ActivityGeologicalBinding>(R.layout.activity_geological) {
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.zmkg.coaloperation.ui.home.adapter
|
||||
|
||||
import com.chad.library.adapter.base.BaseMultiItemQuickAdapter
|
||||
import com.chad.library.adapter.base.viewholder.BaseViewHolder
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.ui.home.bean.HomeMenuBean
|
||||
import com.zmkg.coaloperation.ui.home.utils.getMenuTabImg
|
||||
|
||||
|
||||
/**
|
||||
* 首页tab
|
||||
*/
|
||||
|
||||
class HomeMenuAdapter :
|
||||
BaseMultiItemQuickAdapter<HomeMenuBean, BaseViewHolder>() {
|
||||
|
||||
companion object {
|
||||
const val TYPE_LEFT_RIGHT = 0
|
||||
const val TYPE_TOP_BOTTOM = 1
|
||||
}
|
||||
|
||||
init {
|
||||
addItemType(TYPE_LEFT_RIGHT, R.layout.item_home_menu_left_right)
|
||||
addItemType(TYPE_TOP_BOTTOM, R.layout.item_home_menu_top_bottom)
|
||||
}
|
||||
|
||||
override fun convert(holder: BaseViewHolder, item: HomeMenuBean) {
|
||||
holder.setText(R.id.title, item.name)
|
||||
holder.setImageResource(
|
||||
R.id.img,
|
||||
getMenuTabImg(item.index!!, holder.itemViewType)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zmkg.coaloperation.ui.home.adapter
|
||||
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.viewholder.BaseViewHolder
|
||||
import com.zmkg.coaloperation.R
|
||||
|
||||
|
||||
/**
|
||||
* pager
|
||||
*/
|
||||
|
||||
class PagerDateAdapter : BaseQuickAdapter<String, BaseViewHolder>(
|
||||
R.layout.item_dialog_pager
|
||||
) {
|
||||
|
||||
override fun convert(holder: BaseViewHolder, item: String) {
|
||||
|
||||
holder.apply {
|
||||
setText(R.id.date, item)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.zmkg.coaloperation.ui.home.bean
|
||||
|
||||
import com.chad.library.adapter.base.entity.MultiItemEntity
|
||||
|
||||
|
||||
class HomeMenuBean : MultiItemEntity {
|
||||
var name: String? = null
|
||||
var index: Int? = null
|
||||
var type: Int? = null // 0: 前4个(左右布局),1: 后4个(上下布局)
|
||||
|
||||
override val itemType: Int
|
||||
get() = type!!
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.zmkg.coaloperation.ui.home.bean
|
||||
|
||||
|
||||
data class WaterLedgerBean(
|
||||
val col_end: String,
|
||||
val col_start: String,
|
||||
val row_end: String,
|
||||
val row_start: String,
|
||||
val words: String
|
||||
)
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.zmkg.coaloperation.ui.home.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.listener.OnItemClickListener
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.adapter.common.ViewPagerAdapter
|
||||
import com.zmkg.coaloperation.base.BaseVMBFragment
|
||||
import com.zmkg.coaloperation.databinding.FragmentHomeBinding
|
||||
import com.zmkg.coaloperation.local.DataStoreManager
|
||||
import com.zmkg.coaloperation.superfuntion.addItemTouchCallback
|
||||
import com.zmkg.coaloperation.superfuntion.init
|
||||
import com.zmkg.coaloperation.superfuntion.onPageChangeCallback
|
||||
import com.zmkg.coaloperation.superfuntion.toJson
|
||||
import com.zmkg.coaloperation.ui.home.adapter.HomeMenuAdapter
|
||||
import com.zmkg.coaloperation.ui.home.bean.HomeMenuBean
|
||||
import com.zmkg.coaloperation.ui.home.viewmodel.HomeViewModel
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class HomeFragment :
|
||||
BaseVMBFragment<HomeViewModel, FragmentHomeBinding>(R.layout.fragment_home),
|
||||
OnItemClickListener {
|
||||
|
||||
private val homeMenuAdapter: HomeMenuAdapter by lazy { HomeMenuAdapter() }
|
||||
|
||||
override fun initView(root: View?, savedInstanceState: Bundle?) {
|
||||
mBinding.apply {
|
||||
val layoutManager = GridLayoutManager(requireContext(), 4) // 4列
|
||||
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
return if (homeMenuAdapter.data[position].type == HomeMenuAdapter.TYPE_LEFT_RIGHT) 2 else 1
|
||||
}
|
||||
}
|
||||
rvList.layoutManager = layoutManager
|
||||
rvList.adapter = homeMenuAdapter
|
||||
rvList.addItemTouchCallback {
|
||||
resetItemTypes(homeMenuAdapter.data)
|
||||
DataStoreManager.setHomeData(homeMenuAdapter.data.toJson())
|
||||
homeMenuAdapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
val arrayOf = arrayOf("1", "2", "3")
|
||||
leftPager.init(
|
||||
requireActivity(),
|
||||
arrayOf,
|
||||
object : ViewPagerAdapter.OnCreateFragmentListener {
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return PagerLeftFragment()
|
||||
}
|
||||
})
|
||||
leftPager.onPageChangeCallback(mutableListOf(leftOval1, leftOval2, leftOval3))
|
||||
|
||||
|
||||
|
||||
rightPager.init(
|
||||
requireActivity(),
|
||||
arrayOf,
|
||||
object : ViewPagerAdapter.OnCreateFragmentListener {
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return PagerRightFragment()
|
||||
}
|
||||
})
|
||||
rightPager.onPageChangeCallback(mutableListOf(rightOval1, rightOval2, rightOval3))
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
// mViewModel.getWaterLedgerData()
|
||||
|
||||
val titleNameList = mutableListOf(
|
||||
"涌水量观测",
|
||||
"导线测量",
|
||||
"瓦斯巡检",
|
||||
"防灭火检查",
|
||||
"通风巡检",
|
||||
"地质编录",
|
||||
"水文地质编录",
|
||||
"隐蔽致灾",
|
||||
"地物查询"
|
||||
)
|
||||
var mutableListOf = mutableListOf<HomeMenuBean>()
|
||||
|
||||
val homeData = DataStoreManager.getHomeData()
|
||||
if (TextUtils.isEmpty(homeData)) {
|
||||
|
||||
titleNameList.forEachIndexed { index, s ->
|
||||
val homeMenuBean = HomeMenuBean()
|
||||
homeMenuBean.name = s
|
||||
homeMenuBean.index = index + 1
|
||||
if (index < 4) {
|
||||
homeMenuBean.type = 0
|
||||
} else {
|
||||
homeMenuBean.type = 1
|
||||
}
|
||||
mutableListOf.add(homeMenuBean)
|
||||
}
|
||||
} else {
|
||||
val listType = object : TypeToken<MutableList<HomeMenuBean>?>() {}.getType()
|
||||
mutableListOf = Gson().fromJson(homeData, listType)
|
||||
}
|
||||
|
||||
homeMenuAdapter.setNewInstance(mutableListOf)
|
||||
|
||||
}
|
||||
|
||||
private fun resetItemTypes(data: MutableList<HomeMenuBean>) {
|
||||
data.forEachIndexed { index, item ->
|
||||
item.type =
|
||||
if (index < 4) HomeMenuAdapter.TYPE_LEFT_RIGHT else HomeMenuAdapter.TYPE_TOP_BOTTOM
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun bindEvent() {
|
||||
homeMenuAdapter.setOnItemClickListener(this@HomeFragment)
|
||||
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
|
||||
}
|
||||
|
||||
override fun transparentStatusBar(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int) {
|
||||
val homeMenuBean = adapter.data.get(position) as HomeMenuBean
|
||||
if (homeMenuBean.name.equals("地质编录")) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.zmkg.coaloperation.ui.home.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBFragment
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.FragmentPageLeftBinding
|
||||
|
||||
class PagerLeftFragment :
|
||||
BaseVMBFragment<TestViewModel, FragmentPageLeftBinding>(R.layout.fragment_page_left) {
|
||||
|
||||
|
||||
override fun initView(root: View?, savedInstanceState: Bundle?) {
|
||||
mBinding.circleView.setProgress(160, 180)
|
||||
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
mBinding.rootView.setOnClickListener {
|
||||
// val pagerViewClickDialog = PagerViewClickDialog(requireContext())
|
||||
// pagerViewClickDialog.show()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.zmkg.coaloperation.ui.home.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBFragment
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.FragmentPageRightBinding
|
||||
import com.zmkg.coaloperation.ui.tunneling.activity.TunnelingActivity
|
||||
|
||||
class PagerRightFragment :
|
||||
BaseVMBFragment<TestViewModel, FragmentPageRightBinding>(R.layout.fragment_page_right) {
|
||||
|
||||
|
||||
override fun initView(root: View?, savedInstanceState: Bundle?) {
|
||||
mBinding.circleView.setProgress(160, 180)
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
mBinding.rootView.setOnClickListener {
|
||||
// val pagerViewClickDialog = PagerViewClickDialog(requireContext())
|
||||
// pagerViewClickDialog.show()
|
||||
toActivity(TunnelingActivity::class.java)
|
||||
|
||||
// val pagerViewClickDialog = PagerViewClickDialog(requireContext())
|
||||
// pagerViewClickDialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.zmkg.coaloperation.ui.home.utils
|
||||
|
||||
import com.zmkg.coaloperation.R
|
||||
|
||||
|
||||
fun getMenuTabImg(index: Int, type: Int): Int {
|
||||
return when (index) {
|
||||
1 -> {
|
||||
if (type == 0) {
|
||||
R.mipmap.water_max
|
||||
} else {
|
||||
R.mipmap.water_max_white
|
||||
}
|
||||
}
|
||||
|
||||
2 -> {
|
||||
if (type == 0) {
|
||||
R.mipmap.line_max
|
||||
} else {
|
||||
R.mipmap.line_max_white
|
||||
}
|
||||
}
|
||||
|
||||
3 -> {
|
||||
if (type == 0) {
|
||||
R.mipmap.gas_max
|
||||
} else {
|
||||
R.mipmap.gas_max_white
|
||||
}
|
||||
}
|
||||
|
||||
4 -> {
|
||||
if (type == 0) {
|
||||
R.mipmap.fire_max
|
||||
} else {
|
||||
R.mipmap.fire_max_white
|
||||
}
|
||||
}
|
||||
|
||||
5 -> {
|
||||
if (type == 0) {
|
||||
R.mipmap.wind_max
|
||||
} else {
|
||||
R.mipmap.wind_max_white
|
||||
}
|
||||
}
|
||||
|
||||
6,7 -> {
|
||||
if (type == 0) {
|
||||
R.mipmap.geology_max
|
||||
} else {
|
||||
R.mipmap.geology_max_white
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
8 -> {
|
||||
if (type == 0) {
|
||||
R.mipmap.causing_max
|
||||
} else {
|
||||
R.mipmap.causing_max_white
|
||||
}
|
||||
}
|
||||
|
||||
9 -> {
|
||||
if (type == 0) {
|
||||
R.mipmap.find_max
|
||||
} else {
|
||||
R.mipmap.find_max_white
|
||||
}
|
||||
}
|
||||
|
||||
else -> R.mipmap.water_max
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zmkg.coaloperation.ui.home.viewmodel
|
||||
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel
|
||||
import com.zmkg.coaloperation.data.repository.HomeRepository
|
||||
import com.zmkg.coaloperation.superfuntion.handleRequest
|
||||
import com.zmkg.coaloperation.superfuntion.launch
|
||||
import com.zmkg.coaloperation.ui.home.bean.WaterLedgerBean
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
||||
/**
|
||||
* 首页viewmodel
|
||||
*/
|
||||
class HomeViewModel : BaseViewModel() {
|
||||
|
||||
|
||||
var waterLedgerList = MutableSharedFlow<MutableList<WaterLedgerBean>?>()
|
||||
|
||||
override fun init() {
|
||||
}
|
||||
|
||||
|
||||
fun getWaterLedgerData() {
|
||||
launch(
|
||||
{
|
||||
handleRequest(
|
||||
HomeRepository.getWaterLedgerData(),
|
||||
successBlock = {
|
||||
waterLedgerList.emit(it.data)
|
||||
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.zmkg.coaloperation.ui.login.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.MainActivity
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.ActivityLoginBinding
|
||||
import com.zmkg.coaloperation.local.DataStoreManager
|
||||
import com.zmkg.coaloperation.superfuntion.loginIm
|
||||
|
||||
class LoginActivity : BaseVMBActivity<TestViewModel,ActivityLoginBinding>(R.layout.activity_login) {
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
if (!TextUtils.isEmpty(DataStoreManager.getUserName())) {
|
||||
loginIm(DataStoreManager.getUserName()){}
|
||||
toActivity(MainActivity::class.java)
|
||||
finish()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
addClickViews(mBinding.submit)
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
when(v?.id) {
|
||||
R.id.submit->{
|
||||
val userId = mBinding.loginEtUserName.text.toString()
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
showToast("请输入用户名")
|
||||
return
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(mBinding.loginEtUserPassword.getInputContext())) {
|
||||
showToast("请输入密码")
|
||||
return
|
||||
}
|
||||
|
||||
loginIm(userId) {}
|
||||
DataStoreManager.setUserName(userId)
|
||||
toActivity(MainActivity::class.java)
|
||||
finish()
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun transparentStatusBar():Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zmkg.coaloperation.ui.record.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBFragment
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.FragmentRecordBinding
|
||||
|
||||
class RecordFragment:
|
||||
BaseVMBFragment<TestViewModel, FragmentRecordBinding>(R.layout.fragment_record){
|
||||
override fun initView(root: View?, savedInstanceState: Bundle?) {
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
}
|
||||
|
||||
override fun transparentStatusBar(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.zmkg.coaloperation.ui.report.adapter
|
||||
|
||||
import android.view.View
|
||||
import com.chad.library.adapter.base.module.LoadMoreModule
|
||||
import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.adapter.common.BaseDataBindingAdapter
|
||||
import com.zmkg.coaloperation.bean.ImageBean
|
||||
import com.zmkg.coaloperation.databinding.ItemRecycleImageBinding
|
||||
import com.zmkg.coaloperation.superfuntion.loadRoundedImage
|
||||
import java.io.File
|
||||
|
||||
class ImageAdapter(var maxNum: Int): BaseDataBindingAdapter<ImageBean, ItemRecycleImageBinding>(
|
||||
R.layout.item_recycle_image
|
||||
), LoadMoreModule {
|
||||
private var isEditModel = false
|
||||
private var editImageShow = false
|
||||
override fun bindViewClickListener(
|
||||
viewHolder: BaseDataBindingHolder<ItemRecycleImageBinding>,
|
||||
viewType: Int
|
||||
) {
|
||||
addChildClickViewIds(R.id.btn_delete)
|
||||
super.bindViewClickListener(viewHolder, viewType)
|
||||
}
|
||||
override fun convert(
|
||||
holder: BaseDataBindingHolder<ItemRecycleImageBinding>,
|
||||
item: ImageBean
|
||||
) {
|
||||
val mBinding = holder.dataBinding
|
||||
mBinding?.let {
|
||||
if(item.isAddButton){
|
||||
mBinding.ivImage.setImageResource(R.mipmap.upload)
|
||||
mBinding.btnDelete.visibility = View.GONE
|
||||
}else{
|
||||
if(item.isFilePath){
|
||||
mBinding.ivImage.loadRoundedImage(File(item.imageUrl), 5f)
|
||||
}else{
|
||||
mBinding.ivImage.loadRoundedImage(item.imageUrl, 5f, R.drawable.ic_default)
|
||||
}
|
||||
if(isEditModel){
|
||||
mBinding.btnDelete.visibility = View.VISIBLE
|
||||
}else{
|
||||
mBinding.btnDelete.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fun isEditModel(isEdit: Boolean){
|
||||
isEditModel = isEdit
|
||||
notifyDataSetChanged()
|
||||
if(isEditModel && !editImageShow){
|
||||
showAddButton(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setList(list: Collection<ImageBean>?) {
|
||||
super.setList(list)
|
||||
if(isEditModel){
|
||||
showAddButton(true)
|
||||
}
|
||||
}
|
||||
override fun setNewInstance(list: MutableList<ImageBean>?) {
|
||||
super.setNewInstance(list)
|
||||
if(isEditModel){
|
||||
showAddButton(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addData(newData: Collection<ImageBean>) {
|
||||
if(isEditModel){
|
||||
if(editImageShow){
|
||||
var lastPosition = data.size - 1
|
||||
if(lastPosition < 0){
|
||||
lastPosition = 0
|
||||
}
|
||||
addData(lastPosition, newData)
|
||||
}else{
|
||||
showAddButton(true)
|
||||
}
|
||||
if(data.size > maxNum){
|
||||
showAddButton(false)
|
||||
}
|
||||
}else{
|
||||
super.addData(newData)
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeAt(position: Int) {
|
||||
super.removeAt(position)
|
||||
if(isEditModel && !editImageShow){
|
||||
showAddButton(true)
|
||||
}
|
||||
}
|
||||
fun getImageList(): MutableList<ImageBean>{
|
||||
var list = mutableListOf<ImageBean>()
|
||||
data.forEach { imageBean ->
|
||||
if(!imageBean.isAddButton){
|
||||
list.add(imageBean)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
fun getImageSize(): Int {
|
||||
if(isEditModel && editImageShow){
|
||||
return getDefItemCount() - 1
|
||||
}
|
||||
return getDefItemCount()
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示添加图片按钮
|
||||
* @param isShow true为显示 false为隐藏
|
||||
*/
|
||||
private fun showAddButton(isShow: Boolean){
|
||||
editImageShow = if(isShow){
|
||||
addData(ImageBean(isAddButton = true))
|
||||
true
|
||||
}else{
|
||||
removeAt(data.size-1)
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package com.zmkg.coaloperation.ui.report.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
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.luck.picture.lib.basic.PictureSelectionModel
|
||||
import com.luck.picture.lib.basic.PictureSelector
|
||||
import com.luck.picture.lib.config.SelectMimeType
|
||||
import com.luck.picture.lib.config.SelectModeConfig
|
||||
import com.luck.picture.lib.entity.LocalMedia
|
||||
import com.luck.picture.lib.interfaces.OnResultCallbackListener
|
||||
import com.luck.picture.lib.utils.SandboxTransformUtils
|
||||
import com.zmkg.coaloperation.utils.pictureSelector.ImageFileCompressEngine
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBFragment
|
||||
import com.zmkg.coaloperation.bean.ImageBean
|
||||
import com.zmkg.coaloperation.databinding.FragmentReportBinding
|
||||
import com.zmkg.coaloperation.ui.report.adapter.ImageAdapter
|
||||
import com.zmkg.coaloperation.ui.report.viewmodel.ReportViewModel
|
||||
import com.zmkg.coaloperation.utils.pictureSelector.GlideEngine
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ReportFragment :
|
||||
BaseVMBFragment<ReportViewModel, FragmentReportBinding>(R.layout.fragment_report),
|
||||
OnItemClickListener, OnItemChildClickListener {
|
||||
|
||||
private val imageAdapter by lazy { ImageAdapter(maxImageNum) }
|
||||
lateinit var pageStatus: PageStatus
|
||||
|
||||
companion object {
|
||||
const val maxImageNum = 5
|
||||
}
|
||||
|
||||
override fun initView(root: View?, savedInstanceState: Bundle?) {
|
||||
|
||||
mBinding.apply {
|
||||
val gridLayoutManager = GridLayoutManager(context, 3)
|
||||
layInspectionReport.rvList.layoutManager = gridLayoutManager
|
||||
imageAdapter.setOnItemClickListener(this@ReportFragment)
|
||||
imageAdapter.setOnItemChildClickListener(this@ReportFragment)
|
||||
mBinding.layInspectionReport.rvList.adapter = imageAdapter
|
||||
ViewCompat.setNestedScrollingEnabled(layInspectionReport.rvList, false)
|
||||
}
|
||||
|
||||
setPageModel(PageStatus.ADD)
|
||||
|
||||
}
|
||||
|
||||
enum class PageStatus(val status: Int) {
|
||||
ADD(1),
|
||||
EDIT(2),
|
||||
SEE(3),
|
||||
NO_EDIT(4)
|
||||
}
|
||||
|
||||
private fun setPageModel(status: PageStatus) {
|
||||
this.pageStatus = status
|
||||
mBinding?.apply {
|
||||
when (status) {
|
||||
PageStatus.ADD -> {
|
||||
lifecycleScope.launch {
|
||||
mViewModel.noEdit.emit(false)
|
||||
}
|
||||
}
|
||||
|
||||
PageStatus.EDIT -> {
|
||||
lifecycleScope.launch {
|
||||
mViewModel.noEdit.emit(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PageStatus.SEE -> {
|
||||
lifecycleScope.launch {
|
||||
mViewModel.noEdit.emit(true)
|
||||
}
|
||||
}
|
||||
|
||||
PageStatus.NO_EDIT -> {
|
||||
lifecycleScope.launch {
|
||||
mViewModel.noEdit.emit(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun bindEvent() {
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
}
|
||||
|
||||
override fun transparentStatusBar(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun createObserve() {
|
||||
super.createObserve()
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
mViewModel.noEdit.collectLatest { noEdit ->
|
||||
mBinding.apply {
|
||||
imageAdapter.isEditModel(!noEdit)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int) {
|
||||
val imageBean: ImageBean = adapter.getItem(position) as ImageBean
|
||||
imageBean?.let { it ->
|
||||
if (it.isAddButton) {
|
||||
initPictureSelectorModel()
|
||||
.forResult(object : OnResultCallbackListener<LocalMedia?> {
|
||||
override fun onResult(result: ArrayList<LocalMedia?>?) {
|
||||
result?.let { list ->
|
||||
var resultList = localMediaToImageList(list)
|
||||
imageAdapter.addData(resultList)
|
||||
setImageNum(imageAdapter.getImageSize())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancel() {}
|
||||
})
|
||||
} else {
|
||||
// startFullScreenImageActivity(
|
||||
// it.isFilePath,
|
||||
// it.imageUrl
|
||||
// )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setImageNum(size: Int) {
|
||||
mBinding.layInspectionReport.tvImageNum.text = getString(
|
||||
R.string.image_list_num,
|
||||
size,
|
||||
maxImageNum
|
||||
)
|
||||
}
|
||||
|
||||
private fun initPictureSelectorModel(): PictureSelectionModel {
|
||||
return PictureSelector.create(this)
|
||||
.openGallery(SelectMimeType.TYPE_IMAGE)
|
||||
.setSelectionMode(SelectModeConfig.MULTIPLE)
|
||||
.setMaxSelectNum(maxImageNum - imageAdapter.getImageSize())
|
||||
.setCompressEngine(ImageFileCompressEngine())
|
||||
.setImageEngine(GlideEngine.createGlideEngine())
|
||||
.setSandboxFileEngine { context, srcPath, mineType, call ->
|
||||
if (call != null) {
|
||||
var sandboxPath =
|
||||
SandboxTransformUtils.copyPathToSandbox(context, srcPath, mineType)
|
||||
call.onCallback(srcPath, sandboxPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
override fun onItemChildClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int) {
|
||||
adapter.removeAt(position)
|
||||
}
|
||||
|
||||
fun localMediaToImageList(result: ArrayList<LocalMedia?>): MutableList<ImageBean> {
|
||||
var imageList = mutableListOf<ImageBean>()
|
||||
var imageBean: ImageBean
|
||||
result.forEach {
|
||||
it?.let {
|
||||
imageBean = ImageBean(getImagePath(it), true)
|
||||
imageList.add(imageBean)
|
||||
}
|
||||
}
|
||||
return imageList
|
||||
}
|
||||
|
||||
private fun getImagePath(localMedia: LocalMedia): String {
|
||||
if (!localMedia.cutPath.isNullOrEmpty()) {
|
||||
return localMedia.cutPath
|
||||
}
|
||||
if (!localMedia.compressPath.isNullOrEmpty()) {
|
||||
return localMedia.compressPath
|
||||
}
|
||||
if (!localMedia.sandboxPath.isNullOrEmpty()) {
|
||||
return localMedia.sandboxPath
|
||||
}
|
||||
return localMedia.path
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.zmkg.coaloperation.ui.report.viewmodel
|
||||
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
|
||||
class ReportViewModel :BaseViewModel() {
|
||||
|
||||
var noEdit = MutableStateFlow(false)
|
||||
|
||||
override fun init() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import com.tencent.qcloud.tuikit.timcommon.util.SoftKeyBoardUtil
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.ActivityAddWorkingPointBinding
|
||||
import com.zmkg.coaloperation.databinding.ListItemRockBinding
|
||||
import com.zmkg.coaloperation.utils.PickerUtil
|
||||
import com.zmkg.coaloperation.utils.clickWithDebounce
|
||||
|
||||
/**
|
||||
* 开始记录
|
||||
*/
|
||||
class AddWorkingPointActivity :
|
||||
BaseVMBActivity<TestViewModel, ActivityAddWorkingPointBinding>(R.layout.activity_add_working_point) {
|
||||
|
||||
companion object {
|
||||
const val SHOW_TYPE = "showType"
|
||||
const val FACE_NAME = "faceName"
|
||||
}
|
||||
|
||||
private var showType = 0
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
mBinding.toolbarLay.vLine.visibility = View.GONE
|
||||
showType = intent.extras?.getInt(SHOW_TYPE) ?: 0
|
||||
mBinding.toolbarLay.rightText =
|
||||
if (showType == 0) "开始记录" else "修改记录"
|
||||
|
||||
mBinding.root.setOnClickListener {
|
||||
window?.let {
|
||||
SoftKeyBoardUtil.hideKeyBoard(window)
|
||||
}
|
||||
}
|
||||
mBinding.tvWorkDate.clickWithDebounce {
|
||||
PickerUtil.showTimePicker(this) {date->
|
||||
mBinding.tvWorkDate.text = date
|
||||
}
|
||||
}
|
||||
mBinding.tvFaceName.text = intent.getStringExtra(FACE_NAME)
|
||||
mBinding.toolbarLay.title = intent.getStringExtra(FACE_NAME)
|
||||
|
||||
val teamList = mutableListOf<String>()
|
||||
teamList.add("A地区第1施工队")
|
||||
teamList.add("A地区第2施工队")
|
||||
teamList.add("B地区第1施工队")
|
||||
teamList.add("B地区第2施工队")
|
||||
teamList.add("C地区第1施工队")
|
||||
teamList.add("C地区第2施工队")
|
||||
teamList.add("D地区第1施工队")
|
||||
teamList.add("D地区第2施工队")
|
||||
mBinding.tvWorkTeam.clickWithDebounce {
|
||||
PickerUtil.showOptionsPicker(this, teamList) {team->
|
||||
mBinding.tvWorkTeam.text = team
|
||||
}
|
||||
}
|
||||
val workTypeList = mutableListOf<String>()
|
||||
workTypeList.add("早班")
|
||||
workTypeList.add("中班")
|
||||
workTypeList.add("晚班")
|
||||
mBinding.tvWorkType.clickWithDebounce {
|
||||
PickerUtil.showOptionsPicker(this, workTypeList) {team->
|
||||
mBinding.tvWorkType.text = team
|
||||
}
|
||||
}
|
||||
mBinding.btnAddPoint.clickWithDebounce {
|
||||
addRockPoint()
|
||||
}
|
||||
addRockPoint()
|
||||
}
|
||||
|
||||
private fun addRockPoint() {
|
||||
val itemBinding = ListItemRockBinding.inflate(
|
||||
LayoutInflater.from(this),
|
||||
mBinding.llRockPoint,
|
||||
false
|
||||
)
|
||||
mBinding.llRockPoint.addView(itemBinding.root)
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.databinding.ActivityTunnelingBinding
|
||||
import com.zmkg.coaloperation.event.TunnelingWorkFaceRefreshEvent
|
||||
import com.zmkg.coaloperation.ui.tunneling.adapter.TunnelingHomeAdapter
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.viewmodel.TunnelingViewModel
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 掘进首页列表
|
||||
*/
|
||||
class TunnelingActivity :
|
||||
BaseVMBActivity<TunnelingViewModel, ActivityTunnelingBinding>(R.layout.activity_tunneling) {
|
||||
|
||||
private val tunnelingHomeAdapter: TunnelingHomeAdapter by lazy {
|
||||
TunnelingHomeAdapter {index,surfaceId->
|
||||
mViewModel.getTunnelingHomeItemData(index,surfaceId)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
|
||||
mBinding.toolbarLay.rightText = "新增工作面"
|
||||
mBinding.rvList.adapter = tunnelingHomeAdapter
|
||||
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
mViewModel.getTunnelingHomeData()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// HttpUtil.get(UrlConst.FACE_LIST, doSuccess = {
|
||||
// val type = object : TypeToken<MutableList<TunnelingHomeBean>>() {}
|
||||
// val list: MutableList<TunnelingHomeBean>? = it.toJsonString().toType(typeToken = type)
|
||||
// if (list.isNullOrEmpty()) {
|
||||
// ToastTool.toastShort(this@TunnelingActivity, "未查询到数据")
|
||||
// return@get
|
||||
// }
|
||||
// tunnelingHomeAdapter.setNewInstance(list)
|
||||
// getRecordList(0) {}
|
||||
// }, doFailure = { code, msg ->
|
||||
// if (msg.isNullOrEmpty()) {
|
||||
// return@get
|
||||
// }
|
||||
// ToastTool.toastShort(this@TunnelingActivity, msg)
|
||||
// })
|
||||
//
|
||||
//// val gson = Gson()
|
||||
//// val type: Type = object : TypeToken<MutableList<TunnelingHomeBean>>() {}.type
|
||||
//// val mutableListOf = gson.fromJson<MutableList<TunnelingHomeBean>>(jsonString, type)
|
||||
////
|
||||
//// tunnelingHomeAdapter.setNewInstance(mutableListOf)
|
||||
//
|
||||
// }
|
||||
//
|
||||
// fun getRecordList(index:Int, action:()-> Unit) {
|
||||
// val faceId: Long? = tunnelingHomeAdapter.data[index].surfaceId
|
||||
// HttpUtil.get("${UrlConst.RECORD_LIST + faceId}", doSuccess = {
|
||||
// val type = object : TypeToken<MutableList<TunnelingHomeItemBean>>() {}
|
||||
// val list: MutableList<TunnelingHomeItemBean>? = it.toJsonString().toType(typeToken = type)
|
||||
// if (list.isNullOrEmpty()) {
|
||||
// ToastTool.toastShort(this@TunnelingActivity, "未查询到数据")
|
||||
// return@get
|
||||
// }
|
||||
// tunnelingHomeAdapter.data[0].contentList = list
|
||||
// val holder = mBinding.rvList.findViewHolderForLayoutPosition(0)
|
||||
// val rvContent = holder?.itemView?.findViewById<RecyclerView>(R.id.rv_content)
|
||||
// rvContent?.adapter.let { adapter ->
|
||||
// if (adapter is TunnelingHomeListAdapter) {
|
||||
// adapter.data.clear()
|
||||
// adapter.data.addAll(list)
|
||||
// adapter.notifyDataSetChanged()
|
||||
// }
|
||||
// }
|
||||
// action()
|
||||
// }, doFailure = { code, msg ->
|
||||
// if (msg.isNullOrEmpty()) {
|
||||
// return@get
|
||||
// }
|
||||
// ToastTool.toastShort(this@TunnelingActivity, msg)
|
||||
// })
|
||||
// }
|
||||
|
||||
override fun createObserve() {
|
||||
super.createObserve()
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
mViewModel.tunnelingHomeList.collectLatest { list ->
|
||||
list?.reverse()
|
||||
tunnelingHomeAdapter.setNewInstance(list)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
mViewModel.tunnelingHomeItemList.collectLatest { list ->
|
||||
if (list.isNullOrEmpty()) {
|
||||
showToast("未查询到数据")
|
||||
return@collectLatest
|
||||
}
|
||||
|
||||
tunnelingHomeAdapter.data[mViewModel.itemIndex.value].contentList = list
|
||||
tunnelingHomeAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun bindEvent() {
|
||||
tunnelingHomeAdapter.setOnItemClickListener { adapter, view, position ->
|
||||
val tunnelingHomeBean = adapter.data.get(position) as TunnelingHomeBean
|
||||
// 跳转到工作面详情
|
||||
|
||||
toActivity(WorkingFaceDetailActivity::class.java, Bundle().apply {
|
||||
putString("surfaceId", tunnelingHomeBean.surfaceId)
|
||||
})
|
||||
}
|
||||
|
||||
tunnelingHomeAdapter.setOnItemChildClickListener { adapter, view, position ->
|
||||
val tunnelingHomeBean = adapter.data.get(position) as TunnelingHomeBean
|
||||
// 跳转到开始记录页面
|
||||
|
||||
if (view.id == R.id.start_record) {
|
||||
toActivity(AddWorkingPointActivity::class.java, Bundle().apply {
|
||||
putString(AddWorkingPointActivity.FACE_NAME, tunnelingHomeBean.surfaceName)
|
||||
putInt(AddWorkingPointActivity.SHOW_TYPE, 0)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
mBinding.toolbarLay.titleTvRight.setOnClickListener {
|
||||
|
||||
toActivity(WorkFaceActivity::class.java,Bundle().apply {
|
||||
putString("WorkFaceType", WorkFaceActivity.WorkFaceType.ADD.name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onMessageEvent(event: Any?) {
|
||||
if (event is TunnelingWorkFaceRefreshEvent) {
|
||||
mViewModel.getTunnelingHomeData()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.databinding.ActivityWorkFaceBinding
|
||||
import com.zmkg.coaloperation.event.TunnelingWorkFaceRefreshEvent
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.FaceWorkDetailBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingFaceAddBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.viewmodel.TunnelingViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
/**
|
||||
* 工作面
|
||||
*/
|
||||
class WorkFaceActivity :
|
||||
BaseVMBActivity<TunnelingViewModel, ActivityWorkFaceBinding>(R.layout.activity_work_face) {
|
||||
|
||||
companion object {
|
||||
const val WORK_FACE_TYPE = "WorkFaceType"
|
||||
const val FACE_WORK_DETAIL_DATA = "faceWorkDetailData"
|
||||
}
|
||||
|
||||
var currentFaceType = WorkFaceType.ADD
|
||||
|
||||
enum class WorkFaceType {
|
||||
ADD,//新增
|
||||
|
||||
EDIT,//修改
|
||||
|
||||
SEE//查看
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
val stringExtra = intent.getStringExtra(WORK_FACE_TYPE)
|
||||
if (TextUtils.isEmpty(stringExtra)) {
|
||||
finish()
|
||||
} else if (stringExtra == WorkFaceType.ADD.name) {
|
||||
currentFaceType = WorkFaceType.ADD
|
||||
mBinding.toolbarLay.titleTvName.text = "新增工作面"
|
||||
mBinding.confirm.text = "确认新增"
|
||||
} else if (stringExtra == WorkFaceType.EDIT.name) {
|
||||
currentFaceType = WorkFaceType.EDIT
|
||||
mBinding.toolbarLay.titleTvName.text = "修改工作面"
|
||||
mBinding.confirm.text = "确认修改"
|
||||
val detail = intent.getSerializableExtra(WorkingFaceDetail2Activity.FACE_WORK_DETAIL_DATA) as FaceWorkDetailBean?
|
||||
detail?.let {
|
||||
loadDetail(it)
|
||||
}
|
||||
} else if (stringExtra == WorkFaceType.SEE.name) {
|
||||
currentFaceType = WorkFaceType.SEE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
mBinding.apply {
|
||||
addClickViews(imgExpand, confirm)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createObserve() {
|
||||
super.createObserve()
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
mViewModel.tunnelingWorkFaceAdd.collectLatest {
|
||||
showToast("新增成功")
|
||||
EventBus.getDefault().post(TunnelingWorkFaceRefreshEvent())
|
||||
delay(200)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
when (v?.id) {
|
||||
R.id.img_expand -> {
|
||||
if (mBinding.expandLayout.visibility == View.GONE) {
|
||||
mBinding.expandLayout.visibility = View.VISIBLE
|
||||
mBinding.imgView.background = getDrawable(R.mipmap.arrow_up_white)
|
||||
} else {
|
||||
mBinding.expandLayout.visibility = View.GONE
|
||||
mBinding.imgView.background = getDrawable(R.mipmap.arrow_down_white)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
R.id.confirm -> {
|
||||
if (currentFaceType == WorkFaceType.ADD) {
|
||||
addNewFace()
|
||||
return
|
||||
}
|
||||
if (currentFaceType == WorkFaceType.EDIT) {
|
||||
editFace()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadDetail(it: FaceWorkDetailBean) {
|
||||
mBinding.etWorkfaceName.setText(it.surfaceName)
|
||||
mBinding.etTotalFootage.setText("${it.totalFootage}")
|
||||
mBinding.etCoalSeam.text = it.seamName
|
||||
mBinding.etCoalArea.text = it.areaName
|
||||
mBinding.etFaceAngle.setText(it.surfaceAzimuth)
|
||||
mBinding.etFaceHeight.setText(it.surfaceHeight)
|
||||
mBinding.etFaceWidth.setText(it.surfaceWidth)
|
||||
mBinding.tvCoalType.text = it.tunnelNature
|
||||
|
||||
mBinding.plannedDate1.setText(it.planStartDate)
|
||||
mBinding.plannedDate2.setText(it.planEndDate)
|
||||
|
||||
mBinding.etGeologicalType.setText(it.geologicalType)
|
||||
mBinding.etHydrogeologicalType.setText(it.hydrogeologicalType)
|
||||
mBinding.etSeamIgnition.setText(it.seamIgnition)
|
||||
mBinding.etSeamGas.setText(it.seamGas)
|
||||
mBinding.etSeamBumpPressure.setText(it.seamBumpPressure)
|
||||
mBinding.etSurfaceSupportForm.setText(it.surfaceSupportForm)
|
||||
}
|
||||
|
||||
private fun addNewFace() {
|
||||
if (TextUtils.isEmpty(mBinding.etWorkfaceName.text.toString())) {
|
||||
showToast("请输入工作面名称")
|
||||
return
|
||||
}
|
||||
if (TextUtils.isEmpty(mBinding.etTotalFootage.text.toString())) {
|
||||
showToast("请输入总进尺")
|
||||
return
|
||||
}
|
||||
mViewModel.postTunnellingSurfaceAdd(
|
||||
TunnelingFaceAddBean(
|
||||
surfaceName = mBinding.etWorkfaceName.text.toString(),
|
||||
totalFootage = mBinding.etTotalFootage.text.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun editFace() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.zmkg.coaloperation.adapter.WorkingItemAdapter
|
||||
import com.zmkg.coaloperation.bean.WorkingFaceItem
|
||||
import com.zmkg.coaloperation.databinding.ActivityWorkingFaceDetail2Binding
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.FaceWorkDetailBean
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* 工作面详情2
|
||||
*/
|
||||
class WorkingFaceDetail2Activity :
|
||||
BaseVMBActivity<TestViewModel, ActivityWorkingFaceDetail2Binding>(R.layout.activity_working_face_detail2) {
|
||||
companion object {
|
||||
const val FACE_WORK_DETAIL_DATA = "faceWorkDetailData"
|
||||
}
|
||||
|
||||
private val list: MutableList<WorkingFaceItem> = mutableListOf()
|
||||
|
||||
private var detail:FaceWorkDetailBean?=null
|
||||
private val adapter by lazy {
|
||||
WorkingItemAdapter(list)
|
||||
}
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
mBinding.toolbarLay.vLine.visibility = View.GONE
|
||||
mBinding.toolbarLay.rightText="修改"
|
||||
|
||||
mBinding.rvFaceList.let {
|
||||
it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
it.adapter = adapter
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun initData() {
|
||||
val serializableExtra = intent.getSerializableExtra(FACE_WORK_DETAIL_DATA)
|
||||
if (serializableExtra==null) {
|
||||
finish()
|
||||
} else {
|
||||
detail = serializableExtra as FaceWorkDetailBean
|
||||
detail?.let {
|
||||
mBinding.toolbarLay.title = it.surfaceName
|
||||
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "工作面名称", value = it.surfaceName))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "所属煤层", value = it.seamName))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "所属采区域", value = it.areaName))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "工作面方位角", value = it.surfaceAzimuth))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "工作面巷高", value = it.surfaceHeight))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "工作面巷宽", value = it.surfaceWidth))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "巷道性质", value = it.tunnelNature))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "计划工期", value = "${it.planStartDate} ~ ${it.planEndDate}"))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "地质类型", value = it.geologicalType))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "水文地质类型", value = it.hydrogeologicalType))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "煤层发火性", value = it.seamIgnition))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "瓦斯含量", value = it.seamGas))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "冲击地压危险性", value = it.seamBumpPressure))
|
||||
list.add(WorkingFaceItem(pageType = 0, name = "支护形式", value = it.surfaceSupportForm))
|
||||
}
|
||||
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
mBinding.toolbarLay.titleTvRight.setOnClickListener {
|
||||
toActivity(WorkFaceActivity::class.java, Bundle().apply {
|
||||
putString(WorkFaceActivity.WORK_FACE_TYPE, WorkFaceActivity.WorkFaceType.EDIT.name)
|
||||
putSerializable(WorkFaceActivity.FACE_WORK_DETAIL_DATA, detail)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import androidx.core.graphics.toColorInt
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.zmkg.coaloperation.databinding.ActivityWorkingFaceDetailBinding
|
||||
import com.zmkg.coaloperation.superfuntion.orEmptyDefaultInt
|
||||
import com.zmkg.coaloperation.ui.tunneling.adapter.TunnelingHomeListAdapter
|
||||
import com.zmkg.coaloperation.ui.tunneling.adapter.TunnelingRockNatureAdapter
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.FaceWorkDetailBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.viewmodel.TunnelingViewModel
|
||||
import com.zmkg.coaloperation.utils.ScreenUtil
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.Serializable
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* 工作面详情
|
||||
*/
|
||||
class WorkingFaceDetailActivity :
|
||||
BaseVMBActivity<TunnelingViewModel, ActivityWorkingFaceDetailBinding>(R.layout.activity_working_face_detail) {
|
||||
|
||||
val tunnelingRockNatureAdapter: TunnelingRockNatureAdapter by lazy { TunnelingRockNatureAdapter()}
|
||||
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
mBinding.toolbarLay.rightText = "查看详情"
|
||||
mBinding.toolbarLay.vLine.visibility = View.GONE
|
||||
mBinding.rvRockNature.adapter = tunnelingRockNatureAdapter
|
||||
|
||||
mBinding.arcViewGreen.let {
|
||||
it.arcColor = "#30E0A1".toColorInt()
|
||||
it.startAngle = 0f
|
||||
it.sweepAngle = 360f
|
||||
it.strokeWidth = 12f
|
||||
it.radius = ScreenUtil.dp2px(122f - 12f) / 2f
|
||||
}
|
||||
|
||||
mBinding.arcViewRed.let {
|
||||
it.arcColor = "#FA2256".toColorInt()
|
||||
it.startAngle = -90f
|
||||
it.strokeWidth = 10f
|
||||
it.sweepAngle = 0f
|
||||
it.radius = ScreenUtil.dp2px(100f-10f)/2f
|
||||
}
|
||||
|
||||
mBinding.arcViewBlue.let {
|
||||
it.arcColor = "#246CF9".toColorInt()
|
||||
it.startAngle = -90f
|
||||
it.strokeWidth = 10f
|
||||
it.sweepAngle = 0f
|
||||
it.radius = ScreenUtil.dp2px(100f-10f)/2f
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
val surfaceId = intent.getStringExtra("surfaceId")
|
||||
if (TextUtils.isEmpty(surfaceId)) {
|
||||
finish()
|
||||
} else {
|
||||
mViewModel.getTunnelingSurfaceDetail(surfaceId)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
mBinding.toolbarLay.titleTvRight.setOnClickListener {
|
||||
toActivity(WorkingFaceDetail2Activity::class.java, Bundle().apply {
|
||||
putSerializable(
|
||||
WorkingFaceDetail2Activity.FACE_WORK_DETAIL_DATA,
|
||||
mViewModel.faceWorkDetailData.value as Serializable
|
||||
)
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
}
|
||||
|
||||
override fun createObserve() {
|
||||
super.createObserve()
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
mViewModel.faceWorkDetailData.collectLatest {
|
||||
if (it != null) {
|
||||
setDataView(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setDataView(bean: FaceWorkDetailBean?) {
|
||||
bean ?: return
|
||||
|
||||
mBinding.apply {
|
||||
toolbarLay.title = bean.surfaceName
|
||||
|
||||
tvLenTotal.text = "总进尺:${bean.totalFootage}m"
|
||||
tvLenAccumulate.text = "累计进尺:${bean.accumulativeFootage.orEmptyDefaultInt("0")}m"
|
||||
tvLenRemain.text = "剩余进尺:${bean.remainingFootage.orEmptyDefaultInt("0")}m"
|
||||
|
||||
//累计进尺占比
|
||||
var radio = 0
|
||||
|
||||
//累计进尺圆圈占比
|
||||
var arcViewRadio: Float
|
||||
|
||||
if (bean.accumulativeFootage > bean.totalFootage) {
|
||||
radio = 100
|
||||
arcViewRadio = 360F
|
||||
} else if (bean.accumulativeFootage <= 0) {
|
||||
radio = 0
|
||||
arcViewRadio = 0F
|
||||
} else {
|
||||
radio = (bean.accumulativeFootage * 100F / bean.accumulativeFootage).roundToInt()
|
||||
arcViewRadio = bean.accumulativeFootage * 360F / bean.accumulativeFootage
|
||||
}
|
||||
|
||||
arcViewRed.let {
|
||||
it.sweepAngle = arcViewRadio
|
||||
}
|
||||
|
||||
|
||||
arcViewBlue.let {
|
||||
it.sweepAngle = (360F-arcViewRadio) * -1F
|
||||
}
|
||||
|
||||
|
||||
mBinding.tvCompleteRate.text = "$radio%"
|
||||
|
||||
tvYesterdayLen.text = "${bean?.yesterdayFootage}m"
|
||||
tvWorkingFaceAngle.text = "${bean?.latestRecord?.seamDip.orEmptyDefaultInt()}"
|
||||
tvMonthAccumulateLen.text = "${bean?.monthFootage}m"
|
||||
tvWorkingFaceWater.text = "${bean?.latestRecord?.waterYield.orEmptyDefaultInt()}m"
|
||||
|
||||
val list = bean?.latestRecord?.mineWorkingLithologyList
|
||||
if (list.isNullOrEmpty()) {
|
||||
tvYesterdayRockType.visibility = View.GONE
|
||||
} else {
|
||||
tvYesterdayRockType.visibility = View.VISIBLE
|
||||
tunnelingRockNatureAdapter.setNewInstance(list)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.adapter.WorkingItemAdapter
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.bean.RockItem
|
||||
import com.zmkg.coaloperation.bean.WorkingFaceItem
|
||||
import com.zmkg.coaloperation.databinding.ActivityWorkingPointBinding
|
||||
|
||||
/**
|
||||
* 查看(棋盘井)
|
||||
*/
|
||||
class WorkingPointActivity :
|
||||
BaseVMBActivity<TestViewModel, ActivityWorkingPointBinding>(R.layout.activity_working_point) {
|
||||
|
||||
private val list: MutableList<WorkingFaceItem> = mutableListOf()
|
||||
private val adapter by lazy {
|
||||
WorkingItemAdapter(list)
|
||||
}
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
mBinding.toolbarLay.vLine.visibility = View.GONE
|
||||
mBinding.toolbarLay.rightText = "查看详情"
|
||||
|
||||
mBinding.rvPointList.let {
|
||||
it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
it.adapter = adapter
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun initData() {
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "工作面名称", value = "5-20304回风工作面"))
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "施工日期", value = "2025-08-15"))
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "施工班次", value = "早班"))
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "施工队伍", value = "掘进队"))
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "带班队长", value = "刘某杰"))
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "班进尺", value = "200m"))
|
||||
|
||||
val rockList = mutableListOf<RockItem>()
|
||||
rockList.add(RockItem(startLen = 0, endLen = 1, rockType = "泥"))
|
||||
rockList.add(RockItem(startLen = 0, endLen = 1, rockType = "砂"))
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "顶板岩性", value = "", items = rockList))
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "煤层倾角", value = "60°"))
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "煤层高", value = "20m"))
|
||||
list.add(WorkingFaceItem(pageType = 1, name = "记录人", value = "刘某杰"))
|
||||
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.adapter
|
||||
|
||||
import android.content.Intent
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.viewholder.BaseViewHolder
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.activity.WorkingPointActivity
|
||||
|
||||
|
||||
/**
|
||||
* 掘进首页列表
|
||||
*/
|
||||
|
||||
class TunnelingHomeAdapter(var listener: (Int,String?)->Unit) : BaseQuickAdapter<TunnelingHomeBean, BaseViewHolder>(
|
||||
R.layout.item_geological_list
|
||||
) {
|
||||
|
||||
override fun convert(holder: BaseViewHolder, item: TunnelingHomeBean) {
|
||||
val tunnelingHomeListAdapter: TunnelingHomeListAdapter by lazy { TunnelingHomeListAdapter().apply {
|
||||
setOnItemClickListener { adapter, view, position ->
|
||||
context.startActivity(Intent(context, WorkingPointActivity::class.java))
|
||||
}
|
||||
} }
|
||||
|
||||
val rvList = holder.getView<RecyclerView>(R.id.rv_content)
|
||||
val expand = holder.getView<ImageView>(R.id.expand)
|
||||
val recordLayout = holder.getView<LinearLayout>(R.id.record_layout)
|
||||
|
||||
holder.apply {
|
||||
setText(R.id.title, item.surfaceName)
|
||||
rvList.adapter = tunnelingHomeListAdapter
|
||||
tunnelingHomeListAdapter.setNewInstance(item.contentList?:mutableListOf())
|
||||
}
|
||||
expand.setOnClickListener {
|
||||
val imageView = it as ImageView
|
||||
if (imageView.tag.equals("0")) {//收起状态
|
||||
imageView.setImageResource(R.mipmap.ic_arrow_down_white)
|
||||
recordLayout.visibility = View.VISIBLE
|
||||
imageView.tag = "1"
|
||||
|
||||
if (data[holder.absoluteAdapterPosition].contentList.isNullOrEmpty()) {
|
||||
// if (context is TunnelingActivity) {
|
||||
// (context as TunnelingActivity).getRecordList(holder.layoutPosition) {
|
||||
// tunnelingHomeListAdapter.notifyDataSetChanged()
|
||||
// }
|
||||
// }
|
||||
listener.invoke(holder.absoluteAdapterPosition,data[holder.absoluteAdapterPosition].surfaceId)
|
||||
}
|
||||
} else {//展开状态
|
||||
imageView.setImageResource(R.mipmap.ic_arrow_right)
|
||||
recordLayout.visibility = View.GONE
|
||||
imageView.tag = "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
init {
|
||||
addChildClickViewIds(R.id.start_record)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.adapter
|
||||
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.viewholder.BaseViewHolder
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeItemBean
|
||||
|
||||
|
||||
/**
|
||||
* 掘进首页点击出现的列表
|
||||
*/
|
||||
|
||||
class TunnelingHomeListAdapter :
|
||||
BaseQuickAdapter<TunnelingHomeItemBean, BaseViewHolder>(R.layout.item_geological_list_content) {
|
||||
|
||||
|
||||
override fun convert(holder: BaseViewHolder, item: TunnelingHomeItemBean) {
|
||||
if (holder.absoluteAdapterPosition != 0) {
|
||||
holder.setGone(R.id.head, true)
|
||||
}
|
||||
holder.setText(R.id.time, item.workingDate)
|
||||
.setText(R.id.record, item.recordPerson)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.adapter
|
||||
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.viewholder.BaseViewHolder
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.MineWorkingLithology
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeItemBean
|
||||
|
||||
|
||||
/**
|
||||
* 顶板岩性
|
||||
*/
|
||||
|
||||
class TunnelingRockNatureAdapter :
|
||||
BaseQuickAdapter<MineWorkingLithology, BaseViewHolder>(R.layout.item_rock_nature) {
|
||||
|
||||
|
||||
override fun convert(holder: BaseViewHolder, item: MineWorkingLithology) {
|
||||
holder.setText(R.id.tvRock1Start, "${item.positionStart}")
|
||||
.setText(R.id.tvRock1End, "${item.positionEnd}")
|
||||
.setText(R.id.tvRock1Name, item.lithologyType)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.bean
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
|
||||
/**
|
||||
* 掘进
|
||||
*/
|
||||
data class TunnelingHomeBean(
|
||||
var contentList: MutableList<TunnelingHomeItemBean>?,
|
||||
val createBy: String?,
|
||||
val createTime: String?,
|
||||
val updateBy: String?,
|
||||
val updateTime: String?,
|
||||
val remark: String?,
|
||||
val surfaceId: String?,
|
||||
val totalFootage: String?,
|
||||
val seamId: String?,
|
||||
val areaId: String?,
|
||||
val seamName: String?,
|
||||
val surfaceName: String?,
|
||||
val areaName: String?,
|
||||
val surfaceAzimuth: String?,
|
||||
val surfaceHeight: String?,
|
||||
val surfaceWidth: String?,
|
||||
val tunnelNature: String?,
|
||||
val planStartDate: String?,
|
||||
val planEndDate: String?,
|
||||
val geologicalType: String?,
|
||||
val hydrogeologicalType: String?,
|
||||
val seamIgnition: String?,
|
||||
val seamGas: String?,
|
||||
val seamBumpPressure: String?,
|
||||
val surfaceSupportForm: String?
|
||||
)
|
||||
|
||||
class TunnelingHomeItemBean {
|
||||
var createBy: String? = null
|
||||
var createTime: String? = null
|
||||
var updateBy: String? = null
|
||||
var updateTime: String? = null
|
||||
var remark: String? = null
|
||||
var recordId: String? = null
|
||||
var surfaceId: String? = null
|
||||
var workingDate: String? = null
|
||||
var teamShift: String? = null
|
||||
var teamId: String? = null
|
||||
var teamName: String? = null
|
||||
var teamLeader: String? = null
|
||||
var workingFootage: String? = null
|
||||
var seamDip: String? = null
|
||||
var seamHeight: String? = null
|
||||
var waterYield: String? = null
|
||||
var recordPerson: String? = null
|
||||
var mineWorkingLith: String? = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增工作面 给接口的数据
|
||||
*/
|
||||
data class TunnelingFaceAddBean(
|
||||
|
||||
val surfaceName: String? = null,
|
||||
val totalFootage: String? = null,
|
||||
|
||||
val areaId: Int? = null,
|
||||
val areaName: String? = null,
|
||||
val createBy: String? = null,
|
||||
val createTime: String? = null,
|
||||
val geologicalType: String? = null,
|
||||
val hydrogeologicalType: String? = null,
|
||||
val params: Params? = null,
|
||||
val planEndDate: String? = null,
|
||||
val planStartDate: String? = null,
|
||||
val remark: String? = null,
|
||||
val seamBumpPressure: String? = null,
|
||||
val seamGas: String? = null,
|
||||
val seamId: Int? = null,
|
||||
val seamIgnition: String? = null,
|
||||
val seamName: String? = null,
|
||||
val surfaceAzimuth: String? = null,
|
||||
val surfaceHeight: String? = null,
|
||||
val surfaceId: Int? = null,
|
||||
val surfaceSupportForm: String? = null,
|
||||
val surfaceWidth: String? = null,
|
||||
val tunnelNature: String? = null,
|
||||
val updateBy: String? = null,
|
||||
val updateTime: String? = null
|
||||
)
|
||||
|
||||
data class Params(
|
||||
val additionalProp1: String? = null,
|
||||
val additionalProp2: String? = null,
|
||||
val additionalProp3: String? = null
|
||||
):Serializable
|
||||
|
||||
|
||||
/**
|
||||
* 工作面详情
|
||||
*/
|
||||
data class FaceWorkDetailBean(
|
||||
val accumulativeFootage: Int,
|
||||
val areaId: Int,
|
||||
val areaName: String,
|
||||
val createBy: String,
|
||||
val createTime: String,
|
||||
val geologicalType: String,
|
||||
val hydrogeologicalType: String,
|
||||
val latestRecord: LatestRecord,
|
||||
val params: Params,
|
||||
val planEndDate: String,
|
||||
val planStartDate: String,
|
||||
val remainingFootage: Int,
|
||||
val remark: String,
|
||||
val seamBumpPressure: String,
|
||||
val seamGas: String,
|
||||
val seamId: Int,
|
||||
val seamIgnition: String,
|
||||
val seamName: String,
|
||||
val surfaceAzimuth: String,
|
||||
val surfaceHeight: String,
|
||||
val surfaceId: Int,
|
||||
val surfaceName: String,
|
||||
val surfaceSupportForm: String,
|
||||
val surfaceWidth: String,
|
||||
val totalFootage: Int,
|
||||
val tunnelNature: String,
|
||||
val updateBy: String,
|
||||
val updateTime: String,
|
||||
val yesterdayFootage: String,
|
||||
val monthFootage: String
|
||||
): Serializable
|
||||
|
||||
data class LatestRecord(
|
||||
val createBy: String,
|
||||
val createTime: String,
|
||||
val mineWorkingLithologyList: MutableList<MineWorkingLithology>,
|
||||
val params: Params,
|
||||
val recordId: Int,
|
||||
val recordPerson: String,
|
||||
val remark: String,
|
||||
val seamDip: Int,
|
||||
val seamHeight: Int,
|
||||
val surfaceId: Int,
|
||||
val surfaceName: String,
|
||||
val teamId: Int,
|
||||
val teamLeader: String,
|
||||
val teamName: String,
|
||||
val teamShift: Int,
|
||||
val updateBy: String,
|
||||
val updateTime: String,
|
||||
val waterYield: Int,
|
||||
val workingDate: String,
|
||||
val workingFootage: Int
|
||||
):Serializable
|
||||
|
||||
|
||||
data class MineWorkingLithology(
|
||||
val createBy: String,
|
||||
val createTime: String,
|
||||
val lithologyId: Int,
|
||||
val lithologyType: String,
|
||||
val params: Params,
|
||||
val positionEnd: Int,
|
||||
val positionStart: Int,
|
||||
val recordId: Int,
|
||||
val remark: String,
|
||||
val updateBy: String,
|
||||
val updateTime: String
|
||||
):Serializable
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.zmkg.coaloperation.ui.tunneling.viewmodel
|
||||
|
||||
import com.zmkg.coaloperation.base.viewmodel.BaseViewModel
|
||||
import com.zmkg.coaloperation.data.repository.HomeRepository
|
||||
import com.zmkg.coaloperation.superfuntion.handleRequest
|
||||
import com.zmkg.coaloperation.superfuntion.launch
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.FaceWorkDetailBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingFaceAddBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeBean
|
||||
import com.zmkg.coaloperation.ui.tunneling.bean.TunnelingHomeItemBean
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
|
||||
/**
|
||||
* 掘进
|
||||
*/
|
||||
class TunnelingViewModel : BaseViewModel() {
|
||||
|
||||
|
||||
var tunnelingHomeList = MutableSharedFlow<MutableList<TunnelingHomeBean>?>()
|
||||
var tunnelingHomeItemList = MutableSharedFlow<MutableList<TunnelingHomeItemBean>?>()
|
||||
var tunnelingWorkFaceAdd = MutableSharedFlow<Boolean>()//新增面
|
||||
var faceWorkDetailData = MutableStateFlow<FaceWorkDetailBean?>(null)//面详情
|
||||
|
||||
var itemIndex = MutableStateFlow(0)//item的下标
|
||||
|
||||
override fun init() {
|
||||
}
|
||||
|
||||
|
||||
fun getTunnelingHomeData() {
|
||||
launch(
|
||||
{
|
||||
handleRequest(
|
||||
HomeRepository.getTunnelingHomeData(),
|
||||
successBlock = {
|
||||
tunnelingHomeList.emit(it.data)
|
||||
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun getTunnelingHomeItemData(index: Int,surfaceId: String?) {
|
||||
launch(
|
||||
{
|
||||
itemIndex.emit(index)
|
||||
handleRequest(
|
||||
HomeRepository.getTunnelingHomeItemData(surfaceId),
|
||||
successBlock = {
|
||||
tunnelingHomeItemList.emit(it.data)
|
||||
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun getTunnelingSurfaceDetail(surfaceId: String?) {
|
||||
launch(
|
||||
{
|
||||
handleRequest(
|
||||
HomeRepository.getTunnelingSurfaceDetail(surfaceId),
|
||||
successBlock = {
|
||||
// tunnelingHomeItemList.emit(it.data)
|
||||
faceWorkDetailData.emit(it.data)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun postTunnellingSurfaceAdd(tunnelingFaceAddBean: TunnelingFaceAddBean) {
|
||||
launch(
|
||||
{
|
||||
handleRequest(
|
||||
HomeRepository.postTunnellingSurfaceAdd(tunnelingFaceAddBean),
|
||||
successBlock = {
|
||||
tunnelingWorkFaceAdd.emit(true)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zmkg.coaloperation.ui.user.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.ActivityAboutUsBinding
|
||||
|
||||
/**
|
||||
* 关于我们
|
||||
*/
|
||||
class AboutUsActivity : BaseVMBActivity<TestViewModel,ActivityAboutUsBinding>(R.layout.activity_about_us) {
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.zmkg.coaloperation.ui.user.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.ActivityCacheManageBinding
|
||||
|
||||
/**
|
||||
* 缓存管理
|
||||
*/
|
||||
class CacheManageActivity : BaseVMBActivity<TestViewModel,ActivityCacheManageBinding>(R.layout.activity_cache_manage) {
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.zmkg.coaloperation.ui.user.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBActivity
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.ActivityNetworkConfigBinding
|
||||
|
||||
/**
|
||||
* 网络配置
|
||||
*/
|
||||
class NetworkConfigActivity : BaseVMBActivity<TestViewModel,ActivityNetworkConfigBinding>(R.layout.activity_network_config) {
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
}
|
||||
|
||||
override fun processClick(v: View?) {
|
||||
}
|
||||
|
||||
// override fun transparentStatusBar():Boolean {
|
||||
// return true
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.zmkg.coaloperation.ui.user.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.base.BaseVMBFragment
|
||||
import com.zmkg.coaloperation.base.viewmodel.TestViewModel
|
||||
import com.zmkg.coaloperation.databinding.FragmentUserBinding
|
||||
import com.zmkg.coaloperation.superfuntion.logout
|
||||
import com.zmkg.coaloperation.superfuntion.startLoginActivity
|
||||
import com.zmkg.coaloperation.ui.user.activity.AboutUsActivity
|
||||
import com.zmkg.coaloperation.ui.user.activity.CacheManageActivity
|
||||
import com.zmkg.coaloperation.ui.user.activity.NetworkConfigActivity
|
||||
import com.zmkg.coaloperation.view.CommonDialog
|
||||
|
||||
class UserFragment :
|
||||
BaseVMBFragment<TestViewModel, FragmentUserBinding>(R.layout.fragment_user) {
|
||||
|
||||
private val updateDialog: CommonDialog by lazy {
|
||||
CommonDialog(requireContext(), R.layout.dialog_common_view) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private val exitDialog: CommonDialog by lazy {
|
||||
CommonDialog(requireContext(), R.layout.dialog_common_view) {
|
||||
logout()
|
||||
startLoginActivity(requireContext())
|
||||
activity?.finish()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun initView(root: View?, savedInstanceState: Bundle?) {
|
||||
mBinding.apply {
|
||||
networkConfig.setOrderStateInfo("网络配置", R.mipmap.network)
|
||||
cacheManage.setOrderStateInfo("缓存管理", R.mipmap.buffer)
|
||||
checkUpdate.setOrderStateInfo("检查更新", R.mipmap.checkupdate)
|
||||
systemExit.setOrderStateInfo("系统退出", R.mipmap.systemexit)
|
||||
aboutUs.setOrderStateInfo("关于我们", R.mipmap.about_us)
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindEvent() {
|
||||
mBinding.apply {
|
||||
addClickViews(
|
||||
networkConfig,
|
||||
cacheManage,
|
||||
checkUpdate,
|
||||
systemExit,
|
||||
aboutUs
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
when (v?.id) {
|
||||
R.id.network_config -> {
|
||||
toActivity(NetworkConfigActivity::class.java)
|
||||
}
|
||||
|
||||
R.id.cache_manage -> {
|
||||
toActivity(CacheManageActivity::class.java)
|
||||
}
|
||||
|
||||
R.id.check_update -> {
|
||||
updateDialog.show("提示", "已经是最新版本了")
|
||||
}
|
||||
|
||||
R.id.system_exit -> {
|
||||
exitDialog.show("退出", "确定要退出当前用户?")
|
||||
}
|
||||
|
||||
R.id.about_us -> {
|
||||
toActivity(AboutUsActivity::class.java)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package com.zmkg.coaloperation.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
public class CustomActivityManager {
|
||||
public static Stack<Activity> activityStack;
|
||||
private static CustomActivityManager instance;
|
||||
|
||||
private CustomActivityManager() {
|
||||
}
|
||||
|
||||
public static CustomActivityManager getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (CustomActivityManager.class) {
|
||||
if (instance == null) {
|
||||
instance = new CustomActivityManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void addActivity(Activity activity) {
|
||||
if (activityStack == null) {
|
||||
activityStack = new Stack<>();
|
||||
}
|
||||
activityStack.add(activity);
|
||||
}
|
||||
|
||||
public Activity TopActivity() {
|
||||
Activity activity = null;
|
||||
if (!activityStack.isEmpty()) {
|
||||
activity = activityStack.lastElement();
|
||||
}
|
||||
return activity;
|
||||
}
|
||||
|
||||
public boolean isActivityExist(Class<?> cls) {
|
||||
for (Activity activity : activityStack) {
|
||||
if (activity.getClass().equals(cls)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void finishActivity() {
|
||||
Activity activity = activityStack.lastElement();
|
||||
finishActivity(activity);
|
||||
}
|
||||
|
||||
public Activity currentActivity() {
|
||||
return activityStack.lastElement();
|
||||
}
|
||||
|
||||
public void finishActivity(Activity activity) {
|
||||
if (activity != null) {
|
||||
activityStack.remove(activity);
|
||||
activity.finish();
|
||||
activity=null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 栈移除到目标页面
|
||||
* @param cls
|
||||
*/
|
||||
public void finishActivityTohome(Class<?> cls) {
|
||||
for (int i = activityStack.size()-1; i >=0; i--) {
|
||||
Activity activity=activityStack.get(i);
|
||||
if (activity.getClass().equals(cls)) {
|
||||
return;
|
||||
}else{
|
||||
finishActivity(activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeActivity(Activity activity) {
|
||||
if (activity != null) {
|
||||
activityStack.remove(activity);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeOneActivity(String s) {
|
||||
for (int i = 0; i < activityStack.size(); i++) {
|
||||
if (activityStack.get(i).toString().contains(s)) {
|
||||
activityStack.get(i).finish();
|
||||
activityStack.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void printActivity() {
|
||||
for (int i = 0; i < activityStack.size(); i++) {
|
||||
System.out.println("当前栈中页面:"+activityStack.get(i).toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void finishActivity(Class<?> cls) {
|
||||
for (Activity activity : activityStack) {
|
||||
if (activity.getClass().equals(cls)) {
|
||||
finishActivity(activity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void finishAllActivity() {
|
||||
if (activityStack == null) return;
|
||||
for (int i = 0, size = activityStack.size(); i < size; i++) {
|
||||
if (null != activityStack.get(i)) {
|
||||
activityStack.get(i).finish();
|
||||
}
|
||||
}
|
||||
activityStack.clear();
|
||||
}
|
||||
|
||||
public void finishAllActivity(Activity exceptAct) {
|
||||
while (!activityStack.isEmpty()) {
|
||||
Activity act = (Activity) activityStack.pop();
|
||||
if (act != exceptAct) {
|
||||
act.finish();
|
||||
}
|
||||
}
|
||||
activityStack.push(exceptAct);
|
||||
}
|
||||
|
||||
public void appExit(Context context) {
|
||||
try {
|
||||
finishAllActivity();
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.zmkg.coaloperation.utils
|
||||
|
||||
import android.view.View
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
fun View.clickWithDebounce(delay: Long = 300, action: () -> Unit) {
|
||||
var job: Job? = null
|
||||
setOnClickListener {
|
||||
job?.cancel()
|
||||
job = CoroutineScope(Dispatchers.Main).launch {
|
||||
delay(delay)
|
||||
action()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.zmkg.coaloperation.utils
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
|
||||
inline fun <reified T> String.toType(gson: Gson? = null, typeToken: TypeToken<T>): T {
|
||||
return (gson ?: Gson()).fromJson(this, typeToken.type)
|
||||
}
|
||||
|
||||
inline fun <reified T> String.toObject(gson: Gson? = null): T {
|
||||
return (gson ?: Gson()).fromJson(this, T::class.java)
|
||||
}
|
||||
|
||||
fun Any?.toJsonString(gson: Gson? = null): String {
|
||||
return (gson ?: Gson()).toJson(this) ?: ""
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.zmkg.coaloperation.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.view.View
|
||||
import com.bigkoo.pickerview.builder.OptionsPickerBuilder
|
||||
import com.bigkoo.pickerview.builder.TimePickerBuilder
|
||||
import com.bigkoo.pickerview.listener.OnOptionsSelectListener
|
||||
import com.bigkoo.pickerview.listener.OnTimeSelectListener
|
||||
import okio.Options
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
object PickerUtil {
|
||||
|
||||
// 时间选择器示例
|
||||
fun showTimePicker(context: Context, action: (String) -> Unit) {
|
||||
TimePickerBuilder(context) { date, _ ->
|
||||
val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||
action(sdf.format(date))
|
||||
}.apply {
|
||||
setType(booleanArrayOf(true, true, true, false, false, false)) // 年月日
|
||||
setLabel("年", "月", "日", "", "", "")
|
||||
setDividerColor(Color.GRAY)
|
||||
setContentTextSize(20)
|
||||
setDate(Calendar.getInstance())
|
||||
// 设置日期范围(2023-01-01至2025-12-31)
|
||||
val startDate = Calendar.getInstance().apply { set(2020, 0, 1) }
|
||||
val endDate = Calendar.getInstance().apply { set(2050, 11, 31) }
|
||||
setRangDate(startDate, endDate)
|
||||
}
|
||||
.build()
|
||||
.show()
|
||||
}
|
||||
|
||||
// 三级联动选择器示例
|
||||
fun showOptionsPicker(context: Context, options: List<String>, action: (String) -> Unit) {
|
||||
OptionsPickerBuilder(context) { opt1, _, _, _ ->
|
||||
action(options[opt1])
|
||||
}.apply {
|
||||
setTitleText("请选择地区")
|
||||
setContentTextSize(18)
|
||||
setOutSideCancelable(false)
|
||||
}.build<String>().apply {
|
||||
setPicker(options, null, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.zmkg.coaloperation.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.res.Resources
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.TypedValue
|
||||
|
||||
/**
|
||||
* 屏幕、尺寸相关工具类
|
||||
*
|
||||
*/
|
||||
object ScreenUtil {
|
||||
|
||||
/**
|
||||
* dp转px,也可以使用resources.getDimension(R.dimen.xxx).toInt()
|
||||
*
|
||||
* @param dpVal 要转换的dp值
|
||||
*
|
||||
* @return dp转换为px后的值
|
||||
*/
|
||||
fun dp2px(dpVal: Float): Int {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, Resources.getSystem().displayMetrics).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* sp转px
|
||||
*
|
||||
* @param spVal 要转换的sp值
|
||||
*
|
||||
* @return sp转换为px后的值
|
||||
*/
|
||||
fun sp2px(spVal: Float): Int {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, Resources.getSystem().displayMetrics).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* px转dp
|
||||
*
|
||||
* @param pxVal 要转换的px值
|
||||
*
|
||||
* @return px转换为dp后的值
|
||||
*/
|
||||
fun px2dp(pxVal: Float): Float {
|
||||
return pxVal / Resources.getSystem().displayMetrics.density
|
||||
}
|
||||
|
||||
/**
|
||||
* px转sp
|
||||
*
|
||||
* @param context Context
|
||||
* @param pxVal 要转换的px值
|
||||
*
|
||||
* @return px转换为sp后的值
|
||||
*/
|
||||
fun px2sp(pxVal: Float): Float {
|
||||
return pxVal / Resources.getSystem().displayMetrics.scaledDensity
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取屏幕的宽度(px)
|
||||
*
|
||||
* @param context Context
|
||||
*/
|
||||
fun getScreenWidth(): Int {
|
||||
return Resources.getSystem().displayMetrics.widthPixels
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取屏幕的高度(px)
|
||||
*
|
||||
* @param context Context
|
||||
*/
|
||||
fun getScreenHeight(): Int {
|
||||
return Resources.getSystem().displayMetrics.heightPixels
|
||||
}
|
||||
|
||||
fun getWithAndHeightRatio(): Double {
|
||||
return Resources.getSystem().displayMetrics.widthPixels.toDouble()/Resources.getSystem().displayMetrics.heightPixels.toDouble()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取屏幕的屏幕密度
|
||||
*
|
||||
* @param context Context
|
||||
*/
|
||||
fun getScreenDensity(): Float {
|
||||
return Resources.getSystem().displayMetrics.density
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过反射,获取包含虚拟键的整体屏幕高度
|
||||
*
|
||||
* @return 包含虚拟键的整体屏幕高度
|
||||
*/
|
||||
fun getScreenRealHeight(activity: Activity): Int {
|
||||
var dpi = 0
|
||||
val display = activity.windowManager.defaultDisplay
|
||||
val dm = DisplayMetrics()
|
||||
val c: Class<*>
|
||||
try {
|
||||
c = Class.forName("android.view.Display")
|
||||
val method = c.getMethod("getRealMetrics", DisplayMetrics::class.java)
|
||||
method.invoke(display, dm)
|
||||
dpi = dm.heightPixels
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return dpi
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.zmkg.coaloperation.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.ColorInt
|
||||
|
||||
object StatusbarUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 获取状态栏高度
|
||||
*/
|
||||
fun getStatusBarHeight(context: Context): Int {
|
||||
val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")
|
||||
if (resourceId > 0) {
|
||||
return context.resources.getDimensionPixelSize(resourceId)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态栏高度
|
||||
*/
|
||||
fun setStatusBarHeight(context: Activity,height:Int) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
context.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
}
|
||||
|
||||
var layoutParams = context.window.getDecorView().findViewById<LinearLayout>(android.R.id.content).layoutParams
|
||||
layoutParams.height =height
|
||||
context.window.getDecorView().findViewById<LinearLayout>(android.R.id.content).setLayoutParams(layoutParams)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置状态栏透明
|
||||
*
|
||||
*/
|
||||
fun setStatusBarTransparent(activity: Activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
activity.window.statusBarColor = Color.TRANSPARENT
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置状态栏背景颜色
|
||||
*/
|
||||
fun setStatusBarBgColor(activity: Activity, @ColorInt color: Int) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
activity.window.statusBarColor = color
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置状态栏白色 和 图标黑色
|
||||
*/
|
||||
fun lightMode(activity: Activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
|
||||
activity.window.statusBarColor = Color.WHITE //白底
|
||||
|
||||
activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR //黑字
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置状态栏颜色 和 图标颜色
|
||||
* backgroundColor 背景颜色
|
||||
* isIconBlack 图标+文本颜色 true 是黑色 false 白色
|
||||
*/
|
||||
fun customColorMode(activity: Activity, backgroundColor: String, isIconBlack: Boolean) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
|
||||
activity.window.statusBarColor = Color.parseColor(backgroundColor) //白底
|
||||
|
||||
if (isIconBlack) {
|
||||
activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR //黑色图标+文字
|
||||
} else {
|
||||
activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE //白色图标+文字
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置状态栏透明 是否全屏 图标颜色
|
||||
*
|
||||
* isIconBlack true 黑色黑标+文字 false白色
|
||||
*
|
||||
* isFullScreen 是否是全屏 true全屏,可以实现沉浸式状态栏
|
||||
*/
|
||||
fun transparentMode(activity: Activity, isIconBlack: Boolean, isFullScreen: Boolean = false) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
|
||||
activity.window.statusBarColor = Color.TRANSPARENT
|
||||
|
||||
if (isIconBlack) {
|
||||
if (isFullScreen) {
|
||||
activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN //黑色图标+文字 全屏
|
||||
} else {
|
||||
activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR //黑色图标+文字
|
||||
}
|
||||
} else {
|
||||
if (isFullScreen) {
|
||||
activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN //白色图标+文字 全屏
|
||||
} else {
|
||||
activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
//package com.zmkg.coaloperation.utils
|
||||
//
|
||||
//import android.content.Context
|
||||
//import android.widget.Toast
|
||||
//
|
||||
//object ToastTool {
|
||||
//
|
||||
// fun toastShort(context: Context, msg:String) {
|
||||
// Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.zmkg.coaloperation.utils.pictureSelector;
|
||||
|
||||
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.luck.picture.lib.engine.ImageEngine;
|
||||
import com.luck.picture.lib.utils.ActivityCompatHelper;
|
||||
import com.zmkg.coaloperation.R;
|
||||
|
||||
/**
|
||||
* @describe:PictureSelector库中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(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(R.drawable.ps_image_placeholder)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pauseRequests(Context context) {
|
||||
Glide.with(context).pauseRequests();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resumeRequests(Context context) {
|
||||
Glide.with(context).resumeRequests();
|
||||
}
|
||||
|
||||
private GlideEngine() {
|
||||
}
|
||||
|
||||
private static final class InstanceHolder {
|
||||
static final GlideEngine instance = new GlideEngine();
|
||||
}
|
||||
|
||||
public static GlideEngine createGlideEngine() {
|
||||
return InstanceHolder.instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.zmkg.coaloperation.utils.pictureSelector
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.luck.picture.lib.engine.CompressFileEngine
|
||||
import com.luck.picture.lib.interfaces.OnKeyValueResultCallbackListener
|
||||
import com.luck.picture.lib.utils.DateUtils
|
||||
import top.zibin.luban.Luban
|
||||
import top.zibin.luban.OnNewCompressListener
|
||||
import java.io.File
|
||||
|
||||
class ImageFileCompressEngine : CompressFileEngine {
|
||||
override fun onStartCompress(
|
||||
context: Context,
|
||||
source: java.util.ArrayList<Uri>,
|
||||
call: OnKeyValueResultCallbackListener
|
||||
) {
|
||||
Luban.with(context).load(source).ignoreBy(1000).setRenameListener { filePath ->
|
||||
val indexOf = filePath.lastIndexOf(".")
|
||||
val postfix = if (indexOf != -1) filePath.substring(indexOf) else ".jpg"
|
||||
DateUtils.getCreateFileName("CMP_") + postfix
|
||||
}.setCompressListener(object : OnNewCompressListener {
|
||||
override fun onStart() {}
|
||||
override fun onSuccess(source: String, compressFile: File) {
|
||||
if (call != null) {
|
||||
call.onCallback(source, compressFile.absolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(source: String, e: Throwable) {
|
||||
if (call != null) {
|
||||
call.onCallback(source, null)
|
||||
}
|
||||
}
|
||||
}).launch()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.zmkg.coaloperation.utils.pictureSelector
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.Nullable
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.target.CustomTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import com.luck.picture.lib.engine.CropFileEngine
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import com.yalantis.ucrop.UCropImageEngine
|
||||
|
||||
|
||||
class ImageFileCropEngine: CropFileEngine {
|
||||
override fun onStartCrop(
|
||||
fragment: Fragment?,
|
||||
srcUri: Uri?,
|
||||
destinationUri: Uri?,
|
||||
dataSource: ArrayList<String>?,
|
||||
requestCode: Int
|
||||
) {
|
||||
val options: UCrop.Options = UCrop.Options()
|
||||
options.setHideBottomControls(true)
|
||||
options.setFreeStyleCropEnabled(true)
|
||||
options.setShowCropFrame(true)
|
||||
options.setShowCropGrid(true)
|
||||
options.setCircleDimmedLayer(true)
|
||||
options.withAspectRatio(1f, 1f)
|
||||
val uCrop = UCrop.of(srcUri!!, destinationUri!!, dataSource)
|
||||
uCrop.withOptions(options)
|
||||
uCrop.setImageEngine(object : UCropImageEngine {
|
||||
override fun loadImage(context: Context, url: String?, imageView: ImageView) {
|
||||
|
||||
Glide.with(context).load(url).override(180, 180).into(imageView)
|
||||
}
|
||||
|
||||
override fun loadImage(
|
||||
context: Context,
|
||||
url: Uri?,
|
||||
maxWidth: Int,
|
||||
maxHeight: Int,
|
||||
call: UCropImageEngine.OnCallbackListener<Bitmap?>
|
||||
) {
|
||||
Glide.with(context).asBitmap().load(url).override(maxWidth, maxHeight)
|
||||
.into(object : CustomTarget<Bitmap>() {
|
||||
|
||||
override fun onResourceReady(
|
||||
resource: Bitmap,
|
||||
transition: Transition<in Bitmap?>?
|
||||
) {
|
||||
call?.onCall(resource)
|
||||
}
|
||||
|
||||
override fun onLoadCleared(@Nullable placeholder: Drawable?) {
|
||||
call?.onCall(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
uCrop.start(fragment!!.requireActivity(), fragment!!, requestCode)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.zmkg.coaloperation.view
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
|
||||
class CircleArcView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : View(context, attrs, defStyleAttr) {
|
||||
|
||||
// 可配置属性
|
||||
var arcColor: Int = Color.BLUE
|
||||
set(value) {
|
||||
field = value
|
||||
invalidate()
|
||||
}
|
||||
var strokeWidth: Float = 20f
|
||||
set(value) {
|
||||
field = value
|
||||
invalidate()
|
||||
}
|
||||
var radius: Float = 100f
|
||||
set(value) {
|
||||
field = value
|
||||
invalidate()
|
||||
}
|
||||
var startAngle: Float = 0f
|
||||
set(value) {
|
||||
field = value
|
||||
invalidate()
|
||||
}
|
||||
var sweepAngle: Float = 270f
|
||||
set(value) {
|
||||
field = value
|
||||
invalidate()
|
||||
}
|
||||
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
style = Paint.Style.STROKE
|
||||
strokeCap = Paint.Cap.ROUND
|
||||
}
|
||||
|
||||
private val rectF = RectF()
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
|
||||
// 计算绘制区域
|
||||
val centerX = width / 2f
|
||||
val centerY = height / 2f
|
||||
rectF.set(
|
||||
centerX - radius,
|
||||
centerY - radius,
|
||||
centerX + radius,
|
||||
centerY + radius
|
||||
)
|
||||
|
||||
// 配置画笔
|
||||
paint.color = arcColor
|
||||
paint.strokeWidth = strokeWidth
|
||||
|
||||
// 绘制圆弧
|
||||
canvas.drawArc(rectF, startAngle, sweepAngle, false, paint)
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val size = (radius * 2 + strokeWidth).toInt()
|
||||
setMeasuredDimension(size, size)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package com.zmkg.coaloperation.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.zmkg.coaloperation.R;
|
||||
|
||||
|
||||
/**
|
||||
* 双半圆环
|
||||
*/
|
||||
|
||||
public class CircleDoubleArcView extends View {
|
||||
|
||||
//外环圆弧宽度
|
||||
private float outStrokeWidth = 25f;
|
||||
//外环圆弧当前进度颜色
|
||||
private int outStrokeProgressColor = Color.parseColor("#FF7500");
|
||||
|
||||
//内环圆弧宽度
|
||||
private float inStrokeWidth = 25f;
|
||||
//内环圆弧当前进度颜色
|
||||
private int inStrokeProgressColor = Color.parseColor("#04DAB3");
|
||||
|
||||
//drawText1 color
|
||||
private int drawText1Color = Color.parseColor("#333333");
|
||||
|
||||
//drawText2 color
|
||||
private int drawText2Color = Color.parseColor("#333333");
|
||||
|
||||
//默认的圆弧颜色
|
||||
private int defaultStrokeColor = Color.parseColor("#222840");
|
||||
//默认开始角度
|
||||
private int startAngle = 135;
|
||||
//默认扫过的弧度
|
||||
private int defaultSweepAngle = 270;
|
||||
//当前外环长度
|
||||
private int currentOutLength = 0;//外环
|
||||
//当前内环长度
|
||||
private int currentInLength = 0;//内环
|
||||
|
||||
//两个圆环之间的间距 文字间距
|
||||
private float stokeOffset = 60;
|
||||
//文字大小
|
||||
private int inTextSize = 30;
|
||||
private float inTextHeight = 0;
|
||||
//当前步数文字大小
|
||||
private float centerText1Size = 50F;
|
||||
|
||||
private float centerText2Size = 50F;
|
||||
private float inNumHeight = 0;
|
||||
private String drawText1 = "";
|
||||
private String drawText2 = "";
|
||||
private float drawTextSetOff1 = 0;
|
||||
private float drawTextSetOff2 = 0;
|
||||
|
||||
private boolean isInProgressGone = false;//内环是否隐藏
|
||||
|
||||
|
||||
public CircleDoubleArcView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public CircleDoubleArcView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initAttrs(attrs, context);//初始化属性
|
||||
}
|
||||
|
||||
public CircleDoubleArcView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
}
|
||||
|
||||
private void initAttrs(AttributeSet attrs, Context context) {
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleArcView);
|
||||
outStrokeWidth = typedArray.getDimension(R.styleable.CircleArcView_outStrokeWidth, 25f);
|
||||
outStrokeProgressColor = typedArray.getColor(R.styleable.CircleArcView_outProgressColor, Color.parseColor("#FF7500"));
|
||||
inStrokeProgressColor = typedArray.getColor(R.styleable.CircleArcView_inProgressColor, Color.parseColor("#04DAB3"));
|
||||
drawText1Color = typedArray.getColor(R.styleable.CircleArcView_centerTextSetOff1Color, Color.parseColor("#333333"));
|
||||
drawText2Color = typedArray.getColor(R.styleable.CircleArcView_centerTextSetOff2Color, Color.parseColor("#333333"));
|
||||
inStrokeWidth = outStrokeWidth;
|
||||
stokeOffset = typedArray.getDimension(R.styleable.CircleArcView_stokeOffset, 60);
|
||||
drawTextSetOff1 = typedArray.getDimension(R.styleable.CircleArcView_drawTextSetOff1, 0);
|
||||
drawTextSetOff2 = typedArray.getDimension(R.styleable.CircleArcView_drawTextSetOff2, 0);
|
||||
centerText1Size = typedArray.getDimension(R.styleable.CircleArcView_centerText1Size, 14F);
|
||||
centerText2Size = typedArray.getDimension(R.styleable.CircleArcView_centerText2Size, 14F);
|
||||
isInProgressGone = typedArray.getBoolean(R.styleable.CircleArcView_inProgressGone, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置圆弧宽度
|
||||
*
|
||||
* @param circularWith
|
||||
*/
|
||||
public void setCircularWith(int circularWith) {
|
||||
outStrokeWidth = circularWith;
|
||||
inStrokeWidth = circularWith;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置圆弧的间距
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setStokeOffset(int value) {
|
||||
stokeOffset = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内环进度
|
||||
*
|
||||
* @param value 外环
|
||||
* @param value2 内环
|
||||
*/
|
||||
public void setProgress(int value, int value2) {
|
||||
if (value > 270) {
|
||||
currentOutLength = 270;
|
||||
} else {
|
||||
currentOutLength = value;
|
||||
}
|
||||
|
||||
if (value2 > 270) {
|
||||
currentInLength = 270;
|
||||
} else {
|
||||
currentInLength = value2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内环进度
|
||||
*
|
||||
* @param text1 文本
|
||||
* @param text2 文本
|
||||
*/
|
||||
public void setDrawText(String text1, String text2) {
|
||||
drawText1 = text1;
|
||||
drawText2 = text2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内环进度
|
||||
*
|
||||
* @param text1 文本
|
||||
*/
|
||||
public void setDrawText1(String text1) {
|
||||
drawText1 = text1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内环进度
|
||||
*
|
||||
* @param text2 文本
|
||||
*/
|
||||
public void setDrawText2(String text2) {
|
||||
drawText2 = text2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内环进度
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setDefaultLength(int value) {
|
||||
defaultSweepAngle = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字体大小
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setTextSize(int value) {
|
||||
centerText1Size = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
//中心点坐标
|
||||
float centerX = getWidth() / 2;
|
||||
//外环外矩形区域
|
||||
RectF outRectF = new RectF();
|
||||
float outL = outStrokeWidth / 2;
|
||||
float outT = outStrokeWidth / 2;
|
||||
float outR = centerX * 2 - outStrokeWidth / 2;
|
||||
float outB = outR;
|
||||
outRectF.set(outL, outT, outR, outB);
|
||||
//内环外矩形区域
|
||||
RectF inRectF = new RectF();
|
||||
float inL = outStrokeWidth / 2 + stokeOffset;
|
||||
float inT = outStrokeWidth / 2 + stokeOffset;
|
||||
float inR = centerX * 2 - outStrokeWidth / 2 - stokeOffset;
|
||||
float inB = inR;
|
||||
inRectF.set(inL, inT, inR, inB);
|
||||
//绘制外环圆弧
|
||||
drawOutStroke(canvas, centerX, outRectF);
|
||||
//绘制内环圆弧
|
||||
if (!isInProgressGone) {
|
||||
drawInStroke(canvas, centerX, inRectF);
|
||||
}
|
||||
//绘制文字
|
||||
// drawText(canvas, centerX);
|
||||
//绘制当前步数
|
||||
drawInNum(canvas, centerX);
|
||||
//绘制强度文字
|
||||
// drawStrongerText(canvas, centerX);
|
||||
}
|
||||
|
||||
|
||||
private void drawInNum(Canvas canvas, float centerX) {
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(drawText1Color);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
paint.setTextSize(centerText1Size);
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
Rect textF = new Rect();
|
||||
inNumHeight = textF.height();
|
||||
float textY = textF.height() / 2 + outStrokeWidth / 2 + inStrokeWidth + 2 * stokeOffset + inTextHeight + stokeOffset / 2;
|
||||
canvas.drawText(drawText1, centerX, textY + drawTextSetOff1, paint);
|
||||
paint.setColor(drawText2Color);
|
||||
paint.setTextSize(centerText2Size);
|
||||
canvas.drawText(drawText2, centerX, textY + drawTextSetOff2, paint);
|
||||
}
|
||||
|
||||
private void drawText(Canvas canvas, float centerX) {
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(Color.BLACK);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setTextSize(inTextSize);
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
Rect textF = new Rect();
|
||||
//文字高度
|
||||
inTextHeight = textF.height();
|
||||
float textY = textF.height() / 2 + outStrokeWidth / 2 + inStrokeWidth + 2 * stokeOffset;
|
||||
}
|
||||
|
||||
//外环所有的绘制
|
||||
private void drawOutStroke(Canvas canvas, float x, RectF f) {
|
||||
//绘制外环默认的圆弧
|
||||
drawDefaultOutStroke(canvas, f, outStrokeWidth);
|
||||
//绘制当前进度
|
||||
if (currentOutLength != 2147483647) {
|
||||
drawProgressOutStroke(canvas, f);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawProgressOutStroke(Canvas canvas, RectF f) {
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(outStrokeProgressColor);
|
||||
paint.setStrokeJoin(Paint.Join.ROUND);
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(outStrokeWidth);
|
||||
canvas.drawArc(f, startAngle, currentOutLength, false, paint);
|
||||
}
|
||||
|
||||
|
||||
//内环所有绘制
|
||||
private void drawInStroke(Canvas canvas, float x, RectF f) {
|
||||
//绘制内环默认的圆弧
|
||||
drawDefaultOutStroke(canvas, f, inStrokeWidth);
|
||||
//绘制当前进度
|
||||
if (currentInLength != 2147483647) {
|
||||
drawProgressInStroke(canvas, f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void drawProgressInStroke(Canvas canvas, RectF f) {
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(inStrokeProgressColor);
|
||||
paint.setStrokeJoin(Paint.Join.ROUND);
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(inStrokeWidth);
|
||||
if (!isInProgressGone) {
|
||||
canvas.drawArc(f, startAngle, currentInLength, false, paint);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawDefaultOutStroke(Canvas canvas, RectF f, float strokeWidth) {
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(defaultStrokeColor);
|
||||
paint.setStrokeJoin(Paint.Join.ROUND);
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
canvas.drawArc(f, startAngle, defaultSweepAngle, false, paint);
|
||||
}
|
||||
|
||||
public void isInProgressGone(boolean gone) {
|
||||
isInProgressGone = gone;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.zmkg.coaloperation.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.zmkg.coaloperation.R;
|
||||
|
||||
|
||||
/**
|
||||
* 圆
|
||||
*/
|
||||
|
||||
public class CircleView extends View {
|
||||
private Paint paint;
|
||||
private int contextColor=Color.parseColor("#FFFFFF");
|
||||
|
||||
|
||||
public CircleView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public CircleView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleView);
|
||||
contextColor = typedArray.getColor(R.styleable.CircleView_contextColor, Color.parseColor("#FFFFFF"));
|
||||
}
|
||||
|
||||
public void setContextColor(int contextColor) {
|
||||
this.contextColor = contextColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
paint = new Paint();
|
||||
|
||||
paint.setColor(contextColor); // 设置圆的颜色
|
||||
paint.setAntiAlias(true); // 设置抗锯齿
|
||||
paint.setStyle(Paint.Style.FILL); // 设置填充模式
|
||||
|
||||
int centerX = getWidth() / 2; // 获取中心点X坐标
|
||||
int centerY = getHeight() / 2; // 获取中心点Y坐标
|
||||
int radius = Math.min(getWidth(), getHeight()) / 2; // 获取半径,确保圆完全显示在View内
|
||||
canvas.drawCircle(centerX, centerY, radius, paint); // 绘制圆形
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.zmkg.coaloperation.view
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import android.widget.TextView
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import com.zmkg.coaloperation.R
|
||||
|
||||
/**
|
||||
* 常用弹框框架
|
||||
* 需要自己写UI布局,确认按钮有回调,其他按钮没有
|
||||
*/
|
||||
class CommonDialog(context: Context, val layoutId: Int, var listener: (() -> Unit)? = null) :
|
||||
Dialog(context) {
|
||||
lateinit var mBinding: ViewDataBinding
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
super.onCreate(savedInstanceState)
|
||||
mBinding = DataBindingUtil.inflate(
|
||||
LayoutInflater.from(context), layoutId, null, false
|
||||
)
|
||||
setContentView(mBinding.root)
|
||||
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))//设置dialog背景透明
|
||||
window?.setGravity(Gravity.CENTER)
|
||||
window?.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM)
|
||||
setCanceledOnTouchOutside(true)
|
||||
setCancelable(true)
|
||||
|
||||
mBinding.root.findViewById<View>(R.id.confirm)?.setOnClickListener {
|
||||
dismiss()
|
||||
listener?.invoke()
|
||||
|
||||
}
|
||||
mBinding.root.findViewById<View>(R.id.cancel)?.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
fun show(title: String? = null, message: String? = null) {
|
||||
super.show()
|
||||
val messageText = mBinding.root.findViewById<TextView>(R.id.message)
|
||||
val titleText = mBinding.root.findViewById<TextView>(R.id.title)
|
||||
if (!TextUtils.isEmpty(title)) {
|
||||
titleText?.text = title
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(message)) {
|
||||
messageText?.text = message
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.zmkg.coaloperation.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.databinding.CustomMyInfoViewBinding
|
||||
|
||||
/**
|
||||
* 文本和跳转
|
||||
*/
|
||||
class CustomInfoView(context: Context?, attrs: AttributeSet?) : RelativeLayout(context, attrs, 0) {
|
||||
|
||||
var mContext:Context?= context
|
||||
|
||||
private var mBinding: CustomMyInfoViewBinding = DataBindingUtil.inflate(
|
||||
LayoutInflater.from(context),
|
||||
R.layout.custom_my_info_view, this,true)
|
||||
|
||||
|
||||
fun setOrderStateInfo(name:String, id:Int){
|
||||
mBinding.apply {
|
||||
if (id==0) {
|
||||
customInfoMenuIcon.visibility=View.GONE
|
||||
}else{
|
||||
customInfoMenuIcon.visibility=View.VISIBLE
|
||||
}
|
||||
customInfoMenuIcon.setImageResource(id)
|
||||
customInfoMenuName.setText(name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.zmkg.coaloperation.view
|
||||
|
||||
import android.content.Context
|
||||
import android.text.method.HideReturnsTransformationMethod
|
||||
import android.text.method.PasswordTransformationMethod
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.databinding.CustomPasswordViewBinding
|
||||
|
||||
class CustomPasswordView(context: Context?, attrs: AttributeSet?) :
|
||||
RelativeLayout(context, attrs, 0) {
|
||||
|
||||
var mContext: Context? = context
|
||||
private var mBinding: CustomPasswordViewBinding = DataBindingUtil.inflate(
|
||||
LayoutInflater.from(context),
|
||||
R.layout.custom_password_view, this, true
|
||||
)
|
||||
|
||||
init {
|
||||
mBinding.loginEtUserPassword.setTransformationMethod(PasswordTransformationMethod.getInstance())
|
||||
mBinding.loginIvEye.setOnClickListener {
|
||||
mBinding?.let {
|
||||
var selection = it.loginEtUserPassword.selectionEnd
|
||||
if (it.loginEtUserPassword.transformationMethod == PasswordTransformationMethod.getInstance()) {
|
||||
it.loginEtUserPassword.setTransformationMethod(
|
||||
HideReturnsTransformationMethod.getInstance()
|
||||
)
|
||||
it.loginIvEye.setImageResource(R.mipmap.eye_hide)
|
||||
} else {
|
||||
it.loginEtUserPassword.setTransformationMethod(PasswordTransformationMethod.getInstance())
|
||||
it.loginIvEye.setImageResource(R.mipmap.eye_show)
|
||||
}
|
||||
it.loginEtUserPassword.setSelection(selection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getInputContext(): String {
|
||||
return mBinding.loginEtUserPassword.text.toString().trim()
|
||||
}
|
||||
|
||||
fun setInputContext(password: String) {
|
||||
mBinding.loginEtUserPassword.setText(password)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.zmkg.coaloperation.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.databinding.CustomTextEditViewBinding
|
||||
|
||||
/**
|
||||
* 文本和输入框
|
||||
*/
|
||||
class CustomTextEditView(context: Context?, attrs: AttributeSet?) :
|
||||
RelativeLayout(context, attrs, 0) {
|
||||
|
||||
|
||||
private var mBinding: CustomTextEditViewBinding = DataBindingUtil.inflate(
|
||||
LayoutInflater.from(context),
|
||||
R.layout.custom_text_edit_view, this, true
|
||||
)
|
||||
|
||||
fun setTextContext(text: String): CustomTextEditViewBinding {
|
||||
mBinding.etInput.setText(text)
|
||||
return mBinding
|
||||
}
|
||||
|
||||
fun setTitle(title: String): CustomTextEditViewBinding {
|
||||
mBinding.title.setText(title)
|
||||
return mBinding
|
||||
}
|
||||
|
||||
fun getTextContext() {
|
||||
mBinding.etInput.text.toString()
|
||||
|
||||
}
|
||||
|
||||
init {
|
||||
val typedArray = context!!.obtainStyledAttributes(attrs, R.styleable.CustomTextView)
|
||||
var title = typedArray.getString(R.styleable.CustomTextView_title)
|
||||
mBinding.title.setText(title)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.zmkg.coaloperation.view
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.github.gzuliyujiang.wheelpicker.OptionPicker
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.databinding.CustomTextSelectViewBinding
|
||||
|
||||
/**
|
||||
* 文本和下拉选择
|
||||
*/
|
||||
class CustomTextSelectView(context: Context?, attrs: AttributeSet?) :
|
||||
RelativeLayout(context, attrs, 0) {
|
||||
var optionPicker: OptionPicker? = null
|
||||
var isSelectText = false
|
||||
|
||||
private var mBinding: CustomTextSelectViewBinding = DataBindingUtil.inflate(
|
||||
LayoutInflater.from(context),
|
||||
R.layout.custom_text_select_view, this, true
|
||||
)
|
||||
|
||||
fun setDataList(activity: Activity, list: MutableList<String>) {
|
||||
optionPicker = OptionPicker(activity)
|
||||
optionPicker!!.setBackgroundResource(R.drawable.rectangle_top_round_corner20_white)
|
||||
optionPicker!!.setTitle("")
|
||||
optionPicker!!.setDefaultPosition(0)
|
||||
optionPicker!!.wheelView.setFormatter { value ->
|
||||
value.toString()
|
||||
}
|
||||
optionPicker!!.setOnOptionPickedListener { position, item ->
|
||||
mBinding.selectText.setTextColor(Color.WHITE)
|
||||
mBinding.selectText.setText(item.toString())
|
||||
isSelectText = true
|
||||
}
|
||||
|
||||
optionPicker!!.setData(list)
|
||||
|
||||
}
|
||||
|
||||
fun getSelectText(): String? {
|
||||
return if (isSelectText) {
|
||||
mBinding.selectText.text.toString()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val typedArray = context!!.obtainStyledAttributes(attrs, R.styleable.CustomTextView)
|
||||
var title = typedArray.getString(R.styleable.CustomTextView_title)
|
||||
mBinding.title.setText(title)
|
||||
|
||||
mBinding.selectText.setOnClickListener {
|
||||
optionPicker?.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.zmkg.coaloperation.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.zmkg.coaloperation.R;
|
||||
|
||||
|
||||
/**
|
||||
* 自定义弹出对话框
|
||||
*/
|
||||
public class CustomToast extends Toast {
|
||||
|
||||
private TextView textView;
|
||||
private static String mText = "";
|
||||
private View view;
|
||||
private int time;
|
||||
private Context context;
|
||||
private Drawable drawable;
|
||||
private static CustomToast result;
|
||||
|
||||
public CustomToast(Context context, String text, int time) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
this.mText = text;
|
||||
this.time = time;
|
||||
init();
|
||||
}
|
||||
|
||||
public CustomToast(Context context, String text, int time, Drawable drawable) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
this.mText = text;
|
||||
this.time = time;
|
||||
this.drawable=drawable;
|
||||
init();
|
||||
}
|
||||
public CustomToast(Context context, String text, int time, int gravity ) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
this.mText = text;
|
||||
this.time = time;
|
||||
init2(gravity);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
try {
|
||||
view = View.inflate(context, R.layout.custom_toast, null);
|
||||
setView(view);
|
||||
textView = (TextView) view.findViewById(R.id.textView);
|
||||
textView.setText(mText);
|
||||
if (drawable!=null) {
|
||||
textView.setCompoundDrawables(null,drawable,null,null);
|
||||
}
|
||||
setGravity(Gravity.CENTER, 0, -100);
|
||||
setDuration(time);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
private void init2(int gravity) {
|
||||
try {
|
||||
view = View.inflate(context, R.layout.custom_toast, null);
|
||||
setView(view);
|
||||
textView = (TextView) view.findViewById(R.id.textView);
|
||||
textView.setText(mText);
|
||||
textView.setGravity(gravity);
|
||||
if (drawable!=null) {
|
||||
textView.setCompoundDrawables(null,drawable,null,null);
|
||||
}
|
||||
setGravity(Gravity.CENTER, 0, -100);
|
||||
setDuration(time);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static CustomToast makeText(Context context, CharSequence text, int duration,int gravity) {
|
||||
if (result == null || !mText.equals(text) ) {
|
||||
result = new CustomToast(context, text.toString(), duration,gravity);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public static CustomToast makeText(Context context, CharSequence text, int duration) {
|
||||
if (result == null || !mText.equals(text) ) {
|
||||
result = new CustomToast(context, text.toString(), duration);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static CustomToast makeText(Context context, CharSequence text, int duration, Drawable drawable) {
|
||||
if (result == null || !mText.equals(text) ) {
|
||||
result = new CustomToast(context, text.toString(), duration,drawable);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void reset(){
|
||||
result=null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.zmkg.coaloperation.view;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.zmkg.coaloperation.R;
|
||||
|
||||
|
||||
/**
|
||||
* 加载中Dialog
|
||||
*/
|
||||
public class LoadingDialog extends Dialog {
|
||||
|
||||
|
||||
private TextView tips_loading_msg;
|
||||
private int layoutResId;
|
||||
private String message = null;
|
||||
private Activity mActivity;
|
||||
View view = null;
|
||||
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
String contentmsg;
|
||||
private boolean isDissmiss = false;
|
||||
private Handler mHandler=new Handler(){
|
||||
@Override
|
||||
public void handleMessage(@NonNull Message msg) {
|
||||
isDissmiss = false;
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
};
|
||||
private ImageView mIvProgress;
|
||||
private ProgressDrawable mProgressDrawable;
|
||||
|
||||
public LoadingDialog(Context context, int themeResId, String content) {
|
||||
super(context, R.style.MyLoadingDialog);
|
||||
mActivity = (Activity) context;
|
||||
this.contentmsg = content;
|
||||
view = LayoutInflater.from(context).inflate(
|
||||
R.layout.view_tips_loading, null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
this.setContentView(R.layout.view_tips_loading);
|
||||
mIvProgress = (ImageView) findViewById(R.id.iv_progress);
|
||||
mProgressDrawable = new ProgressDrawable();
|
||||
mProgressDrawable.setColor(0xffffffff);
|
||||
mIvProgress.setImageDrawable(mProgressDrawable);
|
||||
tips_loading_msg = (TextView) findViewById(R.id.tips_loading_msg);
|
||||
if (contentmsg.length() == 0) {
|
||||
tips_loading_msg.setVisibility(View.GONE);
|
||||
} else {
|
||||
tips_loading_msg.setVisibility(View.VISIBLE);
|
||||
}
|
||||
tips_loading_msg.setText(this.contentmsg);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// @Override
|
||||
// public void onBackPressed() {
|
||||
// if (ConstantUtils.INSTANCE.getMIsCloseDialog()) {
|
||||
// customDismiss();
|
||||
// }
|
||||
// super.onBackPressed();
|
||||
// }
|
||||
//
|
||||
// private void customDismiss() {
|
||||
// if (!isDissmiss) {
|
||||
// isDissmiss = true;
|
||||
// CustomToast.makeText(mActivity, "再按一次退出页面", Toast.LENGTH_SHORT).show();
|
||||
// // 利用handler延迟发送更改状态信息
|
||||
// mHandler.sendEmptyMessageDelayed(0, 2000);
|
||||
// } else {
|
||||
// dismiss();
|
||||
// mActivity.finish();
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
super.dismiss();
|
||||
if (mActivity.isFinishing())
|
||||
return;
|
||||
if (mProgressDrawable != null) {
|
||||
mProgressDrawable.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if (mActivity == null || mActivity.isFinishing() || mActivity.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
if (!this.isShowing()) {
|
||||
super.show();
|
||||
}
|
||||
if (tips_loading_msg != null) {
|
||||
tips_loading_msg.setText(contentmsg);
|
||||
}
|
||||
if (mProgressDrawable != null) {
|
||||
mProgressDrawable.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnDismissListener(OnDismissListener listener) {
|
||||
super.setOnDismissListener(listener);
|
||||
}
|
||||
|
||||
public void setMessage(String _message) {
|
||||
contentmsg = _message;
|
||||
}
|
||||
|
||||
public void setMessageProgress(String _message) {
|
||||
contentmsg = _message;
|
||||
if (tips_loading_msg != null) {
|
||||
if (_message.length() == 0) {
|
||||
tips_loading_msg.setVisibility(View.GONE);
|
||||
} else {
|
||||
tips_loading_msg.setVisibility(View.VISIBLE);
|
||||
tips_loading_msg.setText(_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mProgressDrawable = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.zmkg.coaloperation.view
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import com.zmkg.coaloperation.R
|
||||
import com.zmkg.coaloperation.databinding.DialogPagerViewBinding
|
||||
import com.zmkg.coaloperation.ui.home.adapter.PagerDateAdapter
|
||||
|
||||
class PagerViewClickDialog(context: Context) :
|
||||
Dialog(context) {
|
||||
lateinit var mBinding: DialogPagerViewBinding
|
||||
|
||||
private val pagerDateAdapter: PagerDateAdapter by lazy { PagerDateAdapter() }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
super.onCreate(savedInstanceState)
|
||||
mBinding = DataBindingUtil.inflate(
|
||||
LayoutInflater.from(context), R.layout.dialog_pager_view, null, false
|
||||
)
|
||||
setContentView(mBinding.root)
|
||||
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))//设置dialog背景透明
|
||||
window?.setGravity(Gravity.CENTER)
|
||||
window?.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM)
|
||||
setCanceledOnTouchOutside(true)
|
||||
setCancelable(true)
|
||||
|
||||
val mutableListOf = mutableListOf<String>()
|
||||
|
||||
|
||||
(1..30).forEach {
|
||||
mutableListOf.add("2025-06-"+it)
|
||||
}
|
||||
pagerDateAdapter.addHeaderView(getHeaderView())
|
||||
mBinding.rvList.adapter=pagerDateAdapter
|
||||
pagerDateAdapter.setNewInstance(mutableListOf)
|
||||
|
||||
}
|
||||
|
||||
private fun getHeaderView(): View {
|
||||
|
||||
// val inflate = ItemDialogPagerHeadBinding.inflate(LayoutInflater.from(context))
|
||||
var headerBinding =
|
||||
DataBindingUtil.inflate<ViewDataBinding>(
|
||||
LayoutInflater.from(context),
|
||||
R.layout.item_dialog_pager_head,
|
||||
mBinding.rvList,
|
||||
false
|
||||
)
|
||||
|
||||
return headerBinding.root
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.zmkg.coaloperation.view;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
|
||||
/**
|
||||
* 旋转动画
|
||||
*/
|
||||
|
||||
public class ProgressDrawable extends Drawable implements Animatable {
|
||||
|
||||
private int mProgressDegree = 0;
|
||||
private ValueAnimator mValueAnimator;
|
||||
private Path mPath = new Path();
|
||||
private Paint mPaint = new Paint();
|
||||
|
||||
public ProgressDrawable() {
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setColor(0xffaaaaaa);
|
||||
setupAnimators();
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
mPaint.setColor(color);
|
||||
}
|
||||
|
||||
//<editor-fold desc="Drawable">
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
Rect bounds = getBounds();
|
||||
int width = bounds.width();
|
||||
int height = bounds.height();
|
||||
canvas.save();
|
||||
canvas.rotate(mProgressDegree, (width) / 2, (height) / 2);
|
||||
final int r = Math.max(1, width / 20);
|
||||
for (int i = 0; i < 12; i++) {
|
||||
mPath.reset();
|
||||
mPath.addCircle(width - r, height / 2, r, Path.Direction.CW);
|
||||
mPath.addRect(width - 5 * r, height / 2 - r, width - r, height / 2 + r, Path.Direction.CW);
|
||||
mPath.addCircle(width - 5 * r, height / 2, r, Path.Direction.CW);
|
||||
mPaint.setAlpha((i+5) * 0x11);
|
||||
canvas.rotate(30, (width) / 2, (height) / 2);
|
||||
canvas.drawPath(mPath, mPaint);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
mPaint.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
mPaint.setColorFilter(cf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
private void setupAnimators() {
|
||||
mValueAnimator = ValueAnimator.ofInt(30, 3600);
|
||||
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
int value = (int) animation.getAnimatedValue();
|
||||
mProgressDegree = 30 * (value / 30);
|
||||
invalidateSelf();
|
||||
}
|
||||
});
|
||||
mValueAnimator.setDuration(10000);
|
||||
mValueAnimator.setInterpolator(new LinearInterpolator());
|
||||
mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
|
||||
mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (!mValueAnimator.isRunning()) {
|
||||
mValueAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (mValueAnimator.isRunning()) {
|
||||
mValueAnimator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return mValueAnimator.isRunning();
|
||||
}
|
||||
|
||||
public int width() {
|
||||
return getBounds().width();
|
||||
}
|
||||
|
||||
public int height() {
|
||||
return getBounds().height();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/white" android:state_selected="true" />
|
||||
<item android:color="#77849E" android:state_selected="false"/>
|
||||
<item android:color="#77849E"/>
|
||||
</selector>
|
||||
|
After Width: | Height: | Size: 114 B |
|
After Width: | Height: | Size: 807 B |
|
After Width: | Height: | Size: 1018 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 869 B |