Cannot access 'number': it is internal in 'CardParams' - kotlin

I have been trying to compile my app in android studio but I am getting this error "Cannot access 'number': it is internal in 'CardParams'"
val cardNumber = binding.cardInput.cardParams!!.number
val expiryYear = binding.cardInput.cardParams!!.expYear
val expiryMonth = binding.cardInput.cardParams!!.expMonth
val cvc = binding.cardInput.cardParams!!.cvc
val token = "{\"cardNumber\":${cardNumber},\"cvv\":${cvc},\"expiryMonth\":${expiryMonth},\"expiryYear\":${expiryYear}}"
chargeAccount(amountDouble, token)
}
else -> {
binding.waitingForPayment = true
GetPaymentLink(selectedPayment!!.id, amount = amountDouble, currency = currency!!, serverUrl = Config.Backend).execute<GetPaymentLinkResult> {
binding.waitingForPayment = false
when (it) {
is RemoteResponse.Success -> {
val intent = Intent(this#ChargeAccountActivity, PaymentActivity::class.java)
intent.putExtra("redirectionUrl", it.body.url)
startActivityForResult(intent, WEB_PAYMENT_CALLBACK)
}
is RemoteResponse.Error -> {
it.error.showAlert(this)
}

internal means it can only be accessed from within the same module. Is cardInput in another module, or some library you're using?
You're not meant to be touching cardParams directly, basically. If it's under your control you could make it public, or add a public getter function

Related

Returning one of different object types from single function in kotlin

I have the following structure at present:
#Entity
#Table(name = "table_app_settings")
data class AppSetting(
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "app_setting_id")
val id: Long? = null,
#Column(name = "app_setting_name")
val name: String = "",
#Column(name = "app_setting_value")
var value: String = "",
#Column(name = "app_setting_type")
val type: AppSettingType,
)
enum class AppSettingType {
CHAR,
STRING,
BYTE,
SHORT,
INT,
LONG,
DOUBLE,
FLOAT,
BOOLEAN,
}
This is then saved to the database with the following:
override fun saveAppSetting(setting: AppSetting): DatabaseResult<AppSetting> {
log.info("Saving App Setting ${setting.name} to database.")
return try {
// Attempt to save the entity to the database. If we do not throw an exception, return success.
val savedSetting = appSettingsRepository.save(setting)
DatabaseResult(
code = ResultCode.CREATION_SUCCESS,
entity = savedSetting
)
} catch(exception: DataAccessException) {
log.error("Unable to save App Setting ${setting.name} to database. Reason: ${exception.message}")
DatabaseResult(
code = ResultCode.CREATION_FAILURE
)
}
}
Now, let's say that I wish to save a Char type to database, I figure I would use the following:
override fun saveAppSetting(name: String, value: Char): DatabaseResult<Char> {
val appSettingResult = saveAppSetting(AppSetting(
name = name,
value = value.toString(),
type = AppSettingType.CHAR,
))
return if(appSettingResult.code != ResultCode.CREATION_FAILURE) {
val entity = getAppSetting<Char>(appSettingResult.entity?.name!!).entity.toString().first()
DatabaseResult(
code = appSettingResult.code,
entity = entity
)
} else {
DatabaseResult(
code = ResultCode.CREATION_FAILURE,
)
}
}
I also figured that I would need to do the following in order to retrieve the correct object type:
override fun getAppSetting(name: String): DatabaseResult<Any?> {
log.info("Getting App Setting $name from database.")
val appSetting = appSettingsRepository.findAppSettingByName(name)
return if(appSetting != null) {
log.info("App Setting $name has ID of ${appSetting.id} within the database")
when(appSetting.type) {
AppSettingType.CHAR -> {
DatabaseResult<Char>(
code = ResultCode.FETCH_SUCCESS,
entity = appSetting.value.first(),
)
}
AppSettingType.STRING -> {
DatabaseResult<String>(
code = ResultCode.FETCH_SUCCESS,
entity = appSetting.value,
)
}
AppSettingType.BYTE -> {
DatabaseResult<Byte>(
code = ResultCode.FETCH_SUCCESS,
entity = appSetting.value.toByte(),
)
}
AppSettingType.SHORT -> {
DatabaseResult<Short>(
code = ResultCode.FETCH_SUCCESS,
entity = appSetting.value.toShort(),
)
}
AppSettingType.INT -> {
DatabaseResult<Int>(
code = ResultCode.FETCH_SUCCESS,
entity = appSetting.value.toInt(),
)
}
AppSettingType.LONG -> {
DatabaseResult<Long>(
code = ResultCode.FETCH_SUCCESS,
entity = appSetting.value.toLong(),
)
}
AppSettingType.DOUBLE -> {
DatabaseResult<Double>(
code = ResultCode.FETCH_SUCCESS,
entity = appSetting.value.toDouble(),
)
}
AppSettingType.FLOAT -> {
DatabaseResult<Float>(
code = ResultCode.FETCH_SUCCESS,
entity = appSetting.value.toFloat()
)
}
AppSettingType.BOOLEAN -> {
DatabaseResult<Boolean>(
code = ResultCode.FETCH_SUCCESS,
entity = appSetting.value.toBoolean()
)
}
}
} else {
log.error("App Setting $name does not seem to exist within the database.")
DatabaseResult(
code = ResultCode.FETCH_FAILURE
)
}
However, when I then wish to use said object, I still have to write something like the following:
val newBarcode = getAppSetting("barcode_value").entity.toString().toInt()
Assuming I've "initialised" barcode_value with a value of 177 (for example).
How can I get the function to return what I need without having to do .toString.to...()?
Yes this all possible, here is a simplified demo, firstly
import kotlin.reflect.KClass
data class AppSetting(
val id: Long? = null,
val name: String = "",
var value: String = "",
val type: AppSettingType,
)
enum class AppSettingType(val clazz: KClass<out Any>) {
CHAR(Char::class),
STRING(String::class),
INT(Int::class),
}
So I added a clazz so from the enum we know the Kotlin type
and now a function to simulate your repository fetch
fun findAppSettingByName(name: String): AppSetting? {
return when(name) {
"Char thing" -> AppSetting(value= "C", type = AppSettingType.CHAR)
"String thing" -> AppSetting(value= "Str", type = AppSettingType.STRING)
"Int thing" -> AppSetting(value= "42", type = AppSettingType.INT)
else -> throw IllegalArgumentException()
}
}
Next in the function declaration I have made it generic with T and for the purposes of the demo removed the DatabaseResult container. Then I added a clazz parameter which is the typical Java way of carrying the required class information into the function:
fun <T : Any> getAppSetting(name: String, clazz: KClass<T>): T? {
val appSetting: AppSetting? = findAppSettingByName(name)
return appSetting?.let {
require(clazz == appSetting.type.clazz) {
"appSetting.type=${appSetting.type.clazz} mismatched with requested class=${clazz}"
}
when (appSetting.type) {
AppSettingType.CHAR -> appSetting.value.first()
AppSettingType.STRING -> appSetting.value
AppSettingType.INT -> appSetting.value.toInt()
} as T
}
}
the as T is important to cast the values into the required return type - this is unchecked but the when() clause should be creating the correct types.
Now let's test it:
val c1: Char? = getAppSetting("Char thing", Char::class)
val s1: String? = getAppSetting("String thing", String::class)
val i1: Int? = getAppSetting("Int thing", Int::class)
println("c1=$c1 s1=$s1 i1=$i1")
val c2: Char? = getAppSetting("Char thing")
val s2: String? = getAppSetting("String thing")
val i2: Int? = getAppSetting("Int thing")
println("c2=$c2 s2=$s2 i2=$i2")
}
The output is
c1=C s1=Str i1=42
c2=C s2=Str i2=42
But how do c2/s2/i2 work, the final part is this function
inline fun <reified T : Any> getAppSetting(name: String) = getAppSetting(name, T::class)
This is reified generic parameters... there is no need to pass the clazz because this can be found from the data type of the receiving variable.
There are many articles about this advanced topic, e.g.
https://typealias.com/guides/getting-real-with-reified-type-parameters/
https://medium.com/kotlin-thursdays/introduction-to-kotlin-generics-reified-generic-parameters-7643f53ba513
Now, I didn't completely answer what you wanted because you wanted to receive a DatabaseResult<T> wrapper. What might be possible, is to have a function that returns DatabaseResult<T> and you can obtain the T from it as the "clazz" parameter, but I'll leave that for someone else to improve on :-) but I think that gets you pretty close.

find value in arraylist in kotlin

Hey I am working in kotlin. I am working on tree data structure. I added the value in list and now I want to find that value and modified their property. But I am getting the error.
VariantNode, StrengthNode, ProductVariant
StrengthNode.kt
class StrengthNode : VariantNode() {
var pricePerUnit: String? = null
var defaultValue = AtomicBoolean(false)
}
ActivityViewModel.kt
class ActivityViewModel : ViewModel() {
var baseNode: VariantNode = VariantNode()
private val defaultValueId = "12643423243324"
init {
createGraph()
}
private fun createGraph() {
val tempHashMap: MutableMap<String, VariantNode> = mutableMapOf()
val sortedList = getSortedList()
sortedList.forEach { productVariant ->
productVariant.strength?.let { strength ->
if (tempHashMap.containsKey("strength_${strength.value}")) {
baseNode.children.contains(VariantNode(strength.value)) // getting error
return#let
}
val tempNode = StrengthNode().apply {
value = strength
pricePerUnit = productVariant.pricePerUnit?.value
if (productVariant.id == defaultValueId) {
defaultValue.compareAndSet(false, true)
}
}
baseNode.children.add(tempNode)
tempHashMap["strength_${strength.value}"] = tempNode
}
productVariant.quantity?.let { quantity ->
if (tempHashMap.containsKey("strength_${productVariant.strength?.value}_quantity_${quantity.value}")) {
return#let
}
val tempNode = QuantityNode().apply {
value = quantity
}
val parent =
tempHashMap["strength_${productVariant.strength?.value}"] ?: baseNode
parent.children.add(tempNode)
tempHashMap["strength_${productVariant.strength?.value}_quantity_${quantity.value}"] =
tempNode
}
productVariant.subscription?.let { subscription ->
val tempNode = SubscriptionNode().apply {
value = subscription
}
val parent =
tempHashMap["strength_${productVariant.strength?.value}_quantity_${productVariant.quantity?.value}"]
?: baseNode
parent.children.add(tempNode)
}
}
baseNode
}
}
I am getting error on this.
I want to find that node value and modified other property.
Your class VariantNode only has a single no-arg constructor, but you're trying to call it with arguments, hence the error
Too many arguments for public constructor VariantNode() defined in com.example.optionsview.VariantNode
Either you have to provide a constructor, that matches your call, e.g.
open class VariantNode(var value: ProductValue?) {
var children: MutableList<VariantNode> = arrayListOf()
}
or you need to adjust your code to use the no-arg constructor instead.
val node = VariantNode()
node.value = strength.value
baseNode.children.contains(node)
Note however, that your call to contains most likely will not work, because you do not provide a custom implementation for equals. This is provided by default, when using a data class.
If you just want to validate whether baseNode.children has any element, where value has the expected value, you can use any instead, e.g.:
baseNode.children.any { it.value == strength.value }

How to inject scopeId into Koin to get the dependency?

In https://github.com/InsertKoinIO/koin/blob/master/koin-projects/docs/reference/koin-android/scope.md#sharing-instances-between-components-with-scopes it is shown the below example
module {
// Shared user session data
scope(named("session")) {
scoped { UserSession() }
}
// Inject UserSession instance from "session" Scope
factory { (scopeId : ScopeID) -> Presenter(getScope(scopeId).get())}
}
But I don't even know how to get presenter?
I try
val nameScope = getKoin().createScope("SomeName", named("session"))
val presenter = get<Presenter>(nameScope.id)
but it's not the correct. How to get my presenter?
After tracing the code, the way to do it is to use parameter to pass over the scopeId
For the above example, it will be
val nameScope = getKoin().createScope("SomeName", named("session"))
val presenter = get<Presenter>(parameters = { parametersOf(nameScope.id) )
If there's qualifier, we just need to send through them as well
One Example as below where we need a parameter of the lambda to send through scopeId and name of the qualifier. (the argument is self definable through the parameters of any type).
module {
scope(named("AScopeName")) {
scoped(qualifier = named("scopedName")) { Dependency() }
factory(qualifier = named("factoryName")) { Dependency() }
}
factory { (scopeId: ScopeID, name: String) ->
Environment(getScope(scopeId).get(qualifier = named(name)))
}
}
Then the calling is as simple as below
val nameScope = getKoin().createScope("SomeName", named("AScopeName"))
val environment = get<Environment>(parameters = { parametersOf(nameScope.id, "scopedName") })
Or we could also
val nameScope = getKoin().createScope("SomeName", named("AScopeName"))
val environment = get<Environment>(parameters = { parametersOf("SomeName", "scopedName") })

Why is the variable dowloadUrl returning null in the saveProfile method?

The following code shows the firebase storage upload task which I am using to get the variable downloadUrl, downloadUrl isn't null as it prints in the log but when I call the function saveProfile it returns null, why?
var downloadUrl: String? = null
fun upload(bytes: ByteArray) {
val storageReference = FirebaseStorage.getInstance().reference
.child(
"images/users/${FirebaseAuth.getInstance().currentUser!!.uid}/profile_image"
)
val metadata = StorageMetadata.Builder()
.setContentType("image/jpg")
.setContentLanguage("en")
.build()
storageReference.putBytes(bytes, metadata).addOnSuccessListener {
model.listener!!.progressBarGone()
model.listener!!.toast("Uploaded Successfully")
val urlTask = it.storage.downloadUrl
while (!urlTask.isSuccessful);
this.downloadUrl = urlTask.result.toString()
Log.d("Upload", "DownloadUrl $downloadUrl")
And this is the saveProfile function.
fun saveProfile() {
val user = User()
if (model.name.isNullOrEmpty() || model.phone.isNullOrEmpty()) {
model.listener!!.toast("Fields cannot be empty")
return
}
if (downloadUrl.isNullorEmpty()) {
log.d(TAG, "URL empty")
}
user.name = model.name
user.phone = model.phone
user.profile_image = downloadUrl
When you call
this.downloadUrl = urlTask.result.toString()
You assign downloadUrl to the object that is bound to the lambda you pass to addOnSuccessListener, not the global downloadUrl. For quick fix, I'd suggest you renaming global downloadUrl to some other name that wouldn't be shadowed.

KTOR: How I can find Location Info before call processing?

I made a custom feature that should check the user's permissions to use the request. Can I monitor request LocationInfo?
Can this looks like that?
if (!User.accessTo.contains(CALL_LOCATION_INFO)){
call.respond(HttpStatusCode.BadRequest) }
That`s my feature code:
data class UserRights(
val haveFullAccess:Boolean,
val accessTo:List<String>,
val canUpdate:Boolean,
val canDelete:Boolean,
val canBan:Boolean,
val canMute:Boolean)
var User = UserRights(false, listOf(""),false,false,false,false)
class RightsChecker(configuration: Configuration) {
val prop = configuration.prop // get snapshot of config into immutable property
class Configuration {
var prop = "value"
}
companion object Feature : ApplicationFeature<ApplicationCallPipeline, Configuration, RightsChecker> {
override val key = AttributeKey<RightsChecker>("RightsChecker")
override fun install(pipeline: ApplicationCallPipeline, configure: Configuration.() -> Unit): RightsChecker {
val configuration = RightsChecker.Configuration().apply(configure)
val feature = RightsChecker(configuration)
val FilterPhase = PipelinePhase("CallFilter")
pipeline.insertPhaseAfter(ApplicationCallPipeline.Infrastructure, FilterPhase)
pipeline.intercept(FilterPhase) {
val session = call.sessions.get<SessionData>() ?: SessionData(0, "Guest")
when (session.role) {
"Guest" -> User = UserRights(
haveFullAccess = false,
accessTo = listOf(""),
canUpdate = false,
canDelete = false,
canBan = false,
canMute = false)
"User" -> User = UserRights(
haveFullAccess = false,
accessTo = listOf("lUsers"),
canUpdate = false,
canDelete = false,
canBan = false,
canMute = false)
"Admin" -> User = UserRights(
haveFullAccess = true,
accessTo = listOf("lUsers"),
canUpdate = true,
canDelete = true,
canBan = true,
canMute = true)
}
if (!User.accessTo.contains(CALL_LOCATION_INFO)){
call.respond(HttpStatusCode.BadRequest)
}
}
return feature
}
}
}
How you can see, I`m using UserRights data class with rights in it. "accesTo" - is list of location names (format can be changed) what user can use. Feature must just check location name contain in "accesTo" list before request processing.
Thank you for help!
UPD: Locations code:
#Location("/login") data class lLoginData(val email:String, val password: String)
#Location("/users") data class lGetUsers(val page:Int, val limit:Int)
#Location("/users/user") data class lUser(val email: String)
#Location("/users") data class lUpdateData(val userID: Int, val datatype:String, val newData:String)
#Location("/users") data class lRegData(val email: String, val username:String, val userpass:String)
If I understand you correctly, then you simply want to know what route / uri was called.
Here is a small server that answers with the route called.
private val locationKey = AttributeKey("location")
val module = fun Application.() {
install(Routing) {
intercept(ApplicationCallPipeline.Call) {
val location = call.request.local.uri
call.attributes.put(locationKey, location)
}
get("{...}") {
val location = call.attributes[locationKey]
call.respond(location)
}
}
}
As can be seen, I am using call.request.local.uri to get the uri of the call.
When I navigate to http://localhost:5001/hello/route, the server answers with /hello/route.
Does this answer your question?