Load class into val with Picasso - android

I want to load a String out of a class to load it with picasso
val pic = String
Picasso.get().load(User1::profileImageUrl).into(pic)
but the "load" gets a red line underneath it and it doesnt work.
here you can see my class
class User1(val uid: String, val username: String, val profileImageUrl: String)
so later I want to use that string with glide like this
Glide.with(applicationContext).load(personPhotoUrl)
.thumbnail(0.3f)
.apply(RequestOptions.circleCropTransform())
.into(profilepicture!!)
any Ideas?

I am not familiar with Picasso, but from javadoc load method takes String, Uri, File or resource id. You pass some kind of reflection reference on a property (if this construction makes sense at all).
If you want create pic one time you should use an instance of user:
val user : User1 = getUserSomewhere()
Picasso.get().load(user1.profileImageUrl).into(pic)
Or you can make a method:
fun loadUserProfileImage(user: User1, target: ImageView) {
Picasso.get().load(user1.profileImageUrl).into(target)
}
Also underneath red line tells you that there is an error and it has a message of what's wrong.)
Also this: val pic = String is not correct, at least in your case. pic here is of type StringCompanionObject.

Related

Is there any efficient way to search throughout a list of objects every field?

Let's say I have an object
data class Person(
val name: String,
val surname: String,
val street: String,
val postalCode: String,
val telephoneNumber: String,
)
And then I have a list of persons :
val personsList = listOf(
Person(name="John", surname="Hams", street="Gariolg", postalCode="929429", telephoneNumer="+2142422422",),
Person(name="Karl", surname="Hamsteel", street="Gariolg", postalCode="124215", telephoneNumer="+3526522",),
Person(name="Stepf", surname="Hiol", street="Bubmp", postalCode="5342", telephoneNumer="+7574535",),
Person(name="Germa", surname="Foo", street="Hutioa", postalCode="235236", telephoneNumer="+112355",)
)
So now if the user types for instance Hams it should return John and Karl, because both have the word "Hams" inside the object. What I mean is doesn't matter if the user types postalCode, name, or whatever I'd like to loop throughout the object to check if there's any coincidence.
How i would do it, is create a function inside the data class, say, for example, like this. This will check if any field inside your data class matches with the given string.
In my example i check if whole string matches, but you can change this however you want. You probably want it.contains(searchString) inside the any block.
fun checkIfStringMatches(searchString: String) : Boolean =
setOf(this.name, this.surname, this.strees, this.postalCode, this.telephone).any { it == string }
Then, you can use this function on your list of persons to filter if any object matches your string search.
personList.filter{it.checkIfStringMatches(mySearchString)} // this will return a list with all the objects that match your search criteria
The problem is that if you add more fields, you will have to change this function and add it to the listOf() block. But i don't know any way to do this automatically without reflection, which is not really recommended to use. If you still want to use it, here is a question on this topic. Kotlin: Iterate over components of object
Try this, it will work.
personsList.filter { it.surname.startsWith("Hams") }.map {
Log.d("filter_name", it.name)
}
Hey You can apply filter method on list and grab the expected output like below :
val filtered = personsList.filter { it.toString().contains("Hams", true) }

Verify if POJO data class was mapped correctly

