diff --git a/base/src/main/kotlin/io/goooler/demoapp/base/util/BaseBindingAdapters.kt b/base/src/main/kotlin/io/goooler/demoapp/base/util/BaseBindingAdapters.kt index 6c04bce70..6ef34bdb3 100644 --- a/base/src/main/kotlin/io/goooler/demoapp/base/util/BaseBindingAdapters.kt +++ b/base/src/main/kotlin/io/goooler/demoapp/base/util/BaseBindingAdapters.kt @@ -5,17 +5,23 @@ package io.goooler.demoapp.base.util import android.graphics.Color import android.graphics.Outline import android.graphics.Paint +import android.graphics.PorterDuff import android.graphics.Typeface import android.graphics.drawable.GradientDrawable import android.view.View import android.view.ViewGroup import android.view.ViewOutlineProvider +import android.widget.ImageView import android.widget.TextView import androidx.annotation.ColorInt import androidx.annotation.Px import androidx.databinding.BindingAdapter // ------------------------View --------------------------// +@BindingAdapter("binding_isEnabled") +internal fun View.bindingIsEnabled(enabled: Boolean) { + this.isEnabled = enabled +} @BindingAdapter("binding_isGone") internal fun View.bindingIsGone(gone: Boolean) { @@ -81,6 +87,19 @@ internal fun View.bindingMarginEnd(@Px margin: Float) { marginDirection(2, margin) } +@BindingAdapter("binding_onLongClick") +internal fun View.bindingOnLongClick(body: () -> Unit) { + setOnLongClickListener { + body() + true + } +} + +@BindingAdapter("binding_tint") +fun ImageView.bindingTint(@ColorInt color: Int) { + setColorFilter(color, PorterDuff.Mode.SRC_IN) +} + // ------------------------View Bg Shape---------------------// @BindingAdapter( diff --git a/base/src/main/kotlin/io/goooler/demoapp/base/util/BaseExtensions.kt b/base/src/main/kotlin/io/goooler/demoapp/base/util/BaseExtensions.kt index 6228195ed..7a86d7452 100644 --- a/base/src/main/kotlin/io/goooler/demoapp/base/util/BaseExtensions.kt +++ b/base/src/main/kotlin/io/goooler/demoapp/base/util/BaseExtensions.kt @@ -49,6 +49,7 @@ import androidx.lifecycle.coroutineScope import androidx.lifecycle.findViewTreeLifecycleOwner import java.io.File import java.io.Serializable +import java.lang.reflect.Method import java.math.BigDecimal import java.util.Collections import java.util.UUID @@ -102,6 +103,33 @@ fun T.deepCopy(): T? { } } +@Throws(ReflectiveOperationException::class) +fun lazyReflectedMethod( + declaringClass: Class<*>, + methodName: String, + vararg parameterTypes: Any +): Lazy = lazy { + getReflectedMethod(declaringClass, methodName, *getParameterTypes(parameterTypes)) +} + +@Throws(ReflectiveOperationException::class) +fun getParameterTypes(parameterTypes: Array): Array> = + Array(parameterTypes.size) { + when (val parameterType = parameterTypes[it]) { + is Class<*> -> parameterType + is String -> Class.forName(parameterType) + else -> throw IllegalArgumentException(parameterType.toString()) + } + } + +@Throws(ReflectiveOperationException::class) +fun getReflectedMethod( + declaringClass: Class<*>, + methodName: String, + vararg parameterTypes: Class<*> +): Method = + declaringClass.getDeclaredMethod(methodName, *parameterTypes).also { it.isAccessible = true } + // ---------------------CharSequence-------------------------------// operator fun String.times(@IntRange(from = 0) num: Int): String { @@ -126,6 +154,11 @@ fun String.onlyDigits(): String = replace(Regex("\\D*"), "") fun String.removeAllSpecialCharacters(): String = replace(Regex("[^a-zA-Z]+"), "") +/** + * Validate given text is a valid filename. + * + * @return true if given text is a valid filename + */ fun String.isValidFilename(): Boolean { val filenameRegex = Pattern.compile("[\\\\\\/:\\*\\?\"<>\\|\\x01-\\x1F\\x7F]", Pattern.CASE_INSENSITIVE) @@ -391,17 +424,17 @@ fun Intent.getStringExtra(name: String, defaultValue: String): String = fun Intent.getCharSequenceExtra(name: String, defaultValue: CharSequence): CharSequence = getCharSequenceExtra(name) ?: defaultValue -fun Intent.getParcelableExtra(name: String, defaultValue: T): T = +inline fun Intent.getParcelableExtra(name: String, defaultValue: T): T = getParcelableExtra(name) ?: defaultValue -fun Intent.getSerializableExtra( +inline fun Intent.getSerializableExtra( name: String, - defaultValue: Serializable -): Serializable = getSerializableExtra(name) ?: defaultValue + defaultValue: T +): T = (getSerializableExtra(name) ?: defaultValue) as T // ---------------------Fragment-------------------------------// -fun T.putArguments(bundle: Bundle): T { +fun T.putArguments(bundle: Bundle?): T { arguments = bundle return this } diff --git a/base/src/main/kotlin/io/goooler/demoapp/base/widget/StatusBarView.kt b/base/src/main/kotlin/io/goooler/demoapp/base/widget/StatusBarView.kt index 8e61b9aac..18d275287 100644 --- a/base/src/main/kotlin/io/goooler/demoapp/base/widget/StatusBarView.kt +++ b/base/src/main/kotlin/io/goooler/demoapp/base/widget/StatusBarView.kt @@ -18,7 +18,7 @@ class StatusBarView(context: Context, attrs: AttributeSet? = null) : View(contex private fun getStatusBarHeight(): Int { val resources = Resources.getSystem() @SuppressLint("InternalInsetResource") - @DimenRes val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android") - return resources.getDimensionPixelSize(resourceId) + @DimenRes val resId = resources.getIdentifier("status_bar_height", "dimen", "android") + return resources.getDimensionPixelSize(resId) } } diff --git a/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingActivity.kt b/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingActivity.kt index 1be3237ab..9f61e8a5b 100644 --- a/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingActivity.kt +++ b/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingActivity.kt @@ -4,13 +4,15 @@ import android.annotation.SuppressLint import android.content.pm.ActivityInfo import android.content.res.Resources import android.os.Bundle +import android.view.LayoutInflater import android.view.WindowManager import androidx.databinding.ViewDataBinding +import androidx.viewbinding.ViewBinding import com.blankj.utilcode.util.AdaptScreenUtils import com.blankj.utilcode.util.BarUtils import com.blankj.utilcode.util.ScreenUtils import io.goooler.demoapp.base.core.BaseActivity -import io.goooler.demoapp.common.util.inflateBinding +import java.lang.reflect.ParameterizedType abstract class BaseBindingActivity : BaseActivity(), IBinding { @@ -39,4 +41,16 @@ abstract class BaseBindingActivity : BaseActivity(), IBind else AdaptScreenUtils.adaptHeight(super.getResources(), 640) } + + companion object { + @Suppress("UNCHECKED_CAST") + internal fun Any.inflateBinding(inflater: LayoutInflater): T { + return (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments + .filterIsInstance>() + .first() + .getDeclaredMethod("inflate", LayoutInflater::class.java) + .also { it.isAccessible = true } + .invoke(null, inflater) as T + } + } } diff --git a/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingDialogFragment.kt b/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingDialogFragment.kt index 78311a368..ef5e9a744 100644 --- a/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingDialogFragment.kt +++ b/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingDialogFragment.kt @@ -6,7 +6,7 @@ import android.view.View import android.view.ViewGroup import androidx.databinding.ViewDataBinding import io.goooler.demoapp.base.core.BaseDialogFragment -import io.goooler.demoapp.common.util.inflateBinding +import io.goooler.demoapp.common.base.binding.BaseBindingActivity.Companion.inflateBinding abstract class BaseBindingDialogFragment : BaseDialogFragment(), diff --git a/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingFragment.kt b/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingFragment.kt index f133dec9e..e7bf346c1 100644 --- a/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingFragment.kt +++ b/common/src/main/kotlin/io/goooler/demoapp/common/base/binding/BaseBindingFragment.kt @@ -6,7 +6,7 @@ import android.view.View import android.view.ViewGroup import androidx.databinding.ViewDataBinding import io.goooler.demoapp.base.core.BaseFragment -import io.goooler.demoapp.common.util.inflateBinding +import io.goooler.demoapp.common.base.binding.BaseBindingActivity.Companion.inflateBinding abstract class BaseBindingFragment : BaseFragment(), diff --git a/common/src/main/kotlin/io/goooler/demoapp/common/util/CommonExtensions.kt b/common/src/main/kotlin/io/goooler/demoapp/common/util/CommonExtensions.kt index 337159586..d4de0bb1c 100644 --- a/common/src/main/kotlin/io/goooler/demoapp/common/util/CommonExtensions.kt +++ b/common/src/main/kotlin/io/goooler/demoapp/common/util/CommonExtensions.kt @@ -3,9 +3,12 @@ package io.goooler.demoapp.common.util +import android.content.ContentResolver +import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.drawable.Drawable -import android.view.LayoutInflater +import android.text.format.DateFormat +import android.text.format.Formatter import android.view.View import android.widget.TextView import androidx.annotation.AnyThread @@ -17,10 +20,8 @@ import androidx.annotation.PluralsRes import androidx.annotation.Px import androidx.annotation.StringRes import androidx.core.widget.doAfterTextChanged -import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.AsyncDifferConfig import androidx.recyclerview.widget.DiffUtil -import androidx.viewbinding.ViewBinding import com.blankj.utilcode.util.AdaptScreenUtils import com.blankj.utilcode.util.ColorUtils import com.blankj.utilcode.util.ImageUtils @@ -29,6 +30,7 @@ import com.blankj.utilcode.util.ResourceUtils import com.blankj.utilcode.util.SPUtils import com.blankj.utilcode.util.SizeUtils import com.blankj.utilcode.util.StringUtils +import com.blankj.utilcode.util.TimeUtils import com.google.android.material.textfield.TextInputLayout import com.scwang.smart.refresh.layout.SmartRefreshLayout import io.goooler.demoapp.base.util.Dp @@ -38,7 +40,7 @@ import io.goooler.demoapp.base.util.ToastUtil import io.goooler.demoapp.common.BuildConfig import io.goooler.demoapp.common.CommonApplication import io.goooler.demoapp.common.type.SpKeys -import java.lang.reflect.ParameterizedType +import java.util.Locale import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asExecutor @@ -63,25 +65,23 @@ fun @receiver:StringRes Int.showToast() { ToastUtil.show(CommonApplication.app, this) } -@MainThread -fun SmartRefreshLayout.finishRefreshAndLoadMore() { - finishRefresh() - finishLoadMore() +inline fun DiffUtil.ItemCallback.asConfig(): AsyncDifferConfig { + return AsyncDifferConfig.Builder(this) + .setBackgroundThreadExecutor(Dispatchers.Default.asExecutor()) + .build() } -@MainThread -fun SmartRefreshLayout.enableRefreshAndLoadMore(enable: Boolean = true) { - setEnableRefresh(enable) - setEnableLoadMore(enable) -} +val contentResolver: ContentResolver get() = CommonApplication.app.contentResolver -@MainThread -fun SmartRefreshLayout.disableRefreshAndLoadMore() { - enableRefreshAndLoadMore(false) -} +val packageManager: PackageManager get() = CommonApplication.app.packageManager // ---------------------String-------------------------------// +fun Long.formatFileSize(): String = Formatter.formatFileSize(CommonApplication.app, this) + +fun Long.millis2String(pattern: String = "yyyyMMddHHmmss"): String = + TimeUtils.millis2String(this, DateFormat.getBestDateTimePattern(Locale.getDefault(), pattern)) + @AnyThread fun String.showToast() { ToastUtil.show(CommonApplication.app, this) @@ -158,19 +158,19 @@ fun TextView.hideTextInputLayoutErrorOnTextChange(textInputLayout: TextInputLayo doAfterTextChanged { textInputLayout.error = null } } -inline fun DiffUtil.ItemCallback.asConfig(): AsyncDifferConfig { - return AsyncDifferConfig.Builder(this) - .setBackgroundThreadExecutor(Dispatchers.Default.asExecutor()) - .build() +@MainThread +fun SmartRefreshLayout.finishRefreshAndLoadMore() { + finishRefresh() + finishLoadMore() } -// ---------------------VM & Binding-------------------------------// +@MainThread +fun SmartRefreshLayout.enableRefreshAndLoadMore(enable: Boolean = true) { + setEnableRefresh(enable) + setEnableLoadMore(enable) +} -@Suppress("UNCHECKED_CAST") -fun LifecycleOwner.inflateBinding(inflater: LayoutInflater): T { - return (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments - .filterIsInstance>() - .first() - .getDeclaredMethod("inflate", LayoutInflater::class.java) - .invoke(null, inflater) as T +@MainThread +fun SmartRefreshLayout.disableRefreshAndLoadMore() { + enableRefreshAndLoadMore(false) }