How can ı upload file or image using retrofit on kotlin? - kotlin

ı dont know how to upload file or image etc. using retrofit multipart. Can anyone help me ?strong text

First, you have to create API Interface like this with #Multipart annotation:
#Multipart
#POST(Constants.API_LINK)
fun createProfile(
#Part("name") name: RequestBody,
#Part("email") email: RequestBody,
#Part image: MultipartBody.Part?
): Call<CreateProfileResponse>
Now, choose the image using MediaStore, get it's URI Path and use that to make a MultipartBody.Part object of that image like this:
val mediaType: String = "image/png"
val fileName: String = "photo_" + System.currentTimeMillis() + ".png"
val file: File = File(uriPath!!)
val reqFile = file.asRequestBody(mediaType.toMediaTypeOrNull())
profilePic = MultipartBody.Part.createFormData("file", fileName, reqFile)
Now just call the API using retrofit and pass this profilePic object in the respective parameter.
For more info about structuring your Retrofit and calling APIs, you can refer to my previous detailed answer here Retrofit calling APIs

Related

Use KTOR as a pipe for simultaneously fetching and responding a file

I have a KTOR backend which serves as a broker between the frontend-client and an external REST API. I want to make KTOR fetch the chunks of a file from the REST API, and as it receives these chunks KTOR should pass them on to the client, without having to temporarily store the entire file. The file can be very large, which is why the only option is to stream it.
I have made this simple illustration to show what I want to achieve:
I have something like this in my code so far, but it doesn't seem to work correctly:
get("/file") {
val uri = "/rest-api"
downloadFileClient.prepareGet(uri).execute {response ->
call.respondOutputStream(ContentType.Application.Pdf, HttpStatusCode.OK, producer = {response.bodyAsChannel()})
}
}
You can respond with an object of the OutgoingContent.ReadChannelContent class which can use client's response as a source:
get("/file") {
val uri = "/rest-api"
downloadFileClient.prepareGet(uri).execute { response ->
val channel = response.bodyAsChannel()
call.respond(object : OutgoingContent.ReadChannelContent() {
override fun readFrom(): ByteReadChannel = channel
override val status: HttpStatusCode = HttpStatusCode.OK
override val contentType: ContentType = ContentType.Application.Pdf
})
}
}

Passing Multiple Mime Types to ActivityResultLauncher.launch()

I have following code
val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
//Some code here..
}
and somewhere else ,
getContent.launch("application/vnd.openxmlformats-officedocument.wordprocessingml.document")
I can successfully select the docx file . I need to select either pdf or doc or text or docx rather just to be able to select one kind(here docx).
I would recommend using OpenDocument instead of GetContent.
val documentPick =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
// do something
}
While launching the intent just add the mime types you want to get
documentPick.launch(
arrayOf(
"application/pdf",
"application/msword",
"application/ms-doc",
"application/doc",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"text/plain"
)
)
Using array doesn't work in my case. Instead, the following worked correctly.
Here custom class of ActivityResultContracts.GetContent is used. fun "createIntent" is overrided to customize method to make intent from the input.
// custom class of GetContent: input string has multiple mime types divided by ";"
// Here multiple mime type are divided and stored in array to pass to putExtra.
// super.createIntent creates ordinary intent, then add the extra.
class GetContentWithMultiFilter:ActivityResultContracts.GetContent() {
override fun createIntent(context:Context, input:String):Intent {
val inputArray = input.split(";").toTypedArray()
val myIntent = super.createIntent(context, "*/*")
myIntent.putExtra(Intent.EXTRA_MIME_TYPES, inputArray)
return myIntent
}
}
// define ActivityResultLauncher to launch : using custom GetContent
val getContent=registerForActivityResult(GetContentWithMultiFilter()){uri ->
... // do something
}
// launch it
// multiple mime types are separated by ";".
val inputString="audio/mpeg;audio/x-wav;audio/wav"
getContent.launch(inputString)

Parsing pdf with Kotlin using a Uri?

