From 7fb882d2900e0a0b89d427ae33267e7b7840a34e Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Sun, 23 Oct 2022 13:20:42 +0100 Subject: [PATCH 01/15] Migrated project to Gradle 7.5.1 --- app/build.gradle | 33 +++++----- build.gradle | 29 ++------- gradle.properties | 8 ++- gradle/wrapper/gradle-wrapper.properties | 6 +- settings.gradle | 15 +++++ simplesearchview/build.gradle | 79 ++++++++++++------------ 6 files changed, 81 insertions(+), 89 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 02b7c56..e006f32 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,20 +1,20 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} android { - compileSdkVersion rootProject.compileSdkVersion + compileSdkVersion 32 defaultConfig { applicationId 'com.ferfalk.simplesearchviewexample' - minSdkVersion rootProject.minSdkVersion - targetSdkVersion rootProject.compileSdkVersion + minSdkVersion 21 + targetSdkVersion 32 versionCode 1 versionName '1.0' testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } - buildFeatures { - viewBinding = true - } +// buildFeatures {viewBinding = true} buildTypes { release { minifyEnabled true @@ -26,25 +26,20 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() + jvmTarget = '1.8' } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "androidx.core:core-ktx:1.3.1" + implementation "androidx.core:core-ktx:1.8.0" - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.1' - implementation 'com.google.android.material:material:1.2.1' + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'com.google.android.material:material:1.6.1' implementation project(':simplesearchview') testImplementation 'junit:junit:4.13' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' -} -repositories { - mavenCentral() + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' } diff --git a/build.gradle b/build.gradle index 227df10..62d0e4c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,31 +1,10 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - ext.kotlin_version = '1.4.0' - - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' - classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } +plugins { + id 'com.android.application' version '7.2.0' apply false + id 'com.android.library' version '7.2.0' apply false + id 'org.jetbrains.kotlin.android' version '1.6.21' apply false } task clean(type: Delete) { delete rootProject.buildDir -} - -ext { - compileSdkVersion = 30 - minSdkVersion = 16 } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 8de5058..5a32bbf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,13 @@ # The setting is particularly useful for tweaking memory settings. android.enableJetifier=true android.useAndroidX=true -org.gradle.jvmargs=-Xmx1536m +org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.parallel=true +org.gradle.daemon=true +org.gradle.configureondemand=true +org.gradle.caching=true +org.gradle.unsafe.configuration-cache=true +org.gragle.warning.mode=none # 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 188807f..8731f18 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Sep 05 18:50:01 CEST 2020 +#Sun Oct 23 12:22:34 GMT+01:00 2022 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle b/settings.gradle index ba0a130..e739cb4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "SimpleSearchView" include ':app', ':simplesearchview' diff --git a/simplesearchview/build.gradle b/simplesearchview/build.gradle index 8b5e9ba..39da718 100644 --- a/simplesearchview/build.gradle +++ b/simplesearchview/build.gradle @@ -1,21 +1,23 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'com.github.dcendents.android-maven' +//apply plugin: 'com.github.dcendents.android-maven' +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} android { - compileSdkVersion rootProject.compileSdkVersion + compileSdkVersion 32 defaultConfig { - minSdkVersion rootProject.minSdkVersion - targetSdkVersion rootProject.compileSdkVersion + minSdkVersion 21 + targetSdkVersion 32 versionCode 20 versionName "0.2.0" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' vectorDrawables.useSupportLibrary = true } - buildFeatures { - viewBinding = true - } +// buildFeatures { +// viewBinding = true +// } buildTypes { release { minifyEnabled false @@ -27,45 +29,40 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() + jvmTarget = '1.8' } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "androidx.core:core-ktx:1.3.1" + implementation "androidx.core:core-ktx:1.8.0" - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.1' - implementation 'com.google.android.material:material:1.2.1' + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'com.google.android.material:material:1.6.1' testImplementation 'junit:junit:4.13' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' -} - -task sourcesJar(type: Jar) { - from android.sourceSets.main.java.srcDirs - getArchiveClassifier().value('sources') -} - -task javadoc(type: Javadoc) { - failOnError false - source = android.sourceSets.main.java.sourceFiles - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - classpath += configurations.compile -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - getArchiveClassifier().value('javadoc') - from javadoc.destinationDir + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' } -artifacts { - archives sourcesJar - archives javadocJar -} -repositories { - mavenCentral() -} +//task sourcesJar(type: Jar) { +// from android.sourceSets.main.java.srcDirs +// getArchiveClassifier().value('sources') +//} +// +//task javadoc(type: Javadoc) { +// failOnError false +// source = android.sourceSets.main.java.sourceFiles +// classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) +// classpath += configurations.compile +//} +// +//task javadocJar(type: Jar, dependsOn: javadoc) { +// getArchiveClassifier().value('javadoc') +// from javadoc.destinationDir +//} +// +//artifacts { +// archives sourcesJar +// archives javadocJar +//} \ No newline at end of file From e2126b9de913dd03cfa492181a9bd2d4e10f5838 Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Sun, 23 Oct 2022 13:25:59 +0100 Subject: [PATCH 02/15] ContextUtils.kt: Using Android platform R class to access theme colors --- .../java/com/ferfalk/simplesearchview/utils/ContextUtils.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/ContextUtils.kt b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/ContextUtils.kt index f13e6ef..f3a5ebc 100644 --- a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/ContextUtils.kt +++ b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/ContextUtils.kt @@ -7,7 +7,6 @@ import android.util.TypedValue import android.view.View import android.view.inputmethod.InputMethodManager import androidx.annotation.ColorInt -import com.ferfalk.simplesearchview.R /** * @author Fernando A. H. Falkiewicz @@ -26,7 +25,7 @@ object ContextUtils { @ColorInt fun getPrimaryColor(context: Context): Int { val value = TypedValue() - context.theme.resolveAttribute(R.attr.colorPrimary, value, true) + context.theme.resolveAttribute(android.R.attr.colorPrimary, value, true) return value.data } @@ -34,7 +33,7 @@ object ContextUtils { @ColorInt fun getAccentColor(context: Context): Int { val value = TypedValue() - context.theme.resolveAttribute(R.attr.colorAccent, value, true) + context.theme.resolveAttribute(android.R.attr.colorAccent, value, true) return value.data } From 34909bb1c3eda24298b8ed58d57feb0f8995b1c6 Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Sun, 23 Oct 2022 13:34:46 +0100 Subject: [PATCH 03/15] EditTextReflectionUtils.kt: Using EditText API to change cursor drawable on Android Q and above --- .../utils/EditTextReflectionUtils.kt | 72 +++++++++++-------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/EditTextReflectionUtils.kt b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/EditTextReflectionUtils.kt index eaaefe4..41caeb6 100644 --- a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/EditTextReflectionUtils.kt +++ b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/EditTextReflectionUtils.kt @@ -1,10 +1,12 @@ package com.ferfalk.simplesearchview.utils -import android.graphics.PorterDuff -import android.graphics.drawable.Drawable +import android.annotation.SuppressLint +import android.graphics.drawable.ColorDrawable +import android.os.Build import android.util.Log import android.widget.EditText import android.widget.TextView +import androidx.annotation.ChecksSdkIntAtLeast import androidx.annotation.ColorInt import androidx.core.content.ContextCompat import androidx.core.graphics.BlendModeColorFilterCompat @@ -22,45 +24,59 @@ object EditTextReflectionUtils { /** * Uses reflection to set an EditText cursor drawable */ + @SuppressLint("DiscouragedPrivateApi") @JvmStatic fun setCursorDrawable(editText: EditText, drawable: Int) { - try { - // https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564 - val f = TextView::class.java.getDeclaredField(EDIT_TEXT_FIELD_CURSOR_DRAWABLE_RES) - f.isAccessible = true - f[editText] = drawable - } catch (e: Exception) { - Log.e(TAG, e.message, e) + if (isAndroidQ()) { + editText.setTextCursorDrawable(drawable) + } else { + try { + // https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564 + val f = TextView::class.java.getDeclaredField(EDIT_TEXT_FIELD_CURSOR_DRAWABLE_RES) + f.isAccessible = true + f[editText] = drawable + } catch (e: Exception) { + Log.e(TAG, e.message, e) + } + } } /** * Uses reflection to set an EditText cursor color */ + @SuppressLint("DiscouragedPrivateApi") @JvmStatic fun setCursorColor(editText: EditText, @ColorInt color: Int) { - try { - // Get the cursor resource id - var field = TextView::class.java.getDeclaredField(EDIT_TEXT_FIELD_CURSOR_DRAWABLE_RES) - field.isAccessible = true - val drawableResId = field.getInt(editText) + if (isAndroidQ()) { + editText.textCursorDrawable = ColorDrawable(color) + } else { + try { + // Get the cursor resource id + var field = TextView::class.java.getDeclaredField(EDIT_TEXT_FIELD_CURSOR_DRAWABLE_RES) + field.isAccessible = true + val drawableResId = field.getInt(editText) - // Get the editor - field = TextView::class.java.getDeclaredField(EDIT_TEXT_FIELD_EDITOR) - field.isAccessible = true - val editor = field[editText] + // Get the editor + field = TextView::class.java.getDeclaredField(EDIT_TEXT_FIELD_EDITOR) + field.isAccessible = true + val editor = field[editText] - // Get the drawable and set a color filter - val drawable = ContextCompat.getDrawable(editText.context, drawableResId) - drawable?.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_IN) - val drawables = arrayOf(drawable, drawable) + // Get the drawable and set a color filter + val drawable = ContextCompat.getDrawable(editText.context, drawableResId) + drawable?.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_IN) + val drawables = arrayOf(drawable, drawable) - // Set the drawables - field = editor.javaClass.getDeclaredField(EDIT_TEXT_FIELD_CURSOR_DRAWABLE) - field.isAccessible = true - field[editor] = drawables - } catch (e: Exception) { - Log.e(TAG, e.message, e) + // Set the drawables + field = editor.javaClass.getDeclaredField(EDIT_TEXT_FIELD_CURSOR_DRAWABLE) + field.isAccessible = true + field[editor] = drawables + } catch (e: Exception) { + Log.e(TAG, e.message, e) + } } } + + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.Q) + fun isAndroidQ() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q } \ No newline at end of file From 541a3488befe596d806e585203f103ddd5cb5aaa Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Sun, 23 Oct 2022 13:41:58 +0100 Subject: [PATCH 04/15] SimpleAnimationUtils.kt: Removed obsolete SDK checks --- .../utils/SimpleAnimationUtils.kt | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/SimpleAnimationUtils.kt b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/SimpleAnimationUtils.kt index 0522d74..b67ca50 100644 --- a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/SimpleAnimationUtils.kt +++ b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/utils/SimpleAnimationUtils.kt @@ -5,14 +5,10 @@ import android.animation.AnimatorListenerAdapter import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.graphics.Point -import android.os.Build import android.view.View import android.view.ViewAnimationUtils import android.view.animation.Interpolator -import androidx.annotation.RequiresApi -import androidx.core.animation.addListener import androidx.interpolator.view.animation.FastOutSlowInInterpolator -import java.util.* import kotlin.math.ceil import kotlin.math.pow import kotlin.math.sqrt @@ -26,11 +22,7 @@ object SimpleAnimationUtils { @JvmStatic @JvmOverloads fun revealOrFadeIn(view: View, duration: Int = ANIMATION_DURATION_DEFAULT, listener: AnimationListener? = null, center: Point? = null): Animator { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - reveal(view, duration, listener, center) - } else { - fadeIn(view, duration, listener) - } + return reveal(view, duration, listener, center) } @JvmStatic @@ -58,11 +50,7 @@ object SimpleAnimationUtils { @JvmStatic @JvmOverloads fun hideOrFadeOut(view: View, duration: Int = ANIMATION_DURATION_DEFAULT, listener: AnimationListener? = null, center: Point? = null): Animator { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - hide(view, duration, listener, center) - } else { - fadeOut(view, duration, listener) - } + return hide(view, duration, listener, center) } @JvmStatic @@ -87,49 +75,41 @@ object SimpleAnimationUtils { - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun reveal(view: View, duration: Int): Animator { return reveal(view, duration, null, null) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun reveal(view: View, duration: Int, center: Point?): Animator { return reveal(view, duration, null, center) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun reveal(view: View, duration: Int, listener: AnimationListener?): Animator { return reveal(view, duration, listener, null) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun reveal(view: View): Animator { return reveal(view, ANIMATION_DURATION_DEFAULT) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun reveal(view: View, listener: AnimationListener?): Animator { return reveal(view, ANIMATION_DURATION_DEFAULT, listener, null) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun reveal(view: View, center: Point?): Animator { return reveal(view, ANIMATION_DURATION_DEFAULT, null, center) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun reveal(view: View, listener: AnimationListener?, center: Point?): Animator { return reveal(view, ANIMATION_DURATION_DEFAULT, listener, center) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun reveal(view: View, duration: Int, listener: AnimationListener?, center: Point?): Animator { var centerMutable = center @@ -150,49 +130,41 @@ object SimpleAnimationUtils { - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun hide(view: View, duration: Int): Animator { return hide(view, duration, null, null) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun hide(view: View, duration: Int, center: Point?): Animator { return hide(view, duration, null, center) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun hide(view: View, duration: Int, listener: AnimationListener?): Animator { return hide(view, duration, listener, null) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun hide(view: View): Animator { return hide(view, ANIMATION_DURATION_DEFAULT) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun hide(view: View, listener: AnimationListener?): Animator { return hide(view, ANIMATION_DURATION_DEFAULT, listener, null) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun hide(view: View, center: Point?): Animator { return hide(view, ANIMATION_DURATION_DEFAULT, null, center) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun hide(view: View, listener: AnimationListener?, center: Point?): Animator { return hide(view, ANIMATION_DURATION_DEFAULT, listener, center) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @JvmStatic fun hide(view: View, duration: Int, listener: AnimationListener?, center: Point?): Animator { var centerMutable = center From 2cc28dfebe41294421d81b75f7306bfcc97f3d85 Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Sun, 23 Oct 2022 13:44:14 +0100 Subject: [PATCH 05/15] search_view.xml: Using app:tint to tint ImageButton --- simplesearchview/src/main/res/layout/search_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simplesearchview/src/main/res/layout/search_view.xml b/simplesearchview/src/main/res/layout/search_view.xml index ca454b7..6f86350 100644 --- a/simplesearchview/src/main/res/layout/search_view.xml +++ b/simplesearchview/src/main/res/layout/search_view.xml @@ -36,9 +36,9 @@ android:layout_height="match_parent" android:alpha="0.87" android:contentDescription="@string/action_back" - android:tint="?attr/colorPrimary" app:layout_constraintStart_toStartOf="parent" - app:srcCompat="@drawable/ic_arrow_back_black_24dp" /> + app:srcCompat="@drawable/ic_arrow_back_black_24dp" + app:tint="?attr/colorPrimary" /> Date: Mon, 24 Oct 2022 20:16:48 +0100 Subject: [PATCH 06/15] SimpleSearchView.kt: Changed viewBinding to legacy findViewById() --- .../simplesearchview/SimpleSearchView.kt | 140 ++++++++++-------- 1 file changed, 78 insertions(+), 62 deletions(-) diff --git a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt index f480dc3..63bf4c4 100644 --- a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt +++ b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt @@ -1,5 +1,6 @@ package com.ferfalk.simplesearchview +import android.annotation.SuppressLint import android.app.Activity import android.content.Context import android.content.Intent @@ -19,14 +20,17 @@ import android.util.Log import android.view.* import android.view.View.OnFocusChangeListener import android.view.inputmethod.EditorInfo +import android.widget.EditText import android.widget.FrameLayout +import android.widget.ImageButton import android.widget.TextView import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.annotation.IntDef +import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat +import androidx.core.text.trimmedLength import androidx.core.widget.ImageViewCompat -import com.ferfalk.simplesearchview.databinding.SearchViewBinding import com.ferfalk.simplesearchview.utils.ContextUtils.getAccentColor import com.ferfalk.simplesearchview.utils.ContextUtils.getPrimaryColor import com.ferfalk.simplesearchview.utils.ContextUtils.hideKeyboard @@ -45,7 +49,21 @@ import com.google.android.material.tabs.TabLayout /** * @author Fernando A. H. Falkiewicz */ +@SuppressLint("InflateParams") class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : FrameLayout(creationContext, attrs, defStyleAttr) { + + companion object { + const val REQUEST_VOICE_SEARCH = 735 + const val CARD_CORNER_RADIUS = 4 + const val ANIMATION_CENTER_PADDING = 26 + private const val CARD_PADDING = 6 + private const val CARD_ELEVATION = 2 + private const val BACK_ICON_ALPHA_DEFAULT = 0.87f + private const val ICONS_ALPHA_DEFAULT = 0.54f + const val STYLE_BAR = 0 + const val STYLE_CARD = 1 + } + @IntDef(STYLE_BAR, STYLE_CARD) @kotlin.annotation.Retention(AnnotationRetention.SOURCE) annotation class Style @@ -94,7 +112,23 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs private var searchIsClosing = false private var keepQuery = false - private val binding = SearchViewBinding.inflate(LayoutInflater.from(context), this, true) + private val root by lazy { LayoutInflater.from(context).inflate(R.layout.search_view, null) } + private val searchContainer by lazy { root.findViewById(R.id.searchContainer) } + private val searchEditText by lazy { root.findViewById(R.id.searchEditText) } + private val backButton by lazy { root.findViewById(R.id.backButton) } + private val voiceButton by lazy { root.findViewById(R.id.voiceButton) } + private val clearButton by lazy { root.findViewById(R.id.clearButton) } + private val bottomLine by lazy { root.findViewById(R.id.bottomLine) } + + init { + initStyle(attrs, defStyleAttr) + initSearchEditText() + initClickListeners() + showVoice(true) + if (!isInEditMode) { + visibility = INVISIBLE + } + } private fun initStyle(attrs: AttributeSet?, defStyleAttr: Int) { val typedArray = context.obtainStyledAttributes(attrs, R.styleable.SimpleSearchView, defStyleAttr, 0) @@ -149,32 +183,32 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs typedArray.recycle() } - private fun initSearchEditText() = with(binding) { - searchEditText.setOnEditorActionListener { _: TextView?, _: Int, _: KeyEvent? -> + private fun initSearchEditText() = with(searchEditText) { + setOnEditorActionListener { _: TextView?, _: Int, _: KeyEvent? -> onSubmitQuery() true } - searchEditText.addTextChangedListener(object : SimpleTextWatcher() { + addTextChangedListener(object : SimpleTextWatcher() { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { if (!searchIsClosing) { this@SimpleSearchView.onTextChanged(s) } } }) - searchEditText.onFocusChangeListener = OnFocusChangeListener { _: View?, hasFocus: Boolean -> + onFocusChangeListener = OnFocusChangeListener { _: View?, hasFocus: Boolean -> if (hasFocus) { showKeyboard(searchEditText) } } } - private fun initClickListeners() = with(binding) { + private fun initClickListeners() { backButton.setOnClickListener { closeSearch() } clearButton.setOnClickListener { clearSearch() } voiceButton.setOnClickListener { voiceSearch() } } - override fun clearFocus() = with(binding) { + override fun clearFocus() { isClearingFocus = true hideKeyboard(this@SimpleSearchView) super.clearFocus() @@ -182,7 +216,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs isClearingFocus = false } - override fun requestFocus(direction: Int, previouslyFocusedRect: Rect?): Boolean = with(binding) { + override fun requestFocus(direction: Int, previouslyFocusedRect: Rect?): Boolean { if (isClearingFocus) { return false } @@ -228,14 +262,14 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs activity.startActivityForResult(intent, REQUEST_VOICE_SEARCH) } - private fun clearSearch() = with(binding) { + private fun clearSearch() { searchEditText.text = null onQueryChangeListener?.onQueryTextCleared() } - private fun onTextChanged(newText: CharSequence) = with(binding) { + private fun onTextChanged(newText: CharSequence) { query = newText - val hasText = !TextUtils.isEmpty(newText) + val hasText = newText.isNotEmpty() if (hasText) { clearButton.visibility = VISIBLE showVoice(false) @@ -243,20 +277,23 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs clearButton.visibility = GONE showVoice(true) } + if(newText == oldQuery) if (!TextUtils.equals(newText, oldQuery)) { onQueryChangeListener?.onQueryTextChange(newText.toString()) } oldQuery = newText.toString() } - private fun onSubmitQuery() = with(binding) { + private fun onSubmitQuery() { val submittedQuery: CharSequence? = searchEditText.text - if (submittedQuery != null && TextUtils.getTrimmedLength(submittedQuery) > 0) { - if(onQueryChangeListener == null || !onQueryChangeListener!!.onQueryTextSubmit(submittedQuery.toString())) { - closeSearch() - searchIsClosing = true - searchEditText.text = null - searchIsClosing = false + submittedQuery?.let { + if(it.trimmedLength() > 0) { + if(onQueryChangeListener == null || !onQueryChangeListener!!.onQueryTextSubmit(submittedQuery.toString())) { + closeSearch() + searchIsClosing = true + searchEditText.text = null + searchIsClosing = false + } } } } @@ -285,9 +322,9 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs * @param animate true to animate */ @JvmOverloads - fun showSearch(animate: Boolean = true) = with(binding) { + fun showSearch(animate: Boolean = true) { if (isSearchOpen) { - return null + return } searchEditText.setText(if (keepQuery) query else null) searchEditText.requestFocus() @@ -313,9 +350,9 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs * @param animate true if should be animated */ @JvmOverloads - fun closeSearch(animate: Boolean = true) = with(binding) { + fun closeSearch(animate: Boolean = true) { if (!isSearchOpen) { - return null + return } searchIsClosing = true searchEditText.text = null @@ -438,7 +475,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs @get:Style var cardStyle: Int get() = style - set(value) = with(binding) { + set(value) { style = value val layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) var elevation = 0f @@ -447,7 +484,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs searchContainer.background = cardStyleBackground bottomLine.visibility = GONE val cardPadding = convertDpToPx(CARD_PADDING, context) - layoutParams.setMargins(cardPadding, cardPadding, cardPadding, cardPadding) + cardPadding.let{ layoutParams.setMargins(it, it, it, it) } elevation = convertDpToPx(CARD_ELEVATION, context).toFloat() } STYLE_BAR -> { @@ -475,7 +512,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs /** * Sets icons alpha, does not set the back/up icon */ - fun setIconsAlpha(alpha: Float) = with(binding) { + fun setIconsAlpha(alpha: Float) { clearButton.alpha = alpha voiceButton.alpha = alpha } @@ -483,7 +520,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs /** * Sets icons colors, does not set back/up icon */ - fun setIconsColor(@ColorInt color: Int) = with(binding) { + fun setIconsColor(@ColorInt color: Int) { ImageViewCompat.setImageTintList(clearButton, ColorStateList.valueOf(color)) ImageViewCompat.setImageTintList(voiceButton, ColorStateList.valueOf(color)) } @@ -491,69 +528,69 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs /** * Sets the back/up icon alpha; does not set other icons */ - fun setBackIconAlpha(alpha: Float) = with(binding) { + fun setBackIconAlpha(alpha: Float) { backButton.alpha = alpha } /** * Sets the back/up icon drawable; does not set other icons */ - fun setBackIconColor(@ColorInt color: Int) = with(binding) { + fun setBackIconColor(@ColorInt color: Int) { ImageViewCompat.setImageTintList(backButton, ColorStateList.valueOf(color)) } /** * Sets the back/up icon drawable */ - fun setBackIconDrawable(drawable: Drawable?) = with(binding) { + fun setBackIconDrawable(drawable: Drawable?) { backButton.setImageDrawable(drawable) } /** * Sets a custom Drawable for the voice search button */ - fun setVoiceIconDrawable(drawable: Drawable?) = with(binding) { + fun setVoiceIconDrawable(drawable: Drawable?) { voiceButton.setImageDrawable(drawable) } /** * Sets a custom Drawable for the clear text button */ - fun setClearIconDrawable(drawable: Drawable?) = with(binding) { + fun setClearIconDrawable(drawable: Drawable?) { clearButton.setImageDrawable(drawable) } - fun setSearchBackground(background: Drawable?) = with(binding) { + fun setSearchBackground(background: Drawable?) { searchContainer.background = background } - fun setTextColor(@ColorInt color: Int) = with(binding) { + fun setTextColor(@ColorInt color: Int) { searchEditText.setTextColor(color) } - fun setHintTextColor(@ColorInt color: Int) = with(binding) { + fun setHintTextColor(@ColorInt color: Int) { searchEditText.setHintTextColor(color) } - fun setHint(hint: CharSequence?) = with(binding) { + fun setHint(hint: CharSequence?) { searchEditText.hint = hint } - fun setInputType(inputType: Int) = with(binding) { + fun setInputType(inputType: Int) { searchEditText.inputType = inputType } /** * Uses reflection to set the search EditText cursor drawable */ - fun setCursorDrawable(@DrawableRes drawable: Int) = with(binding) { + fun setCursorDrawable(@DrawableRes drawable: Int) { setCursorDrawable(searchEditText, drawable) } /** * Uses reflection to set the search EditText cursor color */ - fun setCursorColor(@ColorInt color: Int) = with(binding) { + fun setCursorColor(@ColorInt color: Int) { setCursorColor(searchEditText, color) } @@ -565,7 +602,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs * @param sequence query text * @param submit true to submit the query */ - fun setQuery(sequence: CharSequence?, submit: Boolean) = with(binding) { + fun setQuery(sequence: CharSequence?, submit: Boolean) { searchEditText.setText(sequence) if (sequence != null) { searchEditText.setSelection(searchEditText.length()) @@ -581,7 +618,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs * * @param show true to enable the voice search icon */ - fun showVoice(show: Boolean) = with(binding) { + fun showVoice(show: Boolean) { if (show && isVoiceAvailable && allowVoiceSearch) { voiceButton.visibility = VISIBLE } else { @@ -703,25 +740,4 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs fun onSearchViewClosedAnimation() } - companion object { - const val REQUEST_VOICE_SEARCH = 735 - const val CARD_CORNER_RADIUS = 4 - const val ANIMATION_CENTER_PADDING = 26 - private const val CARD_PADDING = 6 - private const val CARD_ELEVATION = 2 - private const val BACK_ICON_ALPHA_DEFAULT = 0.87f - private const val ICONS_ALPHA_DEFAULT = 0.54f - const val STYLE_BAR = 0 - const val STYLE_CARD = 1 - } - - init { - initStyle(attrs, defStyleAttr) - initSearchEditText() - initClickListeners() - showVoice(true) - if (!isInEditMode) { - visibility = INVISIBLE - } - } } \ No newline at end of file From 68fa2fbf01c3480e9fb1298c0f218d02001be053 Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Mon, 24 Oct 2022 20:29:04 +0100 Subject: [PATCH 07/15] SimpleSearchView.kt: Improved Parcelable implementation --- .../java/com/ferfalk/simplesearchview/SimpleSearchView.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt index 63bf4c4..fb549d6 100644 --- a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt +++ b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt @@ -16,7 +16,6 @@ import android.os.Parcelable import android.speech.RecognizerIntent import android.text.TextUtils import android.util.AttributeSet -import android.util.Log import android.view.* import android.view.View.OnFocusChangeListener import android.view.inputmethod.EditorInfo @@ -685,8 +684,9 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs companion object { //required field that makes Parcelables from a Parcel - val CREATOR: Parcelable.Creator = object : Parcelable.Creator { - override fun createFromParcel(`in`: Parcel): SavedState? { + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(`in`: Parcel): SavedState { return SavedState(`in`) } From f60ddd242444835c971e54e1b147e362a8f74b7b Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Mon, 24 Oct 2022 20:41:34 +0100 Subject: [PATCH 08/15] SimpleSearchView.kt: Minor code clean up --- .../java/com/ferfalk/simplesearchview/SimpleSearchView.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt index fb549d6..e464d5d 100644 --- a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt +++ b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt @@ -10,7 +10,6 @@ import android.graphics.Point import android.graphics.Rect import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable -import android.os.Build import android.os.Parcel import android.os.Parcelable import android.speech.RecognizerIntent @@ -68,8 +67,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs annotation class Style /** - * @param animationDuration duration, in ms, of the reveal or fade animations - * @return current reveal or fade animations duration + * The duration (in ms) of the reveal or fade animations */ var animationDuration = SimpleAnimationUtils.ANIMATION_DURATION_DEFAULT @@ -496,9 +494,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs } } searchContainer.layoutParams = layoutParams - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - searchContainer.elevation = elevation - } + searchContainer.elevation = elevation } private val cardStyleBackground: GradientDrawable get() { From 76225f3b56d306e871ea9d72ed498ed75b4d5646 Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Mon, 24 Oct 2022 20:46:28 +0100 Subject: [PATCH 09/15] strings.xml: Translatable string fix --- app/src/main/res/values/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a0750a9..511bba1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,12 +1,12 @@ - SimpleSearchView Example - SimpleSearchView - Tab 1 - Tab 2 - Tab 3 - Hello World from section: %1$d - Example - changed: %1$s - submitted: %1$s - cleared + SimpleSearchView Example + SimpleSearchView + Tab 1 + Tab 2 + Tab 3 + Hello World from section: %1$d + Example + changed: %1$s + submitted: %1$s + cleared From d3c1601896c2b4a2ecdfee22fdf5df26dc14ccfa Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Mon, 24 Oct 2022 20:50:18 +0100 Subject: [PATCH 10/15] activity_main.xml: Switched to ViewPager2 --- app/src/main/res/layout/activity_main.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 8919d78..3ecc2de 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -63,7 +63,7 @@ - Date: Mon, 24 Oct 2022 21:06:25 +0100 Subject: [PATCH 11/15] MainActivity.kt: Switched to legacy findViewById() --- .../simplesearchviewexample/MainActivity.kt | 82 ++++++++++--------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/com/ferfalk/simplesearchviewexample/MainActivity.kt b/app/src/main/java/com/ferfalk/simplesearchviewexample/MainActivity.kt index a0597d4..13deb00 100644 --- a/app/src/main/java/com/ferfalk/simplesearchviewexample/MainActivity.kt +++ b/app/src/main/java/com/ferfalk/simplesearchviewexample/MainActivity.kt @@ -9,33 +9,36 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter +import androidx.fragment.app.FragmentActivity +import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.widget.ViewPager2 import com.ferfalk.simplesearchview.SimpleSearchView import com.ferfalk.simplesearchview.utils.DimensUtils.convertDpToPx -import com.ferfalk.simplesearchviewexample.databinding.ActivityMainBinding import com.google.android.material.tabs.TabLayout -import com.google.android.material.tabs.TabLayout.TabLayoutOnPageChangeListener class MainActivity : AppCompatActivity() { - private lateinit var binding: ActivityMainBinding private val TAG = MainActivity::class.java.simpleName + private val container by lazy { findViewById(R.id.container) } + private val toolbar by lazy { findViewById(R.id.toolbar) } + private val searchView by lazy { findViewById(R.id.searchView) } + private val tabLayout by lazy { findViewById(R.id.tabLayout) } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivityMainBinding.inflate(layoutInflater) - setContentView(binding.root) + setContentView(R.layout.activity_main) init() } - private fun init() = with(binding) { + private fun init() { setSupportActionBar(toolbar) - container.adapter = SectionsPagerAdapter(supportFragmentManager) - container.addOnPageChangeListener(TabLayoutOnPageChangeListener(tabLayout)) - tabLayout.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(container)) + container.adapter = SectionsPagerAdapter(this) +// container.addOnPageChangeListener(TabLayoutOnPageChangeListener(tabLayout)) +// tabLayout.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(container)) } override fun onCreateOptionsMenu(menu: Menu): Boolean { @@ -45,40 +48,42 @@ class MainActivity : AppCompatActivity() { return true } - private fun setupSearchView(menu: Menu) = with(binding) { + private fun setupSearchView(menu: Menu) { val item = menu.findItem(R.id.action_search) - searchView.setMenuItem(item) - searchView.setTabLayout(tabLayout) - searchView.setOnQueryTextListener(object : SimpleSearchView.OnQueryTextListener{ - override fun onQueryTextChange(newText: String): Boolean { - Log.e(TAG, getString(R.string.changed, newText)) - return false - } - - override fun onQueryTextSubmit(query: String): Boolean { - Log.e(TAG, getString(R.string.submitted, query)) - return false - } - - override fun onQueryTextCleared(): Boolean { - Log.e(TAG, getString(R.string.cleared)) - return false - } - }) + searchView.apply { + setMenuItem(item) + setTabLayout(this@MainActivity.tabLayout) + setOnQueryTextListener(object : SimpleSearchView.OnQueryTextListener{ + override fun onQueryTextChange(newText: String): Boolean { + Log.e(TAG, getString(R.string.changed, newText)) + return false + } + + override fun onQueryTextSubmit(query: String): Boolean { + Log.e(TAG, getString(R.string.submitted, query)) + return false + } + + override fun onQueryTextCleared(): Boolean { + Log.e(TAG, getString(R.string.cleared)) + return false + } + }) + } // Adding padding to the animation because of the hidden menu item val revealCenter = searchView.revealAnimationCenter revealCenter!!.x -= convertDpToPx(EXTRA_REVEAL_CENTER_PADDING, this@MainActivity) } - override fun onBackPressed() = with(binding) { + override fun onBackPressed() { if (searchView.onBackPressed()) { return } super.onBackPressed() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) = with(binding) { + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (searchView.onActivityResult(requestCode, resultCode, data!!)) { return } @@ -89,7 +94,7 @@ class MainActivity : AppCompatActivity() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val rootView = inflater.inflate(R.layout.fragment_main, container, false) val textView = rootView.findViewById(R.id.section_label) - textView.text = getString(R.string.section_format, arguments!!.getInt(ARG_SECTION_NUMBER)) + textView.text = getString(R.string.section_format, requireArguments().getInt(ARG_SECTION_NUMBER)) return rootView } @@ -105,14 +110,11 @@ class MainActivity : AppCompatActivity() { } } - class SectionsPagerAdapter internal constructor(fm: FragmentManager) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - override fun getItem(position: Int): Fragment { - return PlaceholderFragment.newInstance(position + 1) - } + class SectionsPagerAdapter internal constructor(fm: FragmentActivity) : FragmentStateAdapter(fm) { - override fun getCount(): Int { - return 3 - } + override fun getItemCount() = 3 + + override fun createFragment(position: Int) = PlaceholderFragment.newInstance(position + 1) } companion object { From f03c883c16801862da3adc9ebc22a0e01107f2c0 Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Mon, 24 Oct 2022 21:12:55 +0100 Subject: [PATCH 12/15] SimpleSearchView.kt: Switch to Kotlin CharSequence extensions from TextUtils --- .../ferfalk/simplesearchview/SimpleSearchView.kt | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt index e464d5d..442c6c8 100644 --- a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt +++ b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt @@ -13,7 +13,6 @@ import android.graphics.drawable.GradientDrawable import android.os.Parcel import android.os.Parcelable import android.speech.RecognizerIntent -import android.text.TextUtils import android.util.AttributeSet import android.view.* import android.view.View.OnFocusChangeListener @@ -274,8 +273,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs clearButton.visibility = GONE showVoice(true) } - if(newText == oldQuery) - if (!TextUtils.equals(newText, oldQuery)) { + if(!(newText == oldQuery)) { onQueryChangeListener?.onQueryTextChange(newText.toString()) } oldQuery = newText.toString() @@ -455,7 +453,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs val matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) if (!matches.isNullOrEmpty()) { val searchWrd = matches[0] - if (!TextUtils.isEmpty(searchWrd)) { + if (searchWrd.isNotEmpty()) { setQuery(searchWrd, submit) } } @@ -599,12 +597,12 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs */ fun setQuery(sequence: CharSequence?, submit: Boolean) { searchEditText.setText(sequence) - if (sequence != null) { + sequence?.let { searchEditText.setSelection(searchEditText.length()) - query = sequence - } - if (submit && !TextUtils.isEmpty(sequence)) { - onSubmitQuery() + query = it + if (submit && it.isNotEmpty()) { + onSubmitQuery() + } } } From 5d5e99b49eecd06e772ea53dfa36fd81666e47af Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Thu, 27 Oct 2022 21:24:01 +0100 Subject: [PATCH 13/15] AndroidManifest.xml: Exported MainActivity --- app/src/main/AndroidManifest.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6c6d60a..821c624 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,7 +9,10 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - + From 913ef09597b9698e1ab4c4aea4b92f26d4100e29 Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Fri, 28 Oct 2022 08:35:00 +0100 Subject: [PATCH 14/15] SimpleSearchView.kt: Fixed inflate error --- .../simplesearchview/SimpleSearchView.kt | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt index 442c6c8..b57aa61 100644 --- a/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt +++ b/simplesearchview/src/main/java/com/ferfalk/simplesearchview/SimpleSearchView.kt @@ -71,7 +71,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs var animationDuration = SimpleAnimationUtils.ANIMATION_DURATION_DEFAULT /** - * @param revealAnimationCenter center of the reveal animation, used to customize the origin of the animation + * The center of the reveal animation, used to customize the origin of the animation * @return center of the reveal animation, by default it is placed where the rightmost MenuItem would be */ var revealAnimationCenter: Point? = null @@ -108,15 +108,15 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs private var searchIsClosing = false private var keepQuery = false - private val root by lazy { LayoutInflater.from(context).inflate(R.layout.search_view, null) } - private val searchContainer by lazy { root.findViewById(R.id.searchContainer) } - private val searchEditText by lazy { root.findViewById(R.id.searchEditText) } - private val backButton by lazy { root.findViewById(R.id.backButton) } - private val voiceButton by lazy { root.findViewById(R.id.voiceButton) } - private val clearButton by lazy { root.findViewById(R.id.clearButton) } - private val bottomLine by lazy { root.findViewById(R.id.bottomLine) } + private val searchContainer by lazy { findViewById(R.id.searchContainer) } + private val searchEditText by lazy { findViewById(R.id.searchEditText) } + private val backButton by lazy { findViewById(R.id.backButton) } + private val voiceButton by lazy { findViewById(R.id.voiceButton) } + private val clearButton by lazy { findViewById(R.id.clearButton) } + private val bottomLine by lazy { findViewById(R.id.bottomLine) } init { + inflate(context, R.layout.search_view, this) initStyle(attrs, defStyleAttr) initSearchEditText() initClickListeners() @@ -294,6 +294,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs } private val isVoiceAvailable: Boolean + @SuppressLint("QueryPermissionsNeeded") get() { if (isInEditMode) { return true @@ -465,7 +466,7 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs /** * Will reset the search background as the default for the selected style * - * @param style STYLE_CARD or STYLE_BAR + * STYLE_CARD or STYLE_BAR */ @get:Style var cardStyle: Int @@ -676,17 +677,14 @@ class SimpleSearchView @JvmOverloads constructor(creationContext: Context, attrs out.writeInt(if (keepQuery) 1 else 0) } - companion object { - //required field that makes Parcelables from a Parcel - @JvmField - val CREATOR = object : Parcelable.Creator { - override fun createFromParcel(`in`: Parcel): SavedState { - return SavedState(`in`) - } + //required field that makes Parcelables from a Parcel + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(`in`: Parcel): SavedState { + return SavedState(`in`) + } - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } + override fun newArray(size: Int): Array { + return arrayOfNulls(size) } } } From da24e008434fe10d4cc03d710065f39f23b1255b Mon Sep 17 00:00:00 2001 From: IODevBlue Date: Fri, 28 Oct 2022 08:37:19 +0100 Subject: [PATCH 15/15] MainActivity.kt: Included a TabLayoutMediator implementation --- .../com/ferfalk/simplesearchviewexample/MainActivity.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/ferfalk/simplesearchviewexample/MainActivity.kt b/app/src/main/java/com/ferfalk/simplesearchviewexample/MainActivity.kt index 13deb00..9ed06ea 100644 --- a/app/src/main/java/com/ferfalk/simplesearchviewexample/MainActivity.kt +++ b/app/src/main/java/com/ferfalk/simplesearchviewexample/MainActivity.kt @@ -17,6 +17,7 @@ import androidx.viewpager2.widget.ViewPager2 import com.ferfalk.simplesearchview.SimpleSearchView import com.ferfalk.simplesearchview.utils.DimensUtils.convertDpToPx import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator class MainActivity : AppCompatActivity() { @@ -26,19 +27,18 @@ class MainActivity : AppCompatActivity() { private val toolbar by lazy { findViewById(R.id.toolbar) } private val searchView by lazy { findViewById(R.id.searchView) } private val tabLayout by lazy { findViewById(R.id.tabLayout) } + private val tabTitles = arrayOf("Tab 1", "Tab 2", "Tab 3") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - init() } private fun init() { setSupportActionBar(toolbar) container.adapter = SectionsPagerAdapter(this) -// container.addOnPageChangeListener(TabLayoutOnPageChangeListener(tabLayout)) -// tabLayout.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(container)) + TabLayoutMediator(tabLayout, container) { tab, pos -> tab.text = tabTitles[pos]}.attach() } override fun onCreateOptionsMenu(menu: Menu): Boolean {