#Entity
data class EmailMessage (
#Id var id: Long = 0,
var subject: String = "",
var body: String = "",
var attachments: ToMany<Attachment>? = null,
)
for 'attachments', Is there a better way to do it without assigning null?
Related
I'm having a NumberFormatException which is likely due passing an empty string to product_quantity in the product and cart data class. I'm having difficulty assigning value to the product_quantity in my code before parsing it toInt()
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.hardextech.store, PID: 22948
java.lang.NumberFormatException: For input string: ""
at java.lang.Integer.parseInt(Integer.java:627)
at java.lang.Integer.parseInt(Integer.java:650)
at com.hardextech.store.ui.activities.ui.activities.CartListActivity.successfullyGetTheCartItemList(CartListActivity.kt:90)
at com.hardextech.store.firestore.FirestoreClass.getCartList$lambda-28(FirestoreClass.kt:493)
at com.hardextech.store.firestore.FirestoreClass.$r8$lambda$Uc6EU1OaDQc7HeKgs7cM5uEsC2A(Unknown Source:0)
at com.hardextech.store.firestore.FirestoreClass$$ExternalSyntheticLambda12.onSuccess(Unknown Source:4)
at com.google.android.gms.tasks.zzn.run(com.google.android.gms:play-services-tasks##17.2.0:4)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6819)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:912)
This is the successfullyGetCartTheCartItemList method referenced from the debugging console
fun successfullyGetTheCartItemList(listOfItemInTheCart: ArrayList<Cart>){
dismissProgressDialogue()
// checking for the product list in the stock-- determining if the product is available in the stock
for (everyProductInTheProductList in mProductList){
for (everyProductInTheCart in listOfItemInTheCart){
if (everyProductInTheProductList.product_id == everyProductInTheCart.product_id){
everyProductInTheCart.product_quantity = everyProductInTheProductList.product_quantity
// if there are no products in the stock
if (everyProductInTheProductList.product_quantity.toInt() == 0){
everyProductInTheCart.cart_quantity = everyProductInTheProductList.product_quantity
}
}
}
}
// initializing the mCartDataClassDetails
mCartDataClassDetails = listOfItemInTheCart
// checking for the product list in the cart
if (mCartDataClassDetails.size >0){
rv_cart_item_list.visibility = View.VISIBLE
ll_check_out.visibility = View.VISIBLE
tv_no_cart_item_found.visibility = View.GONE
rv_cart_item_list.layoutManager = LinearLayoutManager(this)
rv_cart_item_list.setHasFixedSize(true)
// create an adapter variable for the recycler view
val cartListAdapter = CartItemListAdapter(this, listOfItemInTheCart)
// pass the adapter to the recyclerview
rv_cart_item_list.adapter = cartListAdapter
// assign double to the sub-total in the itemListCart
var subTotal: Double = 0.0
// run through all product in the list
for (everyItemInTheCart in mCartDataClassDetails){
// checking for the available quantity of product
val availableProductQuantity = everyItemInTheCart.product_quantity.toInt()
if (availableProductQuantity > 0){
Log.i("Cart Title", everyItemInTheCart.product_title)
// convert the price to Double
val price = everyItemInTheCart.product_price.toDouble()
// convert the quantity to Int
val quantity = everyItemInTheCart.cart_quantity.toInt()
// calculate the sub-total cost
subTotal+=(price*quantity)
}
}
// assign the value of the sub total for each product sales
tv_product_subTotal.text = "NGN $subTotal"
// assigning the delivery cost for each product sales
// TODO: Seek for API to calculate the delivery cost for each product and/or write the code criteria for calculating it
tv_delivery_cost.text = (subTotal*0.05).toString()
if (subTotal > 0){
ll_check_out.visibility = View.VISIBLE
// TODO: Change the logic for the delivery cost
val totalProductCost = subTotal + (subTotal*0.05)
tv_total_product_cost.text = "NGN $totalProductCost"
} else{
ll_check_out.visibility = View.GONE
}
} else{
rv_cart_item_list.visibility = View.GONE
ll_check_out.visibility = View.GONE
tv_no_cart_item_found.visibility = View.VISIBLE
}
}
This is method from the Firestore class
fun getCartList(activity: Activity){
// the method for downloading the cart item list
mFireStore.collection(Constants.CART_ITEMS_COLLECTION)
// get the cart items for the logged in user
.whereEqualTo(Constants.USER_ID, getCurrentUserID())
.get()
.addOnSuccessListener { document->
Log.i(activity.javaClass.simpleName, document.documents.toString())
// get the list of the cart items--- number of products in the cart
val listOfCartItems: ArrayList<Cart> = ArrayList()
// run through each of the document(FireStore document field) in the list
for (loopingThroughCartItems in document.documents){
// converting the products in the cart to an object and surround with null check
val cartItemListObject = loopingThroughCartItems.toObject(Cart::class.java)!!
cartItemListObject.id= loopingThroughCartItems.id
// add the result of the loop to the cart item arrayList
listOfCartItems.add(cartItemListObject)
}
when(activity){
is CartListActivity->{
activity.successfullyGetTheCartItemList(listOfCartItems)
}
}
}.addOnFailureListener {e->
Log.e(activity.javaClass.simpleName, " Error downloading products in the cart", e)
when(activity){
is CartListActivity->{
activity.dismissProgressDialogue()
}
}
}
}
This is Product Data class
#Parcelize
data class Product(
val user_id: String = "",
var id: String = "",
val product_image: String = "",
val product_title: String = "",
val product_price: String = "",
val product_description: String = "",
val product_quantity: String = "",
val user_name: String = "",
var product_id:String =""
): Parcelable
This is the cart data class
#kotlinx.parcelize.Parcelize
data class Cart(
val user_id: String = "",
val product_id: String = "",
val product_title: String = "",
val product_image: String = "",
val product_price: String = "",
var cart_quantity: String = "",
var product_quantity: String ="",
var id: String = ""
): Parcelable
You can use toIntOrNull, which returns parsed Int or null when failed to parse. Then, use let with ?., like this:
string.toIntOrNull()?.let { parsedInt ->
// Your code here
}
This warning is really weird to me because I was able to create one of the data type but the other 2 are not. You will see the implement + init are mostly the same.
1 small question, if my graphql API does not have id, which is the best way to implement the id? I'm currently use country name for id. which I think is a pretty bad practice
Thank you in advance!
typealias CountryData = ScpecificCountryQuery.Data
struct Countries: Decodable {
var countries: [Country]
init(_ countries: CountryData?) {
self.countries = countries?.countries.map({ country -> Country in
Country(country)
}) ?? []
}
struct Country: Identifiable, Decodable {
var id: String {
return currency
}
var code: String
var name: String
var phone: String
var capital: String
var currency : String
var continent: Continent ( Does not have any warning)
var languages : Lan ("Type of expression is ambiguous without more context")
var states: State ("Type of expression is ambiguous without more context")
init(_ country: ScpecificCountryQuery.Data.Country?) {
self.name = country?.name ?? ""
self.code = country?.code ?? ""
self.phone = country?.phone ?? ""
self.capital = country?.capital ?? ""
self.currency = country?.currency ?? ""
self.emoji = country?.emoji ?? ""
self.continent = Continent(country?.continent)
self.languages = Lan(country?.languages)
self.states = State(country?.states)
}
struct Lan: Decodable {
var code: String
var name: String
init(_ lan: ScpecificCountryQuery.Data.Country.Language?) {
self.code = lan?.code ?? ""
self.name = lan?.name ?? ""
}
}
struct Continent: Decodable {
var code: String
var name: String
init (_ continent: ScpecificCountryQuery.Data.Country.Continent?) {
self.code = continent?.code ?? ""
self.name = continent?.name ?? ""
}
}
struct State {
var code: String
var name: String
init (_ state: ScpecificCountryQuery.Data.Country.State?) {
self.code = state?.code ?? ""
self.name = state?.name ?? ""
}
}
}
}
I want to sort list descending based on UTC DateTime which is in String form.
My Class
data class CartEntity( val itemId: String, var itemName: String, var createdDate: String)
in this createdDate is "2020-07-28T14:28:52.877Z"
What I have tried
const val UTC_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
Collections.sort(list, object : Comparator<CartEntity> {
var f: DateFormat =
SimpleDateFormat(
AppConstants.UTC_FORMAT, Locale.ENGLISH
)
override fun compare(o1: CartEntity?, o2: CartEntity?): Int {
return try {
val firstitem = f.parse(o1?.createdDate!!)
val seconditem = f.parse(o2?.createdDate!!)
firstitem.compareTo(seconditem)
} catch (e: ParseException) {
throw IllegalArgumentException(e)
}
}
})
But still sort by descending is not working as expected
In kotlin style, you can use the standard library functions (following idioms):
Create a new sorted list out of the list you wanna sort:
fun main() {
val list = listOf<CartEntity>(
CartEntity(itemId = "", itemName = "", createdDate = "2020-07-28T14:28:52.877Z"),
CartEntity(itemId = "", itemName = "", createdDate = "2020-09-28T14:28:52.877Z"),
CartEntity(itemId = "", itemName = "", createdDate = "2020-08-28T14:28:52.877Z"),
CartEntity(itemId = "", itemName = "", createdDate = "2020-04-28T14:28:52.877Z"),
)
val format: DateFormat = SimpleDateFormat(AppConstants.UTC_FORMAT, Locale.ENGLISH)
val sortedList = list.sortedByDescending { format.parse(it.createdDate) }
println(sortedList) // `sortedList` is sorted out list, the `list` is holding the original order
}
Sort the original list (List should be mutable):
fun main() {
val list = mutableListOf<CartEntity>(
CartEntity(itemId = "", itemName = "", createdDate = "2020-07-28T14:28:52.877Z"),
CartEntity(itemId = "", itemName = "", createdDate = "2020-09-28T14:28:52.877Z"),
CartEntity(itemId = "", itemName = "", createdDate = "2020-08-28T14:28:52.877Z"),
CartEntity(itemId = "", itemName = "", createdDate = "2020-04-28T14:28:52.877Z"),
)
val format: DateFormat = SimpleDateFormat(AppConstants.UTC_FORMAT, Locale.ENGLISH)
list.sortByDescending { format.parse(it.createdDate) }
println(list) // `list` is sorted out list
}
This could be done using following approach.
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class Tester {
static class Car {
private String date;
String getDate() {
return this.date;
}
void setDate(String date) {
this.date = date;
}
#Override
public String toString() {
return date;
}
// Imagine if you keep date not as strings
ZonedDateTime toDateTime(){
return ZonedDateTime.parse(this.date);
}
}
public static void main(String[] args) {
Car first = new Car();
first.setDate("2020-07-28T14:28:52.877Z");
Car second = new Car();
second.setDate("2010-07-28T14:28:52.877Z");
Car third = new Car();
third.setDate("2021-07-28T14:28:52.877Z");
List<Car> cars = Arrays.asList(first, second, third);
List<Car> sorted = cars.stream().sorted(Comparator.nullsLast(
(current, next) -> {
ZonedDateTime currentDate = ZonedDateTime.parse(current.getDate());
ZonedDateTime nextDate = ZonedDateTime.parse(next.getDate());
return nextDate.compareTo(currentDate);
})).collect(Collectors.toList());
}
}
If you keep the date as regular Date object it will be easier to work with them and the code above could be simplified a bit.
List<Car> sorted = cars.stream()
.sorted(Comparator.comparing(Car::toDateTime, Comparator.nullsLast(Comparator.reverseOrder())))
.collect(Collectors.toList());
Your code works pretty much fine #Charwaka.
data class CartEntity(val itemId: String, var itemName: String, var createdDate: String)
const val UTC_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
fun main() {
val list = mutableListOf<CartEntity>().apply {
add(CartEntity(itemId = "", itemName = "", createdDate = "2020-07-28T14:28:52.877Z"))
add(CartEntity(itemId = "", itemName = "", createdDate = "2020-09-28T14:28:52.877Z"))
add(CartEntity(itemId = "", itemName = "", createdDate = "2020-08-28T14:28:52.877Z"))
add(CartEntity(itemId = "", itemName = "", createdDate = "2020-04-28T14:28:52.877Z"))
}
Collections.sort(list, object : Comparator<CartEntity> {
var f: DateFormat = SimpleDateFormat(UTC_FORMAT, Locale.ENGLISH)
override fun compare(o1: CartEntity, o2: CartEntity): Int {
return try {
val firstitem = f.parse(o1.createdDate)
val seconditem = f.parse(o2.createdDate)
seconditem.compareTo(firstitem)
} catch (e: ParseException) {
throw IllegalArgumentException(e)
}
}
})
list
}
output:
CartEntity(itemId=, itemName=, createdDate=2020-09-28T14:28:52.877Z),
CartEntity(itemId=, itemName=, createdDate=2020-08-28T14:28:52.877Z),
CartEntity(itemId=, itemName=, createdDate=2020-07-28T14:28:52.877Z),
CartEntity(itemId=, itemName=, createdDate=2020-04-28T14:28:52.877Z)
code from #Animesh Sahu also works!
val format: DateFormat = SimpleDateFormat(AppConstants.UTC_FORMAT, Locale.ENGLISH)
list.sortByDescending { format.parse(it.createdDate) }
I have an arraylist of event
var approvedEvents = ArrayList<Event>()
the class of Event is like this
class Event() {
var eventID : String = ""
var createdBy: String = "" // uid of user creator
var creatorFullName: String = ""
var creatorIsVerified : Boolean = false
var creatorProfilePictureImagePath = ""
var createdAt : Date = Calendar.getInstance().time
var hasBeenApproved : Boolean = false
var title : String = ""
var speaker : String? = null
var coordinate : GeoPoint = City.defaultCityCoordinate
var address : String = ""
var city : String = ""
var venue : String = ""
}
so I want to find an index in approvedEvents arraylist that its eventID match selectedEvent.eventID how to do that in Kotlin ? is there specific method that I can use ?
Use indexOfFirst or indexOfLast to find the index of an item in an ArrayList based on your own criteria like below:
val index = approvedEvents.indexOfFirst{
it.eventID == selectedEvent.eventID
}
First of all, you have to override equals function in your Event class like
------
------
var city : String = ""
var venue : String = ""
override fun equals(other: Any?): Boolean{
if(other is Event){
return eventID.equals(other.eventID)
}
return false;
}
}
Now when you want to search for an Event object with eventId in a list, first create a temporary event object with that eventId which you want to search like
val temp=Event()
temp.eventID="102"
and simply get the index
print(events.indexOf(temp))
*SOLUTION IS IN THE FIRST ANSWER
I'm pretty noob using SimpleXML Converter so models and annotations may be wrong.
This is the XML I receive:
<?xml version="1.0" encoding="UTF-8"?>
<cards-summary-response xmlns="http:/mywebpage.com/rest-api">
<card-summary>
<identifier>51641C1B23931</identifier>
<display-name>Debit Card</display-name>
<program-name>plastic_debit</program-name>
<status>Blocked</status>
</card-summary>
<card-summary>
<identifier>4E1BDFCC1D6</identifier>
<display-name>Virtual Debit</display-name>
<program-name>virtual_debit</program-name>
<status>Active</status>
</card-summary>
</cards-summary-response>
My models:
CardSummaryResponse.kt
#Root(strict = false, name = "cards-summary-response")
data class CardSummaryResponse constructor(
#ElementList(
required = false,
name = "card-summary",
entry = "card-summary",
inline = true,
empty = true
)
var cardsSummaryList: MutableList<CardSummary>? = null
)
CardSummary.kt
#Root(name = "card-summary")
data class CardSummary #JvmOverloads constructor(
#field:Element(name = "identifier", required = true)
var identifier: String = "",
#field:Element(name = "status", required = true)
var status: String = ""
)
API configuration:
retrofit = Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.createNonStrict(
Persister(AnnotationStrategy())
)
)
.baseUrl(CallsConfiguration.BASE_URL_WIRECARD)
.client(clientBuilder.build())
.build()
service = retrofit.create(RetrofitInterface::class.java)
And RetrofitInterface (this class is in Java):
#GET("webservices/wd-test.phtml")
Call<CardSummaryResponse> getCardsSummary();
I'm always getting the same exception:
java.lang.Error: org.simpleframework.xml.core.ConstructorException:
Parameter 'card-summary' does not have a match in class
com.app.account.model.CardSummaryResponse
Any suggestions?
I have managed to make it work using the following models:
CardSummaryResponse.tk
#Root(strict = false, name = "cards-summary-response")
data class CardSummaryResponse constructor(
#field:ElementList(
required = false,
name = "card-summary",
entry = "card-summary",
inline = true,
empty = true
)
var cardsSummaryList: MutableList<CardSummary>? = null
)
CardSummary.tk
#Root(name = "card-summary")
data class CardSummary constructor(
#field:Element(name = "identifier", required = true)
var identifier: String = "",
#field:Element(name = "status", required = true)
var status: String = ""
)
In my case, I was using 'val' in the data class. After spending 3 hours, I found the solution: just replace 'val with 'var' and give the default value.
Here are my data classes that are working fine after the solution:
sealed class Feeds {
#Root(name = "rss", strict = false)
data class RssFeed constructor(#field:Element(name = "channel") var channel: RssChannel? = null) :
Feeds()
#Root(name = "channel", strict = false)
data class RssChannel constructor(
#field:ElementList(
name = "item",
inline = true,
required = false
) var item: List<RssItem>? = null
) : Feeds()
#Root(name = "item", strict = false)
data class RssItem constructor(
#field:Element(name = "title") var title: String = "",
#field:Element(name = "description") var description: String = "",
#field:Element(name = "link") var link: String = ""
) : Feeds()
}
Happy Coding!!!