更新界面
This commit is contained in:
@@ -19,7 +19,7 @@ import io.legato.kazusa.R
|
||||
import splitties.views.onLongClick
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
open class Preference(context: Context, attrs: AttributeSet) :
|
||||
open class Preference(context: Context, attrs: AttributeSet?) :
|
||||
androidx.preference.Preference(context, attrs) {
|
||||
|
||||
private var onLongClick: ((preference: Preference) -> Boolean)? = null
|
||||
@@ -68,7 +68,7 @@ open class Preference(context: Context, attrs: AttributeSet) :
|
||||
if (iconView is ImageView) {
|
||||
iconView.isVisible = icon != null
|
||||
iconView.setImageDrawable(icon)
|
||||
//iconView.setColorFilter(context.accentColor)
|
||||
// iconView.setColorFilter(context.primaryColor)
|
||||
}
|
||||
|
||||
if (weightLayoutRes != null && weightLayoutRes != 0 && viewId != null && viewId != 0) {
|
||||
|
||||
@@ -7,6 +7,9 @@ import androidx.core.view.isVisible
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.lib.theme.primaryColor
|
||||
import io.legato.kazusa.utils.themeColor
|
||||
|
||||
//import io.legado.app.lib.theme.accentColor
|
||||
//import io.legado.app.lib.theme.backgroundColor
|
||||
|
||||
@@ -25,7 +28,7 @@ class PreferenceCategory(context: Context, attrs: AttributeSet) :
|
||||
if (view is TextView) { // && !view.isInEditMode
|
||||
view.text = title
|
||||
if (view.isInEditMode) return
|
||||
//view.setTextColor(context.accentColor)
|
||||
// view.setTextColor(context.primaryColor)
|
||||
view.isVisible = !title.isNullOrEmpty()
|
||||
|
||||
// val da = holder.findViewById(R.id.preference_divider_above)
|
||||
|
||||
@@ -31,11 +31,6 @@ class AppLogDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
|
||||
LogAdapter(requireContext())
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setLayout(0.9f, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
binding.run {
|
||||
//toolBar.setBackgroundColor(primaryColor)
|
||||
@@ -46,13 +41,21 @@ class AppLogDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
adapter.setItems(AppLog.logs)
|
||||
updateEmptyView()
|
||||
}
|
||||
|
||||
private fun updateEmptyView() {
|
||||
binding.emptyView.visibility =
|
||||
if (adapter.itemCount == 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||
when (item?.itemId) {
|
||||
R.id.menu_clear -> {
|
||||
AppLog.clear()
|
||||
adapter.clearItems()
|
||||
updateEmptyView()
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -93,8 +93,8 @@ class ImportBookSourceDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_r
|
||||
}
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
binding.rotateLoading.gone()
|
||||
binding.tvMsg.apply {
|
||||
text = it
|
||||
binding.emptyView.apply {
|
||||
setMessage(it)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
@@ -104,8 +104,8 @@ class ImportBookSourceDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_r
|
||||
adapter.setItems(viewModel.allSources)
|
||||
upSelectText()
|
||||
} else {
|
||||
binding.tvMsg.apply {
|
||||
setText(R.string.wrong_format)
|
||||
binding.emptyView.apply {
|
||||
setMessage(R.string.wrong_format)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,20 +80,20 @@ class ImportDictRuleDialog() : BaseDialogFragment(R.layout.dialog_recycler_view)
|
||||
upSelectText()
|
||||
}
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.tvMsg.apply {
|
||||
text = it
|
||||
binding.rotateLoading.gone()
|
||||
binding.emptyView.apply {
|
||||
setMessage(it)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
viewModel.successLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.rotateLoading.gone()
|
||||
if (it > 0) {
|
||||
adapter.setItems(viewModel.allSources)
|
||||
upSelectText()
|
||||
} else {
|
||||
binding.tvMsg.apply {
|
||||
setText(R.string.wrong_format)
|
||||
binding.emptyView.apply {
|
||||
setMessage(R.string.wrong_format)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import io.legato.kazusa.databinding.ItemSourceImportBinding
|
||||
import io.legato.kazusa.ui.widget.dialog.CodeDialog
|
||||
import io.legato.kazusa.ui.widget.dialog.WaitDialog
|
||||
import io.legato.kazusa.utils.GSON
|
||||
import io.legato.kazusa.utils.gone
|
||||
import io.legato.kazusa.utils.setLayout
|
||||
import io.legato.kazusa.utils.showDialogFragment
|
||||
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
|
||||
@@ -83,20 +84,20 @@ class ImportHttpTtsDialog() : BaseDialogFragment(R.layout.dialog_recycler_view),
|
||||
upSelectText()
|
||||
}
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.tvMsg.apply {
|
||||
text = it
|
||||
binding.rotateLoading.gone()
|
||||
binding.emptyView.apply {
|
||||
setMessage(it)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
viewModel.successLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.rotateLoading.gone()
|
||||
if (it > 0) {
|
||||
adapter.setItems(viewModel.allSources)
|
||||
upSelectText()
|
||||
} else {
|
||||
binding.tvMsg.apply {
|
||||
setText(R.string.wrong_format)
|
||||
binding.emptyView.apply {
|
||||
setMessage(R.string.wrong_format)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,20 +88,20 @@ class ImportReplaceRuleDialog() : BaseDialogFragment(R.layout.dialog_recycler_vi
|
||||
upSelectText()
|
||||
}
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.tvMsg.apply {
|
||||
text = it
|
||||
binding.rotateLoading.gone()
|
||||
binding.emptyView.apply {
|
||||
setMessage(it)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
viewModel.successLiveData.observe(this) {
|
||||
// binding.rotateLoading.gone()
|
||||
binding.rotateLoading.gone()
|
||||
if (it > 0) {
|
||||
adapter.setItems(viewModel.allRules)
|
||||
upSelectText()
|
||||
} else {
|
||||
binding.tvMsg.apply {
|
||||
setText(R.string.wrong_format)
|
||||
binding.emptyView.apply {
|
||||
setMessage(R.string.wrong_format)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,20 +92,20 @@ class ImportRssSourceDialog() : BaseDialogFragment(R.layout.dialog_recycler_view
|
||||
upSelectText()
|
||||
}
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.tvMsg.apply {
|
||||
text = it
|
||||
binding.rotateLoading.gone()
|
||||
binding.emptyView.apply {
|
||||
setMessage(it)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
viewModel.successLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.rotateLoading.gone()
|
||||
if (it > 0) {
|
||||
adapter.setItems(viewModel.allSources)
|
||||
upSelectText()
|
||||
} else {
|
||||
binding.tvMsg.apply {
|
||||
setText(R.string.wrong_format)
|
||||
binding.emptyView.apply {
|
||||
setMessage(R.string.wrong_format)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import io.legato.kazusa.help.config.ThemeConfig
|
||||
import io.legato.kazusa.ui.widget.dialog.CodeDialog
|
||||
import io.legato.kazusa.ui.widget.dialog.WaitDialog
|
||||
import io.legato.kazusa.utils.GSON
|
||||
import io.legato.kazusa.utils.gone
|
||||
import io.legato.kazusa.utils.setLayout
|
||||
import io.legato.kazusa.utils.showDialogFragment
|
||||
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
|
||||
@@ -82,20 +83,20 @@ class ImportThemeDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_recycl
|
||||
upSelectText()
|
||||
}
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.tvMsg.apply {
|
||||
text = it
|
||||
binding.rotateLoading.gone()
|
||||
binding.emptyView.apply {
|
||||
setMessage(it)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
viewModel.successLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.rotateLoading.gone()
|
||||
if (it > 0) {
|
||||
adapter.setItems(viewModel.allSources)
|
||||
upSelectText()
|
||||
} else {
|
||||
binding.tvMsg.apply {
|
||||
setText(R.string.wrong_format)
|
||||
binding.emptyView.apply {
|
||||
setMessage(R.string.wrong_format)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import io.legato.kazusa.databinding.ItemSourceImportBinding
|
||||
import io.legato.kazusa.ui.widget.dialog.CodeDialog
|
||||
import io.legato.kazusa.ui.widget.dialog.WaitDialog
|
||||
import io.legato.kazusa.utils.GSON
|
||||
import io.legato.kazusa.utils.gone
|
||||
import io.legato.kazusa.utils.setLayout
|
||||
import io.legato.kazusa.utils.showDialogFragment
|
||||
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
|
||||
@@ -82,20 +83,20 @@ class ImportTxtTocRuleDialog() : BaseDialogFragment(R.layout.dialog_recycler_vie
|
||||
upSelectText()
|
||||
}
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.tvMsg.apply {
|
||||
text = it
|
||||
binding.rotateLoading.gone()
|
||||
binding.emptyView.apply {
|
||||
setMessage(it)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
viewModel.successLiveData.observe(this) {
|
||||
//binding.rotateLoading.gone()
|
||||
binding.rotateLoading.gone()
|
||||
if (it > 0) {
|
||||
adapter.setItems(viewModel.allSources)
|
||||
upSelectText()
|
||||
} else {
|
||||
binding.tvMsg.apply {
|
||||
setText(R.string.wrong_format)
|
||||
binding.emptyView.apply {
|
||||
setMessage(R.string.wrong_format)
|
||||
visible()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
|
||||
).catch {
|
||||
AppLog.put("发现界面更新数据出错", it)
|
||||
}.conflate().flowOn(IO).collect {
|
||||
binding.tvEmptyMsg.isGone = it.isNotEmpty() || searchView.text.isNotEmpty() == true
|
||||
binding.emptyView.isGone = it.isNotEmpty() || searchView.text.isNotEmpty() == true
|
||||
adapter.setItems(it, diffItemCallBack)
|
||||
delay(500)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package io.legato.kazusa.ui.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.utils.dpToPx
|
||||
import androidx.core.content.withStyledAttributes
|
||||
|
||||
class EmptyMessageView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null
|
||||
) : LinearLayout(context, attrs) {
|
||||
|
||||
private val faceTextView: TextView
|
||||
private val messageTextView: TextView
|
||||
|
||||
private val faces = listOf(
|
||||
"(๑`^´๑)", "(´・ᴗ・`)", "(•̀ᴗ•́)و", "(ᵔᴥᵔ)", "(¬‿¬)", "(ಥ﹏ಥ)", "(。•́︿•̀。)"
|
||||
)
|
||||
|
||||
init {
|
||||
orientation = VERTICAL
|
||||
gravity = Gravity.CENTER
|
||||
layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
|
||||
setPadding(16.dpToPx(), 16.dpToPx(), 16.dpToPx(), 16.dpToPx())
|
||||
|
||||
post {
|
||||
val faceWidth = faceTextView.width
|
||||
if (faceWidth > 0) {
|
||||
messageTextView.maxWidth = (faceWidth * 2f).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
faceTextView = TextView(context).apply {
|
||||
layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
|
||||
gravity = Gravity.CENTER
|
||||
textSize = 32f
|
||||
text = faces.random()
|
||||
}
|
||||
|
||||
messageTextView = TextView(context).apply {
|
||||
layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
|
||||
topMargin = 8.dpToPx()
|
||||
}
|
||||
gravity = Gravity.CENTER
|
||||
text = R.string.empty.toString()
|
||||
}
|
||||
|
||||
addView(faceTextView)
|
||||
addView(messageTextView)
|
||||
|
||||
attrs?.let {
|
||||
context.withStyledAttributes(it, R.styleable.EmptyMessageView) {
|
||||
val msg = getString(R.styleable.EmptyMessageView_messageText)
|
||||
messageTextView.text = msg ?: ""
|
||||
faceTextView.text = faces.random()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 设置文字消息 */
|
||||
fun setMessage(@StringRes resId: Int) {
|
||||
messageTextView.setText(resId)
|
||||
}
|
||||
|
||||
fun setMessage(msg: String) {
|
||||
messageTextView.text = msg
|
||||
}
|
||||
|
||||
|
||||
/** 可选:手动刷新随机颜文字 */
|
||||
fun refreshFace() {
|
||||
faceTextView.text = faces.random()
|
||||
}
|
||||
}
|
||||
@@ -1,327 +0,0 @@
|
||||
package io.legato.kazusa.ui.widget.checkbox
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.Checkable
|
||||
import androidx.core.view.postDelayed
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.lib.theme.ThemeStore
|
||||
import io.legato.kazusa.utils.dpToPx
|
||||
import io.legato.kazusa.utils.getCompatColor
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class SmoothCheckBox @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : View(context, attrs), Checkable {
|
||||
private var mPaint: Paint
|
||||
private var mTickPaint: Paint
|
||||
private var mFloorPaint: Paint
|
||||
private var mTickPoints: Array<Point>
|
||||
private var mCenterPoint: Point
|
||||
private var mTickPath: Path
|
||||
private var mLeftLineDistance = 0f
|
||||
private var mRightLineDistance = 0f
|
||||
private var mDrewDistance = 0f
|
||||
private var mScaleVal = 1.0f
|
||||
private var mFloorScale = 1.0f
|
||||
private var mWidth = 0
|
||||
private var mAnimDuration = 0
|
||||
private var mStrokeWidth = 0
|
||||
private var mCheckedColor = 0
|
||||
private var mUnCheckedColor = 0
|
||||
private var mFloorColor = 0
|
||||
private var mFloorUnCheckedColor = 0
|
||||
private var mChecked = false
|
||||
private var mTickDrawing = false
|
||||
var onCheckedChangeListener: ((checkBox: SmoothCheckBox, isChecked: Boolean) -> Unit)? = null
|
||||
|
||||
init {
|
||||
val ta = context.obtainStyledAttributes(attrs, R.styleable.SmoothCheckBox)
|
||||
var tickColor = ThemeStore.accentColor(context)
|
||||
//mCheckedColor = context.getCompatColor(R.color.background_menu)
|
||||
//mUnCheckedColor = context.getCompatColor(R.color.background_menu)
|
||||
mFloorColor = context.getCompatColor(R.color.transparent30)
|
||||
tickColor = ta.getColor(R.styleable.SmoothCheckBox_color_tick, tickColor)
|
||||
mAnimDuration = ta.getInt(R.styleable.SmoothCheckBox_duration, DEF_ANIM_DURATION)
|
||||
mFloorColor = ta.getColor(R.styleable.SmoothCheckBox_color_unchecked_stroke, mFloorColor)
|
||||
mCheckedColor = ta.getColor(R.styleable.SmoothCheckBox_color_checked, mCheckedColor)
|
||||
mUnCheckedColor = ta.getColor(R.styleable.SmoothCheckBox_color_unchecked, mUnCheckedColor)
|
||||
mStrokeWidth = ta.getDimensionPixelSize(R.styleable.SmoothCheckBox_stroke_width, 0)
|
||||
ta.recycle()
|
||||
mFloorUnCheckedColor = mFloorColor
|
||||
mTickPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
mTickPaint.style = Paint.Style.STROKE
|
||||
mTickPaint.strokeCap = Paint.Cap.ROUND
|
||||
mTickPaint.color = tickColor
|
||||
mFloorPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
mFloorPaint.style = Paint.Style.FILL
|
||||
mFloorPaint.color = mFloorColor
|
||||
mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
mPaint.style = Paint.Style.FILL
|
||||
mPaint.color = mCheckedColor
|
||||
mTickPath = Path()
|
||||
mCenterPoint = Point()
|
||||
mTickPoints = arrayOf(Point(), Point(), Point())
|
||||
setOnClickListener {
|
||||
toggle()
|
||||
mTickDrawing = false
|
||||
mDrewDistance = 0f
|
||||
if (isChecked) {
|
||||
startCheckedAnimation()
|
||||
} else {
|
||||
startUnCheckedAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isChecked(): Boolean {
|
||||
return mChecked
|
||||
}
|
||||
|
||||
override fun setChecked(checked: Boolean) {
|
||||
mChecked = checked
|
||||
reset()
|
||||
invalidate()
|
||||
onCheckedChangeListener?.invoke(this@SmoothCheckBox, mChecked)
|
||||
}
|
||||
|
||||
override fun toggle() {
|
||||
this.isChecked = !isChecked
|
||||
}
|
||||
|
||||
/**
|
||||
* checked with animation
|
||||
*
|
||||
* @param checked checked
|
||||
* @param animate change with animation
|
||||
*/
|
||||
fun setChecked(checked: Boolean, animate: Boolean) {
|
||||
if (animate) {
|
||||
mTickDrawing = false
|
||||
mChecked = checked
|
||||
mDrewDistance = 0f
|
||||
if (checked) {
|
||||
startCheckedAnimation()
|
||||
} else {
|
||||
startUnCheckedAnimation()
|
||||
}
|
||||
onCheckedChangeListener?.invoke(this@SmoothCheckBox, mChecked)
|
||||
} else {
|
||||
this.isChecked = checked
|
||||
}
|
||||
}
|
||||
|
||||
private fun reset() {
|
||||
mTickDrawing = true
|
||||
mFloorScale = 1.0f
|
||||
mScaleVal = if (isChecked) 0f else 1.0f
|
||||
mFloorColor = if (isChecked) mCheckedColor else mFloorUnCheckedColor
|
||||
mDrewDistance = if (isChecked) mLeftLineDistance + mRightLineDistance else 0f
|
||||
}
|
||||
|
||||
private fun measureSize(measureSpec: Int): Int {
|
||||
val defSize: Int = DEF_DRAW_SIZE.dpToPx()
|
||||
val specSize = MeasureSpec.getSize(measureSpec)
|
||||
val specMode = MeasureSpec.getMode(measureSpec)
|
||||
var result = 0
|
||||
when (specMode) {
|
||||
MeasureSpec.UNSPECIFIED, MeasureSpec.AT_MOST -> result = min(defSize, specSize)
|
||||
MeasureSpec.EXACTLY -> result = specSize
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
setMeasuredDimension(measureSize(widthMeasureSpec), measureSize(heightMeasureSpec))
|
||||
}
|
||||
|
||||
override fun onLayout(
|
||||
changed: Boolean,
|
||||
left: Int,
|
||||
top: Int,
|
||||
right: Int,
|
||||
bottom: Int
|
||||
) {
|
||||
mWidth = measuredWidth
|
||||
mStrokeWidth = if (mStrokeWidth == 0) measuredWidth / 10 else mStrokeWidth
|
||||
mStrokeWidth =
|
||||
if (mStrokeWidth > measuredWidth / 5) measuredWidth / 5 else mStrokeWidth
|
||||
mStrokeWidth = if (mStrokeWidth < 3) 3 else mStrokeWidth
|
||||
mCenterPoint.x = mWidth / 2
|
||||
mCenterPoint.y = measuredHeight / 2
|
||||
mTickPoints[0].x = (measuredWidth.toFloat() / 30 * 7).roundToInt()
|
||||
mTickPoints[0].y = (measuredHeight.toFloat() / 30 * 14).roundToInt()
|
||||
mTickPoints[1].x = (measuredWidth.toFloat() / 30 * 13).roundToInt()
|
||||
mTickPoints[1].y = (measuredHeight.toFloat() / 30 * 20).roundToInt()
|
||||
mTickPoints[2].x = (measuredWidth.toFloat() / 30 * 22).roundToInt()
|
||||
mTickPoints[2].y = (measuredHeight.toFloat() / 30 * 10).roundToInt()
|
||||
mLeftLineDistance = sqrt(
|
||||
(mTickPoints[1].x - mTickPoints[0].x.toDouble()).pow(2.0) +
|
||||
(mTickPoints[1].y - mTickPoints[0].y.toDouble()).pow(2.0)
|
||||
).toFloat()
|
||||
mRightLineDistance = sqrt(
|
||||
(mTickPoints[2].x - mTickPoints[1].x.toDouble()).pow(2.0) +
|
||||
(mTickPoints[2].y - mTickPoints[1].y.toDouble()).pow(2.0)
|
||||
).toFloat()
|
||||
mTickPaint.strokeWidth = mStrokeWidth.toFloat()
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
drawBorder(canvas)
|
||||
drawCenter(canvas)
|
||||
drawTick(canvas)
|
||||
}
|
||||
|
||||
private fun drawCenter(canvas: Canvas) {
|
||||
mPaint.color = mUnCheckedColor
|
||||
val radius = (mCenterPoint.x - mStrokeWidth) * mScaleVal
|
||||
canvas.drawCircle(mCenterPoint.x.toFloat(), mCenterPoint.y.toFloat(), radius, mPaint)
|
||||
}
|
||||
|
||||
private fun drawBorder(canvas: Canvas) {
|
||||
mFloorPaint.color = mFloorColor
|
||||
val radius = mCenterPoint.x
|
||||
canvas.drawCircle(
|
||||
mCenterPoint.x.toFloat(),
|
||||
mCenterPoint.y.toFloat(),
|
||||
radius * mFloorScale,
|
||||
mFloorPaint
|
||||
)
|
||||
}
|
||||
|
||||
private fun drawTick(canvas: Canvas) {
|
||||
if (mTickDrawing && isChecked) {
|
||||
drawTickPath(canvas)
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawTickPath(canvas: Canvas) {
|
||||
mTickPath.reset()
|
||||
// draw left of the tick
|
||||
if (mDrewDistance < mLeftLineDistance) {
|
||||
val step: Float = if (mWidth / 20.0f < 3) 3f else mWidth / 20.0f
|
||||
mDrewDistance += step
|
||||
val stopX =
|
||||
mTickPoints[0].x + (mTickPoints[1].x - mTickPoints[0].x) * mDrewDistance / mLeftLineDistance
|
||||
val stopY =
|
||||
mTickPoints[0].y + (mTickPoints[1].y - mTickPoints[0].y) * mDrewDistance / mLeftLineDistance
|
||||
mTickPath.moveTo(mTickPoints[0].x.toFloat(), mTickPoints[0].y.toFloat())
|
||||
mTickPath.lineTo(stopX, stopY)
|
||||
canvas.drawPath(mTickPath, mTickPaint)
|
||||
if (mDrewDistance > mLeftLineDistance) {
|
||||
mDrewDistance = mLeftLineDistance
|
||||
}
|
||||
} else {
|
||||
mTickPath.moveTo(mTickPoints[0].x.toFloat(), mTickPoints[0].y.toFloat())
|
||||
mTickPath.lineTo(mTickPoints[1].x.toFloat(), mTickPoints[1].y.toFloat())
|
||||
canvas.drawPath(mTickPath, mTickPaint)
|
||||
// draw right of the tick
|
||||
if (mDrewDistance < mLeftLineDistance + mRightLineDistance) {
|
||||
val stopX =
|
||||
mTickPoints[1].x + (mTickPoints[2].x - mTickPoints[1].x) * (mDrewDistance - mLeftLineDistance) / mRightLineDistance
|
||||
val stopY =
|
||||
mTickPoints[1].y - (mTickPoints[1].y - mTickPoints[2].y) * (mDrewDistance - mLeftLineDistance) / mRightLineDistance
|
||||
mTickPath.reset()
|
||||
mTickPath.moveTo(mTickPoints[1].x.toFloat(), mTickPoints[1].y.toFloat())
|
||||
mTickPath.lineTo(stopX, stopY)
|
||||
canvas.drawPath(mTickPath, mTickPaint)
|
||||
val step: Float = if (mWidth / 20f < 3) 3f else mWidth / 20f
|
||||
mDrewDistance += step
|
||||
} else {
|
||||
mTickPath.reset()
|
||||
mTickPath.moveTo(mTickPoints[1].x.toFloat(), mTickPoints[1].y.toFloat())
|
||||
mTickPath.lineTo(mTickPoints[2].x.toFloat(), mTickPoints[2].y.toFloat())
|
||||
canvas.drawPath(mTickPath, mTickPaint)
|
||||
}
|
||||
}
|
||||
// invalidate
|
||||
if (mDrewDistance < mLeftLineDistance + mRightLineDistance) {
|
||||
postDelayed(10) { this.postInvalidate() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun startCheckedAnimation() {
|
||||
val animator = ValueAnimator.ofFloat(1.0f, 0f)
|
||||
animator.duration = mAnimDuration / 3 * 2.toLong()
|
||||
animator.interpolator = LinearInterpolator()
|
||||
animator.addUpdateListener { animation: ValueAnimator ->
|
||||
mScaleVal = animation.animatedValue as Float
|
||||
mFloorColor = getGradientColor(
|
||||
mUnCheckedColor,
|
||||
mCheckedColor,
|
||||
1 - mScaleVal
|
||||
)
|
||||
postInvalidate()
|
||||
}
|
||||
animator.start()
|
||||
val floorAnimator = ValueAnimator.ofFloat(1.0f, 0.8f, 1.0f)
|
||||
floorAnimator.duration = mAnimDuration.toLong()
|
||||
floorAnimator.interpolator = LinearInterpolator()
|
||||
floorAnimator.addUpdateListener { animation: ValueAnimator ->
|
||||
mFloorScale = animation.animatedValue as Float
|
||||
postInvalidate()
|
||||
}
|
||||
floorAnimator.start()
|
||||
drawTickDelayed()
|
||||
}
|
||||
|
||||
private fun startUnCheckedAnimation() {
|
||||
val animator = ValueAnimator.ofFloat(0f, 1.0f)
|
||||
animator.duration = mAnimDuration.toLong()
|
||||
animator.interpolator = LinearInterpolator()
|
||||
animator.addUpdateListener { animation: ValueAnimator ->
|
||||
mScaleVal = animation.animatedValue as Float
|
||||
mFloorColor = getGradientColor(
|
||||
mCheckedColor,
|
||||
mFloorUnCheckedColor,
|
||||
mScaleVal
|
||||
)
|
||||
postInvalidate()
|
||||
}
|
||||
animator.start()
|
||||
val floorAnimator = ValueAnimator.ofFloat(1.0f, 0.8f, 1.0f)
|
||||
floorAnimator.duration = mAnimDuration.toLong()
|
||||
floorAnimator.interpolator = LinearInterpolator()
|
||||
floorAnimator.addUpdateListener { animation: ValueAnimator ->
|
||||
mFloorScale = animation.animatedValue as Float
|
||||
postInvalidate()
|
||||
}
|
||||
floorAnimator.start()
|
||||
}
|
||||
|
||||
private fun drawTickDelayed() {
|
||||
postDelayed(mAnimDuration.toLong()) {
|
||||
mTickDrawing = true
|
||||
postInvalidate()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DEF_DRAW_SIZE = 25
|
||||
private const val DEF_ANIM_DURATION = 300
|
||||
private fun getGradientColor(startColor: Int, endColor: Int, percent: Float): Int {
|
||||
val startA = Color.alpha(startColor)
|
||||
val startR = Color.red(startColor)
|
||||
val startG = Color.green(startColor)
|
||||
val startB = Color.blue(startColor)
|
||||
val endA = Color.alpha(endColor)
|
||||
val endR = Color.red(endColor)
|
||||
val endG = Color.green(endColor)
|
||||
val endB = Color.blue(endColor)
|
||||
val currentA = (startA * (1 - percent) + endA * percent).toInt()
|
||||
val currentR = (startR * (1 - percent) + endR * percent).toInt()
|
||||
val currentG = (startG * (1 - percent) + endG * percent).toInt()
|
||||
val currentB = (startB * (1 - percent) + endB * percent).toInt()
|
||||
return Color.argb(currentA, currentR, currentG, currentB)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import io.legato.kazusa.lib.theme.ThemeStore
|
||||
class PrimaryTextView(context: Context, attrs: AttributeSet) :
|
||||
AppCompatTextView(context, attrs) {
|
||||
|
||||
init {
|
||||
setTextColor(ThemeStore.textColorPrimary(context))
|
||||
}
|
||||
// init {
|
||||
// setTextColor(ThemeStore.textColorPrimary(context))
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
package io.legato.kazusa.ui.widget.text
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.lib.theme.*
|
||||
import io.legato.kazusa.utils.dpToPx
|
||||
import io.legato.kazusa.utils.getCompatColor
|
||||
|
||||
@Suppress("unused")
|
||||
open class StrokeTextView(context: Context, attrs: AttributeSet?) :
|
||||
AppCompatTextView(context, attrs) {
|
||||
|
||||
private var radius = 1.dpToPx()
|
||||
private val isBottomBackground: Boolean
|
||||
|
||||
init {
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.StrokeTextView)
|
||||
radius = typedArray.getDimensionPixelOffset(R.styleable.StrokeTextView_radius, radius)
|
||||
isBottomBackground =
|
||||
typedArray.getBoolean(R.styleable.StrokeTextView_isBottomBackground, false)
|
||||
typedArray.recycle()
|
||||
upBackground()
|
||||
}
|
||||
|
||||
fun setRadius(radius: Int) {
|
||||
this.radius = radius.dpToPx()
|
||||
upBackground()
|
||||
}
|
||||
|
||||
private fun upBackground() {
|
||||
when {
|
||||
isInEditMode -> {
|
||||
background = Selector.shapeBuild()
|
||||
.setCornerRadius(radius)
|
||||
.setStrokeWidth(1.dpToPx())
|
||||
.setDisabledStrokeColor(context.getCompatColor(R.color.md_grey_500))
|
||||
.setDefaultStrokeColor(context.getCompatColor(R.color.secondaryText))
|
||||
//.setSelectedStrokeColor(context.getCompatColor(R.color.accent))
|
||||
.setPressedBgColor(context.getCompatColor(R.color.transparent30))
|
||||
.create()
|
||||
setTextColor(
|
||||
Selector.colorBuild()
|
||||
.setDefaultColor(context.getCompatColor(R.color.secondaryText))
|
||||
//.setSelectedColor(context.getCompatColor(R.color.accent))
|
||||
.setDisabledColor(context.getCompatColor(R.color.md_grey_500))
|
||||
.create()
|
||||
)
|
||||
}
|
||||
isBottomBackground -> {
|
||||
//val isLight = ColorUtils.isColorLight(context.bottomBackground)
|
||||
background = Selector.shapeBuild()
|
||||
.setCornerRadius(radius)
|
||||
.setStrokeWidth(1.dpToPx())
|
||||
.setDisabledStrokeColor(context.getCompatColor(R.color.md_grey_500))
|
||||
// .setDefaultStrokeColor(context.getPrimaryTextColor(isLight))
|
||||
// .setSelectedStrokeColor(context.accentColor)
|
||||
.setPressedBgColor(context.getCompatColor(R.color.transparent30))
|
||||
.create()
|
||||
setTextColor(
|
||||
Selector.colorBuild()
|
||||
// .setDefaultColor(context.getPrimaryTextColor(isLight))
|
||||
// .setSelectedColor(context.accentColor)
|
||||
.setDisabledColor(context.getCompatColor(R.color.md_grey_500))
|
||||
.create()
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
background = Selector.shapeBuild()
|
||||
.setCornerRadius(radius)
|
||||
.setStrokeWidth(1.dpToPx())
|
||||
.setDisabledStrokeColor(context.getCompatColor(R.color.md_grey_500))
|
||||
.setDefaultStrokeColor(ThemeStore.textColorSecondary(context))
|
||||
.setSelectedStrokeColor(ThemeStore.accentColor(context))
|
||||
.setPressedBgColor(context.getCompatColor(R.color.transparent30))
|
||||
.create()
|
||||
setTextColor(
|
||||
Selector.colorBuild()
|
||||
.setDefaultColor(ThemeStore.textColorSecondary(context))
|
||||
.setSelectedColor(ThemeStore.accentColor(context))
|
||||
.setDisabledColor(context.getCompatColor(R.color.md_grey_500))
|
||||
.create()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user