mirror of
https://github.com/nacabaro/vbhelper.git
synced 2026-01-27 16:05:32 +00:00
Create a small test widget, I just wanted to learn hoe Jetpack Compose Glance works?
This commit is contained in:
parent
d46769b0cb
commit
93f568dd8d
@ -91,4 +91,7 @@ dependencies {
|
||||
implementation("com.google.android.material:material:1.2.0")
|
||||
implementation(libs.protobuf.javalite)
|
||||
implementation("androidx.compose.material:material")
|
||||
implementation("androidx.glance:glance:1.1.1")
|
||||
implementation("androidx.glance:glance-appwidget:1.1.1")
|
||||
implementation("androidx.work:work-runtime-ktx:2.9.0")
|
||||
}
|
||||
@ -27,6 +27,15 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<receiver android:name=".widget.CharacterDisplayWidgetReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_info" />
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -0,0 +1,117 @@
|
||||
package com.github.nacabaro.vbhelper.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.glance.GlanceTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.glance.background
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import androidx.glance.GlanceId
|
||||
import androidx.glance.GlanceModifier
|
||||
import androidx.glance.Image
|
||||
import androidx.glance.ImageProvider
|
||||
import androidx.glance.appwidget.GlanceAppWidget
|
||||
import androidx.glance.appwidget.provideContent
|
||||
import androidx.glance.layout.Alignment
|
||||
import androidx.glance.layout.Column
|
||||
import androidx.glance.layout.fillMaxSize
|
||||
import androidx.glance.layout.size
|
||||
import androidx.glance.state.PreferencesGlanceStateDefinition
|
||||
import androidx.glance.text.Text
|
||||
import androidx.glance.unit.ColorProvider
|
||||
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||
import com.github.nacabaro.vbhelper.utils.getBitmap
|
||||
|
||||
/*
|
||||
RANT: Why did they have to create the components from Jetpack Compose
|
||||
with a different API for Glance? Now there are things I use in Jetpack Compose
|
||||
like the filterQuality, which isn't here.
|
||||
*/
|
||||
|
||||
val CURRENT_IMAGE_KEY = booleanPreferencesKey("current_image")
|
||||
|
||||
class CharacterDisplayWidget : GlanceAppWidget() {
|
||||
override suspend fun provideGlance(context: Context, id: GlanceId) {
|
||||
val application = context.applicationContext as VBHelper
|
||||
val storageRepository = application.container.db
|
||||
|
||||
val currentCharacter = storageRepository
|
||||
.userCharacterDao()
|
||||
.getActiveCharacter()
|
||||
|
||||
val multiplier = 4
|
||||
|
||||
provideContent {
|
||||
var bitmapIdle1 by remember { mutableStateOf<Bitmap?>(null) }
|
||||
var bitmapIdle2 by remember { mutableStateOf<Bitmap?>(null) }
|
||||
var dpSize by remember { mutableStateOf(0.dp) }
|
||||
|
||||
if (currentCharacter != null) {
|
||||
val currentCharacterBitmapIdle1 = BitmapData(
|
||||
currentCharacter.spriteIdle,
|
||||
currentCharacter.spriteWidth,
|
||||
currentCharacter.spriteHeight
|
||||
)
|
||||
|
||||
val currentCharacterBitmapIdle2 = BitmapData(
|
||||
currentCharacter.spriteIdle2,
|
||||
currentCharacter.spriteWidth,
|
||||
currentCharacter.spriteHeight
|
||||
)
|
||||
|
||||
bitmapIdle1 = currentCharacterBitmapIdle1.getBitmap()
|
||||
bitmapIdle2 = currentCharacterBitmapIdle2.getBitmap()
|
||||
|
||||
val density: Float = application.resources.displayMetrics.density
|
||||
dpSize = (currentCharacterBitmapIdle1.width * multiplier / density).dp
|
||||
}
|
||||
|
||||
WidgetContent(
|
||||
imageBitmapFrame1 = bitmapIdle1,
|
||||
imageBitmapFrame2 = bitmapIdle2,
|
||||
dpSize = dpSize
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WidgetContent(
|
||||
imageBitmapFrame1: Bitmap?,
|
||||
imageBitmapFrame2: Bitmap?,
|
||||
dpSize: Dp
|
||||
) {
|
||||
GlanceTheme {
|
||||
Column (
|
||||
horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
|
||||
verticalAlignment = Alignment.Vertical.CenterVertically,
|
||||
modifier = GlanceModifier
|
||||
.fillMaxSize()
|
||||
.background(ColorProvider(MaterialTheme.colorScheme.background))
|
||||
) {
|
||||
if (imageBitmapFrame1 != null) {
|
||||
Image(
|
||||
provider = ImageProvider(
|
||||
bitmap = imageBitmapFrame1
|
||||
),
|
||||
contentDescription = "Character",
|
||||
modifier = GlanceModifier
|
||||
.size(dpSize)
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = "No character selected"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
package com.github.nacabaro.vbhelper.widget
|
||||
|
||||
import androidx.glance.state.PreferencesGlanceStateDefinition
|
||||
@ -0,0 +1,8 @@
|
||||
package com.github.nacabaro.vbhelper.widget
|
||||
|
||||
import androidx.glance.appwidget.GlanceAppWidget
|
||||
import androidx.glance.appwidget.GlanceAppWidgetReceiver
|
||||
|
||||
class CharacterDisplayWidgetReceiver : GlanceAppWidgetReceiver() {
|
||||
override val glanceAppWidget: GlanceAppWidget = CharacterDisplayWidget()
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.github.nacabaro.vbhelper.widget
|
||||
|
||||
import android.content.Context
|
||||
import androidx.glance.appwidget.GlanceAppWidgetManager
|
||||
import androidx.glance.appwidget.state.updateAppWidgetState
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
|
||||
class CharacterDisplayWidgetWorker(
|
||||
appContext: Context,
|
||||
workerParams: WorkerParameters
|
||||
) : CoroutineWorker(appContext, workerParams) {
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
// Get all widget IDs for your ImageSwapWidget
|
||||
val glanceIds = GlanceAppWidgetManager(applicationContext)
|
||||
.getGlanceIds(CharacterDisplayWidget::class.java)
|
||||
|
||||
glanceIds.forEach { glanceId ->
|
||||
// Update the widget's state (toggle the boolean)
|
||||
updateAppWidgetState(
|
||||
context = applicationContext,
|
||||
glanceId = glanceId
|
||||
) { prefs ->
|
||||
val currentImageIsImage1 = prefs[CURRENT_IMAGE_KEY] ?: true
|
||||
prefs[CURRENT_IMAGE_KEY] = !currentImageIsImage1 // Toggle the boolean
|
||||
}
|
||||
// Trigger the widget to redraw itself with the new state
|
||||
CharacterDisplayWidget().update(applicationContext, glanceId)
|
||||
}
|
||||
|
||||
// Indicate that the work was successful
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
10
app/src/main/res/xml/widget_info.xml
Normal file
10
app/src/main/res/xml/widget_info.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:initialLayout="@layout/glance_default_loading_layout"
|
||||
android:minWidth="40dp"
|
||||
android:minHeight="20dp"
|
||||
android:minResizeWidth="20dp"
|
||||
android:previewImage="@drawable/baseline_image_24"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:updatePeriodMillis="300000"
|
||||
android:widgetCategory="home_screen" />
|
||||
Loading…
x
Reference in New Issue
Block a user