package com.runt.open.mvi.base
|
|
import android.app.ActivityManager
|
import android.content.Context
|
import android.content.Intent
|
import android.content.pm.PackageManager
|
import android.os.Build
|
import android.os.Bundle
|
import android.os.Environment
|
import android.util.Log
|
import android.view.MotionEvent
|
import android.view.View
|
import android.view.WindowManager
|
import android.view.inputmethod.InputMethodManager
|
import android.widget.EditText
|
import android.widget.Toast
|
import androidx.activity.ComponentActivity
|
import androidx.activity.compose.setContent
|
import androidx.activity.result.ActivityResult
|
import androidx.activity.result.ActivityResultCallback
|
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.annotation.ColorRes
|
import androidx.annotation.StringRes
|
import androidx.collection.ArraySet
|
import androidx.core.content.ContextCompat
|
import androidx.lifecycle.Observer
|
import androidx.lifecycle.ViewModelProvider
|
import com.runt.open.mvi.R
|
import com.runt.open.mvi.base.model.BaseViewModel
|
import com.runt.open.mvi.base.model.ViewModelFactory
|
import com.runt.open.mvi.utils.PreferencesUtils
|
import java.io.File
|
import java.lang.reflect.ParameterizedType
|
|
/**
|
* @author Runt(qingingrunt2010@qq.com)
|
* @purpose
|
* @date 6/1/24
|
*/
|
abstract class BaseActivity<L: LayoutView<VM> ,VM : BaseViewModel>: ComponentActivity() {
|
|
|
protected var TAG : String? = null
|
|
var mContext:Context? = null
|
|
//viewbind
|
protected var mLayout : L? = null
|
|
//viewmodel
|
protected var mViewModel : VM? = null
|
|
val PARAMS_TITLE = "title"
|
|
|
override fun onCreate(savedInstanceState : Bundle?) {
|
super.onCreate(savedInstanceState) // get genericity "B"
|
setStatusBarBgColor(R.color.white) //白色状态栏
|
setStatusBarTextColor(true) //状态栏文本黑色
|
val type = this.javaClass.genericSuperclass as ParameterizedType
|
try { //实例化泛型类
|
val vmClass : Class<VM> = type.actualTypeArguments[1] as Class<VM>
|
mViewModel = ViewModelProvider(this , getViewModelFactory()).get(vmClass)
|
val entityClass : Class<L> = type.actualTypeArguments[0] as Class<L>
|
//val method = entityClass.getMethod("inflate" , LayoutInflater::class.java) //get method from name "inflate";
|
//mLayout = method.invoke(entityClass , layoutInflater) as L //execute method to create a objct of viewbind;
|
var constructor = entityClass.getDeclaredConstructor(vmClass);
|
mLayout = constructor.newInstance(mViewModel)
|
//titleBarView = mBinding.getClass().getDeclaredField("titleBar").get(mBinding) as TitleBarView
|
//titleBarView.setLeftClick { v -> onBackPressed() }
|
} catch (e : Exception) {
|
e.printStackTrace()
|
finish()
|
return
|
}
|
init();
|
//setContentView(mLayout)
|
setContent {
|
mLayout!!.layout()
|
}
|
mContext = this
|
TAG = this.javaClass.simpleName
|
initViews() //初始化UI
|
mViewModel!!.onCreate(this as BaseActivity<LayoutView<BaseViewModel> , BaseViewModel>)
|
loadData() //加载数据
|
}
|
abstract fun init()
|
|
abstract fun initViews()
|
|
abstract fun loadData()
|
|
fun registerPermissionResult(){
|
permissionsLauncher = this.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
|
if (result == null || result.size === 0) {
|
permissionObserver !!.onChanged("")
|
return@registerForActivityResult
|
}
|
Log.d(TAG , "result:" + result + " size:" + result.size)
|
var allGranted = true
|
for (key in result.keys) {
|
Log.d(TAG , "permission:" + key + " granted:" + result.get(key))
|
if (result.get(key) == false) {
|
allGranted = false
|
break
|
}
|
}
|
if (! allGranted) {
|
permissionObserver !!.onChanged("")
|
} else {
|
permissionObserver !!.onChanged(com.google.gson.Gson().toJson(result.keys).replace("[" , "").replace("]" , "").replace("\"" , ""))
|
}
|
}
|
}
|
|
fun registerForActivityResult(callback : ActivityResultCallback<ActivityResult>):ActivityResultLauncher<Intent>{
|
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(),callback)
|
}
|
|
/**
|
* viewmodel 工厂创建实例
|
* @return
|
*/
|
fun getViewModelFactory() : ViewModelProvider.Factory {
|
return ViewModelFactory.instance!!
|
}
|
|
/**
|
* 透明状态栏
|
* @param isBlack 是否为黑色文本
|
*/
|
fun setStatusBarTransparent(isBlack : Boolean) { //透明状态栏
|
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) //透明导航栏
|
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
|
setStatusBarTextColor(isBlack)
|
/*val layoutParams = titleBarView.getLayoutParams() as MarginLayoutParams
|
layoutParams.topMargin = layoutParams.topMargin + getStatusBarHeight()
|
titleBarView.setLayoutParams(layoutParams)*/
|
}
|
|
/**
|
* 修改状态栏颜色,支持4.4以上版本
|
* @param colorId
|
*/
|
fun setStatusBarBgColor(@ColorRes colorId : Int) {
|
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
window.statusBarColor = resources.getColor(colorId)
|
}
|
|
/**
|
* 修改状态栏文本颜色
|
* @param isBlack
|
*/
|
fun setStatusBarTextColor(isBlack : Boolean) {
|
val decor = window.decorView
|
if (isBlack) {
|
decor.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
} else {
|
decor.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
}
|
}
|
|
/**
|
* 隐藏虚拟按键
|
*/
|
fun hideBottomUIMenu() { //隐藏虚拟按键
|
if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
|
val v = window.decorView
|
v.systemUiVisibility = View.GONE
|
} else if (Build.VERSION.SDK_INT >= 19) { //for new api versions.
|
val decorView = window.decorView
|
val uiOptions = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
|
decorView.systemUiVisibility = uiOptions
|
}
|
}
|
|
override fun dispatchTouchEvent(ev : MotionEvent) : Boolean {
|
if (ev.action == MotionEvent.ACTION_DOWN) { //把操作放在用户点击的时候
|
val v = currentFocus //得到当前页面的焦点,ps:有输入框的页面焦点一般会被输入框占据
|
if (isShouldHideKeyboard(v , ev)) { //判断用户点击的是否是输入框以外的区域
|
hideSoftKeyboard() //收起键盘
|
}
|
}
|
return super.dispatchTouchEvent(ev)
|
}
|
|
/**
|
* 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘,因为当用户点击EditText时则不能隐藏
|
*
|
* @param v
|
* @param event
|
* @return
|
*/
|
private fun isShouldHideKeyboard(v : View? , event : MotionEvent) : Boolean {
|
if (v != null && v is EditText) { //判断得到的焦点控件是否包含EditText
|
val l = intArrayOf(0 , 0)
|
v.getLocationInWindow(l)
|
val left = l[0] //得到输入框在屏幕中上下左右的位置
|
val top = l[1]
|
val bottom = top + v.getHeight()
|
val right = left + v.getWidth()
|
return if (event.x > left && event.x < right && event.y > top && event.y < bottom) { // 点击位置如果是EditText的区域,忽略它,不收起键盘。
|
false
|
} else {
|
true
|
}
|
} // 如果焦点不是EditText则忽略
|
return false
|
}
|
|
/**
|
* 判断软键盘输入法是否弹出
|
*/
|
fun isKeyboardVisbility(context : Context , v : View) : Boolean {
|
val imm = context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
return if (imm.hideSoftInputFromWindow(v.windowToken , 0)) {
|
imm.showSoftInput(v , 0)
|
true //键盘显示中
|
} else {
|
false //键盘未显示
|
}
|
}
|
|
protected fun hideSoftKeyboard() {
|
if (window.attributes.softInputMode !== WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
|
if (currentFocus != null) (getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(currentFocus !!.windowToken , InputMethodManager.HIDE_NOT_ALWAYS)
|
}
|
}
|
|
/**
|
* 状态栏高度
|
* @return
|
*/
|
fun getStatusBarHeight() : Int {
|
var result = 0
|
val resId = resources.getIdentifier("status_bar_height" , "dimen" , "android")
|
if (resId > 0) {
|
result = resources.getDimensionPixelOffset(resId)
|
}
|
return result
|
}
|
|
@Suppress("DEPRECATION")
|
protected fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
|
val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
|
if (serviceClass.name == service.service.className) {
|
return true
|
}
|
}
|
return false
|
}
|
|
/**
|
* 检查权限
|
*
|
* @param permissions
|
* @return
|
*/
|
fun checkPermissions(permissions : String) : Boolean {
|
return checkPermissions(permissions , false)
|
}
|
|
fun checkPermissions(permissions : String , showPop : Boolean) : Boolean {
|
Log.i(TAG , "permissions:$permissions")
|
val list = permissions.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
var allGranted = true
|
for (permission in list) {
|
if (ContextCompat.checkSelfPermission(this , permission) != PackageManager.PERMISSION_GRANTED) {
|
allGranted = false
|
if (showPop) {
|
// TODO:
|
//showPermissionPopu(permission)
|
}
|
break
|
}
|
}
|
return allGranted
|
}
|
|
var permissionsLauncher : ActivityResultLauncher<Array<String>>? = null //权限
|
var permissionObserver : Observer<String>? = null //权限和文件请求回调
|
/**
|
* 统一权限申请
|
*/
|
fun requestPermissions(permissions : String , observer : Observer<String>) {
|
Log.i(TAG , "permissions:$permissions")
|
val allGranted = checkPermissions(permissions , true)
|
if (! allGranted) {
|
permissionObserver = observer
|
permissionsLauncher?.launch(permissions.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray())
|
} else {
|
observer.onChanged(permissions)
|
}
|
}
|
var mExitTime : Long = 0
|
|
/**
|
* 返回键退出程序
|
*/
|
fun backExit() {
|
if (System.currentTimeMillis() - mExitTime > 2000) {
|
Toast.makeText(this , "再按一次退出" , Toast.LENGTH_SHORT).show()
|
mExitTime = System.currentTimeMillis()
|
} else { //此方法导致app关闭后重启
|
//MyApplication.getApplication().quitApp()
|
System.exit(0) //quitApp();
|
}
|
}
|
|
fun showToast(message : String) {
|
Log.i(TAG , "showToast $message")
|
runOnUiThread { Toast.makeText(mContext , message , Toast.LENGTH_SHORT).show() }
|
}
|
|
fun showToast(@StringRes msg : Int) {
|
showToast(getString(msg))
|
}
|
|
/**
|
* 获取文件保存路径 sdcard根目录/download/文件名称
|
* @param fileUrl
|
* @return
|
*/
|
fun getSaveFilePath(fileUrl : String) : String {
|
val fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1 , fileUrl.length) //获取文件名称
|
val storePath = Environment.getExternalStorageDirectory().absolutePath + File.separator + "Download"
|
val appDir = File(storePath)
|
if (! appDir.exists()) {
|
appDir.mkdirs()
|
}
|
return storePath + File.separator + fileName
|
}
|
|
//===========================================
|
//以下为preferences操作
|
fun getBooleanUserPrefrence(key : String) : Boolean {
|
return getBooleanUserPrefrence(key,false)
|
}
|
|
fun getBooleanUserPrefrence(key : String,value : Boolean) : Boolean {
|
return PreferencesUtils.getBoolean(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun getBooleanProjectPrefrence(key : String) : Boolean {
|
return getBooleanProjectPrefrence(key,false)
|
}
|
|
fun getBooleanProjectPrefrence(key : String,value : Boolean) : Boolean {
|
return PreferencesUtils.getBoolean(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun getStringUserPrefrence(key : String) : String {
|
return getStringUserPrefrence(key,"");
|
}
|
|
fun getStringUserPrefrence(key : String,value : String?) : String {
|
return PreferencesUtils.getString(this , key , value, PreferencesUtils.PROJECT)
|
}
|
|
fun getStringProjectPrefrence(key : String) : String {
|
return getStringProjectPrefrence(key,"");
|
}
|
|
fun getStringProjectPrefrence(key : String,value : String?) : String {
|
return PreferencesUtils.getString(this , key , value, PreferencesUtils.PROJECT)
|
}
|
|
fun getIntProjectPrefrence(key : String) : Int {
|
return getIntProjectPrefrence(key,0);
|
}
|
|
fun getIntProjectPrefrence(key : String,value : Int) : Int {
|
return PreferencesUtils.getInt(this , key , value , PreferencesUtils.PROJECT)
|
}
|
|
fun getLongProjectPrefrence(key : String) : Long {
|
return getLongProjectPrefrence(key,0);
|
}
|
|
fun getLongProjectPrefrence(key : String,value : Long) : Long {
|
return PreferencesUtils.getLong(this , key , value , PreferencesUtils.PROJECT)
|
}
|
|
fun getFloatProjectPrefrence(key : String) : Float {
|
return getFloatProjectPrefrence(key,0f);
|
}
|
|
fun getFloatProjectPrefrence(key : String,value : Float) : Float {
|
return PreferencesUtils.getFloat(this , key , value , PreferencesUtils.PROJECT)
|
}
|
|
fun getStringSetProjectPrefrence(key : String) : Set<*> {
|
return getStringSetProjectPrefrence(key, ArraySet<Any?>() )
|
}
|
|
fun getStringSetProjectPrefrence(key : String,value : Set<*>?) : Set<*> {
|
return PreferencesUtils.getStringSet(this , key ,value, PreferencesUtils.PROJECT)
|
}
|
|
fun getIntUserPrefrence(key : String) : Int {
|
return getIntUserPrefrence(key,0)
|
}
|
|
fun getIntUserPrefrence(key : String,value : Int) : Int {
|
return PreferencesUtils.getInt(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun getLongUserPrefrence(key : String) : Long {
|
return getLongUserPrefrence(key,0)
|
}
|
|
fun getLongUserPrefrence(key : String,value : Long) : Long {
|
return PreferencesUtils.getLong(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun getFloatUserPrefrence(key : String) : Float {
|
return getFloatUserPrefrence(key,0f)
|
}
|
|
fun getFloatUserPrefrence(key : String,value : Float) : Float {
|
return PreferencesUtils.getFloat(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun getStringSetUserPrefrence(key : String) : Set<*> {
|
return getStringSetUserPrefrence(key,ArraySet<Any?>())
|
}
|
|
fun getStringSetUserPrefrence(key : String,value : Set<*>) : Set<*> {
|
return PreferencesUtils.getStringSet(this , key ,value, PreferencesUtils.USER)
|
}
|
|
fun putBooleanUserPrefrence(key : String , value : Boolean) {
|
PreferencesUtils.putBoolean(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun putBooleanProjectPrefrence(key : String , value : Boolean) {
|
PreferencesUtils.putBoolean(this , key , value , PreferencesUtils.PROJECT)
|
}
|
|
fun putStringUserPrefrence(key : String , value : String?) {
|
PreferencesUtils.putString(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun putStringProjectPrefrence(key : String , value : String?) {
|
PreferencesUtils.putString(this , key , value , PreferencesUtils.PROJECT)
|
}
|
|
fun putIntProjectPrefrence(key : String , value : Int) {
|
PreferencesUtils.putInt(this , key , value , PreferencesUtils.PROJECT)
|
}
|
|
fun putLongProjectPrefrence(key : String , value : Long) {
|
PreferencesUtils.putLong(this , key , value , PreferencesUtils.PROJECT)
|
}
|
|
fun putFloatProjectPrefrence(key : String , value : Float) {
|
PreferencesUtils.putFloat(this , key , value , PreferencesUtils.PROJECT)
|
}
|
|
fun putStringSetProjectPrefrence(key : String , value : Set<*>?) {
|
PreferencesUtils.putStringSet(this , key , value , PreferencesUtils.PROJECT)
|
}
|
|
fun putIntUserPrefrence(key : String , value : Int) {
|
PreferencesUtils.putInt(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun putLongUserPrefrence(key : String , value : Long) {
|
PreferencesUtils.putLong(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun putFloatUserPrefrence(key : String , value : Float) {
|
PreferencesUtils.putFloat(this , key , value , PreferencesUtils.USER)
|
}
|
|
fun putStringSetUserPrefrence(key : String , value : Set<*>?) {
|
PreferencesUtils.putStringSet(this , key , value , PreferencesUtils.USER)
|
}
|
|
|
fun removeUserKey(key : String) {
|
PreferencesUtils.removeKey(this , key , PreferencesUtils.USER)
|
}
|
|
fun removeProjectKey(key : String) {
|
PreferencesUtils.removeKey(this , key , PreferencesUtils.PROJECT)
|
}
|
|
fun removeUserValue(Value : String?) {
|
PreferencesUtils.removeValue(this , Value , PreferencesUtils.USER)
|
}
|
|
fun removeProjectValue(Value : String?) {
|
PreferencesUtils.removeValue(this , Value , PreferencesUtils.PROJECT)
|
}
|
|
|
fun clearProjectData() {
|
PreferencesUtils.clearData(this , PreferencesUtils.PROJECT)
|
}
|
|
fun clearUserData() {
|
PreferencesUtils.clearData(this , PreferencesUtils.USER)
|
}
|
|
}
|