I write Kotlin code in Android Studio. The user chooses a file from the phone (I need to access the content as a string). There I get a Uri?. With that Uri? I can extract text from .csv and .txt files:
if (typeOfFile == ".txt" || typeOfFile == ".csv") {
try {
val ins: InputStream? = contentResolver?.openInputStream(uriFromSelectedFile)
val reader = BufferedReader(ins!!.reader())
textIWant = reader.readText()
...
Getting the file type also works fine, but when it comes to opening pdf files, nothing seems to work. I tried using PDFBox from Apache in various ways. The pdf I try to open is a simple onePager and contains only extractable text (can be copied) like this pdf.
This is one of the things I tried, the phone freezes when the file to open is a pdf:
if (typeOfFile == ".pdf") {
try {
val myPDDocument:PDDocument = PDDocument(COSDocument(ScratchFile(File(uriFromSelectedFile.path))))
textIWant = PDFTextStripper().getText(myPDDocument)
...
I´ve been trying for days. Does anyone know, how it works in Kotlin?
It worked using tom_roush.pdfbox and a companion object:
import com.tom_roush.pdfbox.text.PDFTextStripper
class MainActivity : AppCompatActivity() {
companion object PdfParser {
fun parse(fis: InputStream): String {
var content = ""
com.tom_roush.pdfbox.pdmodel.PDDocument.load(fis).use { pdfDocument ->
if (!pdfDocument.isEncrypted) {
content = PDFTextStripper().getText(pdfDocument)
}
}
return content
}
}
Calling the parse function of the companion object:
val fis: InputStream = contentResolver?.openInputStream(uriFromSelectedFile)!!
textIWant = parse(fis)

Kotlin - get Firebase Image DownloadUrl returns "com.google.android.gms.tasks.zzu"

I am trying to upload images to Real time Firebase Database by creating two folders using Compressor library and need to display image like messenger with username but i am unable to display image due to url issue
var filePath = mStorageRef!!.child("chat_profile_images")
.child(userId + ".jpg")
//Create another directory for thumbimages ( smaller, compressed images)
var thumbFilePath = mStorageRef!!.child("chat_profile_images")
.child("thumbs")
.child(userId + ".jpg")
filePath.putFile(resultUri)
.addOnCompleteListener{
task: Task<UploadTask.TaskSnapshot> ->
if (task.isSuccessful) {
//Let's get the pic url
var donwloadUrl = task.result?.storage?.downloadUrl.toString()
Log.d(TAG, "Profilepic link: $donwloadUrl")
//Upload Task
var uploadTask: UploadTask = thumbFilePath
.putBytes(thumbByteArray)
uploadTask.addOnCompleteListener{
task: Task<UploadTask.TaskSnapshot> ->
var thumbUrl = task.getResult()?.storage?.downloadUrl.toString()
Log.d(TAG, "Profilepic link: $thumbUrl")
i tried to change downloadUrl
filepath.downloadUrl.toString
thumbFilePath.downloadUrl.toString
but both these values getting "com.google.android.gms.tasks.zzu"
i also tried to change
task.result.sessionurl.downloadUrl.toString
for this one i am getting downloadUrl but not a complete solution for my problem as still i cannot display image i need to get thumbUrl downloadUrl
You have the exact same and very common misunderstanding as in this question, except it's in java. You should follow the documentation here to understand get getDownloadUrl works. As you can see from the linked API documentation, it's not a property getter, it's actually a method that returns a Task<Uri> that tracks the asynchronous fetch of the URL you want, just like the upload task:
filePath.downloadUrl
.addOnSuccessListener { urlTask ->
// download URL is available here
val url = urlTask.result.toString()
}.addOnFailureListener { e ->
// Handle any errors
}
This will only work after the upload is fully complete.
Correct way of getting download link after uploading
here
Just putting out there, I also encounter the same problem,
but both these values getting "com.google.android.gms.tasks.zzu"
but it wasn't the same mistake from the OP
used addOnCompleteListener instead of addOnSuccesslistener
My Error code:
imageRef.downloadUrl.addOnCompleteListener { url ->
val imageURL = url.toString()
println("imageURL: $imageURL , url: $url")
addUserToDatabase(imageURL)
}

Kotlin enviromental values

I'm learning kotlin, I stumbled across an open-source repo, cloned it and ran on my computer, it is a update tool to update an existing jar, although looking at their code how do they approached to that, they did something like this.
private fun updateJar(frame: LaunchFrame, project: Project) {
val sourcePath = project.jarSourcePath
val jarPath = project.jarPath
val repoName = project.repoName
frame.log("Reading source URL from '$sourcePath'")
val sourceUrl = readTextFile(sourcePath)?.let { URI(it) }
frame.log("Source URL: $sourceUrl")
frame.log("Connecting to GitHub")
val github = GitHub.connectAnonymously()
frame.log("Using repository '$repoName'")
val repo = github.getRepository(repoName)
frame.log("Finding latest release")
val latestRelease = repo.listReleases().first()
val assets = latestRelease.assets
check(assets.size == 1) { "Release must only have one asset" }
val asset = assets.first()
val downloadUrl = URI(asset.browserDownloadUrl)
frame.log("Latest URL: $downloadUrl")
if (sourceUrl == null || sourceUrl != downloadUrl || !verifyJar(jarPath)) {
frame.log("Downloading '$downloadUrl' to '$jarPath'")
downloadFile(downloadUrl, jarPath)
frame.log("Writing '$downloadUrl' to '$sourcePath'")
writeTextFile(sourcePath, downloadUrl.toString())
} else {
frame.log("'$jarPath' is up to date")
}
}
Which looks pretty much straight-forward, but here's the catch, there are no actual URL's for the $sourceUrl and others, can someone shed some light to this question? It starts downloading the repo which is runestar/client but there are no actual links for the exact repo what it's trying to download, so how did they do that?
The values are being extracted using some logic, scattered around various places in the code.
For example, see https://github.com/RuneStar/launcher/blob/3e8dcb59c32d2818c917705c6c4432f9fc12c449/src/main/java/org/runestar/launcher/RuneStar.kt#L15
override val repoName: String get() = "RuneStar/client"
It's not environment variables, and it's not downloading from a URL, it's writing to one on the local filesystem.
The Project interface sets up the file locations and the RuneStar class sets up a specfic Github repository.