-
Notifications
You must be signed in to change notification settings - Fork 143
Add Drop functionality #75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5687530
72345b8
ca2de4d
eb16038
2cceaca
1ed9702
183781f
b079263
f190ae4
59b7b92
3d14b5d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.android.developers.testing.repository | ||
|
||
import android.net.Uri | ||
import androidx.activity.ComponentActivity | ||
import androidx.compose.ui.draganddrop.DragAndDropEvent | ||
import androidx.compose.ui.draganddrop.DragAndDropTarget | ||
import com.android.developers.androidify.data.DropBehaviourFactory | ||
|
||
class FakeDropImageFactory : DropBehaviourFactory { | ||
override fun shouldStartDragAndDrop(event: DragAndDropEvent): Boolean = true | ||
|
||
override fun createTargetCallback( | ||
activity: ComponentActivity, | ||
onImageDropped: (Uri) -> Unit, | ||
onDropStarted: () -> Unit, | ||
onDropEnded: () -> Unit, | ||
): DragAndDropTarget = object : DragAndDropTarget { | ||
override fun onDrop(event: DragAndDropEvent): Boolean { | ||
return false | ||
} | ||
|
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package com.android.developers.androidify.data | ||
|
||
import android.graphics.BitmapFactory | ||
import android.net.Uri | ||
import androidx.activity.ComponentActivity | ||
import androidx.compose.ui.draganddrop.DragAndDropEvent | ||
import androidx.compose.ui.draganddrop.DragAndDropTarget | ||
import androidx.compose.ui.draganddrop.mimeTypes | ||
import androidx.compose.ui.draganddrop.toAndroidDragEvent | ||
import androidx.lifecycle.lifecycleScope | ||
import com.android.developers.androidify.util.LocalFileProvider | ||
import kotlinx.coroutines.launch | ||
import java.util.UUID | ||
import javax.inject.Inject | ||
|
||
|
||
interface DropBehaviourFactory { | ||
fun shouldStartDragAndDrop(event: DragAndDropEvent): Boolean | ||
fun createTargetCallback( | ||
activity: ComponentActivity, | ||
onImageDropped: (Uri) -> Unit, | ||
onDropStarted: () -> Unit = {}, | ||
onDropEnded: () -> Unit = {}, | ||
): DragAndDropTarget | ||
} | ||
|
||
class DropBehaviourFactoryImpl @Inject constructor(val localFileProvider: LocalFileProvider) : | ||
DropBehaviourFactory { | ||
|
||
override fun shouldStartDragAndDrop(event: DragAndDropEvent): Boolean = | ||
event.mimeTypes().contains("image/jpeg") | ||
|
||
override fun createTargetCallback( | ||
activity: ComponentActivity, | ||
onImageDropped: (Uri) -> Unit, | ||
onDropStarted: () -> Unit, | ||
onDropEnded: () -> Unit, | ||
) = | ||
object : DragAndDropTarget { | ||
override fun onStarted(event: DragAndDropEvent) { | ||
super.onStarted(event) | ||
onDropStarted() | ||
} | ||
|
||
override fun onEnded(event: DragAndDropEvent) { | ||
super.onEnded(event) | ||
onDropEnded() | ||
} | ||
|
||
/** | ||
* Dropping an image requires the app to obtain the permission to use the image being | ||
* dropped. This permission only lasts until the event is completed. The easiest way | ||
* of being able to display the image being dropped is to temporarily copy it inside | ||
* the app storage and use that copy for the processing. | ||
*/ | ||
override fun onDrop(event: DragAndDropEvent): Boolean { | ||
val targetEvent = event.toAndroidDragEvent() | ||
|
||
if (targetEvent.clipData.itemCount == 0) { | ||
return false | ||
} | ||
|
||
activity.lifecycleScope.launch { | ||
val permission = activity.requestDragAndDropPermissions(targetEvent) | ||
if (permission != null) { | ||
try { | ||
val inputUri = targetEvent.clipData.getItemAt(0).uri | ||
activity.contentResolver.openInputStream(inputUri)?.use { inputStream -> | ||
val bitmap = BitmapFactory.decodeStream(inputStream) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might make more sense to use LocalFileProvider here instead of |
||
|
||
bitmap?.let { | ||
val cacheFile = | ||
localFileProvider.createCacheFile("dropped_image_${UUID.randomUUID()}.jpg") | ||
localFileProvider.saveBitmapToFile(bitmap, cacheFile) | ||
onImageDropped(localFileProvider.sharingUriForFile(cacheFile)) | ||
} | ||
} | ||
} finally { | ||
permission.release() | ||
} | ||
} | ||
} | ||
return true | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we always assume it'll be at 0 index?