PayPal android integration infinite loading on payment - kotlin

I am trying to implement paypal payment, using their documentation on sandbox accounts. So, my code looks like this:
fun setupPayPal(
payPalButton: PayPalButton, bottomSheetDialog: BottomSheetDialog,
orderRequest: OrderRequest
) {
val config = CheckoutConfig(
application = fragmentActivity.application,
clientId = Config.PAYPAL_CLIENT_ID,
environment = Environment.SANDBOX,
returnUrl = "com.example.shopkotlin://paypalpay",
currencyCode = CurrencyCode.USD,
userAction = UserAction.PAY_NOW,
settingsConfig = SettingsConfig(
loggingEnabled = true
))
PayPalCheckout.setConfig(config)
payPalButton.setup(
createOrder =
CreateOrder { createOrderActions ->
val order =
Order(
intent = OrderIntent.CAPTURE,
appContext = AppContext(userAction = UserAction.PAY_NOW),
purchaseUnitList =
listOf(
PurchaseUnit(
amount =
Amount(currencyCode = CurrencyCode.USD, value = "10.00")
)
),
processingInstruction = ProcessingInstruction.ORDER_COMPLETE_ON_PAYMENT_APPROVAL
)
createOrderActions.create(order)
},
onApprove =
OnApprove { approval ->
approval.orderActions.capture {
orderRequest.paymentMethod = "PayPal"
orderViewModel!!.createOrder(token, orderRequest)
bottomSheetDialog.cancel()
}
},
onError = OnError { errorInfo ->
println("error $errorInfo")
}
)
}
The problem is that it's starts properly, i am logging in, however it stucks and infinite loading at sandbox.paypal.com , i am using Kotlin, on my Java application the same code works as charm, but this one does not, does someone knows why? I looked into logs, no error so far.

Fixed by changing the return URL correctly. In paypal.developer we should set the URL how it is in my code, however we must make sure that URL matches, check in build.gradle (module).

Related

Why does the author add key(task) for the items function in LazyColumn?

The Code A is from the offical sample project.
I don't understand why the author need to add key(task) for the items function in LazyColumn, could you tell me?
I think the Code B can work well and it's simple.
Code A
val allTasks = stringArrayResource(R.array.tasks)
val tasks = remember { mutableStateListOf(*allTasks) }
...
items(count = tasks.size) { i ->
val task = tasks.getOrNull(i)
if (task != null) {
key(task) {
TaskRow(
task = task,
onRemove = { tasks.remove(task) }
)
}
}
}
Code B
...
items(tasks) { task ->
TaskRow(
task = task,
onRemove = { tasks.remove(task) }
)
}
Keys in general are used to avoid unnecessary recompositions. If you have a list of items, and some items are reordered, Compose will find existing components in the composition based on their key and reorder them accordingly instead of recomposing all of them.
That said, items() already supports a key parameter. So code A could indeed be simplified this way if the tasks in the list are non-nullable:
items(tasks, key = { it }) { task ->
TaskRow(
task = task,
onRemove = { tasks.remove(task) },
)
}
But code B would use the items' positions instead of the items themselves as key by default, which is not desirable.
Disclaimer: I'm no expert in JetPack Compose

How to do an API call with Future and Uri.Https constructor in Flutter