I am using a POJO data class with GSON to parse the data which is being called from the Firestore database.
For example, I have a POJO class with few non-nullable, and nullable values like userID
data class Users(id:String="", userID:String="" ...)
I am then using GSON to parse the JSON data to object for that class
val gson = Gson()
val jsonObjects = gson.toJson(querySnapshot.data)
val parseData = gson.fromJson(jsonObjects,Users::class.java)
My question is if someone uploads data in the database and forgets to add the userID (i.e. it is null), is there a way I can check if the User data class is valid when being parsed?
I am using a check like if(userID == ""){return false} . But as the number of non-nullable fields grows it gets tedious and there must be a better way to check this.
My question is if someone uploads data in the database and forgets to add the userID (i.e. it is null), is there a way I can check if the User data class is valid when being parsed?
If you don't want to have null values at all, why would you then let the user the possibility to provide incomplete data? The simplest solution would be to restrict the data that is added to the database. How? Simply by creating some constraints. For example, your users cannot get access to a feature in your app if they do not fill in all the required fields. That's an operation that is widely used.
If you already have null values, then checking against nullity is a solution you can go ahead with. In Kotlin, null safety can be handled in many ways, either by checking for null in conditions, using safe calls, elvis operator or even using the !! operator.
Maybe the extension method of Kotlin is an accepted approach.
Let me show a demo, I assume the class User looks like this:
data class User(
val id: String,
val userId: String? // nullable
)
Create a extension method User.isValid() to verify the fields you want.
fun User.isValid() = when {
userId.isNullOrEmpty() -> false
else -> true
}
The method isNullOrEmpty() is in stdlib of Kotlin. I test the code, it works fine.
val user1 = User("id 001", null)
val user2 = User("id 002", "userId 001")
println(user1.isValid()) //==> print false
println(user2.isValid()) //==> print true
Now, back to your worry point:
...But as the number of non nullable fields grow it gets tedious
I changed the class User
data class User(
val id: String,
val userId: String?,
val email: String?,
val name: String?
)
it means that when the fields of userId, email, name, any of them is null, the User is invalid.
Just add conditions in extention method, like this:
fun User.isValid() = when {
userId.isNullOrEmpty()
|| email.isNullOrEmpty()
|| name.isNullOrEmpty() -> false
else -> true
}
We just need to maintain the method of isValid.
conclusion
Kotlin Extension Method can be used in your case.
It's better don't use id="", also can create an extension method for this empty string if need.
fun String.Companion.empty() = ""
data class User(
val id: String,
val userId: String? = String.empty()
...
)
All the extension methods can be placed in a class, like UserExt.kt for easy maintaining.

Simple method of calling an API from Kotlin

In my quest to learn Kotlin I am trying to write an Android app that will take 3 photos and upload them in binary format to my database via an API.
Thanks to the help of people here and the Google documentation, I have been able to get my 3 photos and display a nice thumbnail image for each one. I have also worked out how to save the image to a physical file. I don't want to physically save the file first (not least because I'd still have to upload it to the database somehow). What I'm struggling with though is (a) converting the file to binary and (b) calling an API.
I get the file(s) into a variable using:
val imageBitmap = data?.extras?.get("data") as Bitmap
This is within:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
So, at this point I have a variable (imageBitmap) which is holding the photo. My API;
http://api.domain.com/api/photos?key={APIkey}&ipaddress=1.1.1.1&activity=new&imgdate=2021-05-04&img=x0x0x0x0x0
is structured as above (img is the aspect that I need to pass the photo image through). Is it as simple as:
urlString = "http://api.domain.com/api/photos?key={APIkey}&ipaddress=1.1.1.1&activity=new&imgdate=2021-05-04&img=" + imageBitmap
Would the above not be invalidly trying to concatenate a string and an object?
The API is written in C# through Visual Studio and calls a stored proc in my database. The img parameter in the proc is varbinary(max) so base64 encoded.
I found a lot of references to using OKHttp3, but I can't find an example that is clear enough for a beginner. What I was envisaging was that I'd call a function that encompasses the call and returns the json response. I took the code below from an example, and whilst it doesn't error, it doesn't make a call either:
fun doAPICall(url: String, body: String): String {
val apiClient = OKHttpClient()
var resp: String = ""
val request = Request.Builder().url(url).build()
//Define the body if present
apiClient.newCall(request).enqueue(object: Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) {
resp = response.body()?.string()!!
}
})
}
So, I have two problems that I'm struggling to understand here. Firstly how do I convert imageBitmap into a binary string that I can pass in the API as a part of the url parameter, and secondly, how do I call the API and get the response back?
I tried a very simple example to see if the code worked by just calling an API and trying to write the response value to a TextView:
txtResponse.text = doAPICall("http://api.domain.com/api/photos?key={APIkey}&ipaddress=1.1.1.1&activity=getName", "")
This doesn't throw an error, but doesn't put the response into the textview either. The response for this should be:
{
"APIResult": [
{
"id": 200,
"status_message": "Success",
"name": "Testing"
}
]
}
Can someone provide some pointers for me please?

