diff --git a/Jetchat/README.md b/Jetchat/README.md index 992389bdb5..0433a4585d 100644 --- a/Jetchat/README.md +++ b/Jetchat/README.md @@ -25,6 +25,10 @@ This sample showcases: + + + + ### Status: 🚧 In progress Jetchat is still in under development, and some features are not yet implemented. diff --git a/Jetchat/app/build.gradle.kts b/Jetchat/app/build.gradle.kts index f23f12439e..4972acab23 100644 --- a/Jetchat/app/build.gradle.kts +++ b/Jetchat/app/build.gradle.kts @@ -87,6 +87,8 @@ dependencies { implementation(composeBom) androidTestImplementation(composeBom) + implementation(libs.androidx.glance.appwidget) + implementation(libs.androidx.glance.material3) implementation(libs.kotlin.stdlib) implementation(libs.kotlinx.coroutines.android) diff --git a/Jetchat/app/src/main/AndroidManifest.xml b/Jetchat/app/src/main/AndroidManifest.xml index 602380c02e..064d10dd21 100644 --- a/Jetchat/app/src/main/AndroidManifest.xml +++ b/Jetchat/app/src/main/AndroidManifest.xml @@ -35,6 +35,14 @@ - + + + + + + diff --git a/Jetchat/app/src/main/java/com/example/compose/jetchat/components/JetchatDrawer.kt b/Jetchat/app/src/main/java/com/example/compose/jetchat/components/JetchatDrawer.kt index 5a5d11e482..8081baa1d4 100644 --- a/Jetchat/app/src/main/java/com/example/compose/jetchat/components/JetchatDrawer.kt +++ b/Jetchat/app/src/main/java/com/example/compose/jetchat/components/JetchatDrawer.kt @@ -16,6 +16,11 @@ package com.example.compose.jetchat.components +import android.appwidget.AppWidgetManager +import android.content.ComponentName +import android.content.Context +import android.os.Build +import android.widget.Toast import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -44,13 +49,16 @@ import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.example.compose.jetchat.R import com.example.compose.jetchat.data.colleagueProfile import com.example.compose.jetchat.data.meProfile import com.example.compose.jetchat.theme.JetchatTheme +import com.example.compose.jetchat.widget.WidgetReceiver @Composable fun JetchatDrawerContent( @@ -73,9 +81,13 @@ fun JetchatDrawerContent( ProfileItem("Taylor Brooks", colleagueProfile.photo) { onProfileClicked(colleagueProfile.userId) } + DividerItem(modifier = Modifier.padding(horizontal = 28.dp)) + DrawerItemHeader("Settings") + WidgetDiscoverability() } } + @Composable private fun DrawerHeader() { Row(modifier = Modifier.padding(16.dp), verticalAlignment = CenterVertically) { @@ -90,6 +102,7 @@ private fun DrawerHeader() { ) } } + @Composable private fun DrawerItemHeader(text: String) { Box( @@ -199,6 +212,7 @@ fun DrawerPreview() { } } } + @Composable @Preview fun DrawerPreviewDark() { @@ -210,3 +224,50 @@ fun DrawerPreviewDark() { } } } + + +@Composable +private fun WidgetDiscoverability() { + val context = LocalContext.current + Row( + modifier = Modifier + .height(56.dp) + .fillMaxWidth() + .padding(horizontal = 12.dp) + .clip(CircleShape) + .clickable(onClick = { + addWidgetToHomeScreen(context) + }), + verticalAlignment = CenterVertically + ) { + Text( + stringResource(id = R.string.add_widget_to_home_page), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.padding(start = 12.dp) + ) + } +} + +private fun addWidgetToHomeScreen(context: Context) { + val appWidgetManager = AppWidgetManager.getInstance(context) + val myProvider = ComponentName(context, WidgetReceiver::class.java) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (appWidgetManager.isRequestPinAppWidgetSupported) { + appWidgetManager.requestPinAppWidget(myProvider, null, null) + } else { + Toast.makeText( + context, + "Unable to add widget, please add from home screen", + Toast.LENGTH_LONG + ).show() + } + } else { + Toast.makeText( + context, + "Unable to add widget, please add from home screen", + Toast.LENGTH_LONG + ).show() + } +} diff --git a/Jetchat/app/src/main/java/com/example/compose/jetchat/conversation/ConversationUiState.kt b/Jetchat/app/src/main/java/com/example/compose/jetchat/conversation/ConversationUiState.kt index 452e4eeb41..edd61c738d 100644 --- a/Jetchat/app/src/main/java/com/example/compose/jetchat/conversation/ConversationUiState.kt +++ b/Jetchat/app/src/main/java/com/example/compose/jetchat/conversation/ConversationUiState.kt @@ -39,5 +39,5 @@ data class Message( val content: String, val timestamp: String, val image: Int? = null, - val authorImage: Int = if (author == "me") R.drawable.ali else R.drawable.someone_else + val authorImage: Int = if (author == "me") R.drawable.ali else R.drawable.someone_else, ) diff --git a/Jetchat/app/src/main/java/com/example/compose/jetchat/data/FakeData.kt b/Jetchat/app/src/main/java/com/example/compose/jetchat/data/FakeData.kt index 1c996a40d3..a37b493349 100644 --- a/Jetchat/app/src/main/java/com/example/compose/jetchat/data/FakeData.kt +++ b/Jetchat/app/src/main/java/com/example/compose/jetchat/data/FakeData.kt @@ -64,6 +64,58 @@ private val initialMessages = listOf( "8:03 PM" ) ) +val unreadMessages = listOf( + Message( + "Taylor Brooks", + "You can use all the same stuff", + "8:05 PM" + ), + Message( + "Taylor Brooks", + "@aliconors Take a look at the `Flow.collectAsStateWithLifecycle()` APIs", + "8:05 PM" + ), + Message( + "Taylor Brooks", + "You can use all the same stuff", + "8:05 PM" + ), + Message( + "Taylor Brooks", + "@aliconors Take a look at the `Flow.collectAsStateWithLifecycle()` APIs", + "8:05 PM" + ), + Message( + "Taylor Brooks", + "You can use all the same stuff", + "8:05 PM" + ), + Message( + "Taylor Brooks", + "@aliconors Take a look at the `Flow.collectAsStateWithLifecycle()` APIs", + "8:05 PM" + ), + Message( + "Taylor Brooks", + "You can use all the same stuff", + "8:05 PM" + ), + Message( + "Taylor Brooks", + "@aliconors Take a look at the `Flow.collectAsStateWithLifecycle()` APIs", + "8:05 PM" + ), + Message( + "Taylor Brooks", + "You can use all the same stuff", + "8:05 PM" + ), + Message( + "Taylor Brooks", + "@aliconors Take a look at the `Flow.collectAsStateWithLifecycle()` APIs", + "8:05 PM" + ), +) val exampleUiState = ConversationUiState( initialMessages = initialMessages, diff --git a/Jetchat/app/src/main/java/com/example/compose/jetchat/widget/JetChatWidget.kt b/Jetchat/app/src/main/java/com/example/compose/jetchat/widget/JetChatWidget.kt new file mode 100644 index 0000000000..747db7cf8e --- /dev/null +++ b/Jetchat/app/src/main/java/com/example/compose/jetchat/widget/JetChatWidget.kt @@ -0,0 +1,19 @@ +package com.example.compose.jetchat.widget + +import android.content.Context +import androidx.glance.GlanceId +import androidx.glance.GlanceTheme +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.provideContent +import com.example.compose.jetchat.widget.composables.MessagesWidget + +class JetChatWidget : GlanceAppWidget() { + + override suspend fun provideGlance(context: Context, id: GlanceId) { + provideContent { + GlanceTheme { + MessagesWidget() + } + } + } +} \ No newline at end of file diff --git a/Jetchat/app/src/main/java/com/example/compose/jetchat/widget/WidgetReceiver.kt b/Jetchat/app/src/main/java/com/example/compose/jetchat/widget/WidgetReceiver.kt new file mode 100644 index 0000000000..e96306395c --- /dev/null +++ b/Jetchat/app/src/main/java/com/example/compose/jetchat/widget/WidgetReceiver.kt @@ -0,0 +1,11 @@ +package com.example.compose.jetchat.widget + +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.GlanceAppWidgetReceiver + +class WidgetReceiver : GlanceAppWidgetReceiver() { + + override val glanceAppWidget: GlanceAppWidget + get() = JetChatWidget() + +} \ No newline at end of file diff --git a/Jetchat/app/src/main/java/com/example/compose/jetchat/widget/composables/MessagesWidget.kt b/Jetchat/app/src/main/java/com/example/compose/jetchat/widget/composables/MessagesWidget.kt new file mode 100644 index 0000000000..db42c8d57c --- /dev/null +++ b/Jetchat/app/src/main/java/com/example/compose/jetchat/widget/composables/MessagesWidget.kt @@ -0,0 +1,60 @@ +package com.example.compose.jetchat.widget.composables + +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.dp +import androidx.glance.GlanceModifier +import androidx.glance.ImageProvider +import androidx.glance.LocalContext +import androidx.glance.action.actionStartActivity +import androidx.glance.action.clickable +import androidx.glance.appwidget.components.Scaffold +import androidx.glance.appwidget.components.TitleBar +import androidx.glance.appwidget.lazy.LazyColumn +import androidx.glance.layout.Column +import androidx.glance.layout.Spacer +import androidx.glance.layout.fillMaxWidth +import androidx.glance.layout.height +import androidx.glance.text.FontWeight +import androidx.glance.text.Text +import androidx.glance.text.TextStyle +import com.example.compose.jetchat.NavActivity +import com.example.compose.jetchat.R +import com.example.compose.jetchat.conversation.Message +import com.example.compose.jetchat.data.unreadMessages + +@Composable +fun MessagesWidget() { + Scaffold(titleBar = { + TitleBar( + startIcon = ImageProvider(R.drawable.ic_jetchat), + iconColor = null, + title = LocalContext.current.getString(R.string.app_name_unreads), + ) + }) { + val unreadMessage = unreadMessages + LazyColumn(modifier = GlanceModifier.fillMaxWidth()) { + unreadMessage.forEach { + item { + Column(modifier = GlanceModifier.fillMaxWidth()) { + MessageItem(it) + Spacer(modifier = GlanceModifier.height(10.dp)) + } + } + } + } + } +} + +@Composable +fun MessageItem(message: Message) { + Column(modifier = GlanceModifier.clickable(actionStartActivity()).fillMaxWidth()) { + Text( + text = message.author, + style = TextStyle(fontWeight = FontWeight.Bold) + ) + Text( + text = message.content, + style = TextStyle(fontWeight = FontWeight.Normal) + ) + } +} \ No newline at end of file diff --git a/Jetchat/app/src/main/res/drawable/widget_icon.png b/Jetchat/app/src/main/res/drawable/widget_icon.png new file mode 100644 index 0000000000..70d386ee16 Binary files /dev/null and b/Jetchat/app/src/main/res/drawable/widget_icon.png differ diff --git a/Jetchat/app/src/main/res/layout/widget_error_layout.xml b/Jetchat/app/src/main/res/layout/widget_error_layout.xml new file mode 100644 index 0000000000..dceb0aa87c --- /dev/null +++ b/Jetchat/app/src/main/res/layout/widget_error_layout.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/Jetchat/app/src/main/res/layout/widget_loading_layout.xml b/Jetchat/app/src/main/res/layout/widget_loading_layout.xml new file mode 100644 index 0000000000..baa2d8ac39 --- /dev/null +++ b/Jetchat/app/src/main/res/layout/widget_loading_layout.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/Jetchat/app/src/main/res/values/strings.xml b/Jetchat/app/src/main/res/values/strings.xml index aae598c1fe..020432ab25 100644 --- a/Jetchat/app/src/main/res/values/strings.xml +++ b/Jetchat/app/src/main/res/values/strings.xml @@ -67,5 +67,8 @@ More options Touch and hold to record Record voice message + Cannot load Widget + JetChat (Un-Reads) + Add Widget to Home Page diff --git a/Jetchat/app/src/main/res/xml/my_app_widget_info.xml b/Jetchat/app/src/main/res/xml/my_app_widget_info.xml new file mode 100644 index 0000000000..dd3ae12af4 --- /dev/null +++ b/Jetchat/app/src/main/res/xml/my_app_widget_info.xml @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/Jetchat/screenshots/widget.png b/Jetchat/screenshots/widget.png new file mode 100644 index 0000000000..7a3cf48e39 Binary files /dev/null and b/Jetchat/screenshots/widget.png differ diff --git a/Jetchat/screenshots/widget_discoverability.png b/Jetchat/screenshots/widget_discoverability.png new file mode 100644 index 0000000000..a59e4d5b09 Binary files /dev/null and b/Jetchat/screenshots/widget_discoverability.png differ