Trying to build a Recipe App using Spoonacular API. Tried googling for answers but it seems like there was a change in uri.https format and all of the search results are from last year and older. I can't figure out the correct format for this? This is my first time calling APIs in flutter and I can't seem to get it right.
Here's the tutorial: https://youtu.be/l3CIMZSAaIk
And here's the source code: https://github.com/MarcusNg/flutter_recipe_app
This link shows how to generate a meal plan:
https://spoonacular.com/food-api/docs#Generate-Meal-Plan
Here's how I'm trying to call it in URL form:
https://api.spoonacular.com/mealplanner/generate?apiKey=[CHANGE_THIS_TO_APIKEY]&timeFrame=day&1700&vegan
This works perfectly in the browser and I need to convert it to flutter code:
class APIservice {
APIservice._instantiate();
static final APIservice instance = APIservice._instantiate();
final String _baseUrl = 'api.spoonacular.com';
static const String API_KEY = '[APIKEY HERE]';
//Generate Meal Plan
Future<MealPlan> generateMealPlan({int targetCalories, String diet}) async {
if (diet == 'None') diet = '';
Map<String, String> parameters = {
'apiKey': API_KEY,
'timeFrame': 'day',
'targetCalories': targetCalories.toString(),
'diet': diet,
};
Uri uri = Uri.https(
_baseUrl,
'/mealplanner/generate',
parameters,
);
Map<String, String> headers = {
HttpHeaders.contentTypeHeader: 'application/json',
};
try {
var response = await http.get(uri, headers: headers);
Map<String, dynamic> data = json.decode(response.body);
MealPlan mealPlan = MealPlan.fromMap(data);
return mealPlan;
} catch (err) {
throw err.toString();
}
}
When I run the app I get the error below:
E/flutter ( 6458): [ERROR:flutter/lib/ui/ui_dart_state.cc(171)] Unhandled Exception: Invalid argument(s)
[38;5;248mE/flutter ( 6458): #0 APIservice.generateMealPlan [39;49m
E/flutter ( 6458):
It looks like it's having problems piecing the parameters to turn into URL. I'm not sure if I wrote the MAP parameters and URI format correctly though.
The issue was with the Meal model. The Meal model you had was different from what the api was returning:
I fixed the Meal model, check the code below:
class Meal {
int id;
String imageType;
String title;
int readyInMinutes;
int servings;
String sourceUrl;
Meal(
{this.id,
this.imageType,
this.title,
this.readyInMinutes,
this.servings,
this.sourceUrl});
Meal.fromMap(Map<String, dynamic> json) {
id = json['id'];
imageType = json['imageType'];
title = json['title'];
readyInMinutes = json['readyInMinutes'];
servings = json['servings'];
sourceUrl = json['sourceUrl'];
}
}
For some reasons, looks like the api doesn't really provide adequate support for the respective images, some images link are broken.
The app result looks like below:

In Ktor how do I get the sessionId within a get() {}?

install(Sessions) {
header<MySession>("MY_SESSION", SessionStorageMemory())
}
get("/session/increment") {
val session = call.sessions.get<MySession>() ?: throw AuthorizationException()
call.sessions.set(session.copy(count = session.count + 1))
// insert code here to get sessionId ?
call.respondText("Counter is ${session.count}. Refresh to increment.")
}
I've been trying to get it out of the attributes but it seems the framework has made all those data structures private to prevent me from getting the sessionId and have no working solution yet.
val attributeKey = call.attributes.allKeys.map{
val x = it as AttributeKey<Any>
call.attributes.get(x)
}
// AttributeKey<SessionData>("SessionKey")
SessionData is private so I can't get access to data structure that holds sessionId

How to create custom build step based on existing one in TeamCity Kotlin DSL?

I use TeamCity Kotlin DSL 2018.1 to set up build configuration. My settings.kts file looks like this:
version = "2018.1"
project {
buildType {
id("some-id")
name = "name"
steps {
ant {
name = "Step1"
targets = "target1"
mode = antFile { path = "/some/path" }
workingDir = "/some/dir"
jdkHome = "some_jdk"
}
ant {
name = "Step2"
targets = "target2"
mode = antFile { path = "/some/path" }
workingDir = "/some/dir"
jdkHome = "some_jdk"
}
...
}
}
}
It works as expected, but I want to avoid writing the same repeating parameters for every step over and over again.
I tried to write function, which would construct build step pre-filled with default values:
fun customAnt(init: AntBuildStep.() -> kotlin.Unit): AntBuildStep {
val ant_file = AntBuildStep.Mode.AntFile()
ant_file.path = "/some/path"
val ant = AntBuildStep()
ant.mode = ant_file
ant.workingDir = "/some/dir"
ant.jdkHome = "some_jdk"
return ant
}
project {
buildType {
id("some-id")
name = "name"
steps {
customAnt {
name = "Step1"
targets = "target1"
}
customAnt {
name = "Step2"
targets = "target2"
}
...
}
}
}
It compiles but doesn't work: TeamCity just ignores build steps, defined in this way.
Unfortunately, official documentation doesn't contain any information about customizing and extending DSL. Probably, I'm doing something wrong with Kotlin's () -> Unit construction, but can't find out what exactly is wrong.
I got it.
Actually, I was close. The following code works just as I wanted:
version = "2018.1"
fun BuildSteps.customAnt(init: AntBuildStep.() -> Unit): AntBuildStep {
val ant_file = AntBuildStep.Mode.AntFile()
ant_file.path = "/some/path"
val result = AntBuildStep(init)
result.mode = ant_file
result.workingDir = "/some/dir"
result.jdkHome = "some_jdk"
step(result)
return result
}
project {
buildType {
steps {
customAnt {
name = "step1"
targets = "target1"
}
customAnt {
name = "step2"
targets = "target2"
}
...
}
}
}

Scala Actors suspends unexpected when connecting to a database

I have a problem with my understanding of the standard actor library in Scala. In the code below I have created a simple swing, which basically should test if it is able to connect to a postgreSQL server. However it doesnt make it that far, I use Actors since the UI otherwise would freeze up while doing the work needed to connect to the database.
When er i use this line (meaning that I use actors instead of a single thread)
PostgresCheck ! new GetInfo()
The Swing will never be updated. However if I comment the line out and use the next three lines. (meaning the actors wont be used)
val result = PostgresCheck.checkPostgreSQL
if (result == "OK") pgText.background = GREEN else pgText.background = RED
pgText.text = result
The Swing will freeze but after about 25 seconds the swing will be updated.
import dbc.Database
import dbc.vendor.PostgreSQL
import java.awt.Dimension
import java.net.URI
import java.sql.Connection
import swing.event._
import swing._
import actors.Actor
import java.awt.Color._
import scala.actors.Actor._
case class Info(reply: String)
case class GetInfo()
object Example extends SimpleSwingApplication {
val pgButton = new Button("Check PostgreSQL")
val pgText = new TextArea("Not Checked Yet")
val pgPanel = new GridPanel(1, 2)
pgPanel.contents += pgButton
pgPanel.contents += pgText
def top = new MainFrame {
title = "StateChecker"
contents = pgPanel
}
listenTo(pgButton)
reactions += {
case e: ButtonClicked if (e.source.eq(pgButton)) => {
PostgresCheck ! new GetInfo()
//val result = PostgresCheck.checkPostgreSQL
//if (result == "OK") pgText.background = GREEN else pgText.background = RED
//pgText.text = result
}
}
val guiActor = new Actor {
def act() = {
loop {
react {
case e: String => {
val result = e
if (result == "OK") pgText.background = GREEN else pgText.background = RED
pgText.text = result
}
case e => println(e.toString)
}
}
}
}
guiActor.start
}
object PostgresCheck extends Actor {
def checkPostgreSQL() = {
try {
val db = new Database(myPgSQL)
val con: Connection = myPgSQL.getConnection // Freezes while doing this method
val statement = con.createStatement
if (statement.getResultSet.getMetaData.getColumnCount == 1) "OK"
else statement.getWarnings.toString
}
catch {
case e => e.toString
}
}
def act() = {
loop {
react {
case e: GetInfo => {
sender ! new Info(checkPostgreSQL)
}
}
}
}
start()
}
object myPgSQL extends PostgreSQL {
val uri = new URI("jdbc:postgresql://whatever.com")
val user = "1234"
val pass = "1234"
}
You are sending the message outside an actor, it seems. Try this:
Actor.actor { PostgresCheck ! new GetInfo() }
Not sure if it will help, but it is standard advise.
And, now that I think of it, to whom will the answer be sent? You are replying to the non-existent sender. I suppose you want the answer going to guiActor, but I don't see you doing so.
Okay here we go, the problem was related to the line
sender ! new Info(checkPostgreSQL)
It should actually have been
Example.guiActor! new Info(checkPostgreSQL)
For some reason related to the Actor library it actually suspends when waiting for the database connection, and wont return because of an unknown sender. For instance the following lines result in a printout of just a single line in console with "1".
val db = new Database(myPgSQL)
println("1")
// Freezes while doing this method
val con: Connection = myPgSQL.getConnection
println("2")
When changing the mentioned line, the code behave as expected.