Replace TextDrawable with an implementation that supports tint
This commit is contained in:
parent
0e1ca1c1f9
commit
fa22eb4d71
@ -107,7 +107,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation(libs.lottie.core)
|
implementation(libs.lottie.core)
|
||||||
|
|
||||||
implementation(libs.textdrawable)
|
|
||||||
|
|
||||||
implementation(libs.bundles.materialdialogs)
|
implementation(libs.bundles.materialdialogs)
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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",
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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,29 +15,27 @@ 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.*
|
||||||
|
|
||||||
class CalendarEvent(
|
class CalendarEvent(
|
||||||
override val label: String,
|
override val label: String,
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val color: Int,
|
val color: Int,
|
||||||
val startTime: Long,
|
val startTime: Long,
|
||||||
val endTime: Long,
|
val endTime: Long,
|
||||||
val allDay: Boolean,
|
val allDay: Boolean,
|
||||||
val location: String,
|
val location: String,
|
||||||
val attendees: List<String>,
|
val attendees: List<String>,
|
||||||
val description: String,
|
val description: String,
|
||||||
val calendar: Long
|
val calendar: Long
|
||||||
) : Searchable() {
|
) : Searchable() {
|
||||||
|
|
||||||
override val key: String
|
override val key: String
|
||||||
@ -51,31 +48,27 @@ 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,
|
||||||
background = background,
|
background = background,
|
||||||
foregroundScale = 0.74f
|
foregroundScale = 0.74f
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,14 +77,15 @@ class CalendarEvent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun search(context: Context,
|
fun search(
|
||||||
query: String,
|
context: Context,
|
||||||
intervalStart: Long,
|
query: String,
|
||||||
intervalEnd: Long,
|
intervalStart: Long,
|
||||||
limit: Int = 10,
|
intervalEnd: Long,
|
||||||
hideAllDayEvents: Boolean = false,
|
limit: Int = 10,
|
||||||
unselectedCalendars: List<Long> = emptyList(),
|
hideAllDayEvents: Boolean = false,
|
||||||
hiddenEvents: List<Long> = emptyList()
|
unselectedCalendars: List<Long> = emptyList(),
|
||||||
|
hiddenEvents: List<Long> = emptyList()
|
||||||
): List<CalendarEvent> {
|
): List<CalendarEvent> {
|
||||||
val results = mutableListOf<CalendarEvent>()
|
val results = mutableListOf<CalendarEvent>()
|
||||||
if (!query.isEmpty() && query.length < 3) return results
|
if (!query.isEmpty() && query.length < 3) return results
|
||||||
@ -104,15 +98,15 @@ class CalendarEvent(
|
|||||||
ContentUris.appendId(builder, intervalEnd)
|
ContentUris.appendId(builder, intervalEnd)
|
||||||
val uri = builder.build()
|
val uri = builder.build()
|
||||||
val projection = arrayOf(
|
val projection = arrayOf(
|
||||||
CalendarContract.Instances.EVENT_ID,
|
CalendarContract.Instances.EVENT_ID,
|
||||||
CalendarContract.Instances.TITLE,
|
CalendarContract.Instances.TITLE,
|
||||||
CalendarContract.Instances.BEGIN,
|
CalendarContract.Instances.BEGIN,
|
||||||
CalendarContract.Instances.END,
|
CalendarContract.Instances.END,
|
||||||
CalendarContract.Instances.ALL_DAY,
|
CalendarContract.Instances.ALL_DAY,
|
||||||
CalendarContract.Instances.DISPLAY_COLOR,
|
CalendarContract.Instances.DISPLAY_COLOR,
|
||||||
CalendarContract.Instances.EVENT_LOCATION,
|
CalendarContract.Instances.EVENT_LOCATION,
|
||||||
CalendarContract.Instances.CALENDAR_ID,
|
CalendarContract.Instances.CALENDAR_ID,
|
||||||
CalendarContract.Instances.DESCRIPTION
|
CalendarContract.Instances.DESCRIPTION
|
||||||
)
|
)
|
||||||
val selection = mutableListOf<String>()
|
val selection = mutableListOf<String>()
|
||||||
if (query.isNotEmpty()) selection.add("${CalendarContract.Instances.TITLE} LIKE ?")
|
if (query.isNotEmpty()) selection.add("${CalendarContract.Instances.TITLE} LIKE ?")
|
||||||
@ -120,25 +114,32 @@ 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 ""
|
||||||
?: return mutableListOf()
|
val cursor = context.contentResolver.query(
|
||||||
|
uri,
|
||||||
|
projection,
|
||||||
|
selection.joinToString(separator = " AND "),
|
||||||
|
selArgs,
|
||||||
|
sort
|
||||||
|
)
|
||||||
|
?: return mutableListOf()
|
||||||
val proj = arrayOf(
|
val proj = arrayOf(
|
||||||
CalendarContract.Attendees.EVENT_ID,
|
CalendarContract.Attendees.EVENT_ID,
|
||||||
CalendarContract.Attendees.ATTENDEE_NAME,
|
CalendarContract.Attendees.ATTENDEE_NAME,
|
||||||
CalendarContract.Attendees.ATTENDEE_EMAIL
|
CalendarContract.Attendees.ATTENDEE_EMAIL
|
||||||
)
|
)
|
||||||
val s = "${CalendarContract.Attendees.ATTENDEE_NAME} COLLATE NOCASE ASC"
|
val s = "${CalendarContract.Attendees.ATTENDEE_NAME} COLLATE NOCASE ASC"
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
val sel = "${CalendarContract.Attendees.EVENT_ID} = ${cursor.getLong(0)}"
|
val sel = "${CalendarContract.Attendees.EVENT_ID} = ${cursor.getLong(0)}"
|
||||||
val cur = context.contentResolver.query(
|
val cur = context.contentResolver.query(
|
||||||
CalendarContract.Attendees.CONTENT_URI,
|
CalendarContract.Attendees.CONTENT_URI,
|
||||||
proj, sel, null, s
|
proj, sel, null, s
|
||||||
) ?: return mutableListOf()
|
) ?: return mutableListOf()
|
||||||
val attendees = mutableListOf<String>()
|
val attendees = mutableListOf<String>()
|
||||||
while (cur.moveToNext()) {
|
while (cur.moveToNext()) {
|
||||||
attendees.add(cur.getString(1).takeUnless { it.isNullOrBlank() }
|
attendees.add(cur.getString(1).takeUnless { it.isNullOrBlank() }
|
||||||
?: cur.getString(2))
|
?: cur.getString(2))
|
||||||
}
|
}
|
||||||
cur.close()
|
cur.close()
|
||||||
val allday = cursor.getInt(4) > 0
|
val allday = cursor.getInt(4) > 0
|
||||||
@ -150,17 +151,17 @@ class CalendarEvent(
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
val event = CalendarEvent(
|
val event = CalendarEvent(
|
||||||
label = cursor.getString(1) ?: "",
|
label = cursor.getString(1) ?: "",
|
||||||
id = cursor.getLong(0),
|
id = cursor.getLong(0),
|
||||||
color = cursor.getInt(5),
|
color = cursor.getInt(5),
|
||||||
startTime = begin - tzOffset,
|
startTime = begin - tzOffset,
|
||||||
endTime = cursor.getLong(3) - tzOffset - if (allday) 1 else 0,
|
endTime = cursor.getLong(3) - tzOffset - if (allday) 1 else 0,
|
||||||
allDay = allday,
|
allDay = allday,
|
||||||
location = cursor.getString(6) ?: "",
|
location = cursor.getString(6) ?: "",
|
||||||
attendees = attendees,
|
attendees = attendees,
|
||||||
description = cursor.getStringOrNull(8)
|
description = cursor.getStringOrNull(8)
|
||||||
?: "",
|
?: "",
|
||||||
calendar = cursor.getLong(7)
|
calendar = cursor.getLong(7)
|
||||||
)
|
)
|
||||||
results.add(event)
|
results.add(event)
|
||||||
}
|
}
|
||||||
@ -173,24 +174,26 @@ class CalendarEvent(
|
|||||||
val calendars = mutableListOf<UserCalendar>()
|
val calendars = mutableListOf<UserCalendar>()
|
||||||
val uri = CalendarContract.Calendars.CONTENT_URI
|
val uri = CalendarContract.Calendars.CONTENT_URI
|
||||||
val proj = arrayOf(
|
val proj = arrayOf(
|
||||||
CalendarContract.Calendars._ID,
|
CalendarContract.Calendars._ID,
|
||||||
CalendarContract.Calendars.NAME,
|
CalendarContract.Calendars.NAME,
|
||||||
CalendarContract.Calendars.ACCOUNT_NAME,
|
CalendarContract.Calendars.ACCOUNT_NAME,
|
||||||
CalendarContract.Calendars.CALENDAR_COLOR,
|
CalendarContract.Calendars.CALENDAR_COLOR,
|
||||||
CalendarContract.Calendars.VISIBLE,
|
CalendarContract.Calendars.VISIBLE,
|
||||||
CalendarContract.Calendars.CALENDAR_DISPLAY_NAME,
|
CalendarContract.Calendars.CALENDAR_DISPLAY_NAME,
|
||||||
)
|
)
|
||||||
if (!context.checkPermission(Manifest.permission.READ_CALENDAR)) return calendars
|
if (!context.checkPermission(Manifest.permission.READ_CALENDAR)) return calendars
|
||||||
val cursor = context.contentResolver.query(uri, proj, null, null, null)
|
val cursor = context.contentResolver.query(uri, proj, null, null, null)
|
||||||
?: 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)
|
||||||
@ -235,8 +250,8 @@ class CalendarEvent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class UserCalendar(
|
data class UserCalendar(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val name: String,
|
val name: String,
|
||||||
val owner: String,
|
val owner: String,
|
||||||
val color: Int
|
val color: Int
|
||||||
)
|
)
|
||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -1,33 +1,33 @@
|
|||||||
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,
|
||||||
val firstName: String,
|
val firstName: String,
|
||||||
val lastName: String,
|
val lastName: String,
|
||||||
val displayName: String,
|
val displayName: String,
|
||||||
val lookupKey: String,
|
val lookupKey: String,
|
||||||
val phones: Set<String>,
|
val phones: Set<String>,
|
||||||
val emails: Set<String>,
|
val emails: Set<String>,
|
||||||
val telegram: Set<String>,
|
val telegram: Set<String>,
|
||||||
val whatsapp: Set<String>,
|
val whatsapp: Set<String>,
|
||||||
val postals: Set<String>
|
val postals: Set<String>
|
||||||
) : Searchable() {
|
) : Searchable() {
|
||||||
override val key: String
|
override val key: String
|
||||||
get() = "contact://$id"
|
get() = "contact://$id"
|
||||||
@ -40,19 +40,22 @@ 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)
|
||||||
?: return null
|
?.asBitmap()
|
||||||
|
?: return null
|
||||||
return LauncherIcon(
|
return LauncherIcon(
|
||||||
foreground = bmp.toDrawable(context.resources)
|
foreground = bmp.toDrawable(context.resources)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,13 +73,14 @@ class Contact(
|
|||||||
return mutableListOf()
|
return mutableListOf()
|
||||||
}
|
}
|
||||||
val proj = arrayOf(
|
val proj = arrayOf(
|
||||||
ContactsContract.RawContacts.CONTACT_ID,
|
ContactsContract.RawContacts.CONTACT_ID,
|
||||||
ContactsContract.RawContacts._ID
|
ContactsContract.RawContacts._ID
|
||||||
)
|
)
|
||||||
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()) {
|
||||||
@ -92,7 +96,7 @@ class Contact(
|
|||||||
|
|
||||||
internal fun contactById(context: Context, id: Long, rawIds: Set<Long>): Contact? {
|
internal fun contactById(context: Context, id: Long, rawIds: Set<Long>): Contact? {
|
||||||
val s = "(" + rawIds.joinToString(separator = " OR ",
|
val s = "(" + rawIds.joinToString(separator = " OR ",
|
||||||
transform = { "${ContactsContract.Data.RAW_CONTACT_ID} = $it" }) + ")" +
|
transform = { "${ContactsContract.Data.RAW_CONTACT_ID} = $it" }) + ")" +
|
||||||
" AND (${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE}\"" +
|
" AND (${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE}\"" +
|
||||||
" OR ${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE}\"" +
|
" OR ${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE}\"" +
|
||||||
" OR ${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE}\"" +
|
" OR ${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE}\"" +
|
||||||
@ -101,8 +105,8 @@ class Contact(
|
|||||||
" OR ${ContactsContract.Data.MIMETYPE} = \"vnd.android.cursor.item/vnd.com.whatsapp.profile\"" +
|
" OR ${ContactsContract.Data.MIMETYPE} = \"vnd.android.cursor.item/vnd.com.whatsapp.profile\"" +
|
||||||
")"
|
")"
|
||||||
val dataCursor = context.contentResolver.query(
|
val dataCursor = context.contentResolver.query(
|
||||||
ContactsContract.Data.CONTENT_URI,
|
ContactsContract.Data.CONTENT_URI,
|
||||||
null, s, null, null
|
null, s, null, null
|
||||||
) ?: return null
|
) ?: return null
|
||||||
val phones = mutableSetOf<String>()
|
val phones = mutableSetOf<String>()
|
||||||
val emails = mutableSetOf<String>()
|
val emails = mutableSetOf<String>()
|
||||||
@ -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)
|
||||||
@ -139,14 +149,14 @@ class Contact(
|
|||||||
}
|
}
|
||||||
"vnd.android.cursor.item/vnd.org.telegram.messenger.android.profile" -> {
|
"vnd.android.cursor.item/vnd.org.telegram.messenger.android.profile" -> {
|
||||||
val data1 = dataCursor.getStringOrNull(data1Column)
|
val data1 = dataCursor.getStringOrNull(data1Column)
|
||||||
?: continue@loop
|
?: continue@loop
|
||||||
val data3 = dataCursor.getStringOrNull(data3Column)
|
val data3 = dataCursor.getStringOrNull(data3Column)
|
||||||
?: continue@loop
|
?: continue@loop
|
||||||
telegram.add("$data1$$data3")
|
telegram.add("$data1$$data3")
|
||||||
}
|
}
|
||||||
"vnd.android.cursor.item/vnd.com.whatsapp.profile" -> {
|
"vnd.android.cursor.item/vnd.com.whatsapp.profile" -> {
|
||||||
val data1 = dataCursor.getStringOrNull(data1Column)
|
val data1 = dataCursor.getStringOrNull(data1Column)
|
||||||
?: continue@loop
|
?: continue@loop
|
||||||
val dataId = dataCursor.getLong(idColumn)
|
val dataId = dataCursor.getLong(idColumn)
|
||||||
whatsapp.add("$dataId$+${data1.substringBefore('@')}")
|
whatsapp.add("$dataId$+${data1.substringBefore('@')}")
|
||||||
}
|
}
|
||||||
@ -155,11 +165,11 @@ class Contact(
|
|||||||
dataCursor.close()
|
dataCursor.close()
|
||||||
|
|
||||||
val lookupKeyCursor = context.contentResolver.query(
|
val lookupKeyCursor = context.contentResolver.query(
|
||||||
ContactsContract.Contacts.CONTENT_URI,
|
ContactsContract.Contacts.CONTENT_URI,
|
||||||
arrayOf(ContactsContract.Contacts.LOOKUP_KEY),
|
arrayOf(ContactsContract.Contacts.LOOKUP_KEY),
|
||||||
"${ContactsContract.Contacts._ID} = ?",
|
"${ContactsContract.Contacts._ID} = ?",
|
||||||
arrayOf(id.toString()),
|
arrayOf(id.toString()),
|
||||||
null
|
null
|
||||||
) ?: return null
|
) ?: return null
|
||||||
var lookUpKey = ""
|
var lookUpKey = ""
|
||||||
if (lookupKeyCursor.moveToNext()) {
|
if (lookupKeyCursor.moveToNext()) {
|
||||||
@ -168,16 +178,16 @@ class Contact(
|
|||||||
lookupKeyCursor.close()
|
lookupKeyCursor.close()
|
||||||
|
|
||||||
return Contact(
|
return Contact(
|
||||||
id = id,
|
id = id,
|
||||||
emails = emails,
|
emails = emails,
|
||||||
phones = phones,
|
phones = phones,
|
||||||
firstName = firstName,
|
firstName = firstName,
|
||||||
lastName = lastName,
|
lastName = lastName,
|
||||||
displayName = displayName,
|
displayName = displayName,
|
||||||
postals = postals,
|
postals = postals,
|
||||||
telegram = telegram,
|
telegram = telegram,
|
||||||
whatsapp = whatsapp,
|
whatsapp = whatsapp,
|
||||||
lookupKey = lookUpKey
|
lookupKey = lookUpKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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")
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user