feat embalajes #refs 4021

This commit is contained in:
Sergio De la torre 2024-06-18 12:05:00 +02:00
parent c405f1ede4
commit ee7bbf69a0
6 changed files with 175 additions and 165 deletions

View File

@ -108,6 +108,9 @@ interface OnImageTrashClickListener {
interface OnEditSubQuantityListener { interface OnEditSubQuantityListener {
fun OnEditSubQuantityListener(item: Any, text: String) fun OnEditSubQuantityListener(item: Any, text: String)
} }
interface AdapterCallback {
fun getPosition():Int
}
interface OnItemClickListener { interface OnItemClickListener {
fun onItemClickListener(item: ItemSupplier) fun onItemClickListener(item: ItemSupplier)

View File

@ -1,6 +1,7 @@
package es.verdnatura.presentation.view.feature.delivery.fragments package es.verdnatura.presentation.view.feature.delivery.fragments
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.KeyEvent
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.ImageView import android.widget.ImageView
@ -12,6 +13,7 @@ import es.verdnatura.R
import es.verdnatura.databinding.FragmentExpeditionSummaryBinding import es.verdnatura.databinding.FragmentExpeditionSummaryBinding
import es.verdnatura.domain.toast import es.verdnatura.domain.toast
import es.verdnatura.presentation.base.BaseFragment import es.verdnatura.presentation.base.BaseFragment
import es.verdnatura.presentation.common.AdapterCallback
import es.verdnatura.presentation.common.OnAddressRowClickListener import es.verdnatura.presentation.common.OnAddressRowClickListener
import es.verdnatura.presentation.common.OnItemImageLoadRowClickListener import es.verdnatura.presentation.common.OnItemImageLoadRowClickListener
import es.verdnatura.presentation.common.OnOptionsSelectedListener import es.verdnatura.presentation.common.OnOptionsSelectedListener
@ -30,7 +32,7 @@ class SummaryFragment(
var route: Int = 0, var route: Int = 0,
) : BaseFragment<FragmentExpeditionSummaryBinding, DeliveryViewModel>( ) : BaseFragment<FragmentExpeditionSummaryBinding, DeliveryViewModel>(
DeliveryViewModel::class DeliveryViewModel::class
) { ) , AdapterCallback {
private var adapter: ExpeditionSummaryAdapter? = null private var adapter: ExpeditionSummaryAdapter? = null
private var pasillerosItemClickListener: OnPasillerosItemClickListener? = null private var pasillerosItemClickListener: OnPasillerosItemClickListener? = null
@ -45,6 +47,9 @@ class SummaryFragment(
private var isScanning = false private var isScanning = false
private var positionSelected = -1 private var positionSelected = -1
override fun getPosition():Int {
return positionSelected
}
companion object { companion object {
fun newInstance(title: String, state: String, route: Int) = fun newInstance(title: String, state: String, route: Int) =
SummaryFragment(title, state, route) SummaryFragment(title, state, route)
@ -63,6 +68,7 @@ class SummaryFragment(
} }
override fun onResume() { override fun onResume() {
if (binding.mainToolbar.toolbarTitle.text != getString(R.string.titleDeliverySummary)) { if (binding.mainToolbar.toolbarTitle.text != getString(R.string.titleDeliverySummary)) {
binding.scanInput.isEnabled = true binding.scanInput.isEnabled = true
@ -154,7 +160,8 @@ class SummaryFragment(
state state
} else { } else {
"FOUND" "FOUND"
} },
isScanned = l.isScanned
) )
} }
@ -197,13 +204,15 @@ class SummaryFragment(
} }
binding.scanInput.setOnEditorActionListener { _, actionId, _ -> binding.scanInput.setOnEditorActionListener { _, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE || actionId == 0) { if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE || actionId == 0) {
if (!binding.scanInput.text.isNullOrEmpty()) { if (!binding.scanInput.text.isNullOrEmpty()) {
isScanning = true isScanning = true
val isScanned =
event != null && event.action == KeyEvent.ACTION_DOWN && event.keyCode == KeyEvent.KEYCODE_ENTER
try { try {
markExpedition( markExpedition(
binding.scanInput.text.toString().toInt(), state binding.scanInput.text.toString().toInt(), state, if (isScanned) 1 else 0
) )
} catch (ex: Exception) { } catch (ex: Exception) {
@ -219,7 +228,7 @@ class SummaryFragment(
} }
private fun markExpedition(expedNumber: Int, state: String) { private fun markExpedition(expedNumber: Int, state: String, isScanned : Int) {
var found = false var found = false
if (myList.filter { it.addressFk == addressFkSelected }.filter { it.id == expedNumber } if (myList.filter { it.addressFk == addressFkSelected }.filter { it.id == expedNumber }
.any { it.code == state }) { .any { it.code == state }) {
@ -229,12 +238,17 @@ class SummaryFragment(
if (exped.id == expedNumber) { if (exped.id == expedNumber) {
found = true found = true
exped.code = state exped.code = state
exped.isScanned = isScanned
break break
} }
} }
if (found) { if (found) {
ma.messageWithSound(message ="", isError = false, isPlayed = true, isToasted = false) ma.messageWithSound(
message = "",
isError = false,
isPlayed = true,
isToasted = false
)
} else { } else {
ma.messageWithSound(message = "", isError = true, isPlayed = true, isToasted = null) ma.messageWithSound(message = "", isError = true, isPlayed = true, isToasted = null)
} }
@ -307,6 +321,9 @@ class SummaryFragment(
} }
setTitleSummary() setTitleSummary()
} }
@ -332,20 +349,19 @@ class SummaryFragment(
addressFkSelected = item.addressFk addressFkSelected = item.addressFk
isScanning = false isScanning = false
callBack(viewModel.getExpeditionFromRoute(routeSelected)) callBack(viewModel.getExpeditionFromRoute(routeSelected))
adapter!!.notifyDataSetChanged()
} }
}, object : OnItemImageLoadRowClickListener { }, object : OnItemImageLoadRowClickListener {
override fun onItemImageLoadRowClickListener(item: ExpeditionInfoSummary) { override fun onItemImageLoadRowClickListener(item: ExpeditionInfoSummary) {
openLoadUnLoad(item.addressFk) openLoadUnLoad(item.addressFk)
} }
}) }, adapterCallBack = this@SummaryFragment)
binding.expeditionSummaryRecyclerview.adapter = adapter binding.expeditionSummaryRecyclerview.adapter = adapter
binding.expeditionSummaryRecyclerview.layoutManager = binding.expeditionSummaryRecyclerview.layoutManager =
LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false) LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
// adapter!!.notifyDataSetChanged() adapter!!.notifyDataSetChanged()
//tarea 7278
//adapter!!.changePositionSelected(3)
} }
private fun createList(list: MutableList<ExpeditionInfoLoadUnload>) { private fun createList(list: MutableList<ExpeditionInfoLoadUnload>) {

View File

@ -24,6 +24,9 @@ import okhttp3.MultipartBody
import okhttp3.RequestBody import okhttp3.RequestBody
import retrofit2.Response import retrofit2.Response
import java.io.File import java.io.File
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class PackagingViewModel(val context: Context) : BaseViewModel(context) { class PackagingViewModel(val context: Context) : BaseViewModel(context) {
@ -43,14 +46,20 @@ class PackagingViewModel(val context: Context) : BaseViewModel(context) {
val entry: LiveData<EntrySalix> val entry: LiveData<EntrySalix>
get() = _entry get() = _entry
private val _entryUpdate by lazy { MutableLiveData<EntrySalix>() } private val _entryUpdate by lazy { MutableLiveData<Boolean>() }
val entryUpdate: LiveData<EntrySalix> val entryUpdate: LiveData<Boolean>
get() = _entryUpdate get() = _entryUpdate
val loadEntryUpdate: LiveData<Event<Boolean>> = _entryUpdate.map { Event(it) }
private val _entryAdd by lazy { MutableLiveData<EntrySalix>() } private val _entryAdd by lazy { MutableLiveData<EntrySalix>() }
val entryAdd: LiveData<EntrySalix> val entryAdd: LiveData<EntrySalix>
get() = _entryAdd get() = _entryAdd
private val _uploadEntryImage by lazy { MutableLiveData<EntrySalix>() }
val uploadEntryImage: LiveData<EntrySalix>
get() = _uploadEntryImage
private val _response by lazy { MutableLiveData<ResponseItemVO>() } private val _response by lazy { MutableLiveData<ResponseItemVO>() }
val response: LiveData<ResponseItemVO> val response: LiveData<ResponseItemVO>
get() = _response get() = _response
@ -60,7 +69,7 @@ class PackagingViewModel(val context: Context) : BaseViewModel(context) {
fun getSuppliers() { fun getSuppliers() {
salix.getSuppliers() salix.getSuppliers()
.enqueue(object : .enqueue(object :
SilexCallback<List<Supplier>>(context) { SalixCallback<List<Supplier>>(context) {
override fun onError(t: Throwable) { override fun onError(t: Throwable) {
val listError: ArrayList<Supplier> = ArrayList() val listError: ArrayList<Supplier> = ArrayList()
listError.add( listError.add(
@ -129,29 +138,16 @@ class PackagingViewModel(val context: Context) : BaseViewModel(context) {
}) })
} }
fun getEntries_fromSupplier(supplier: Int) { fun getEntriesFromSupplier(supplier: Int) {
val calendar = Calendar.getInstance()
calendar.add(Calendar.DAY_OF_YEAR, 0)
/* salix.getEntries_fromSupplier("""{"where": { val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
"supplierFk": "$supplier", val today = dateFormat.format(calendar.time)
"created": { "gte": "$yesterday" }
},"limit":5, "order":"created DESC"}""".trimMargin())*/
salix.getEntries_fromSupplier("""{"where": {"supplierFk": "$supplier"},"limit":5, "order":"created ASC"}""") salix.getEntriesFromSupplier("""{"where": {"supplierFk": "$supplier","created":{"gte":"$today"},"typeFk":"packaging","order":"created ASC"},"include": [ { "relation": "travel", "scope": { "fields": ["landed"]}}]}""")
.enqueue(object : .enqueue(object :
SilexCallback<List<EntrySalix>>(context) { SalixCallback<List<EntrySalix>>(context) {
override fun onError(t: Throwable) {
val listError: ArrayList<EntrySalix> = ArrayList()
listError.add(
EntrySalix(
isError = true,
errorMessage = getMessageFromAllResponse(
nameofFunction(this),
t.message!!
)
)
)
_entryList.value = EntryList(listError)
}
override fun onSuccess(response: Response<List<EntrySalix>>) { override fun onSuccess(response: Response<List<EntrySalix>>) {
if (response.body() != null) { if (response.body() != null) {
@ -238,33 +234,13 @@ class PackagingViewModel(val context: Context) : BaseViewModel(context) {
}) })
} }
fun entry_updateObserv(entryId: Int, observation: String) { fun entryUpdateObserv(entryId: Int, observation: String) {
salix.entry_updateObserv(entryId, obervationEntry(observation)) salix.entry_updateObserv(entryId, obervationEntry(observation))
.enqueue(object : .enqueue(object :
SilexCallback<EntrySalix>(context) { SalixCallback<EntrySalix>(context) {
override fun onError(t: Throwable) {
_entryUpdate.value = EntrySalix(
isError = true,
errorMessage = getMessageFromAllResponse(
nameofFunction(this),
t.message!!
)
)
}
override fun onSuccess(response: Response<EntrySalix>) { override fun onSuccess(response: Response<EntrySalix>) {
if (response.body() != null) { _entryUpdate.value = true
_entryUpdate.value = response.body()
} else {
_entryUpdate.value = EntrySalix(
isError = true,
errorMessage = getMessageFromAllResponse(
nameofFunction(this),
response.message()
)
)
}
} }
}) })
} }
@ -281,13 +257,7 @@ class PackagingViewModel(val context: Context) : BaseViewModel(context) {
) { ) {
println("urlImage + $urlImage")
println("urlImage + ${File(urlImage)}")
val file = File(urlImage) val file = File(urlImage)
println("urlImage + ${file.name}")
val fileRequestBody: RequestBody = RequestBody.create(MediaType.parse("image/jpeg"), file) val fileRequestBody: RequestBody = RequestBody.create(MediaType.parse("image/jpeg"), file)
salix.uploadEntryPhoto( salix.uploadEntryPhoto(
@ -302,7 +272,22 @@ class PackagingViewModel(val context: Context) : BaseViewModel(context) {
"file", file.name, fileRequestBody "file", file.name, fileRequestBody
) )
) )
.enqueue(object : SilexCallback<Any>(context) {}) .enqueue(object : SalixCallback<Any>(context) {
override fun onError(t: Throwable) {
_uploadEntryImage.value = EntrySalix(
isError = true,
errorMessage = getMessageFromAllResponse(
nameofFunction(this),
t.message!!
)
)
}
override fun onSuccess(response: Response<Any>) {
super.onSuccess(response)
}
})
} }
fun entry_addFromBuy(id: Number, item: Number, printedStickers: Number) { fun entry_addFromBuy(id: Number, item: Number, printedStickers: Number) {
@ -421,6 +406,8 @@ class PackagingViewModel(val context: Context) : BaseViewModel(context) {
} }
} }
}) })
} }
} }

View File

@ -6,7 +6,10 @@ import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import es.verdnatura.R import es.verdnatura.R
import es.verdnatura.databinding.FragmentPackagingBinding import es.verdnatura.databinding.FragmentPackagingBinding
import es.verdnatura.domain.isoToString import es.verdnatura.domain.ConstAndValues.ENTRYID
import es.verdnatura.domain.ConstAndValues.ENTRYOBSERVATIONORIGINAL
import es.verdnatura.domain.ConstAndValues.SUPPLIERID
import es.verdnatura.domain.ConstAndValues.SUPPLIERNAME
import es.verdnatura.domain.notNull import es.verdnatura.domain.notNull
import es.verdnatura.presentation.base.BaseFragment import es.verdnatura.presentation.base.BaseFragment
import es.verdnatura.presentation.common.OnPasillerosItemClickListener import es.verdnatura.presentation.common.OnPasillerosItemClickListener
@ -46,39 +49,7 @@ class SupplierFragment(
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
viewModel.getSuppliers() viewModel.getSuppliers()
val drawableId: Int =
R.drawable.background_test // Reemplaza "mi_drawable" con el nombre de tu recurso Drawable
/* val uri: Uri = Uri.parse(
ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
context!!.resources.getResourcePackageName(drawableId) + '/' +
context!!.resources.getResourceTypeName(drawableId) + '/' +
context!!.resources.getResourceEntryName(drawableId)
)
val rutaAbsoluta: String = uri.toString()*/
/*
val file = File("/storage/emulated/0/Android/data/es.verdnatura.sfusion/files/Pictures/test.png")
val filePart = MultipartBody.Part.createFormData(
"file",
file.name,
RequestBody.create(MediaType.parse("image/png"), file)
)
viewModel.entry_uploadPhotoSalix(
1,
1,
442,
21,
"1",
"Example description",
false,
file = filePart
)*/
// viewModel.entry_addFromBuy(8,1,100)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
@ -98,19 +69,17 @@ class SupplierFragment(
suppliers suppliers
) { baseSearchDialogCompat, nombre, position -> ) { baseSearchDialogCompat, nombre, position ->
binding.filterSupplier.text = (nombre.getName()) binding.filterSupplier.text = (nombre.getName())
println("nombreSupplier"+nombre.getName())
binding.radiobuttonTypePackaging.visibility = View.VISIBLE
runBlocking { runBlocking {
mobileApplication.dataStoreApp.editDataStoreKey( mobileApplication.dataStoreApp.editDataStoreKey(
"SUPPLIERNAME", SUPPLIERNAME,
nombre.getName() nombre.getName()
) )
mobileApplication.dataStoreApp.editDataStoreKey( mobileApplication.dataStoreApp.editDataStoreKey(
"SUPPLIERID", SUPPLIERID,
nombre.getId().toInt() nombre.getId().toInt()
) )
} }
viewModel.getEntries_fromSupplier(nombre.getId().toInt()) viewModel.getEntriesFromSupplier(nombre.getId().toInt())
baseSearchDialogCompat.dismiss() baseSearchDialogCompat.dismiss()
}.show() }.show()
} }
@ -132,8 +101,7 @@ class SupplierFragment(
ma.onMyBackPressed() ma.onMyBackPressed()
} }
/* binding.radiobuttonTypePackaging.setOnCheckedChangeListener { buttonView, isChecked ->
binding.radiobuttonTypePackaging.setOnCheckedChangeListener { buttonView, isChecked ->
when (isChecked) { when (isChecked) {
R.id.radioButtonRec -> { R.id.radioButtonRec -> {
runBlocking { runBlocking {
@ -150,10 +118,11 @@ class SupplierFragment(
} }
binding.filterEntry.visibility = View.VISIBLE binding.filterEntry.visibility = View.VISIBLE
} }*/
} }
private fun setEntryDialog() { private fun setEntryDialog() {
binding.filterEntry.visibility = View.VISIBLE
binding.filterEntry.setOnClickListener { binding.filterEntry.setOnClickListener {
SimpleSearchDialogCompat( SimpleSearchDialogCompat(
context, context,
@ -162,23 +131,28 @@ class SupplierFragment(
null, null,
entries entries
) { baseSearchDialogCompat, nombre, position -> ) { baseSearchDialogCompat, nombre, position ->
binding.filterEntry.setText((nombre.getName())) binding.filterEntry.text = nombre.getName()
binding.radiobuttonTypePackaging.visibility = View.VISIBLE binding.radiobuttonTypePackaging.visibility = View.VISIBLE
if (nombre.getName() == getString(R.string.newEntry)) { /* if (nombre.getName() == getString(R.string.newEntry)) {
addEntry() addEntry()
} else { } else {*/
runBlocking { runBlocking {
mobileApplication.dataStoreApp.editDataStoreKey( mobileApplication.dataStoreApp.editDataStoreKey(
"ENTRYID", ENTRYID,
nombre.getId().toInt() nombre.getId().toInt()
) )
mobileApplication.dataStoreApp.editDataStoreKey(
ENTRYOBSERVATIONORIGINAL,
nombre.getObservation()
)
mobileApplication.dataStoreApp.deleteImages()
} }
ma.onPasillerosItemClickListener( ma.onPasillerosItemClickListener(
PasillerosItemVO(title = getString(R.string.titlePackagingCount)), PasillerosItemVO(title = getString(R.string.titlePackagingCount)),
getString(R.string.titlePackagingCount) getString(R.string.titlePackagingCount)
) )
} // }
baseSearchDialogCompat.dismiss() baseSearchDialogCompat.dismiss()
}.show() }.show()
} }
@ -196,7 +170,7 @@ class SupplierFragment(
response.observe(viewLifecycleOwner) { response.observe(viewLifecycleOwner) {
if (it.isError) { if (it.isError) {
ma.messageWithSound(it.errorMessage, true, false) ma.messageWithSound(it.errorMessage, isError = true, isPlayed = false)
} }
} }
@ -204,12 +178,12 @@ class SupplierFragment(
loadEntryAdd.observe(viewLifecycleOwner) { event -> loadEntryAdd.observe(viewLifecycleOwner) { event ->
event.getContentIfNotHandled().notNull { event.getContentIfNotHandled().notNull {
if (it.isError) { if (it.isError) {
ma.messageWithSound(it.errorMessage, true, false) ma.messageWithSound(it.errorMessage, isError = true, isPlayed = false)
} else { } else {
runBlocking { runBlocking {
mobileApplication.dataStoreApp.editDataStoreKey( mobileApplication.dataStoreApp.editDataStoreKey(
"ENTRYID", ENTRYID,
it.id!!.toInt() it.id!!.toInt()
) )
} }
@ -238,7 +212,7 @@ class SupplierFragment(
entry.observe(viewLifecycleOwner) { entry.observe(viewLifecycleOwner) {
if (it.isError) { if (it.isError) {
ma.messageWithSound(it.errorMessage, true, false) ma.messageWithSound(it.errorMessage, isError = true, isPlayed = false)
} else { } else {
runBlocking { runBlocking {
@ -259,34 +233,54 @@ class SupplierFragment(
list.forEach { supplier -> list.forEach { supplier ->
if (!supplier.isError) { if (!supplier.isError) {
try { try {
suppliers.add(SearchSupplierModel(supplier.name, supplier.id.toString())) suppliers.add(
} catch (e: Exception) { SearchSupplierModel(
supplier.name,
supplier.id.toString(),
observation = ""
)
)
} catch (ex: Exception) {
ma.messageWithSound(
message = ex.message.toString(),
isError = true,
isPlayed = true
)
} }
} }
} }
} }
private fun createEntryList(list: List<EntrySalix>) { private fun createEntryList(list: List<EntrySalix>) {
list.sortedBy { it.travel?.landed }
entries.clear() entries.clear()
list.forEach { entry -> list.forEach { entry ->
if (!entry.isError) { if (!entry.isError) {
try { try {
entries.add( entries.add(
SearchSupplierModel( SearchSupplierModel(
entry.id.toString() + "->" + (entry.created).isoToString(returnOnlyDate = true), entry.id.toString() + "->" + (entry.travel?.landed),
id = entry.id.toString() id = entry.id.toString(),
observation = entry.observation
) )
) )
} catch (e: Exception) {
} catch (ex: Exception) {
ma.messageWithSound(
message = ex.message.toString(),
isError = true,
isPlayed = true
)
} }
} }
} }
entries.add(SearchSupplierModel(getString(R.string.newEntry), "")) // entries.add(SearchSupplierModel(getString(R.string.newEntry), ""))
setEntryDialog() setEntryDialog()
} }
private fun addEntry() { /* private fun addEntry() {
customDialog.setTitle(getString(R.string.createEntryDescrip)) customDialog.setTitle(getString(R.string.createEntryDescrip))
.setDescription(getString(R.string.sure)) .setDescription(getString(R.string.sure))
@ -311,7 +305,7 @@ class SupplierFragment(
} }
.show() .show()
} }*/
} }

View File

@ -1,18 +1,28 @@
package es.verdnatura.presentation.view.feature.packaging.model package es.verdnatura.presentation.view.feature.packaging.model
import es.verdnatura.domain.isoToString
import es.verdnatura.presentation.common.convertToDateString import es.verdnatura.presentation.common.convertToDateString
class EntrySalix( data class EntrySalix(
var id: Number? = null, var id: Number? = null,
var dated: String? = null, var dated: String? = null,
var created: String? = null, var created: String? = null,
var supplierFk: Number? = null, var supplierFk: Number? = null,
var travelFk: Number? = null, var travelFk: Number? = null,
var companyFk: Number? = null, var companyFk: Number? = null,
var observation: String? = null,
var travel: TravelSalix? = null,
var isError: Boolean = false, var isError: Boolean = false,
var errorMessage: String = "" var errorMessage: String = ""
) )
class TravelSalix {
var landed: String = ""
get() {
return field.isoToString(returnOnlyDate = true)
}
}
fun List<EntrySalix>.toDateFormat(): ArrayList<EntrySalix> { fun List<EntrySalix>.toDateFormat(): ArrayList<EntrySalix> {
val entries: ArrayList<EntrySalix> = ArrayList() val entries: ArrayList<EntrySalix> = ArrayList()
this.forEach { this.forEach {

View File

@ -1,6 +1,5 @@
package es.verdnatura.presentation.view.feature.packaging.model package es.verdnatura.presentation.view.feature.packaging.model
data class Supplier( data class Supplier(
var id: Int? = null, var id: Int? = null,
var name: String? = null, var name: String? = null,
@ -27,6 +26,7 @@ data class ItemSupplier(
var quantityTotal: Int = 0, var quantityTotal: Int = 0,
var printedStickers: Int = 0, var printedStickers: Int = 0,
var buy: Int? = null, var buy: Int? = null,
var url: String? = null,
var isError: Boolean = false, var isError: Boolean = false,
var errorMessage: String? = null var errorMessage: String? = null
) )