Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@
package com.example.compose.snippets.glance

import android.annotation.SuppressLint
import androidx.annotation.RequiresApi
import android.app.Activity
import android.app.Application
import android.app.PendingIntent
import android.app.Service
import android.appwidget.AppWidgetManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.widget.RemoteViews
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material3.ColorScheme
Expand All @@ -41,6 +44,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.glance.Button
import androidx.glance.ColorFilter
import androidx.glance.GlanceId
Expand Down Expand Up @@ -86,13 +90,15 @@ import androidx.glance.layout.Row
import androidx.glance.layout.RowScope
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.layout.width
import androidx.glance.layout.height
import androidx.glance.layout.padding
import androidx.glance.material3.ColorProviders
import androidx.glance.preview.ExperimentalGlancePreviewApi
import androidx.glance.preview.Preview
import androidx.glance.text.FontFamily
import androidx.glance.text.FontWeight
import androidx.glance.text.Text
import androidx.glance.text.TextStyle
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.example.compose.snippets.MyActivity
Expand All @@ -114,7 +120,7 @@ private object GlanceCreateAppWidgetSnippet01 {
private object GlanceCreateAppWidgetSnippet02 {
// [START android_compose_glance_receiver02]
class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {

// Let MyAppWidgetReceiver know which GlanceAppWidget to use
override val glanceAppWidget: GlanceAppWidget = MyAppWidget()
}
Expand Down Expand Up @@ -518,7 +524,9 @@ object BuildUIWithGlance {

LazyColumn {
// [START android_compose_glance_buildUI06]
items(items = peopleList, itemId = { person -> person.id.hashCode().toLong() }) { person ->
items(
items = peopleList,
itemId = { person -> person.id.hashCode().toLong() }) { person ->
Text(person.name)
}
// [END android_compose_glance_buildUI06]
Expand Down Expand Up @@ -684,6 +692,7 @@ object CompoundButton {
)
// [END android_compose_glance_buildUI12]
}

// [START android_compose_glance_buildUI13]
class MyAppWidget : GlanceAppWidget() {

Expand Down Expand Up @@ -749,7 +758,7 @@ object CompoundButton {
uncheckedColor = ColorProvider(day = Color.Red, night = Color.Blue)
),

)
)
// [END android_compose_glance_buildUI14]
}

Expand Down Expand Up @@ -791,7 +800,7 @@ object GlanceTheming {
// [START android_compose_glance_glancetheming06]
// Remember, use the Glance imports
// import androidx.glance.material3.ColorProviders

// Example Imports from your own app
// import com.example.myapp.ui.theme.DarkColors
// import com.example.myapp.ui.theme.LightColors
Expand All @@ -803,6 +812,7 @@ object GlanceTheming {
dark = DarkColors
)
}

// [END android_compose_glance_glancetheming06]
// [START android_compose_glance_glancetheming02]
override suspend fun provideGlance(context: Context, id: GlanceId) {
Expand Down Expand Up @@ -1082,3 +1092,113 @@ class SyncService : Service() {
fun SnapScrollLayoutPreview() {
SnapScrollingSnippet.SnapScrollLayout()
}

private object GlanceHandleTextSnippet {
@Composable
fun TextExample() {
// [START android_compose_glance_handle_text]
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
// [END android_compose_glance_handle_text]
}
}

private object GlanceErrorHandlingSnippets {

class ErrorHandlingTryCatchWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
// [START android_compose_glance_error_try_catch]
provideContent {
var isError = false
var data = listOf<String>()
try {
val repository = (context.applicationContext as MyApplication).myRepository
data = repository.loadData()
} catch (e: Exception) {
isError = true
// TODO: handle error
}

if (isError) {
ErrorView()
} else {
Content(data)
}
}
// [END android_compose_glance_error_try_catch]
}
}

// [START android_compose_glance_error_layout_param]
class UpgradeWidget : GlanceAppWidget(errorUiLayout = R.layout.error_layout) {
// [START_EXCLUDE]
override suspend fun provideGlance(context: Context, id: GlanceId) {}
// [END_EXCLUDE]
}
// [END android_compose_glance_error_layout_param]

class CustomErrorHandlingWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {}

// [START android_compose_glance_on_composition_error_override]
override fun onCompositionError(
context: Context, glanceId: GlanceId, appWidgetId: Int, throwable: Throwable
) {
val rv = RemoteViews(context.packageName, R.layout.error_layout)
rv.setTextViewText(
R.id.error_text_view,
"Error was thrown. \nThis is a custom view \nError Message: `${throwable.message}`"
)
rv.setOnClickPendingIntent(R.id.error_icon, getErrorIntent(context, throwable))
AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, rv)
}
// [END android_compose_glance_on_composition_error_override]

// [START android_compose_glance_error_get_intent]
private fun getErrorIntent(context: Context, throwable: Throwable): PendingIntent {
val intent = Intent(context, UpgradeToHelloWorldPro::class.java)
intent.action = "widgetError"
// [START_EXCLUDE]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you add silent to the tag so ... doesn't show up in the visible snippet on DAC?

// [START_EXCLUDE silent]

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done ✅

intent.putExtra("error_message", throwable.message)
// [END_EXCLUDE]
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
}
// [END android_compose_glance_error_get_intent]
}

class ErrorHandlingWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = CustomErrorHandlingWidget()

// [START android_compose_glance_error_on_receive]
override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent)
Log.e("ErrorOnClick", "Button was clicked.")
}
// [END android_compose_glance_error_on_receive]
}

