diff --git a/emoji/api/current.txt b/emoji/api/current.txt index 51b01dedb6..bcb041e4e3 100644 --- a/emoji/api/current.txt +++ b/emoji/api/current.txt @@ -238,9 +238,6 @@ package com.vanniktech.emoji.internal { method public static inline T! parcelable(android.os.Bundle, String key); } - public final class ThemingKt { - } - public final class UtilsKt { } diff --git a/emoji/build.gradle b/emoji/build.gradle index 3d228c7381..f55d56c25a 100644 --- a/emoji/build.gradle +++ b/emoji/build.gradle @@ -46,6 +46,7 @@ kotlin { api libs.androidx.appcompat api libs.androidx.cardview api libs.androidx.recyclerview + api libs.ui } } diff --git a/emoji/src/androidMain/kotlin/com/vanniktech/emoji/EmojiView.kt b/emoji/src/androidMain/kotlin/com/vanniktech/emoji/EmojiView.kt index 16b9bbc7a6..7b0569d907 100644 --- a/emoji/src/androidMain/kotlin/com/vanniktech/emoji/EmojiView.kt +++ b/emoji/src/androidMain/kotlin/com/vanniktech/emoji/EmojiView.kt @@ -37,7 +37,6 @@ import com.vanniktech.emoji.internal.EmojiVariantPopup import com.vanniktech.emoji.internal.RepeatListener import com.vanniktech.emoji.internal.emojiDrawableProvider import com.vanniktech.emoji.internal.hideKeyboardAndFocus -import com.vanniktech.emoji.internal.setEdgeColor import com.vanniktech.emoji.internal.showKeyboardAndFocus import com.vanniktech.emoji.listeners.OnEmojiBackspaceClickListener import com.vanniktech.emoji.listeners.OnEmojiClickListener @@ -48,6 +47,8 @@ import com.vanniktech.emoji.search.SearchEmoji import com.vanniktech.emoji.search.SearchEmojiManager import com.vanniktech.emoji.variant.VariantEmoji import com.vanniktech.emoji.variant.VariantEmojiManager +import com.vanniktech.ui.Color +import com.vanniktech.ui.themeViewPager import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -102,7 +103,7 @@ class EmojiView @JvmOverloads constructor( } setBackgroundColor(theming.backgroundColor) val emojisPager: ViewPager = findViewById(R.id.emojiViewPager) - emojisPager.setEdgeColor(theming.secondaryColor) + emojisPager.themeViewPager(color = Color(theming.secondaryColor)) val emojiDivider = findViewById(R.id.emojiViewDivider) emojiDivider.setBackgroundColor(theming.dividerColor) if (pageTransformer != null) { diff --git a/emoji/src/androidMain/kotlin/com/vanniktech/emoji/internal/EmojiSearchDialog.kt b/emoji/src/androidMain/kotlin/com/vanniktech/emoji/internal/EmojiSearchDialog.kt index f6889b3d15..8099b02382 100644 --- a/emoji/src/androidMain/kotlin/com/vanniktech/emoji/internal/EmojiSearchDialog.kt +++ b/emoji/src/androidMain/kotlin/com/vanniktech/emoji/internal/EmojiSearchDialog.kt @@ -19,7 +19,6 @@ package com.vanniktech.emoji.internal import android.app.Dialog import android.content.Context import android.content.DialogInterface -import android.content.res.ColorStateList import android.os.Bundle import android.os.Handler import android.os.Looper @@ -35,7 +34,6 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.annotation.Px import androidx.appcompat.app.AlertDialog -import androidx.core.view.ViewCompat import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentActivity import androidx.recyclerview.widget.DiffUtil @@ -46,6 +44,8 @@ import com.vanniktech.emoji.EmojiTheming import com.vanniktech.emoji.R import com.vanniktech.emoji.search.SearchEmoji import com.vanniktech.emoji.search.SearchEmojiResult +import com.vanniktech.ui.Color +import com.vanniktech.ui.themeEditText import java.util.concurrent.Executors import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit @@ -76,11 +76,11 @@ internal class EmojiSearchDialog : DialogFragment() { val editText = dialog.findViewById(R.id.editText)!! editText.setTextColor(theming.textColor) - val secondaryColor = theming.secondaryColor - editText.setCursorDrawableColor(secondaryColor) - editText.setHandlesColor(secondaryColor) - editText.highlightColor = secondaryColor - ViewCompat.setBackgroundTintList(editText, ColorStateList.valueOf(secondaryColor)) + editText.themeEditText( + color = Color(theming.secondaryColor), + colorText = Color(theming.textColor), + colorTextSecondary = Color(theming.textSecondaryColor), + ) val recyclerView = dialog.findViewById(R.id.recyclerView) val adapter = EmojiAdapter( diff --git a/emoji/src/androidMain/kotlin/com/vanniktech/emoji/internal/Theming.kt b/emoji/src/androidMain/kotlin/com/vanniktech/emoji/internal/Theming.kt deleted file mode 100644 index e3a5607dd2..0000000000 --- a/emoji/src/androidMain/kotlin/com/vanniktech/emoji/internal/Theming.kt +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2016 - Niklas Baudy, Ruben Gees, Mario Đanić and contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.vanniktech.emoji.internal - -import android.annotation.SuppressLint -import android.content.Context -import android.content.res.ColorStateList -import android.graphics.drawable.Drawable -import android.graphics.drawable.GradientDrawable -import android.graphics.drawable.InsetDrawable -import android.graphics.drawable.RotateDrawable -import android.graphics.drawable.VectorDrawable -import android.os.Build -import android.util.TypedValue -import android.widget.EdgeEffect -import android.widget.TextView -import androidx.annotation.ColorInt -import androidx.core.content.ContextCompat -import androidx.core.graphics.drawable.DrawableCompat -import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat -import androidx.viewpager.widget.ViewPager -import java.lang.reflect.Field -import kotlin.math.sqrt - -// https://stackoverflow.com/a/27343228/1979703 -internal fun ViewPager.setEdgeColor(@ColorInt color: Int) { - (ViewPager::class.java.getFieldByName("mLeftEdge")?.get(this) as? EdgeEffect)?.color = color - (ViewPager::class.java.getFieldByName("mRightEdge")?.get(this) as? EdgeEffect)?.color = color -} - -// https://stackoverflow.com/a/59488928/1979703 -@SuppressLint("PrivateApi") -internal fun TextView.setHandlesColor(@ColorInt color: Int) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - val size = 22.spToPx(context).toInt() - val corner = size.toFloat() / 2 - val inset = 10.spToPx(context).toInt() - - // left drawable - val drLeft = GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, intArrayOf(color, color)) - drLeft.setSize(size, size) - drLeft.cornerRadii = floatArrayOf(corner, corner, 0f, 0f, corner, corner, corner, corner) - setTextSelectHandleLeft(InsetDrawable(drLeft, inset, 0, inset, inset)) - - // right drawable - val drRight = GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, intArrayOf(color, color)) - drRight.setSize(size, size) - drRight.cornerRadii = floatArrayOf(0f, 0f, corner, corner, corner, corner, corner, corner) - setTextSelectHandleRight(InsetDrawable(drRight, inset, 0, inset, inset)) - - // middle drawable - val drMiddle = GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, intArrayOf(color, color)) - drMiddle.setSize(size, size) - drMiddle.cornerRadii = floatArrayOf(0f, 0f, corner, corner, corner, corner, corner, corner) - val mInset = (sqrt(2f) * corner - corner).toInt() - val insetDrawable = InsetDrawable(drMiddle, mInset, mInset, mInset, mInset) - val rotateDrawable = RotateDrawable() - rotateDrawable.drawable = insetDrawable - rotateDrawable.toDegrees = 45f - rotateDrawable.level = 10000 - setTextSelectHandle(rotateDrawable) - return - } - - try { - val editorField = TextView::class.java.getFieldByName("mEditor") - val editor = editorField?.get(this) ?: this - val editorClass: Class<*> = if (editorField != null) Class.forName("android.widget.Editor") else TextView::class.java - val handles = androidx.collection.ArrayMap(3).apply { - put("mSelectHandleLeft", "mTextSelectHandleLeftRes") - put("mSelectHandleRight", "mTextSelectHandleRightRes") - put("mSelectHandleCenter", "mTextSelectHandleRes") - } - for (i in 0 until handles.size) { - editorClass.getFieldByName(handles.keyAt(i))?.let { field: Field -> - val drawable = field.get(editor) as? Drawable - ?: TextView::class.java.getFieldByName(handles.valueAt(i)) - ?.getInt(this) - ?.let { ContextCompat.getDrawable(context, it) } - - if (drawable != null) field.set(editor, drawable.tinted(color)) - } - } - } catch (ignored: Throwable) { - } -} - -private class CursorDrawable(@ColorInt color: Int) : GradientDrawable(Orientation.BOTTOM_TOP, intArrayOf(color, color)) { - override fun setTint(tintColor: Int) { - // No-op https://github.com/material-components/material-components-android/issues/3255#issuecomment-1442269086 - } - - override fun setTintList(tint: ColorStateList?) { - // No-op https://github.com/material-components/material-components-android/issues/3255#issuecomment-1442269086 - } -} - -// https://stackoverflow.com/a/59269370/1979703 -@SuppressLint("PrivateApi") -internal fun TextView.setCursorDrawableColor(@ColorInt color: Int) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - textCursorDrawable = CursorDrawable(color) - .apply { setSize(2.spToPx(context).toInt(), textSize.toInt()) } - return - } - - try { - val editorField = TextView::class.java.getFieldByName("mEditor") - val editor = editorField?.get(this) ?: this - val editorClass: Class<*> = if (editorField != null) editor.javaClass else TextView::class.java - val cursorRes = TextView::class.java.getFieldByName("mCursorDrawableRes")?.get(this) as? Int - ?: return - - val tintedCursorDrawable = ContextCompat.getDrawable(context, cursorRes)?.tinted(color) - ?: return - - val cursorField = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - editorClass.getFieldByName("mDrawableForCursor") - } else { - null - } - if (cursorField != null) { - cursorField.set(editor, tintedCursorDrawable) - } else { - editorClass.getFieldByName("mCursorDrawable", "mDrawableForCursor") - ?.set(editor, arrayOf(tintedCursorDrawable, tintedCursorDrawable)) - } - } catch (ignored: Throwable) { - } -} - -private fun Class<*>.getFieldByName(vararg name: String): Field? { - name.forEach { - try { - return this.getDeclaredField(it).apply { isAccessible = true } - } catch (ignored: Throwable) { - } - } - return null -} - -private fun Drawable.tinted(@ColorInt color: Int): Drawable = when (this) { - is VectorDrawableCompat -> this.apply { setTintList(ColorStateList.valueOf(color)) } - is VectorDrawable -> this.apply { setTintList(ColorStateList.valueOf(color)) } - else -> DrawableCompat.wrap(this) - .also { DrawableCompat.setTint(it, color) } - .let { DrawableCompat.unwrap(it) } -} - -private fun Number.spToPx(context: Context? = null): Float { - val res = context?.resources ?: android.content.res.Resources.getSystem() - return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this.toFloat(), res.displayMetrics) -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 96e46cdccb..c5e812ac8f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,6 +34,7 @@ plugin-publish = { module = "com.vanniktech:gradle-maven-publish-plugin", versio robolectric = { module = "org.robolectric:robolectric", version = "4.9.2" } screengrab = { module = "tools.fastlane:screengrab", version = "2.1.1" } timber = { module = "com.jakewharton.timber:timber", version = "5.0.1" } +ui = { module = "com.vanniktech:ui", version = "0.5.0" } [plugins] codequalitytools = { id = "com.vanniktech.code.quality.tools", version = "0.22.0" }