初始代码

This commit is contained in:
2025-09-03 18:52:07 +08:00
parent 2d21a47e87
commit 6e3e30efa5
3249 changed files with 239147 additions and 0 deletions
@@ -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("没有这么多tabindex值:$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("没有这么多tabindex值:$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 JSONHTTPS
// 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 SDKs 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 dont 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 SDKs 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;
/**
* @describePictureSelector库中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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

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