private class MyRepo {
fun loadData(): List<String> = listOf("item1", "item2")
}

private class MyApplication : Application() {
val myRepository = MyRepo()
}

@Composable
private fun ErrorView() {
}

@Composable
private fun Content(data: List<String>) {
}

private class UpgradeToHelloWorldPro
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ import androidx.activity.BackEventCompat
import androidx.activity.compose.PredictiveBackHandler
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.animate
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
Expand All @@ -33,21 +36,26 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import kotlin.coroutines.cancellation.CancellationException

@Serializable data object Home
@Serializable data object Settings
Expand Down Expand Up @@ -200,3 +208,58 @@ private enum class DrawerState {
}

private val DrawerWidth = 300.dp

@Composable
private fun PredictiveBackHandlerFlowExample(isBackHandlerEnabled: Boolean) {
// [START android_predictive_back_handler_progress]
PredictiveBackHandler(enabled = isBackHandlerEnabled) { progress: Flow<BackEventCompat> ->
try {
progress.collect { backEvent ->
// Update your UI or animation based on backEvent.progress
}
// Handle the final back action (e.g., navigate back)
} catch (e: CancellationException) {
// Back gesture was cancelled, reset your UI
}
}
// [END android_predictive_back_handler_progress]
}

// [START android_predictive_back_handler_custom_transition]
@Composable
fun DetailScreen(onBack: () -> Unit) {
var scale by remember { mutableFloatStateOf(1f) }
var xOffset by remember { mutableFloatStateOf(0f) }
val scope = rememberCoroutineScope()

PredictiveBackHandler { progressFlow ->
try {
progressFlow.collectLatest { backEvent ->
scale = 1f - backEvent.progress
xOffset = backEvent.progress * 100f
}
// User completed gesture
onBack()
} catch (e: CancellationException) {
// User cancelled gesture
// Animate scale and xOffset back to 1f and 0f respectively
scope.launch {
animate(scale, 1f) { value, _ -> scale = value }
}
scope.launch {
animate(xOffset, 0f) { value, _ -> xOffset = value }
}
}
}
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Surface(
modifier = Modifier
.size(200.dp)
.scale(scale)
.offset { IntOffset(x = xOffset.dp.roundToPx(), y = 0) },
Comment thread
kkuan2011 marked this conversation as resolved.
color = Color.Blue
) {}
}
}
// [END android_predictive_back_handler_custom_transition]

Loading