How do I refer to data class property names for Firestore queries?

I'm using a simple data class Track, then saving it as an object so that fields and values are automatically saved. This is working as intended. However later when I want to query on 1 of those property/field names, I need to provide the String value.
How do I refer to the name of that property in the data class, so that I maintain the "single source of truth" for that value, without hard coding it a second time in the query? Example uses "spotifyId":
data class Track(
val spotifyId: String,
val name: String,
val artist: List<String>,
val duration: String
)
Save a track:
set(trackDocRef, track)
Query for a track:
db.collection("tracks").whereEqualTo("spotifyId", "sdfgsdfswer4543w5yer345").get()
Thank you!
I figured out one way of doing it, not sure how "correct" it is. I used reflection in the TracksContract object to refer to the Track model:
data class Track(
val spotifyId: String,
val name: String,
val artist: List<String>,
val duration: String
)
Single reference to Track model via TracksContract:
object TracksContract {
internal const val COLLECTION_NAME = "Tracks"
object Fields {
val SPOTIFY_ID = Track::spotifyId.name
val NAME = Track::name.name
val ARTIST = Track::artist.name
val DURATION = Track::duration.name
}
}
now if I need to run the query based on that spotifyId, I refer to through the TracksContract:
db.collection(TracksContract.COLLECTION_NAME)
.whereEqualTo(TracksContract.Fields.SPOTIFY_ID, "ID_VALUE")
.get()
Finally if I decide to change the property names in the Track model then the TracksContract will show a compiler error, and I can change the name and refactor references from there if I want to.

Android Kotlin - Firestore image upload and display

At the moment as a sample I'm recreating instagram-like post, where user can post a description and image (along with username since I'm still not configuring authentication). So far as follows I can only post username and description. Along side of that I can load new image as a source into the imageview on the screen.
My data class is:
data class Post(val username: String,
val timestamp: Date,
val postTxt: String,
val numLikes: Int,
val numComments: Int,
val documentId: String)
I put data in a hashmap as follows:
val data = hashMapOf(
NUM_LIKES to 0,
NUM_COMMENTS to 0,
POST_TXT to addPostTxt.text.toString().trim(),
TIMESTAMP to FieldValue.serverTimestamp(),
USERNAME to addUsernameTxt.text.toString().trim()
)
and then pass it to upload to firestore:
FirebaseFirestore.getInstance().collection(POST_REF)
.add(data)
.addOnSuccessListener { finish() }
.addOnFailureListener {
Log.e("Exception", "Could not add post: $it")
toast("Could not add post")
}
And to get the data I created a function which takes snapshot of type QuerySnapshot like so:
// Clear all the posts before relaod
posts.clear()
snapshot.documents.forEach { document ->
val data = document.data
val name = data?.get(USERNAME) as String
val timestamp = data[TIMESTAMP] as Date
val postTxt = data[POST_TXT] as String
val numLikes = data[NUM_LIKES] as Long
val numComments = data[NUM_COMMENTS] as Long
val documentId = document.id
val newPost = Post(name, timestamp, postTxt, numLikes.toInt(), numComments.toInt(), documentId)
posts.add(newPost)
}
postsAdapter.notifyDataSetChanged()
So far uploading text, current time of upload works fine for both upload and reading it from the database; however my question here is:
- What is the best way (following current codebase) to upload image to firestore and storage and display it accordingly in the main window (preferably using Glide or picasso)?
It's generally not a good idea to store binary data like images in Firestore. You could very easily exceed the limit for how much data you can store in a document, which is 1MB. Large documents also take more time to load on the client, which is even worse if you don't even need to use the image at the time of the read.
Instead, consider uploading the image to Cloud Storage and saving a path to that location in a field in your document. Then, when it's time to display the image, load it from there.

Categories

Resources