Skip to content

Commit

Permalink
feat: add per-widget configuration (#333)
Browse files Browse the repository at this point in the history
* feat: add per-widget configuration

* fix: no need to overengineer it

* feat: add cache to bitmap download

dfgdfg

* fix: elvis has left the operation
  • Loading branch information
TwistedUmbrellaX committed Apr 8, 2024
1 parent 47d05e7 commit f96d2ff
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 103 deletions.
67 changes: 48 additions & 19 deletions app/src/main/java/ani/dantotsu/util/BitmapUtil.kt
Original file line number Diff line number Diff line change
@@ -1,33 +1,62 @@
package ani.dantotsu.util

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.BitmapShader
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.RectF
import android.graphics.Shader
import android.graphics.drawable.Drawable
import androidx.collection.LruCache
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL

class BitmapUtil {
companion object {
fun roundCorners(bitmap: Bitmap, cornerRadius: Float = 20f): Bitmap {
val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val paint = Paint()
paint.isAntiAlias = true
paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val rect = RectF(0f, 0f, bitmap.width.toFloat(), bitmap.height.toFloat())
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint)
object BitmapUtil {
private fun roundCorners(bitmap: Bitmap, cornerRadius: Float = 20f): Bitmap {
val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val paint = Paint()
paint.isAntiAlias = true
paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val rect = RectF(0f, 0f, bitmap.width.toFloat(), bitmap.height.toFloat())
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint)

return output
}
return output
}

private val cacheSize = (Runtime.getRuntime().maxMemory() / 1024 / 16).toInt()
private val bitmapCache = LruCache<String, Bitmap>(cacheSize)

fun downloadImageAsBitmap(imageUrl: String): Bitmap? {
var bitmap: Bitmap? = null

runBlocking(Dispatchers.IO) {
val cacheName = imageUrl.substringAfterLast("/")
bitmap = bitmapCache[cacheName]
if (bitmap != null) return@runBlocking
var inputStream: InputStream? = null
var urlConnection: HttpURLConnection? = null
try {
val url = URL(imageUrl)
urlConnection = url.openConnection() as HttpURLConnection
urlConnection.requestMethod = "GET"
urlConnection.connect()

fun convertDrawableToBitmap(drawable: Drawable, width: Int, height: Int): Bitmap {
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
if (urlConnection.responseCode == HttpURLConnection.HTTP_OK) {
inputStream = urlConnection.inputStream
bitmap = BitmapFactory.decodeStream(inputStream)
bitmap?.let { bitmapCache.put(cacheName, it) }
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
inputStream?.close()
urlConnection?.disconnect()
}
}
return bitmap?.let { roundCorners(it) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ class ProfileStatsConfigure : AppCompatActivity(),
binding = StatisticsWidgetConfigureBinding.inflate(layoutInflater)
setContentView(binding.root)

val prefs = getSharedPreferences(ProfileStatsWidget.PREFS_NAME, Context.MODE_PRIVATE)
appWidgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID
)
val prefs = getSharedPreferences(ProfileStatsWidget.getPrefsName(appWidgetId), Context.MODE_PRIVATE)
val topBackground = prefs.getInt(ProfileStatsWidget.PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
(binding.topBackgroundButton as MaterialButton).iconTint = ColorStateList.valueOf(topBackground)
binding.topBackgroundButton.setOnClickListener {
Expand Down Expand Up @@ -192,7 +196,7 @@ class ProfileStatsConfigure : AppCompatActivity(),
)
val subTextColor = typedValueOutline.data

getSharedPreferences(ProfileStatsWidget.PREFS_NAME, Context.MODE_PRIVATE).edit().apply {
getSharedPreferences(ProfileStatsWidget.getPrefsName(appWidgetId), Context.MODE_PRIVATE).edit().apply {
putInt(ProfileStatsWidget.PREF_BACKGROUND_COLOR, backgroundColor)
putInt(ProfileStatsWidget.PREF_BACKGROUND_FADE, backgroundColor)
putInt(ProfileStatsWidget.PREF_TITLE_TEXT_COLOR, textColor)
Expand All @@ -204,12 +208,13 @@ class ProfileStatsConfigure : AppCompatActivity(),
override fun onResult(dialogTag: String, which: Int, extras: Bundle): Boolean {
if (which == SimpleDialog.OnDialogResultListener.BUTTON_POSITIVE) {
if (!isMonetEnabled) {
val prefs = getSharedPreferences(
ProfileStatsWidget.getPrefsName(appWidgetId),
Context.MODE_PRIVATE
)
when (dialogTag) {
ProfileStatsWidget.PREF_BACKGROUND_COLOR -> {
getSharedPreferences(
ProfileStatsWidget.PREFS_NAME,
Context.MODE_PRIVATE
).edit()
prefs.edit()
.putInt(
ProfileStatsWidget.PREF_BACKGROUND_COLOR,
extras.getInt(SimpleColorDialog.COLOR)
Expand All @@ -220,10 +225,7 @@ class ProfileStatsConfigure : AppCompatActivity(),
}

ProfileStatsWidget.PREF_BACKGROUND_FADE -> {
getSharedPreferences(
ProfileStatsWidget.PREFS_NAME,
Context.MODE_PRIVATE
).edit()
prefs.edit()
.putInt(
ProfileStatsWidget.PREF_BACKGROUND_FADE,
extras.getInt(SimpleColorDialog.COLOR)
Expand All @@ -234,10 +236,7 @@ class ProfileStatsConfigure : AppCompatActivity(),
}

ProfileStatsWidget.PREF_TITLE_TEXT_COLOR -> {
getSharedPreferences(
ProfileStatsWidget.PREFS_NAME,
Context.MODE_PRIVATE
).edit()
prefs.edit()
.putInt(
ProfileStatsWidget.PREF_TITLE_TEXT_COLOR,
extras.getInt(SimpleColorDialog.COLOR)
Expand All @@ -248,10 +247,7 @@ class ProfileStatsConfigure : AppCompatActivity(),
}

ProfileStatsWidget.PREF_STATS_TEXT_COLOR -> {
getSharedPreferences(
ProfileStatsWidget.PREFS_NAME,
Context.MODE_PRIVATE
).edit()
prefs.edit()
.putInt(
ProfileStatsWidget.PREF_STATS_TEXT_COLOR,
extras.getInt(SimpleColorDialog.COLOR)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,24 @@ import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.net.Uri
import android.widget.RemoteViews
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.toBitmap
import ani.dantotsu.MainActivity
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.util.BitmapUtil
import ani.dantotsu.util.BitmapUtil.Companion.downloadImageAsBitmap
import ani.dantotsu.widgets.WidgetSizeProvider
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import tachiyomi.core.util.lang.launchIO
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL

/**
* Implementation of App Widget functionality.
Expand Down Expand Up @@ -56,40 +52,14 @@ class ProfileStatsWidget : AppWidgetProvider() {
}

companion object {
private fun downloadImageAsBitmap(imageUrl: String): Bitmap? {
var bitmap: Bitmap? = null

runBlocking(Dispatchers.IO) {
var inputStream: InputStream? = null
var urlConnection: HttpURLConnection? = null
try {
val url = URL(imageUrl)
urlConnection = url.openConnection() as HttpURLConnection
urlConnection.requestMethod = "GET"
urlConnection.connect()

if (urlConnection.responseCode == HttpURLConnection.HTTP_OK) {
inputStream = urlConnection.inputStream
bitmap = BitmapFactory.decodeStream(inputStream)
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
inputStream?.close()
urlConnection?.disconnect()
}
}
return bitmap?.let { BitmapUtil.roundCorners(it) }
}

@OptIn(DelicateCoroutinesApi::class)
fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {

val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
val prefs = context.getSharedPreferences(getPrefsName(appWidgetId), Context.MODE_PRIVATE)
val backgroundColor =
prefs.getInt(PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
val backgroundFade = prefs.getInt(PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
Expand Down Expand Up @@ -120,8 +90,7 @@ class ProfileStatsWidget : AppWidgetProvider() {
val views = RemoteViews(context.packageName, R.layout.statistics_widget).apply {
setImageViewBitmap(
R.id.backgroundView,
BitmapUtil.convertDrawableToBitmap(
gradientDrawable,
gradientDrawable.toBitmap(
width,
height
)
Expand All @@ -133,6 +102,7 @@ class ProfileStatsWidget : AppWidgetProvider() {
1,
Intent(context, ProfileStatsConfigure::class.java).apply {
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
},
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
Expand Down Expand Up @@ -248,7 +218,9 @@ class ProfileStatsWidget : AppWidgetProvider() {
}
}

const val PREFS_NAME = "ani.dantotsu.widgets.ResumableWidget"
fun getPrefsName(appWidgetId: Int): String {
return "ani.dantotsu.widgets.Statistics.${appWidgetId}"
}
const val PREF_BACKGROUND_COLOR = "background_color"
const val PREF_BACKGROUND_FADE = "background_fade"
const val PREF_TITLE_TEXT_COLOR = "title_text_color"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.media.Media
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.util.BitmapUtil.Companion.downloadImageAsBitmap
import ani.dantotsu.util.BitmapUtil.Companion.roundCorners
import ani.dantotsu.util.Logger
import com.google.gson.GsonBuilder
Expand Down Expand Up @@ -183,33 +184,6 @@ class UpcomingRemoteViewsFactory(private val context: Context) :
return rv
}

private fun downloadImageAsBitmap(imageUrl: String): Bitmap? {
var bitmap: Bitmap? = null
var inputStream: InputStream? = null
var urlConnection: HttpURLConnection? = null

try {
val url = URL(imageUrl)
urlConnection = url.openConnection() as HttpURLConnection
urlConnection.requestMethod = "GET"
urlConnection.connect()

if (urlConnection.responseCode == HttpURLConnection.HTTP_OK) {
inputStream = urlConnection.inputStream
bitmap = BitmapFactory.decodeStream(inputStream)
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
inputStream?.close()
urlConnection?.disconnect()
}
return bitmap?.let { roundCorners(it) }
}




override fun getLoadingView(): RemoteViews {
return RemoteViews(context.packageName, R.layout.item_upcoming_widget)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import android.net.Uri
import android.os.Bundle
import android.widget.RemoteViews
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.toBitmap
import ani.dantotsu.MainActivity
import ani.dantotsu.R
import ani.dantotsu.util.BitmapUtil.Companion.convertDrawableToBitmap
import ani.dantotsu.widgets.WidgetSizeProvider

/**
Expand Down Expand Up @@ -97,7 +97,7 @@ class UpcomingWidget : AppWidgetProvider() {
intentTemplate.putExtra("fromWidget", true)

val views = RemoteViews(context.packageName, R.layout.upcoming_widget).apply {
setImageViewBitmap(R.id.backgroundView, convertDrawableToBitmap(gradientDrawable, width, height))
setImageViewBitmap(R.id.backgroundView, gradientDrawable.toBitmap(width, height))
setTextColor(R.id.text_show_title, titleTextColor)
setTextColor(R.id.text_show_countdown, countdownTextColor)
setTextColor(R.id.widgetTitle, titleTextColor)
Expand Down

1 comment on commit f96d2ff

@AbandonedCart
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the optimize imports didn't carry over

Please sign in to comment.