i know this question has been asked several times but everything i can find is only in Java and not very relevant to me...
I'm trying to select a file when i click on a button in my app (images or videos like : /storage/emulated/0/Download/giphy.gif ) and the when the picture or video is selected, i need the path to go inside an edittext.
I have found that code in kotlin for path :
class URIPathHelper {
fun getPath(context: Context, uri: Uri): String? {
val isKitKatorAbove = true
// DocumentProvider
if (isKitKatorAbove && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).toTypedArray()
val type = split[0]
if ("primary".equals(type, ignoreCase = true)) {
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
}
} else if (isDownloadsDocument(uri)) {
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
return getDataColumn(context, contentUri, null, null)
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).toTypedArray()
val type = split[0]
var contentUri: Uri? = null
if ("image" == type) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if ("video" == type) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio" == type) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
}
} else if ("content".equals(uri.scheme, ignoreCase = true)) {
return getDataColumn(context, uri, null, null)
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
return uri.path
}
return null
}
fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
cursor = uri?.let { context.getContentResolver().query(it, projection, selection, selectionArgs,null) }
if (cursor != null && cursor.moveToFirst()) {
val column_index: Int = cursor.getColumnIndexOrThrow(column)
return cursor.getString(column_index)
}
} finally {
if (cursor != null) cursor.close()
}
return null
}
fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
}
And this is what i'm trying :
binding.redloader.setOnClickListener {
val uriPathHelper = URIPathHelper()
val filePath: String? = uriPathHelper.getPath(this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
val uri: Uri = Uri.parse(filePath)
val intent = Intent(Intent.ACTION_VIEW)
intent.type = "image/*"
intent.putExtra(Intent.ACTION_VIEW, uri)
startActivity(Intent.createChooser(intent, "Open file"))
binding.redgif.setText(filePath)
}
When I click on the button it automatically chooses the first picture in the storage, and then it opens google picture but I cannot do anything except watch the pictures...
I'm sorry I know they are some stupid things in my code, I think I have something to do with intent but all I see on the internet is calling private void and it is not working for me...
I'm a complete beginner and I really hope someone can help me...
Update with what i'm trying, i think i'm close :
binding.redloader.setOnClickListener {
val uriPathHelper = URIPathHelper()
intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent = Intent.createChooser(intent, "Choose a file")
val resultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
if (data != null) {
val fileUri: Uri? = data.data
Log.i(LOG_TAG, fileUri.toString())
var fileURIPathHelper: String? = null
try {
fileURIPathHelper = uriPathHelper.getPath(this, EXTERNAL_CONTENT_URI)
} catch (e: Exception) {
Log.e(LOG_TAG, "Error: " + e)
Toast.makeText(this, "Error: " + e, Toast.LENGTH_SHORT).show()
}
this.binding.redgif.setText(fileURIPathHelper)
}
}
}
resultLauncher.launch(intent)
}
I solved it ! :)
val resultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
if (data != null) {
val fileUri: Uri? = data.data
Log.i(PackageManagerCompat.LOG_TAG, fileUri.toString())
val contentUri: String?
try {
contentUri = uriPathHelper.getPath(this, fileUri!!)
this.binding.redgif.setText(contentUri)
} catch (e: Exception) {
Log.e(PackageManagerCompat.LOG_TAG, "Error: " + e)
Toast.makeText(this, "Error: " + e, Toast.LENGTH_SHORT).show()
}
}
}
}
binding.redloader.setOnClickListener {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
intent.addCategory(Intent.CATEGORY_OPENABLE)
startActivity(Intent.createChooser(intent, "Open file"))
resultLauncher.launch(intent)
}
Related
My task is to load recyclerView and show pagination which I both implemented.
I also implemented LoadingState for adapter.
ApiCall:
#GET("top-headlines?sources=bbc-news,techcrunch&apiKey=${BuildConfig.API_KEY}")
suspend fun getTopHeadlinesArticles(
#Query("page") page:Int = 1,
#Query("q") query: String,
) : Response<ArticleListResponse>
I wont show paging because it is working so I will jump to repository:
fun getSearchResult(query: String) =
Pager(
config = PagingConfig(
pageSize = 1,
maxSize = 20,
enablePlaceholders = false
),
pagingSourceFactory = { ArticlePaging(newsService, query)}
).flow
ViewModel:
#OptIn(ExperimentalCoroutinesApi::class)
val news = _currentQuery.flatMapLatest { query ->
articleRepository.getSearchResult(query).cachedIn(viewModelScope)
}
Fragment:
binding.recyclerViewTop.layoutManager = LinearLayoutManager(context)
binding.recyclerViewTop.adapter = adapter.withLoadStateHeaderAndFooter(
header = ArticleLoadStateAdapter { adapter.retry() },
footer = ArticleLoadStateAdapter { adapter.retry() }
)
lifecycleScope.launchWhenCreated {
viewModel.news.collect { articles ->
adapter.submitData(articles)
}
}
And LoadStateViewHolder in LoadStateAdapter:
init {
binding.buttonRetry.setOnClickListener {
retry.invoke()
}
}
fun bind(loadState: LoadState) {
binding.apply {
progressBar.isVisible = loadState is LoadState.Loading
buttonRetry.isVisible = loadState !is LoadState.Loading
textViewError.isVisible = loadState !is LoadState.Loading
}
}
I already predefined DEFAULT_QUERY so I only get 1 Article.
Problem is that progressBar loading is always visible and I have no more articles to show.
Edit: when i have at least 10 items to show this works fine
Edit 2nd: Add ArticlePagingSource if that can help
override fun getRefreshKey(state: PagingState<Int, ArticleResponse>): Int? {
return state.anchorPosition?.let {
val anchorPage = state.closestPageToPosition(it)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}
try {
val currentPageList = params.key ?: 1
response = if(query != ""){
newsService.getTopHeadlinesArticles(currentPageList, query)
} else{
newsService.getTopHeadlinesArticles(currentPageList)
}
val responseList = mutableListOf<ArticleResponse>()
val data = response.body()?.articleResponses ?: emptyList()
responseList.addAll(data)
val prevKey = if (currentPageList == 1) null else currentPageList - 1
return LoadResult.Page(
responseList,
prevKey,
currentPageList.plus(1)
)
I'm trying to add offline capabilities to my TMDB app. I've tried doing it with Room but RemoteMediator only loads the first page.
This is how I implemented the RemoteMediator class
#OptIn(ExperimentalPagingApi::class)
class MoviesPopularMediator(
private val service: ApiService,
private val database: PopularMoviesDatabase
) : RemoteMediator<Int, MoviesModel>() {
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, MoviesModel>
): MediatorResult {
return try {
val loadKey = when(loadType){
LoadType.REFRESH -> {
1
}
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND ->{
state.lastItemOrNull()
?: return MediatorResult.Success(endOfPaginationReached = true)
getMoviesPage()
}
}
val response = service.getPopular(
page = state.config.pageSize,
)
val listing = response.body()
val results = listing?.results
if (listing != null) {
database.withTransaction {
if (loadKey != null) {
database.popularMoviesPageDao().savePopularMoviesPage(MoviesPage(page = listing.page, results = listing.results, total_pages = listing.total_pages))
}
if (results != null) {
database.popularMoviesDao().savePopularMovies(results)
}
}
}
MediatorResult.Success(endOfPaginationReached = response.body()?.page == response.body()?.total_pages)
} catch (exception: IOException) {
MediatorResult.Error(exception)
} catch (exception: HttpException) {
MediatorResult.Error(exception)
}
}
private suspend fun getMoviesPage(): MoviesPage? {
return database.popularMoviesPageDao().getPopularMoviesPage().firstOrNull()
}
}
I get the data from this api: https://api.themoviedb.org/3/.
Any ideas on how I should change this RemoteMediator so that it will load all pages?
If you need more details please feel free to ask
I have been trying to use the MLKit to scan a barcode however I don't seem to get anything on return, the info that I'm getting back is
W/libc: Access denied finding property "ro.hardware.chipname"
This is the code that I'm trying, it does enter in the success listener however I doesn't seem to recognize the format.
private fun scanBarcodes(bitmap: Bitmap) {
val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_CODABAR,
Barcode.FORMAT_UPC_A,
Barcode.FORMAT_UPC_E
)
.build()
val scanner = BarcodeScanning.getClient(options)
val image = InputImage.fromBitmap(bitmap, 0)
scanner.process(image)
.addOnSuccessListener { barcodes ->
// It is succesful
for (barcode in barcodes) {
val bounds = barcode.boundingBox
val corners = barcode.cornerPoints
val rawValue = barcode.rawValue
Log.d("RAWVALUE ->>>", rawValue.toString())
when (barcode.valueType) {
Barcode.FORMAT_UPC_A -> {
Log.d("TASK SUCCESFUL ->>>>>>", "UPC A")
val upc = barcode.url
}
Barcode.FORMAT_UPC_E -> {
Log.d("TASK SUCCESFUL ->>>>>>", "UPC E")
}
Barcode.FORMAT_CODABAR -> {
val title = barcode.url!!.title
val url = barcode.url!!.url
}
}
}
}
.addOnFailureListener {
Log.d(TAG, "Problem")
}
}
The BitMap that I'm passing the scanBarcodes function is the one obtained underneath
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 100 && resultCode == RESULT_OK) {
imageUri = data?.data!!
if (binding.switchCamera?.isChecked == true)
Picasso.get()!!.load(imageUri).resize(300, 300).centerCrop()
.into(binding.imageButton)
}
if (requestCode == cameraCode && resultCode == RESULT_OK) {
imageBitmap = data?.extras?.get("data") as Bitmap
val baos = ByteArrayOutputStream()
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
data2 = baos.toByteArray()
val file = File(cacheDir, "filename.jpg")
file.createNewFile()
val fileOS = FileOutputStream(file)
fileOS.write(data2)
fileOS.flush()
fileOS.close()
if (binding.switchCamera?.isChecked == true) {
binding.imageButton.setImageBitmap(imageBitmap)
} else {
scanBarcodes(imageBitmap)
}
}
}
I'm writing an app using Kotlin.
I'am using ActivityResultLauncher for get permission. I can use ActivityResultLauncher on Activity clearly but when I try to get permission on fragment with ActivityResultLauncher, the app goint to background without getting any error. I will put my code below. Please help me :)
private var selectedPictureUri: Uri? = null
private lateinit var permissionLauncherForGallery: ActivityResultLauncher<String>
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
override fun populateUI(savedInstanceState: Bundle?) {
setClickListener()
registerLauncher()
}
private fun selectMedia() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
//request permission
if (ActivityCompat.shouldShowRequestPermissionRationale(
this#WriteUsActivity,
Manifest.permission.READ_EXTERNAL_STORAGE
)
) {
Snackbar.make(
mBinding!!.root,
"Permission needed for Gallery",
Snackbar.LENGTH_INDEFINITE
).setAction("Give Permission") {
permissionLauncherForGallery.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
}.show()
} else {
permissionLauncherForGallery.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
}
} else {
val intentToGallery =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
activityResultLauncher.launch(intentToGallery)
}
}
private fun registerLauncher() {
activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
val intentFromResult = result.data
if (intentFromResult != null) {
selectedPictureUri = intentFromResult.data
if (selectedPictureUri != null) {
mBinding?.ivPhoto?.visibility= View.VISIBLE
mBinding?.ivPhoto?.setImageURI(selectedPictureUri)
} else {
val bundle = result.data!!.extras
val bitmap = bundle?.get("data")
mBinding?.ivPhoto?.setImageBitmap(bitmap as Bitmap)
}
}
}
}
permissionLauncherForGallery =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { result ->
if (result) {
//permission granted
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
val intentToGallery =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
activityResultLauncher.launch(intentToGallery)
}
} else {
//permission denied
Toast.makeText(this, "Permisson needed!", Toast.LENGTH_LONG).show()
}
}
}
private fun setClickListener() {
mBinding?.apply {
btnPhoto.setOnClickListener {
selectMedia()
}
btnPhoto2.setOnClickListener {
this#WriteUsActivity.toast("Pick Second Photo")
}
btnSend.setOnClickListener {
this#WriteUsActivity.toast("Save")
}
}
}
I'm selecting the image from my phone gallery and want to upload image on server but my app crash every time i don't know the reason.. i already study many tutorials and Question but i did not understand. please help me.
Here is my code
class profileCreate : AppCompatActivity() {
var context: Context? = null
var imageUri: Uri? = null
var picturePath: String? = null
val url = "https://apps.faizeqamar.website/charity/api/donnor_add"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile_create)
val et_name = findViewById<EditText>(R.id.et_name)
val et_cnic = findViewById<EditText>(R.id.et_cnic)
val et_email = findViewById<EditText>(R.id.et_email)
val et_phon = findViewById<EditText>(R.id.et_phon)
val et_address = findViewById<EditText>(R.id.et_address)
val profile_image = findViewById<ImageView>(R.id.profile_image)
profile_image.setOnClickListener {
checkPermission()
}
val btn_create_profile = findViewById<Button>(R.id.btn_create_profile)
btn_create_profile.setOnClickListener {
imageUpload()
}
}
Volley Code
private fun imageUpload() {
val smr =
SimpleMultiPartRequest(
Request.Method.POST, url,
Response.Listener { response ->
Log.d("Response", response)
Toast.makeText(
applicationContext,
"xyz",
Toast.LENGTH_LONG
).show()
}, Response.ErrorListener { error ->
Toast.makeText(
applicationContext,
error.message,
Toast.LENGTH_LONG
).show()
})
var fname = et_name.text.toString()
var cnic = et_cnic.text.toString()
var email = et_email.text.toString()
var phone = et_phon.text.toString()
var address = et_address.text.toString()
smr.addFile("user_image", picturePath)
smr.addStringParam("fname", fname)
smr.addStringParam("cnic", cnic)
smr.addStringParam("email", email)
smr.addStringParam("phone", phone)
smr.addStringParam("address", address)
val mRequestQueue = Volley.newRequestQueue(applicationContext)
mRequestQueue.add(smr)
}
Pick Image from phone
//*********pick image from phone************
var READIMAGE: Int = 253
fun checkPermission() {
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(
this,
android.Manifest.permission.READ_EXTERNAL_STORAGE
) !=
PackageManager.PERMISSION_GRANTED
) {
requestPermissions(
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),
READIMAGE
)
return
}
}
loadImage()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
when (requestCode) {
READIMAGE -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
loadImage()
} else {
Toast.makeText(
applicationContext,
"cannot access your images",
Toast.LENGTH_LONG
).show()
}
}
else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
val PICK_IMAGE_CODE = 123
fun loadImage() {
var intent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
)
startActivityForResult(intent, PICK_IMAGE_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PICK_IMAGE_CODE && data != null && resultCode == RESULT_OK) {
imageUri = data.data
val filePathColum = arrayOf(MediaStore.Images.Media.DATA)
val cursor = contentResolver.query(imageUri!!, filePathColum, null, null, null)
cursor!!.moveToFirst()
val columnIndex = cursor.getColumnIndex(filePathColum[0])
picturePath = cursor.getString(columnIndex)
cursor.close()
profile_image?.setImageBitmap(BitmapFactory.decodeFile(picturePath))
}
}
}
Encode your image to string and send to the server like sending strings
change your onACtivityresult as below
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
try {
if (requestCode == PICK_IMAGE_CODE && data != null && resultCode == RESULT_OK) {
val contentURI = data!!.data
try {
logBitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, contentURI)
encodedImgString = getStringImage(logBitmap!!)
profile_image!!.setImageBitmap(logBitmap)
} catch (e: IOException) {
e.printStackTrace()
Toast.makeText(this, "Failed!", Toast.LENGTH_SHORT).show()
}
}else if (requestCode== IMAGE_CAPTURE_CODE){
img_logo.setImageURI(image_uri)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
here is the getStringImage function
private fun getStringImage(bmp: Bitmap): String {
val baos = ByteArrayOutputStream()
bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val imageBytes = baos.toByteArray()
return Base64.encodeToString(imageBytes, Base64.DEFAULT)
}
You can send the encodedImgString to the server and decode from there