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("com.google.android.material:material:1.2.0")
|
||||||
implementation(libs.protobuf.javalite)
|
implementation(libs.protobuf.javalite)
|
||||||
implementation("androidx.compose.material:material")
|
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" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</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>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</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