diff options
author | Allan Wang <me@allanwang.ca> | 2018-01-02 23:38:51 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-02 23:38:51 -0500 |
commit | 2a9d5916a2acd0b468b9aa28977021fdd483e2aa (patch) | |
tree | a2df6258e213546a1807e15e45aa921ee69f192b | |
parent | 71f5dc2f7ce5b8183421586e6a77be65040a4dff (diff) | |
download | kau-2a9d5916a2acd0b468b9aa28977021fdd483e2aa.tar.gz kau-2a9d5916a2acd0b468b9aa28977021fdd483e2aa.tar.bz2 kau-2a9d5916a2acd0b468b9aa28977021fdd483e2aa.zip |
Fix/searchview (#123)
* Use workaround for kclick
* Add text cleared callback
* Add bundle scene transition functions
* Add applier
* Remove need for explicit context
* Revert
-rw-r--r-- | about/src/main/kotlin/ca/allanwang/kau/about/AboutBinder.kt | 11 | ||||
-rw-r--r-- | about/src/main/res-public/values/public.xml | 2 | ||||
-rw-r--r-- | adapter/src/main/res-public/values/public.xml | 2 | ||||
-rw-r--r-- | android-lib.gradle | 5 | ||||
-rw-r--r-- | core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt | 26 | ||||
-rw-r--r-- | core/src/main/res-public/values/public.xml | 2 | ||||
-rw-r--r-- | docs/Changelog.md | 1 | ||||
-rw-r--r-- | kpref-activity/src/main/res-public/values/public.xml | 2 | ||||
-rw-r--r-- | mediapicker/src/main/res-public/values/public.xml | 2 | ||||
-rw-r--r-- | sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt | 8 | ||||
-rw-r--r-- | searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt | 56 |
11 files changed, 92 insertions, 25 deletions
diff --git a/about/src/main/kotlin/ca/allanwang/kau/about/AboutBinder.kt b/about/src/main/kotlin/ca/allanwang/kau/about/AboutBinder.kt index a5f5318..c99f7c2 100644 --- a/about/src/main/kotlin/ca/allanwang/kau/about/AboutBinder.kt +++ b/about/src/main/kotlin/ca/allanwang/kau/about/AboutBinder.kt @@ -1,6 +1,6 @@ package ca.allanwang.kau.about -import android.app.Activity +import android.content.Context import ca.allanwang.kau.utils.startActivity import ca.allanwang.kau.utils.withSceneTransitionAnimation @@ -11,8 +11,7 @@ import ca.allanwang.kau.utils.withSceneTransitionAnimation /** * About activity launcher */ -inline fun <reified T : AboutActivityBase> Activity.kauLaunchAbout() { - startActivity<T>(bundleBuilder = { - withSceneTransitionAnimation(this@kauLaunchAbout) - }) -}
\ No newline at end of file +inline fun <reified T : AboutActivityBase> Context.kauLaunchAbout() = + startActivity<T>(bundleBuilder = { + withSceneTransitionAnimation(this@kauLaunchAbout) + })
\ No newline at end of file diff --git a/about/src/main/res-public/values/public.xml b/about/src/main/res-public/values/public.xml index 3739dd1..2db68c4 100644 --- a/about/src/main/res-public/values/public.xml +++ b/about/src/main/res-public/values/public.xml @@ -1,4 +1,4 @@ <resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> - <!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> <public name='Kau.About' type='style' /> </resources>
\ No newline at end of file diff --git a/adapter/src/main/res-public/values/public.xml b/adapter/src/main/res-public/values/public.xml index 4d16c2a..cf14680 100644 --- a/adapter/src/main/res-public/values/public.xml +++ b/adapter/src/main/res-public/values/public.xml @@ -1,4 +1,4 @@ <resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> - <!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> <public name='dummy' type='id' /> </resources>
\ No newline at end of file diff --git a/android-lib.gradle b/android-lib.gradle index c1fb523..d3651dc 100644 --- a/android-lib.gradle +++ b/android-lib.gradle @@ -28,11 +28,6 @@ android { testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } - compileOptions { - targetCompatibility 1.8 - sourceCompatibility 1.8 - } - buildTypes { release { minifyEnabled false diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt index 76c314a..82cd577 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt @@ -6,6 +6,8 @@ import android.app.ActivityOptions import android.content.Context import android.os.Bundle import android.support.annotation.AnimRes +import android.util.Pair +import android.view.View import ca.allanwang.kau.R /** @@ -25,7 +27,29 @@ infix fun Bundle.with(bundle: Bundle?): Bundle { @SuppressLint("NewApi") fun Bundle.withSceneTransitionAnimation(context: Context) { if (context !is Activity || !buildIsLollipopAndUp) return - this with ActivityOptions.makeSceneTransitionAnimation(context).toBundle() + val options = ActivityOptions.makeSceneTransitionAnimation(context) + putAll(options.toBundle()) +} + +/** + * Given the parent view and map of view ids to tags, + * create a scene transition animation + */ +fun Bundle.withSceneTransitionAnimation(parent: View, data: Map<Int, String>) = + withSceneTransitionAnimation(parent.context, data.mapKeys { (id, _) -> + parent.findViewById<View>(id) + }) + +/** + * Given a mapping of views to tags, + * create a scene transition animation + */ +@SuppressLint("NewApi") +fun Bundle.withSceneTransitionAnimation(context: Context, data: Map<View, String>) { + if (context !is Activity || !buildIsLollipopAndUp) return + val options = ActivityOptions.makeSceneTransitionAnimation(context, + *data.map { (view, tag) -> Pair(view, tag) }.toTypedArray()) + putAll(options.toBundle()) } fun Bundle.withCustomAnimation(context: Context, diff --git a/core/src/main/res-public/values/public.xml b/core/src/main/res-public/values/public.xml index c309a70..f831c6d 100644 --- a/core/src/main/res-public/values/public.xml +++ b/core/src/main/res-public/values/public.xml @@ -1,5 +1,5 @@ <resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> - <!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> <public name='kau_exit_slide_bottom' type='transition' /> <public name='kau_exit_slide_left' type='transition' /> <public name='kau_enter_slide_right' type='transition' /> diff --git a/docs/Changelog.md b/docs/Changelog.md index e6e4488..88fe4ff 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -2,6 +2,7 @@ ## v3.6.1 * :core: [Breaking] Removed private text field and introduced lazy logging functions +* :adapter: Improve library item layout ## v3.6.0 * :adapter: Create withOnRepeatedClickListener diff --git a/kpref-activity/src/main/res-public/values/public.xml b/kpref-activity/src/main/res-public/values/public.xml index bd4f615..b5fb383 100644 --- a/kpref-activity/src/main/res-public/values/public.xml +++ b/kpref-activity/src/main/res-public/values/public.xml @@ -1,5 +1,5 @@ <resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> - <!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> <public name='kau_pref_barrier' type='id' /> <public name='kau_pref_container' type='id' /> <public name='kau_pref_desc' type='id' /> diff --git a/mediapicker/src/main/res-public/values/public.xml b/mediapicker/src/main/res-public/values/public.xml index 41bcbfd..3c6f0fa 100644 --- a/mediapicker/src/main/res-public/values/public.xml +++ b/mediapicker/src/main/res-public/values/public.xml @@ -1,5 +1,5 @@ <resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> - <!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> <public name='Kau.MediaPicker' type='style' /> <public name='Kau.MediaPicker.Overlay' type='style' /> <public name='kau_blurred_image_selection_overlay' type='color' /> diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt index 6784705..b27a713 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt @@ -1,10 +1,11 @@ package ca.allanwang.kau.sample +import android.content.Context import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem -import ca.allanwang.kau.about.kauLaunchAbout +import ca.allanwang.kau.about.AboutActivityBase import ca.allanwang.kau.email.sendEmail import ca.allanwang.kau.kpref.activity.CoreAttributeContract import ca.allanwang.kau.kpref.activity.KPrefActivity @@ -287,3 +288,8 @@ class MainActivity : KPrefActivity() { } } } + +inline fun <reified T : AboutActivityBase> Context.kauLaunchAbout() = + startActivity<T>(bundleBuilder = { + withSceneTransitionAnimation(this@kauLaunchAbout) + })
\ No newline at end of file diff --git a/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt b/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt index 1cd811e..e3a4678 100644 --- a/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt +++ b/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt @@ -52,19 +52,23 @@ class SearchView @JvmOverloads constructor( * However, these are the main config options */ class Configs { + /** * The foreground color accounts for all text colors and icon colors * Various alpha levels may be used for sub texts/dividers etc */ var foregroundColor: Int = SearchItem.foregroundColor + /** * Namely the background for the card and recycler view */ var backgroundColor: Int = SearchItem.backgroundColor + /** * Icon for the leftmost ImageView, which typically contains the hamburger menu/back arror */ var navIcon: IIcon? = GoogleMaterial.Icon.gmd_arrow_back + /** * Optional icon just to the left of the clear icon * This is not implemented by default, but can be used for anything, such as mic or redirects @@ -72,43 +76,53 @@ class SearchView @JvmOverloads constructor( * Set the iicon as null to hide the extra icon */ var extraIcon: Pair<IIcon, OnClickListener>? = null + /** * Icon for the rightmost ImageView, which typically contains a close icon */ var clearIcon: IIcon? = GoogleMaterial.Icon.gmd_clear + /** * Duration for the circular reveal animation */ var revealDuration: Long = 300L + /** * Duration for the auto transition, which is namely used to resize the recycler view */ var transitionDuration: Long = 100L + /** * Defines whether the edit text and mainAdapter should clear themselves when the searchView is closed */ var shouldClearOnClose: Boolean = false + /** * Callback that will be called every time the searchView opens */ var openListener: ((searchView: SearchView) -> Unit)? = null + /** * Callback that will be called every time the searchView closes */ var closeListener: ((searchView: SearchView) -> Unit)? = null + /** * Draw a divider between the search bar and the suggestion items * The divider is colored based on the [foregroundColor] */ var withDivider: Boolean = true + /** * Hint string to be set in the searchView */ var hintText: String? = null + /** * Hint string res to be set in the searchView */ var hintTextRes: Int = -1 + /** * StringRes for a "no results found" item * If [results] is ever set to an empty list, it will default to @@ -118,29 +132,46 @@ class SearchView @JvmOverloads constructor( * which you may use */ var noResultsFound: Int = -1 + /** * Callback for when the query changes + * This callback does not run on the ui thread! + * It is always on a worker thread, so there is no need for asynchronous calls + * Likewise, calls modifying the UI should be passed through [runOnUiThread] */ var textCallback: (query: String, searchView: SearchView) -> Unit = { _, _ -> } + + /** + * Callback for when the query is changed to an empty string + * Typically, this may be ignored as the adapter will simply be cleared, + * but if we wish to do something else, we may pass a function + * Returns [true] if the action was consumed, [false] otherwise (to execute default behaviour) + */ + var textClearedCallback: (searchView: SearchView) -> Boolean = { _ -> false } + /** * Callback for when the search action key is detected from the keyboard * Returns true if the searchbar should close afterwards, and false otherwise */ var searchCallback: (query: String, searchView: SearchView) -> Boolean = { _, _ -> false } + /** * Debouncing interval between callbacks */ var textDebounceInterval: Long = 0 + /** * Click event for suggestion items * This event is only triggered when [key] is not blank (like in [noResultsFound] */ var onItemClick: (position: Int, key: String, content: String, searchView: SearchView) -> Unit = { _, _, _, _ -> } + /** * Long click event for suggestion items * This event is only triggered when [key] is not blank (like in [noResultsFound] */ var onItemLongClick: (position: Int, key: String, content: String, searchView: SearchView) -> Unit = { _, _, _, _ -> } + /** * If a [SearchItem]'s title contains the submitted query, make that portion bold * See [SearchItem.withHighlights] @@ -198,7 +229,7 @@ class SearchView @JvmOverloads constructor( context.runOnUiThread { cardTransition(); adapter.clear() } } - val configs = Configs() + private val configs = Configs() //views private val shadow: View by bindView(R.id.kau_search_shadow) private val card: BoundedCardView by bindView(R.id.kau_search_cardview) @@ -211,11 +242,17 @@ class SearchView @JvmOverloads constructor( private val recycler: RecyclerView by bindView(R.id.kau_search_recycler) private var textCallback: Debouncer2<String, SearchView> = debounce(0) { query, _ -> KL.d { "Search query $query found; set your own textCallback" } } - val adapter = FastItemAdapter<SearchItem>() - var menuItem: MenuItem? = null + private val adapter = FastItemAdapter<SearchItem>() + private var menuItem: MenuItem? = null val isOpen: Boolean get() = parent != null && card.isVisible + /** + * The current text located in our searchview + */ + val query: String + get() = editText.text.toString().trim() + /* * Ripple start points and search view offset * These are calculated every time the search view is opened, @@ -258,8 +295,12 @@ class SearchView @JvmOverloads constructor( override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { - if (s.isNotBlank()) textCallback(s.toString().trim(), this@SearchView) - else clearResults() + val text = s.toString().trim() + textCallback.cancel() + if (text.isNotEmpty()) + textCallback(text, this@SearchView) + else if (!configs.textClearedCallback(this@SearchView)) + clearResults() } }) editText.setOnEditorActionListener { _, actionId, _ -> @@ -321,12 +362,13 @@ class SearchView @JvmOverloads constructor( menuItem = null } + private val locations = IntArray(2) + private fun configureCoords(item: MenuItem?) { item ?: return if (parent !is ViewGroup) return val view = parentViewGroup.findViewById<View>(item.itemId) ?: return - val locations = IntArray(2) - view.getLocationOnScreen(locations) + view.getLocationInWindow(locations) menuX = (locations[0] + view.width / 2) menuHalfHeight = view.height / 2 menuY = (locations[1] + menuHalfHeight) |