Fix missing avatars in widgets (#1238)

This commit is contained in:
Rafał Borcz 2021-03-21 12:04:55 +01:00 committed by GitHub
parent efafd2094a
commit e03b0dfa01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 101 additions and 21 deletions

View File

@ -1,18 +1,20 @@
package io.github.wulkanowy.ui.base package io.github.wulkanowy.ui.base
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.graphics.PorterDuff
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.databinding.ItemAccountBinding import io.github.wulkanowy.databinding.ItemAccountBinding
import io.github.wulkanowy.utils.createNameInitialsDrawable
import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.nickOrName import io.github.wulkanowy.utils.nickOrName
import javax.inject.Inject import javax.inject.Inject
class WidgetConfigureAdapter @Inject constructor() : RecyclerView.Adapter<WidgetConfigureAdapter.ItemViewHolder>() { class WidgetConfigureAdapter @Inject constructor() :
RecyclerView.Adapter<WidgetConfigureAdapter.ItemViewHolder>() {
var items = emptyList<Pair<Student, Boolean>>() var items = emptyList<Pair<Student, Boolean>>()
@ -27,16 +29,31 @@ class WidgetConfigureAdapter @Inject constructor() : RecyclerView.Adapter<Widget
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val (student, isCurrent) = items[position] val (student, isCurrent) = items[position]
val context = holder.binding.root.context
val checkBackgroundColor = context.getThemeAttrColor(R.attr.colorSurface)
val avatar = context.createNameInitialsDrawable(student.nickOrName, student.avatarColor)
val isDuplicatedStudent = items.filter {
val studentToCompare = it.first
studentToCompare.studentId == student.studentId
&& studentToCompare.schoolSymbol == student.schoolSymbol
&& studentToCompare.symbol == student.symbol
}.size > 1
with(holder.binding) { with(holder.binding) {
accountItemName.text = "${student.nickOrName} ${student.className}" accountItemName.text = "${student.nickOrName} ${student.className}"
accountItemSchool.text = student.schoolName accountItemSchool.text = student.schoolName
accountItemImage.setImageDrawable(avatar)
with(accountItemImage) { with(accountItemAccountType) {
val colorImage = if (isCurrent) context.getThemeAttrColor(R.attr.colorPrimary) setText(if (student.isParent) R.string.account_type_parent else R.string.account_type_student)
else context.getThemeAttrColor(R.attr.colorOnSurface, 153) isVisible = isDuplicatedStudent
}
setColorFilter(colorImage, PorterDuff.Mode.SRC_IN) with(accountItemCheck) {
isVisible = isCurrent
borderColor = checkBackgroundColor
circleColor = checkBackgroundColor
} }
root.setOnClickListener { onClickListener(student) } root.setOnClickListener { onClickListener(student) }

View File

@ -13,6 +13,8 @@ import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.Canvas
import android.widget.RemoteViews import android.widget.RemoteViews
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R import io.github.wulkanowy.R
@ -25,6 +27,8 @@ import io.github.wulkanowy.services.widgets.TimetableWidgetService
import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.createNameInitialsDrawable
import io.github.wulkanowy.utils.getCompatColor
import io.github.wulkanowy.utils.nextOrSameSchoolDay import io.github.wulkanowy.utils.nextOrSameSchoolDay
import io.github.wulkanowy.utils.nextSchoolDay import io.github.wulkanowy.utils.nextSchoolDay
import io.github.wulkanowy.utils.nickOrName import io.github.wulkanowy.utils.nickOrName
@ -72,7 +76,8 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
fun getThemeWidgetKey(appWidgetId: Int) = "timetable_widget_theme_$appWidgetId" fun getThemeWidgetKey(appWidgetId: Int) = "timetable_widget_theme_$appWidgetId"
fun getCurrentThemeWidgetKey(appWidgetId: Int) = "timetable_widget_current_theme_$appWidgetId" fun getCurrentThemeWidgetKey(appWidgetId: Int) =
"timetable_widget_current_theme_$appWidgetId"
} }
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
@ -88,21 +93,29 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
private suspend fun onUpdate(context: Context, intent: Intent) { private suspend fun onUpdate(context: Context, intent: Intent) {
if (intent.getStringExtra(EXTRA_BUTTON_TYPE) === null) { if (intent.getStringExtra(EXTRA_BUTTON_TYPE) === null) {
intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS)?.forEach { appWidgetId -> intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS)?.forEach { appWidgetId ->
val student = getStudent(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId) val student =
getStudent(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
updateWidget(context, appWidgetId, now().nextOrSameSchoolDay, student) updateWidget(context, appWidgetId, now().nextOrSameSchoolDay, student)
} }
} else { } else {
val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE) val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE)
val toggledWidgetId = intent.getIntExtra(EXTRA_TOGGLED_WIDGET_ID, 0) val toggledWidgetId = intent.getIntExtra(EXTRA_TOGGLED_WIDGET_ID, 0)
val student = getStudent(sharedPref.getLong(getStudentWidgetKey(toggledWidgetId), 0), toggledWidgetId) val student = getStudent(
val savedDate = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(toggledWidgetId), 0)) sharedPref.getLong(getStudentWidgetKey(toggledWidgetId), 0),
toggledWidgetId
)
val savedDate =
LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(toggledWidgetId), 0))
val date = when (buttonType) { val date = when (buttonType) {
BUTTON_RESET -> now().nextOrSameSchoolDay BUTTON_RESET -> now().nextOrSameSchoolDay
BUTTON_NEXT -> savedDate.nextSchoolDay BUTTON_NEXT -> savedDate.nextSchoolDay
BUTTON_PREV -> savedDate.previousSchoolDay BUTTON_PREV -> savedDate.previousSchoolDay
else -> now().nextOrSameSchoolDay else -> now().nextOrSameSchoolDay
} }
if (!buttonType.isNullOrBlank()) analytics.logEvent("changed_timetable_widget_day", "button" to buttonType) if (!buttonType.isNullOrBlank()) analytics.logEvent(
"changed_timetable_widget_day",
"button" to buttonType
)
updateWidget(context, toggledWidgetId, date, student) updateWidget(context, toggledWidgetId, date, student)
} }
} }
@ -121,9 +134,15 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
} }
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
private fun updateWidget(context: Context, appWidgetId: Int, date: LocalDate, student: Student?) { private fun updateWidget(
context: Context,
appWidgetId: Int,
date: LocalDate,
student: Student?
) {
val savedConfigureTheme = sharedPref.getLong(getThemeWidgetKey(appWidgetId), 0) val savedConfigureTheme = sharedPref.getLong(getThemeWidgetKey(appWidgetId), 0)
val isSystemDarkMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES val isSystemDarkMode =
context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
var currentTheme = 0L var currentTheme = 0L
var layoutId = R.layout.widget_timetable var layoutId = R.layout.widget_timetable
@ -134,21 +153,28 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
val nextNavIntent = createNavIntent(context, appWidgetId, appWidgetId, BUTTON_NEXT) val nextNavIntent = createNavIntent(context, appWidgetId, appWidgetId, BUTTON_NEXT)
val prevNavIntent = createNavIntent(context, -appWidgetId, appWidgetId, BUTTON_PREV) val prevNavIntent = createNavIntent(context, -appWidgetId, appWidgetId, BUTTON_PREV)
val resetNavIntent = createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET) val resetNavIntent =
createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET)
val adapterIntent = Intent(context, TimetableWidgetService::class.java) val adapterIntent = Intent(context, TimetableWidgetService::class.java)
.apply { .apply {
putExtra(EXTRA_APPWIDGET_ID, appWidgetId) putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
//make Intent unique //make Intent unique
action = appWidgetId.toString() action = appWidgetId.toString()
} }
val accountIntent = PendingIntent.getActivity(context, -Int.MAX_VALUE + appWidgetId, val accountIntent = PendingIntent.getActivity(
context, -Int.MAX_VALUE + appWidgetId,
Intent(context, TimetableWidgetConfigureActivity::class.java).apply { Intent(context, TimetableWidgetConfigureActivity::class.java).apply {
addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK) addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)
putExtra(EXTRA_APPWIDGET_ID, appWidgetId) putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
putExtra(EXTRA_FROM_PROVIDER, true) putExtra(EXTRA_FROM_PROVIDER, true)
}, FLAG_UPDATE_CURRENT) }, FLAG_UPDATE_CURRENT
val appIntent = PendingIntent.getActivity(context, MainView.Section.TIMETABLE.id, )
MainActivity.getStartIntent(context, MainView.Section.TIMETABLE, true), FLAG_UPDATE_CURRENT) val appIntent = PendingIntent.getActivity(
context,
MainView.Section.TIMETABLE.id,
MainActivity.getStartIntent(context, MainView.Section.TIMETABLE, true),
FLAG_UPDATE_CURRENT
)
val remoteView = RemoteViews(context.packageName, layoutId).apply { val remoteView = RemoteViews(context.packageName, layoutId).apply {
setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty) setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty)
@ -160,6 +186,11 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
R.id.timetableWidgetName, R.id.timetableWidgetName,
student?.nickOrName ?: context.getString(R.string.all_no_data) student?.nickOrName ?: context.getString(R.string.all_no_data)
) )
student?.let {
setImageViewBitmap(R.id.timetableWidgetAccount, context.createAvatarBitmap(it))
}
setRemoteAdapter(R.id.timetableWidgetList, adapterIntent) setRemoteAdapter(R.id.timetableWidgetList, adapterIntent)
setOnClickPendingIntent(R.id.timetableWidgetNext, nextNavIntent) setOnClickPendingIntent(R.id.timetableWidgetNext, nextNavIntent)
setOnClickPendingIntent(R.id.timetableWidgetPrev, prevNavIntent) setOnClickPendingIntent(R.id.timetableWidgetPrev, prevNavIntent)
@ -181,13 +212,20 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
} }
} }
private fun createNavIntent(context: Context, code: Int, appWidgetId: Int, buttonType: String): PendingIntent { private fun createNavIntent(
return PendingIntent.getBroadcast(context, code, context: Context,
code: Int,
appWidgetId: Int,
buttonType: String
): PendingIntent {
return PendingIntent.getBroadcast(
context, code,
Intent(context, TimetableWidgetProvider::class.java).apply { Intent(context, TimetableWidgetProvider::class.java).apply {
action = ACTION_APPWIDGET_UPDATE action = ACTION_APPWIDGET_UPDATE
putExtra(EXTRA_BUTTON_TYPE, buttonType) putExtra(EXTRA_BUTTON_TYPE, buttonType)
putExtra(EXTRA_TOGGLED_WIDGET_ID, appWidgetId) putExtra(EXTRA_TOGGLED_WIDGET_ID, appWidgetId)
}, FLAG_UPDATE_CURRENT) }, FLAG_UPDATE_CURRENT
)
} }
private suspend fun getStudent(studentId: Long, appWidgetId: Int) = try { private suspend fun getStudent(studentId: Long, appWidgetId: Int) = try {
@ -208,4 +246,29 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
} }
null null
} }
private fun Context.createAvatarBitmap(student: Student): Bitmap {
val avatarColor = if (student.avatarColor == -2937041L) {
getCompatColor(R.color.colorPrimaryLight).toLong()
} else {
student.avatarColor
}
val avatarDrawable = createNameInitialsDrawable(student.nickOrName, avatarColor, 0.5f)
val avatarBitmap =
if (avatarDrawable.intrinsicWidth <= 0 || avatarDrawable.intrinsicHeight <= 0) {
Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
} else {
Bitmap.createBitmap(
avatarDrawable.intrinsicWidth,
avatarDrawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
}
val canvas = Canvas(avatarBitmap)
avatarDrawable.setBounds(0, 0, canvas.width, canvas.height)
avatarDrawable.draw(canvas)
return avatarBitmap
}
} }