diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c6970e --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +*.iml +.gradle +.idea +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/gradle +/gradlew +/gradlew.bat +/captures +/.idea +.externalNativeBuild diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..44e5537 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,3 @@ +/build +*.iml +/release diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..e550c74 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 29 + defaultConfig { + applicationId "com.devzone.checkabletextview" + minSdkVersion 17 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.core:core-ktx:1.0.2' + implementation project(path: ':checkabletextview') + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2baf89b --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/devzone/ctv_sample/MainActivity.kt b/app/src/main/java/com/devzone/ctv_sample/MainActivity.kt new file mode 100644 index 0000000..a4e763c --- /dev/null +++ b/app/src/main/java/com/devzone/ctv_sample/MainActivity.kt @@ -0,0 +1,24 @@ +package com.devzone.ctv_sample + +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AppCompatActivity +import com.devzone.checkabletextview.CheckableTextView +import kotlinx.android.synthetic.main.activity_main.* + + +class MainActivity : AppCompatActivity(), CheckableTextView.CheckedListener { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + checkedTV.setOnCheckChangeListener(this@MainActivity) + checkedSecondTV.setOnCheckChangeListener(this@MainActivity) + } + + override fun onCheckChange(view: View, isChecked: Boolean) { + when (view.id) { + R.id.checkedTV -> stateTV.text = if (isChecked) "Checked" else "Unchecked" + R.id.checkedSecondTV -> stateSecondTV.text = if (isChecked) "Checked" else "Unchecked" + } + } +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..6348baa --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_cancel_custom_vector.xml b/app/src/main/res/drawable/ic_cancel_custom_vector.xml new file mode 100644 index 0000000..7d2b57e --- /dev/null +++ b/app/src/main/res/drawable/ic_cancel_custom_vector.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..a0ad202 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/font/poppins_light.ttf b/app/src/main/res/font/poppins_light.ttf new file mode 100644 index 0000000..1e74b8a Binary files /dev/null and b/app/src/main/res/font/poppins_light.ttf differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..37b9760 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..bbd3e02 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..bbd3e02 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..898f3ed Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..dffca36 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..64ba76f Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..dae5e08 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..e5ed465 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..14ed0af Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..b0907ca Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..d8ae031 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..2c18de9 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..beed3cd Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..69b2233 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #008577 + #00574B + #D81B60 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..6bb80ba --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + CheckableTextView + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..c1b52fe --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..438d280 --- /dev/null +++ b/build.gradle @@ -0,0 +1,28 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.kotlin_version = '1.3.41' + repositories { + google() + jcenter() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.4.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/checkabletextview/.gitignore b/checkabletextview/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/checkabletextview/.gitignore @@ -0,0 +1 @@ +/build diff --git a/checkabletextview/build.gradle b/checkabletextview/build.gradle new file mode 100644 index 0000000..d0f3cf4 --- /dev/null +++ b/checkabletextview/build.gradle @@ -0,0 +1,38 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion 29 + + + defaultConfig { + minSdkVersion 17 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + vectorDrawables.useSupportLibrary = true + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation "androidx.core:core-ktx:1.0.2" + implementation 'androidx.vectordrawable:vectordrawable:1.1.0-rc01' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + +} +repositories { + mavenCentral() +} diff --git a/checkabletextview/proguard-rules.pro b/checkabletextview/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/checkabletextview/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/checkabletextview/src/main/AndroidManifest.xml b/checkabletextview/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f267354 --- /dev/null +++ b/checkabletextview/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/checkabletextview/src/main/java/com/devzone/checkabletextview/CheckableTextView.kt b/checkabletextview/src/main/java/com/devzone/checkabletextview/CheckableTextView.kt new file mode 100644 index 0000000..c40f2d1 --- /dev/null +++ b/checkabletextview/src/main/java/com/devzone/checkabletextview/CheckableTextView.kt @@ -0,0 +1,147 @@ +package com.devzone.checkabletextview + +import android.content.Context +import android.content.res.TypedArray +import android.graphics.drawable.ColorDrawable +import android.os.Build +import android.util.AttributeSet +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.widget.RelativeLayout +import androidx.appcompat.app.AppCompatDelegate +import androidx.core.content.ContextCompat +import kotlinx.android.synthetic.main.layout_checkable_text.view.* + + +class CheckableTextView : RelativeLayout { + + private var isChecked: Boolean = true + private var listener: CheckedListener? = null + private val defaultCheckIcon = R.drawable.ic_check_circle_vector + private val defaultTextColor = android.R.color.black + private val defaultIconTintColor = android.R.color.transparent + private var checkIcon = defaultCheckIcon + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) { + init(context, attributeSet) + } + + constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super( + context, + attributeSet, + defStyleAttr + ) { + init(context, attributeSet) + } + + + private fun init(context: Context, attributeSet: AttributeSet?) { + AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) + + LayoutInflater.from(context).inflate( + R.layout.layout_checkable_text, + this, true) + attributeSet.let { + val array: TypedArray = context.obtainStyledAttributes(attributeSet, R.styleable.CheckableTextView) + val iconTint = array.getColor( + R.styleable.CheckableTextView_ctv_IconTint, + ContextCompat.getColor(context, defaultIconTintColor) + ) + val textColor = array.getColor( + R.styleable.CheckableTextView_ctv_TextColor, + ContextCompat.getColor(context, defaultTextColor) + ) + val text = array.getString(R.styleable.CheckableTextView_ctv_Text) + isChecked = array.getBoolean(R.styleable.CheckableTextView_ctv_IconChecked, false) + val textSize = array.getDimensionPixelSize(R.styleable.CheckableTextView_ctv_TextSize, 0) + val textStyle = array.getResourceId(R.styleable.CheckableTextView_ctv_TextStyle, 0) + checkIcon = array.getResourceId(R.styleable.CheckableTextView_ctv_Icon, 0) + + //giving applied style attrs least preference (colors n text size will be override by ctv_TextColor & ctv_TextSize as applied later) + applyTextStyle(textStyle, context) + validateCheckIcon(context) + checkedTextTV.text = text + checkedTextTV.isSelected = true + checkedTextTV.setTextColor(textColor) + checkedIV.setImageResource(checkIcon) + + if (isValidRes(textSize)) + checkedTextTV.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize.toFloat()) + if (isValidRes(iconTint)) + checkedIV.setColorFilter(iconTint) + + array.recycle() + } + + animateView(checkedIV, isChecked) + rootRL.setOnClickListener { + checkedTextTV.text = checkedTextTV.text + checkedTextTV.isSelected = true + isChecked = !isChecked + animateView(checkedIV, isChecked) + notifyListener(isChecked) + } + } + + private fun applyTextStyle(textStyle: Int, context: Context) { + if (isValidRes(textStyle)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + checkedTextTV.setTextAppearance(textStyle) + } else { + checkedTextTV.setTextAppearance(context, textStyle) + } + } + } + + private fun animateView(view: View, show: Boolean) { + view.clearAnimation() + val scale = if (show) 1f else 0f + val rotation = if (show) 360f else -360f + view.animate().setStartDelay(20).scaleX(scale).scaleY(scale).rotation(rotation).setDuration(250) + .start() + } + + private fun validateCheckIcon(context: Context) { + if (isValidRes(checkIcon)) { + val drawableIcon = ContextCompat.getDrawable(context, checkIcon) + if (drawableIcon == null) checkIcon = defaultCheckIcon + drawableIcon.let { + if (it is ColorDrawable) { + checkIcon = defaultCheckIcon + } + } + } else checkIcon = defaultCheckIcon + } + + + private fun isValidRes(res: Int) = res != 0 + + private fun notifyListener(isChecked: Boolean) { + listener?.onCheckChange(this, isChecked) + } + + fun setOnCheckChangeListener(listener: CheckedListener) { + this.listener = listener + } + + fun setChecked(isChecked: Boolean, shouldNotifyListeners: Boolean) { + this.isChecked = isChecked + animateView(checkedIV, isChecked) + if (shouldNotifyListeners) + notifyListener(isChecked) + } + + fun setChecked(isChecked: Boolean) { + setChecked(isChecked, false) + } + + interface CheckedListener { + + fun onCheckChange(view: View, isChecked: Boolean) + } +} \ No newline at end of file diff --git a/checkabletextview/src/main/res/drawable/ic_check_circle_vector.xml b/checkabletextview/src/main/res/drawable/ic_check_circle_vector.xml new file mode 100644 index 0000000..1241eda --- /dev/null +++ b/checkabletextview/src/main/res/drawable/ic_check_circle_vector.xml @@ -0,0 +1,9 @@ + + + diff --git a/checkabletextview/src/main/res/layout/layout_checkable_text.xml b/checkabletextview/src/main/res/layout/layout_checkable_text.xml new file mode 100644 index 0000000..2185d13 --- /dev/null +++ b/checkabletextview/src/main/res/layout/layout_checkable_text.xml @@ -0,0 +1,37 @@ + + + + + + + + + diff --git a/checkabletextview/src/main/res/values/attrs.xml b/checkabletextview/src/main/res/values/attrs.xml new file mode 100644 index 0000000..6c0a23b --- /dev/null +++ b/checkabletextview/src/main/res/values/attrs.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/checkabletextview/src/main/res/values/colors.xml b/checkabletextview/src/main/res/values/colors.xml new file mode 100644 index 0000000..c6debb1 --- /dev/null +++ b/checkabletextview/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #464646 + diff --git a/checkabletextview/src/main/res/values/strings.xml b/checkabletextview/src/main/res/values/strings.xml new file mode 100644 index 0000000..6bb80ba --- /dev/null +++ b/checkabletextview/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + CheckableTextView + diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..23339e0 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..60a5c95 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app', ':checkabletextview'