-
Notifications
You must be signed in to change notification settings - Fork 16
Update android side #68
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
base: develop
Are you sure you want to change the base?
Changes from 7 commits
fa51a32
ac64d63
49b7ed0
e658bef
e293202
f6809ab
7bc3ac0
bb02818
af6fab0
db585a3
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 |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| distributionBase=GRADLE_USER_HOME | ||
| distributionPath=wrapper/dists | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip | ||
| zipStoreBase=GRADLE_USER_HOME | ||
| distributionPath=wrapper/dists | ||
| zipStorePath=wrapper/dists | ||
| zipStoreBase=GRADLE_USER_HOME |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,11 +4,13 @@ | |
|
|
||
| package dev.icerock.moko.media | ||
|
|
||
| import android.annotation.SuppressLint | ||
| import android.content.ContentResolver | ||
| import android.content.Context | ||
| import android.media.MediaMetadataRetriever | ||
| import android.net.Uri | ||
| import android.provider.MediaStore | ||
| import android.provider.OpenableColumns | ||
| import androidx.exifinterface.media.ExifInterface | ||
| import dev.icerock.moko.media.BitmapUtils.getBitmapOrientation | ||
| import dev.icerock.moko.media.BitmapUtils.getNormalizedBitmap | ||
|
|
@@ -52,18 +54,14 @@ object MediaFactory { | |
| } | ||
| } | ||
|
|
||
| @Suppress("ThrowsCount") | ||
| @SuppressLint("Range") | ||
| private fun createPhotoMedia( | ||
| contentResolver: ContentResolver, | ||
| uri: Uri | ||
| ): Media { | ||
| val projection = arrayOf( | ||
| MediaStore.Images.ImageColumns.ORIENTATION, | ||
| MediaStore.Images.ImageColumns.TITLE | ||
| ) | ||
|
|
||
| val cursorRef = contentResolver | ||
| .query(uri, projection, null, null, null) | ||
| .query(uri, null, null, null, null) | ||
| ?: throw IllegalArgumentException("can't open cursor") | ||
|
|
||
| return cursorRef.use { cursor -> | ||
|
|
@@ -75,47 +73,36 @@ object MediaFactory { | |
| getBitmapOrientation(it) | ||
| } ?: ExifInterface.ORIENTATION_UNDEFINED | ||
|
|
||
| val titleIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.TITLE) | ||
| val title = cursor.getString(titleIndex) ?: uri.lastPathSegment | ||
| val title = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)) | ||
|
|
||
| val normalizedBitmap = contentResolver.openInputStream(uri)?.use { | ||
| getNormalizedBitmap(it, orientation, sampleSize = null) | ||
| } ?: throw IOException("can't open stream") | ||
|
|
||
| Media( | ||
| name = title.orEmpty(), | ||
| path = uri.toString(), | ||
| path = uri.path ?: uri.toString(), | ||
| type = MediaType.PHOTO, | ||
| preview = Bitmap(normalizedBitmap) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Suppress("ThrowsCount") | ||
| @SuppressLint("Range") | ||
| private fun createVideoMedia( | ||
| contentResolver: ContentResolver, | ||
| uri: Uri | ||
| ): Media { | ||
| val projection = arrayOf( | ||
| MediaStore.Video.VideoColumns._ID, | ||
| MediaStore.Video.VideoColumns.TITLE | ||
| ) | ||
|
|
||
| val cursorRef = contentResolver | ||
| .query(uri, projection, null, null, null) | ||
| .query(uri, null, null, null, null) | ||
|
||
| ?: throw IllegalArgumentException("can't open cursor") | ||
|
|
||
| return cursorRef.use { cursor -> | ||
| if (!cursor.moveToFirst()) { | ||
| error("cursor should have one element") | ||
| } | ||
|
|
||
| val titleColumn = cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE) | ||
| val title = if (titleColumn != -1) { | ||
| cursor.getString(titleColumn) | ||
| } else { | ||
| null | ||
| } ?: uri.lastPathSegment ?: "file" | ||
| val title = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)) | ||
|
|
||
| val idColumn = cursor.getColumnIndex(MediaStore.Video.VideoColumns._ID) | ||
| val thumbnail: android.graphics.Bitmap = if (idColumn != -1) { | ||
|
|
@@ -135,8 +122,8 @@ object MediaFactory { | |
| } ?: throw IOException("can't read thumbnail") | ||
|
|
||
| Media( | ||
| name = title, | ||
| path = uri.toString(), | ||
| name = title.orEmpty(), | ||
| path = uri.path ?: uri.toString(), | ||
| type = MediaType.VIDEO, | ||
| preview = Bitmap(thumbnail) | ||
| ) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,12 +4,11 @@ | |
|
|
||
| package dev.icerock.moko.media.picker | ||
|
|
||
| import android.app.Activity | ||
| import android.content.Intent | ||
| import android.os.Environment | ||
| import android.annotation.SuppressLint | ||
| import android.content.ContentResolver | ||
| import android.provider.OpenableColumns | ||
| import androidx.activity.result.contract.ActivityResultContracts | ||
| import androidx.fragment.app.Fragment | ||
| import com.nbsp.materialfilepicker.MaterialFilePicker | ||
| import com.nbsp.materialfilepicker.ui.FilePickerActivity | ||
| import dev.icerock.moko.media.FileMedia | ||
| import java.io.File | ||
|
|
||
|
|
@@ -19,49 +18,83 @@ class FilePickerFragment : Fragment() { | |
| retainInstance = true | ||
| } | ||
|
|
||
| private val codeCallbackMap = mutableMapOf<Int, CallbackData>() | ||
| private var callback: CallbackData? = null | ||
|
|
||
| fun pickFile(callback: (Result<FileMedia>) -> Unit) { | ||
| val requestCode = codeCallbackMap.keys.maxOrNull() ?: 0 | ||
|
|
||
| codeCallbackMap[requestCode] = CallbackData(callback) | ||
|
|
||
| // TODO нужно убрать использование внешней зависимости, сделать конфигурацию способа | ||
| // выбора файла из вне (аргументом в контроллер передавать) | ||
| val externalStorage = Environment.getExternalStorageDirectory() | ||
| MaterialFilePicker().withSupportFragment(this) | ||
| .withCloseMenu(true) | ||
| .withRootPath(externalStorage.absolutePath) | ||
| .withRequestCode(requestCode) | ||
| .start() | ||
| } | ||
| @SuppressLint("Range") | ||
| private val pickDocument = | ||
| registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri -> | ||
| val callbackData = callback ?: return@registerForActivityResult | ||
| callback = null | ||
|
|
||
| override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { | ||
| super.onActivityResult(requestCode, resultCode, data) | ||
| val callback = callbackData.callback | ||
|
|
||
| val callbackData = codeCallbackMap[requestCode] ?: return | ||
| codeCallbackMap.remove(requestCode) | ||
| if (uri == null) { | ||
| callback.invoke(Result.failure(CanceledException())) | ||
| return@registerForActivityResult | ||
| } | ||
|
|
||
| val callback = callbackData.callback | ||
| if (uri.path == null) { | ||
| callback.invoke(Result.failure(java.lang.IllegalStateException("File is null"))) | ||
| return@registerForActivityResult | ||
| } | ||
|
|
||
| if (resultCode == Activity.RESULT_CANCELED) { | ||
| callback.invoke(Result.failure(CanceledException())) | ||
| return | ||
| } | ||
| val fileNameWithExtension = if (uri.scheme == ContentResolver.SCHEME_CONTENT) { | ||
| val cursor = requireContext().contentResolver.query(uri, null, null, null, null) | ||
| cursor?.use { | ||
| if (!it.moveToFirst()) null | ||
| else it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME)) | ||
| } | ||
| } else null | ||
|
|
||
| processResult(callback, data) | ||
| } | ||
| uri.path?.let { path -> | ||
| val file = File(path) | ||
| val name = file.name | ||
| val byteArray = requireContext() | ||
| .contentResolver | ||
| .openInputStream(uri) | ||
| ?.readBytes() ?: return@registerForActivityResult | ||
|
Comment on lines
+52
to
+55
Member
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. why we should read stream in this time? can we read it later? |
||
|
|
||
| private fun processResult( | ||
| callback: (Result<FileMedia>) -> Unit, | ||
| data: Intent? | ||
| ) { | ||
| val filePath = data?.getStringExtra(FilePickerActivity.RESULT_FILE_PATH) | ||
| callback( | ||
| Result.success( | ||
| FileMedia( | ||
| fileNameWithExtension ?: name, | ||
| uri.toString(), | ||
| byteArray | ||
| ) | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| filePath?.let { path -> | ||
| val name = File(path).name | ||
| callback(Result.success(FileMedia(name, path))) | ||
|
|
||
| fun pickFile(callback: (Result<FileMedia>) -> Unit) { | ||
| this.callback?.let { | ||
| it.callback.invoke(Result.failure(IllegalStateException("Callback should be null"))) | ||
| this.callback = null | ||
| } | ||
|
|
||
| this.callback = CallbackData(callback) | ||
|
|
||
| pickDocument.launch( | ||
| arrayOf( | ||
| "application/pdf", | ||
| "application/octet-stream", | ||
| "application/doc", | ||
| "application/msword", | ||
| "application/ms-doc", | ||
| "application/vnd.ms-excel", | ||
| "application/vnd.ms-powerpoint", | ||
| "application/json", | ||
| "application/zip", | ||
| "text/plain", | ||
| "text/html", | ||
| "text/xml", | ||
| "audio/mpeg", | ||
| "application/vnd.openxmlformats-officedocument.wordprocessingml.document", | ||
| "application/vnd.openxmlformats-officedocument.presentationml.presentation", | ||
| "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | ||
|
Comment on lines
+80
to
+95
Member
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. maybe use something like |
||
| ) | ||
| ) | ||
| } | ||
|
|
||
| class CallbackData(val callback: (Result<FileMedia>) -> Unit) | ||
|
|
||
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.
why projection removed? we use only 2 columns at all