Replace TextDrawable with an implementation that supports tint

This commit is contained in:
MM20 2021-12-04 13:51:38 +01:00
parent 0e1ca1c1f9
commit fa22eb4d71
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
12 changed files with 217 additions and 161 deletions

View File

@ -107,7 +107,6 @@ dependencies {
implementation(libs.lottie.core) implementation(libs.lottie.core)
implementation(libs.textdrawable)
implementation(libs.bundles.materialdialogs) implementation(libs.bundles.materialdialogs)

View File

@ -0,0 +1,47 @@
package de.mm20.launcher2.graphics
import android.content.res.ColorStateList
import android.graphics.*
import android.graphics.drawable.Drawable
class TextDrawable(
val text: String,
val color: Int = Color.WHITE,
fontSize: Float = 13f,
typeface: Typeface = Typeface.DEFAULT
): Drawable() {
private val paint = Paint()
private val rect = Rect()
init {
paint.textAlign = Paint.Align.CENTER
paint.textSize = fontSize
paint.color = color
paint.isAntiAlias = true
paint.typeface = typeface
paint.style = Paint.Style.FILL
}
override fun draw(canvas: Canvas) {
val bounds = bounds
paint.getTextBounds(text, 0, text.length, rect)
canvas.drawText(text, bounds.exactCenterX(), bounds.exactCenterY() + rect.height() / 2f, paint)
}
override fun setAlpha(alpha: Int) {
paint.alpha = alpha
}
override fun setColorFilter(colorFilter: ColorFilter?) {
paint.colorFilter = colorFilter
}
override fun getOpacity(): Int {
return PixelFormat.TRANSLUCENT
}
override fun setTintList(tint: ColorStateList?) {
paint.color = tint?.defaultColor ?: color
}
}

View File

@ -77,14 +77,6 @@ val OpenSourceLicenses = arrayOf(
copyrightNote = "Copyright (c) 2009-2021 Jonathan Hedley <https://jsoup.org/>", copyrightNote = "Copyright (c) 2009-2021 Jonathan Hedley <https://jsoup.org/>",
url = "https://jsoup.org/" url = "https://jsoup.org/"
), ),
OpenSourceLibrary(
name = "TextDrawable",
description = "A light-weight library providing images with letter/text like the Gmail app",
licenseName = R.string.mit_license_name,
licenseText = R.raw.license_mit,
copyrightNote = "Copyright (c) 2014 Amulya Khare",
url = "https://github.com/amulyakhare/TextDrawable"
),
OpenSourceLibrary( OpenSourceLibrary(
name = "Glide", name = "Glide",
description = "A fast and efficient open source media management and image loading framework for Android", description = "A fast and efficient open source media management and image loading framework for Android",

View File

@ -40,7 +40,6 @@ dependencies {
implementation(libs.androidx.core) implementation(libs.androidx.core)
implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompat)
implementation(libs.textdrawable)
implementation(libs.koin.android) implementation(libs.koin.android)

View File

@ -4,7 +4,6 @@ import android.Manifest
import android.content.ContentUris import android.content.ContentUris
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
@ -16,15 +15,13 @@ import androidx.core.graphics.ColorUtils
import androidx.core.graphics.blue import androidx.core.graphics.blue
import androidx.core.graphics.green import androidx.core.graphics.green
import androidx.core.graphics.red import androidx.core.graphics.red
import com.amulyakhare.textdrawable.TextDrawable
import de.mm20.launcher2.calendar.R import de.mm20.launcher2.calendar.R
import de.mm20.launcher2.permissions.PermissionsManager import de.mm20.launcher2.graphics.TextDrawable
import de.mm20.launcher2.icons.LauncherIcon import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.checkPermission import de.mm20.launcher2.ktx.checkPermission
import de.mm20.launcher2.ktx.dp import de.mm20.launcher2.ktx.dp
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherPreferences import de.mm20.launcher2.preferences.LauncherPreferences
import org.json.JSONObject
import java.lang.NullPointerException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -51,26 +48,22 @@ class CalendarEvent(
df.applyPattern("MMM") df.applyPattern("MMM")
val month = df.format(startTime) val month = df.format(startTime)
val fgLayers = arrayOf( val fgLayers = arrayOf(
TextDrawable TextDrawable(
.builder() day,
.beginConfig() color = Color.WHITE,
.textColor(Color.WHITE) fontSize = 40 * context.dp,
.useFont(Typeface.DEFAULT_BOLD) typeface = Typeface.DEFAULT_BOLD
.fontSize((36 * context.dp).toInt()) ),
.endConfig() TextDrawable(
.buildRect(day, 0), month,
TextDrawable color = Color.WHITE,
.builder() fontSize = 26 * context.dp,
.beginConfig() typeface = Typeface.DEFAULT_BOLD
.textColor(Color.WHITE) )
.bold()
.fontSize((26 * context.dp).toInt())
.endConfig()
.buildRect(month, 0)
) )
val foreground = LayerDrawable(fgLayers) val foreground = LayerDrawable(fgLayers)
foreground.setLayerInset(0, 0, 0, 0, (26 * context.dp).toInt()) foreground.setLayerInset(0, 0, 0, 0, (26 * context.dp).toInt())
foreground.setLayerInset(1, 0, (36 * context.dp).toInt(), 0, 0) foreground.setLayerInset(1, 0, (40 * context.dp).toInt(), 0, 0)
val background = ColorDrawable(getDisplayColor(context, color)) val background = ColorDrawable(getDisplayColor(context, color))
return LauncherIcon( return LauncherIcon(
foreground = foreground, foreground = foreground,
@ -84,7 +77,8 @@ class CalendarEvent(
} }
companion object { companion object {
fun search(context: Context, fun search(
context: Context,
query: String, query: String,
intervalStart: Long, intervalStart: Long,
intervalEnd: Long, intervalEnd: Long,
@ -120,8 +114,15 @@ class CalendarEvent(
if (unselectedCalendars.isNotEmpty()) selection.add("${CalendarContract.Instances.CALENDAR_ID} NOT IN (${unselectedCalendars.joinToString()})") if (unselectedCalendars.isNotEmpty()) selection.add("${CalendarContract.Instances.CALENDAR_ID} NOT IN (${unselectedCalendars.joinToString()})")
if (hideAllDayEvents) selection.add("${CalendarContract.Instances.ALL_DAY} = 0") if (hideAllDayEvents) selection.add("${CalendarContract.Instances.ALL_DAY} = 0")
val selArgs = if (query.isBlank()) null else arrayOf("%$query%") val selArgs = if (query.isBlank()) null else arrayOf("%$query%")
val sort = "${CalendarContract.Instances.BEGIN} ASC" + if (limit > -1) " LIMIT $limit" else "" val sort =
val cursor = context.contentResolver.query(uri, projection, selection.joinToString(separator = " AND "), selArgs, sort) "${CalendarContract.Instances.BEGIN} ASC" + if (limit > -1) " LIMIT $limit" else ""
val cursor = context.contentResolver.query(
uri,
projection,
selection.joinToString(separator = " AND "),
selArgs,
sort
)
?: return mutableListOf() ?: return mutableListOf()
val proj = arrayOf( val proj = arrayOf(
CalendarContract.Attendees.EVENT_ID, CalendarContract.Attendees.EVENT_ID,
@ -185,12 +186,14 @@ class CalendarEvent(
?: return emptyList() ?: return emptyList()
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
try { try {
calendars.add(UserCalendar( calendars.add(
UserCalendar(
id = cursor.getLong(0), id = cursor.getLong(0),
name = cursor.getString(5) ?: cursor.getString(1) ?: "", name = cursor.getString(5) ?: cursor.getString(1) ?: "",
owner = cursor.getString(2), owner = cursor.getString(2),
color = cursor.getInt(3) color = cursor.getInt(3)
)) )
)
} catch (e: NullPointerException) { } catch (e: NullPointerException) {
continue continue
} }
@ -206,7 +209,13 @@ class CalendarEvent(
it it
} }
return if (context.resources.getBoolean(R.bool.is_dark_theme)) { return if (context.resources.getBoolean(R.bool.is_dark_theme)) {
if (ColorUtils.calculateContrast(ContextCompat.getColor(context, R.color.calendar_foreground_color), color) < 2.5 || true) { if (ColorUtils.calculateContrast(
ContextCompat.getColor(
context,
R.color.calendar_foreground_color
), color
) < 2.5 || true
) {
if (color.red == color.green && color.red == color.blue) { if (color.red == color.green && color.red == color.blue) {
val level = 0xFF - ((0xFF - color.red) * 0.7f).toInt() val level = 0xFF - ((0xFF - color.red) * 0.7f).toInt()
Color.rgb(level, level, level) Color.rgb(level, level, level)
@ -217,7 +226,13 @@ class CalendarEvent(
} }
} else return color } else return color
} else { } else {
if (ColorUtils.calculateContrast(ContextCompat.getColor(context, R.color.calendar_foreground_color), color) < 1.8) { if (ColorUtils.calculateContrast(
ContextCompat.getColor(
context,
R.color.calendar_foreground_color
), color
) < 1.8
) {
if (color.red == color.green && color.red == color.blue) { if (color.red == color.green && color.red == color.blue) {
val level = (color.red * 0.7f).toInt() val level = (color.red * 0.7f).toInt()
Color.rgb(level, level, level) Color.rgb(level, level, level)

View File

@ -40,7 +40,6 @@ dependencies {
implementation(libs.androidx.core) implementation(libs.androidx.core)
implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompat)
implementation(libs.textdrawable)
implementation(libs.koin.android) implementation(libs.koin.android)

View File

@ -1,21 +1,21 @@
package de.mm20.launcher2.search.data package de.mm20.launcher2.search.data
import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.provider.ContactsContract import android.provider.ContactsContract
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.database.getStringOrNull import androidx.core.database.getStringOrNull
import androidx.core.graphics.drawable.toDrawable import androidx.core.graphics.drawable.toDrawable
import com.amulyakhare.textdrawable.TextDrawable
import de.mm20.launcher2.contacts.R import de.mm20.launcher2.contacts.R
import de.mm20.launcher2.ktx.asBitmap import de.mm20.launcher2.graphics.TextDrawable
import de.mm20.launcher2.ktx.jsonObjectOf
import de.mm20.launcher2.icons.LauncherIcon import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.asBitmap
import de.mm20.launcher2.ktx.sp
import de.mm20.launcher2.permissions.PermissionsManager import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherPreferences import de.mm20.launcher2.preferences.LauncherPreferences
import org.json.JSONObject
class Contact( class Contact(
val id: Long, val id: Long,
@ -40,16 +40,19 @@ class Contact(
} }
override fun getPlaceholderIcon(context: Context): LauncherIcon { override fun getPlaceholderIcon(context: Context): LauncherIcon {
val iconText = if (firstName.isNotEmpty()) firstName[0].toString() else "" + if (lastName.isNotEmpty()) lastName[0].toString() else "" val iconText =
if (firstName.isNotEmpty()) firstName[0].toString() else "" + if (lastName.isNotEmpty()) lastName[0].toString() else ""
return LauncherIcon( return LauncherIcon(
foreground = TextDrawable.builder().buildRect(iconText, ContextCompat.getColor(context, R.color.blue)) foreground = TextDrawable(iconText, Color.WHITE, fontSize = 40 * context.sp, typeface = Typeface.DEFAULT_BOLD),
background = ColorDrawable(ContextCompat.getColor(context, R.color.blue))
) )
} }
override suspend fun loadIconAsync(context: Context, size: Int): LauncherIcon? { override suspend fun loadIconAsync(context: Context, size: Int): LauncherIcon? {
val contentResolver = context.contentResolver val contentResolver = context.contentResolver
val uri = ContactsContract.Contacts.getLookupUri(id, lookupKey) ?: return null val uri = ContactsContract.Contacts.getLookupUri(id, lookupKey) ?: return null
val bmp = ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, uri, false)?.asBitmap() val bmp = ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, uri, false)
?.asBitmap()
?: return null ?: return null
return LauncherIcon( return LauncherIcon(
foreground = bmp.toDrawable(context.resources) foreground = bmp.toDrawable(context.resources)
@ -76,7 +79,8 @@ class Contact(
val sel = "${ContactsContract.RawContacts.DISPLAY_NAME_PRIMARY} LIKE ?" val sel = "${ContactsContract.RawContacts.DISPLAY_NAME_PRIMARY} LIKE ?"
val selArgs = arrayOf("%$query%") val selArgs = arrayOf("%$query%")
val cursor = context.contentResolver.query( val cursor = context.contentResolver.query(
ContactsContract.RawContacts.CONTENT_URI, proj, sel, selArgs, null) ?: return mutableListOf() ContactsContract.RawContacts.CONTENT_URI, proj, sel, selArgs, null
) ?: return mutableListOf()
//Maps raw contact ids to contact ids //Maps raw contact ids to contact ids
val contactMap = mutableMapOf<Long, MutableSet<Long>>() val contactMap = mutableMapOf<Long, MutableSet<Long>>()
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
@ -113,12 +117,18 @@ class Contact(
var lastName = "" var lastName = ""
var displayName = "" var displayName = ""
val mimeTypeColumn = dataCursor.getColumnIndex(ContactsContract.Data.MIMETYPE) val mimeTypeColumn = dataCursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
val emailAddressColumn = dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS) val emailAddressColumn =
val numberColumn = dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER) dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS)
val addressColumn = dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS) val numberColumn =
val displayNameColumn = dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME) dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
val givenNameColumn = dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME) val addressColumn =
val familyNameColumn = dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME) dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS)
val displayNameColumn =
dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME)
val givenNameColumn =
dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME)
val familyNameColumn =
dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME)
val data1Column = dataCursor.getColumnIndex(ContactsContract.Data.DATA1) val data1Column = dataCursor.getColumnIndex(ContactsContract.Data.DATA1)
val data3Column = dataCursor.getColumnIndex(ContactsContract.Data.DATA3) val data3Column = dataCursor.getColumnIndex(ContactsContract.Data.DATA3)
val idColumn = dataCursor.getColumnIndex(ContactsContract.Data._ID) val idColumn = dataCursor.getColumnIndex(ContactsContract.Data._ID)

View File

@ -291,10 +291,6 @@ dependencyResolutionManagement {
.to("org.jsoup", "jsoup") .to("org.jsoup", "jsoup")
.version("1.14.2") .version("1.14.2")
alias("textdrawable")
.to("com.amulyakhare", "com.amulyakhare.textdrawable")
.version("1.0.1")
alias("glide") alias("glide")
.to("com.github.bumptech.glide", "glide") .to("com.github.bumptech.glide", "glide")
.version("4.12.0") .version("4.12.0")

View File

@ -68,7 +68,6 @@ dependencies {
implementation(libs.androidx.transition) implementation(libs.androidx.transition)
implementation(libs.materialcomponents) implementation(libs.materialcomponents)
implementation(libs.viewpropertyobjectanimator) implementation(libs.viewpropertyobjectanimator)
implementation(libs.textdrawable)
implementation(libs.glide) implementation(libs.glide)
implementation(libs.draglinearlayout) implementation(libs.draglinearlayout)
implementation(libs.lottie.core) implementation(libs.lottie.core)

View File

@ -1,12 +1,12 @@
package de.mm20.launcher2.ui.legacy.data package de.mm20.launcher2.ui.legacy.data
import android.content.Context import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.amulyakhare.textdrawable.TextDrawable import de.mm20.launcher2.graphics.TextDrawable
import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.R
import de.mm20.launcher2.icons.LauncherIcon import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.sp
import de.mm20.launcher2.search.data.Searchable import de.mm20.launcher2.search.data.Searchable
/** /**
@ -22,8 +22,7 @@ class InformationText(
override fun getPlaceholderIcon(context: Context): LauncherIcon { override fun getPlaceholderIcon(context: Context): LauncherIcon {
return LauncherIcon( return LauncherIcon(
foreground = TextDrawable.builder() foreground = TextDrawable("i", fontSize = 40 * context.sp),
.buildRect("i", Color.WHITE),
background = ColorDrawable(ContextCompat.getColor(context, R.color.grey)) background = ColorDrawable(ContextCompat.getColor(context, R.color.grey))
) )
} }

View File

@ -46,7 +46,6 @@ dependencies {
implementation(libs.okhttp) implementation(libs.okhttp)
implementation(libs.glide) implementation(libs.glide)
implementation(libs.textdrawable)
implementation(libs.jsoup) implementation(libs.jsoup)
implementation(libs.koin.android) implementation(libs.koin.android)

View File

@ -3,6 +3,7 @@ package de.mm20.launcher2.search.data
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.net.Uri import android.net.Uri
import android.util.Log import android.util.Log
@ -10,11 +11,12 @@ import android.webkit.URLUtil
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
import androidx.palette.graphics.Palette import androidx.palette.graphics.Palette
import com.amulyakhare.textdrawable.TextDrawable
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import de.mm20.launcher2.graphics.TextDrawable
import de.mm20.launcher2.helper.NetworkUtils import de.mm20.launcher2.helper.NetworkUtils
import de.mm20.launcher2.icons.LauncherIcon import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.jsonObjectOf import de.mm20.launcher2.ktx.jsonObjectOf
import de.mm20.launcher2.ktx.sp
import de.mm20.launcher2.preferences.LauncherPreferences import de.mm20.launcher2.preferences.LauncherPreferences
import de.mm20.launcher2.preferences.WebsiteProtocols import de.mm20.launcher2.preferences.WebsiteProtocols
import de.mm20.launcher2.websites.R import de.mm20.launcher2.websites.R
@ -67,7 +69,7 @@ class Website(
override fun getPlaceholderIcon(context: Context): LauncherIcon { override fun getPlaceholderIcon(context: Context): LauncherIcon {
val drawable = if (label.isNotEmpty()) { val drawable = if (label.isNotEmpty()) {
TextDrawable.builder().buildRect(label[0].toString(), 0) TextDrawable(label[0].toString(), typeface = Typeface.DEFAULT_BOLD, fontSize = 40 * context.sp)
} else context.getDrawable(R.drawable.ic_website)!! } else context.getDrawable(R.drawable.ic_website)!!
return LauncherIcon( return LauncherIcon(
foreground = drawable, foreground = drawable,