How do I share content using Android's Sharesheet in Jetpack Compose?
Inside a #Composable you can use an Intent in a standard way.
Something like:
val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
type = "text/plain"
}
val shareIntent = Intent.createChooser(sendIntent, null)
val context = LocalContext.current
Button(onClick = {
context.startActivity(shareIntent)
}){
Text("Share")
}
Related
I want to show picture with Coil from Uri.
Following code shows picture but when I choose one.
I want to store Uri and when Screen starts i want to show it immediately.
val uri = "content://com.android.providers.media.documents/document/image%3A18".toUri()
var imageUri by remember { mutableStateOf<Uri?>(null) }
val context = LocalContext.current
val launcher =
rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()) {
uri: Uri? ->
imageUri = uri
}
Column {
Button(onClick = {
//here we are going to add logic for picking image
launcher.launch(
"image/*"
)
}, content = {
Text(text = "Select Image From Gallery")
})
AsyncImage(
model = ImageRequest.Builder(context = context)
.data(imageUri)
.crossfade(true)
.build(),
contentDescription = "",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(144.dp)
)
Image(
painter = rememberAsyncImagePainter(imageUri),
contentDescription = "Picture",
)
val uri is uri I chooshed before and I copied it and put to string to show image.
But this way first I need to choose picture and it will show. If I put uri instead of imageUri in .data() or rememberAsyncImagePainter nothing happens.
Hey I'm new to kotlin and I'm having problem with this. The images are in the drawable folder. And I need to share the image in jetpack composer. When I click now I can only see the text but not the image to share.
Image(
painter = painterResource(id = image.imgId),
contentDescription = "Test",
modifier = Modifier.fillMaxWidth()
)
var pickedImageUri by remember { mutableStateOf<Uri?>(null) }
val context = LocalContext.current
val intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM, pickedImageUri)
putExtra(Intent.EXTRA_TEXT, "Description of Image")
type = "image/*"
}
val shareIntent = Intent.createChooser(intent, "Share")
Button( onClick = {
//val description = "Image sent"
context.startActivity(shareIntent)
}) {
Text("Share")
}
I am looking for help on how to share image binary content from my PhotoApp to external Social Media apps.
I load the image from an API using Coil and display the image in a composable.
#Composable
fun PhotoDetailsScreen( photo: AstroPhoto ... ) {
val context = LocalContext.current
val imgUri = photo.url.toUri()
.buildUpon()
.scheme("https")
.build()
Column ( ...
//Image
Image(
painter = rememberImagePainter(
data = imgUri,
builder = {
crossfade(true)
placeholder(R.drawable.loading_animation)
}
) ...
//Assist Chip
AssistChip(onClick = { shareAstroPhoto("", context) }
Clicking on the AssistChip calls the below shareAstroPhoto() fxn that takes the uri pointing to the image file to fire an ACTION_SEND Intent
fun shareAstroPhoto(uri:String, context: Context){
val intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM, uri)
type = "image/jpg"
}
context.startActivity(Intent.createChooser(intent, null))
}
I intend to get a Bitmap out of my composable, save the Bitmap in my own ContentProvider or MediaStore (I know how these 2 work) and then pass the uri of the saved BitMap to Intent.EXTRA_STREAM.
Have browsed through similar cases and videos but all I find is working with XML code.
Therefore my query is how to convert Jetpack Compose Image from a composable into a Bitmap to enable sharing the file with other external apps through Android Sharesheet.
I'm not sure if I understand your question. If you just want to share the image, then:
Util function:
fun Context.shareImage(title: String, image: Drawable, filename: String) {
val file = try {
val outputFile = File(cacheDir, "$filename.png")
val outPutStream = FileOutputStream(outputFile)
image.toBitmap().compress(CompressFormat.PNG, 100, outPutStream)
outPutStream.flush()
outPutStream.close()
outputFile
} catch (e: Throwable) {
return toast(e)
}
val uri = file.toUriCompat(this)
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND
type = "image/png"
putExtra(Intent.EXTRA_STREAM, uri)
}
startActivity(Intent.createChooser(shareIntent, title))
}
Share image with (Coil 2.0):
val painter = rememberAsyncImagePainter(
ImageRequest.Builder(LocalContext.current)
.data(url)
.build()
)
Button(
onClick={
val state = painter.state as? AsyncImagePainter.State.Success
val drawable = state?.result.drawable
context.shareImage(
"Share image via",
drawable,
"filename"
)
}
)
Updated
Those are small helper functions, but if you want them:
fun File.toUriCompat(context: Context): Uri {
return FileProvider.getUriForFile(context, context.packageName + ".provider", this)
}
fun Context.toast(throwable: Throwable) =
throwable.message?.let { toast(it) }
?: toast(R.string.unknown_error)
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
You can get drawable using painter in jetpack compose, then use that Drawble to share..
#Composable
fun photoItem(
photoUrl: String,
modifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.Fit
): Drawable? {
val painter = rememberAsyncImagePainter(
Builder(LocalContext.current)
.placeholder(drawable.placeholder)
.data(photoUrl)
.build()
)
Image(
contentScale = contentScale,
painter = painter,
contentDescription = null,
modifier = modifier,
)
val state = painter.state as? AsyncImagePainter.State.Success
return state?.result?.drawable
}
then cast the Drawable to BitmapDrawable
In AndroidManifest.xml, we need to declare our Activity and we can provide a label, i.e.
<activity android:name="MyActivityClass"
android:label="Activity Label" />
In Jetpack Compose, how can I get that Activity Label?
I tried to get from LocalContext.current but can't find it.
#Composable
fun TopBar() {
val context = LocalContext.current
val title = context.getActivity().getTitle() // Wrong API... not there
TopAppBar(
title = { Text(text = title, fontSize = 18.sp) },
backgroundColor = MaterialTheme.colors.primary,
contentColor = Color.White
)
}
The label provided for an Activity in the AndroidManifest.xml can be accessed in general through PackageManager.getActivityInfo(...).
Since you are using Compose anyway, here is a Kotlin flavoured extension function
inline fun <reified T> Context.getActivityLabel(): String {
val componentName = ComponentName(this, T::class.java)
val activityInfo = packageManager.getActivityInfo(componentName, 0)
// loadLabel takes care of cases when the label is specified as a String literal
// as well as cases when the label is specified as a String resource
return activityInfo.loadLabel(packageManager).toString()
}
Usage inside a Composable
val context = LocalContext.current
val title = context.getActivityLabel<MyActivityClass>()
Usage elsewhere
val context: Context = //...
val title = context.getActivityLabel<MyActivityClass>()
I got it through the below approach
#Composable
fun TopBar() {
val activity = LocalContext.current as Activity
val title = activity.title?.toString() ?: "No Title"
TopAppBar(
title = { Text(text = title, fontSize = 18.sp) },
backgroundColor = MaterialTheme.colors.primary,
contentColor = Color.White
)
}
How do I programmatically open an external URL on a button click with Jetpack Compose?
#Composable
fun MyButton() {
Button(onClick = {
//enter code here
})
}
An easier alternative is to use LocalUriHandler:
val uriHandler = LocalUriHandler.current
uriHandler.openUri(uri)
Keep it short and sweet 😊
Here is a possible way to do it:
#Composable
fun MyButton() {
val context = LocalContext.current
val intent = remember { Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com/")) }
Button(onClick = { context.startActivity(intent) }) {
Text(text = "Navigate to Google!")
}
}
Inside #Composable functions, you have one thing called "Composition Locals".
CompositionLocal classes allow passing data implicitly through composable functions to its composable descendants
LocalContext is one of these classes.
The Intent specified, is the common way to open an external URL on Android.
I found that accessing LocalUriHandler.current inside the onClick handler would raise an error: "#Composable invocations can only happen from the context of a #Composable function"
I solved it by moving this line of code outside the Button:
val uriHandler = LocalUriHandler.current
Button(onClick = {
uriHandler.openUri(...)
) {
// Your label goes here
}
#Composable
fun WebButton() {
val context = LocalContext.current
val webIntent: Intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com/"))
OutlinedButton(onClick = { context.startActivity(webIntent) }, modifier = Modifier.padding(8.dp)) {
Text( text = "OPEN WEB",
)
}
}
I've been using CustomTabsIntent which is another possibility when it comes to open a link in the phone browser.
// Within your #Composable function define the context val
val context = LocalContext.current
//Then in your modifier clickable use the CustomTabsIntent builder
modifier = Modifier
.padding(start = 24.dp, end = 16.dp)
.align(Alignment.CenterVertically)
.clickable {
CustomTabsIntent.Builder().build().launchUrl(context, Uri.parse(pageUrl))
}