Monday, May 30, 2022

compose glance - How to create app widget

CounterWidget.kt

package com.cfsuman.widgetexamples

import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.glance.*
import androidx.glance.action.ActionParameters
import androidx.glance.action.actionParametersOf
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
import androidx.glance.appwidget.action.ActionCallback
import androidx.glance.appwidget.action.actionRunCallback
import androidx.glance.appwidget.state.updateAppWidgetState
import androidx.glance.layout.*
import androidx.glance.state.GlanceStateDefinition
import androidx.glance.state.PreferencesGlanceStateDefinition
import androidx.glance.text.Text
import androidx.glance.text.TextAlign
import androidx.glance.text.TextStyle
import androidx.glance.unit.ColorProvider

private val countPreferenceKey = intPreferencesKey("count-key")
private val countParamKey = ActionParameters.Key<Int>("count-key")


class CounterWidget : GlanceAppWidget(){

    override val stateDefinition: GlanceStateDefinition<*> =
        PreferencesGlanceStateDefinition

    @Composable
    override fun Content(){
        val prefs = currentState<Preferences>()
        val count = prefs[countPreferenceKey] ?: 0

        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalAlignment = Alignment.CenterVertically,
            modifier = GlanceModifier
                .background(Color(0xFFD3E9FA))
                .fillMaxSize()
        ) {
            Text(
                text = count.toString(),
                modifier = GlanceModifier.fillMaxWidth(),
                style = TextStyle(
                    textAlign = TextAlign.Center,
                    color = ColorProvider(Color.Blue),
                    fontSize = 50.sp
                )
            )

            Spacer(modifier = GlanceModifier.padding(8.dp))

            Button(
                text = "Up",
                modifier = GlanceModifier
                    .background(Color(0xFFB6C0C9))
                    .size(100.dp,50.dp),
                onClick = actionRunCallback<UpdateActionCallback>(
                    parameters = actionParametersOf(
                        countParamKey to (count + 1)
                    )
                )
            )
        }
    }
}


class UpdateActionCallback : ActionCallback{
    override suspend fun onRun(context: Context, glanceId: GlanceId,
                               parameters: ActionParameters) {

        val count = requireNotNull(parameters[countParamKey])

        updateAppWidgetState(
            context = context,
            definition = PreferencesGlanceStateDefinition,
            glanceId = glanceId
        ){ preferences ->
            preferences.toMutablePreferences()
                .apply {
                    this[countPreferenceKey] = count
                }
        }

        CounterWidget().update(context,glanceId)
    }
}


class CounterWidgetReceiver : GlanceAppWidgetReceiver(){
    override val glanceAppWidget:GlanceAppWidget = CounterWidget()
}
res/xml/counter_widget_info.xml

<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/app_name"
    android:minWidth="100dp"
    android:minHeight="50dp"
    android:resizeMode="horizontal|vertical"
    android:targetCellWidth="3"
    android:targetCellHeight="2"
    android:widgetCategory="home_screen"
    />
AndroidManifest.xml [Part]

<receiver
	android:name=".CounterWidgetReceiver"
	android:enabled="@bool/glance_appwidget_available"
	android:exported="false">
	<intent-filter>
		<action android:name
			="android.appwidget.action.APPWIDGET_UPDATE" />
	</intent-filter>
	<meta-data
		android:name="android.appwidget.provider"
		android:resource="@xml/counter_widget_info" />
</receiver>

build.gradle [app] [dependencies]

implementation "androidx.glance:glance-appwidget:1.0.0-alpha03"