ProgressDialog shows after the method is complete - kotlin

I am trying to make a ProgressDialog show up while the application is looking for an IP Address in the network. In my present codes, even though the initialization of the ProgressDialog is at the beginning, it shows after what I am waiting for finishes.
Here is my code:
val clickListener = View.OnClickListener { view ->
when(view.id) {
R.id.button_upload -> {
progressDialog = ProgressDialog(activity)
progressDialog!!.setMessage("Looking for the server. Please wait...")
progressDialog!!.setCancelable(false)
progressDialog!!.show()
if(findServer()) {
Log.i("TAG", "FOUND")
} else {
Log.i("TAG", "NOT FOUND")
}
}
}
}
private fun findServer(): Boolean {
if(canPingServer()) {
Toast.makeText(context, "We are connected to the server server", Toast.LENGTH_LONG).show()
gView.button_upload.setText("Upload")
gView.button_upload.isEnabled = true
progressDialog!!.dismiss()
return true
} else {
Toast.makeText(context, "We cannot connect to the server.", Toast.LENGTH_LONG).show()
gView.button_upload.setText("Server not found")
gView.button_upload.isEnabled = false
progressDialog!!.dismiss()
return false
}
}
private fun canPingServer(): Boolean {
val runtime = Runtime.getRuntime()
try {
val mIpAddrProcess = runtime.exec("/system/bin/ping -c 1 192.168.1.4")
val mExitValue = mIpAddrProcess.waitFor()
Log.i("TAG","mExitValue $mExitValue")
return mExitValue == 0
} catch (ignore: InterruptedException) {
ignore.printStackTrace()
Log.i("TAG"," Exception:$ignore")
} catch (e: IOException) {
e.printStackTrace()
Log.i("TAG"," Exception:$e")
}
return false
}
I believe that I have to create the AsyncTask<Void, Void, String> for this, but the thing is, this fragment have inherited from another class already like so
class UploadFragment : BaseFragment() {.....}

It's showing because you findServer() function needs to execute on a different thread.
val clickListener = View.OnClickListener { view ->
when(view.id) {
R.id.button_upload -> {
progressDialog = ProgressDialog(activity)
progressDialog!!.setMessage("Looking for the server. Please wait...")
progressDialog!!.setCancelable(false)
progressDialog!!.show()
Thread(Runnable {
if(findServer()) {
Log.i("TAG", "FOUND")
} else {
Log.i("TAG", "NOT FOUND")
}
}).start()
}
}
}
AsyncTask<Void, Void, String> is another way to multi thread in java but I believe the way I showed above would suit your needs better. You need to be careful though because anything that has to run on the main thread I.e. your toasts or where you are setting the text of your elements still needs to happen on the main thread. You can accomplish this by surrounding anything that requires being run on the main thread with
activity.runOnUiThread(java.lang.Runnable {
//put code here that needs to be run on the ui thread
})
In you case an example would be
private fun findServer(): Boolean {
if(canPingServer()) {
activity.runOnUiThread(java.lang.Runnable {
Toast.makeText(context, "We are connected to the server server", Toast.LENGTH_LONG).show()
gView.button_upload.setText("Upload")
gView.button_upload.isEnabled = true
progressDialog!!.dismiss()
})
return true
} else {
activity.runOnUiThread(java.lang.Runnable {
Toast.makeText(context, "We cannot connect to the server.", Toast.LENGTH_LONG).show()
gView.button_upload.setText("Server not found")
gView.button_upload.isEnabled = false
progressDialog!!.dismiss()
})
return false
}
}

Related

Remote Mediator loads only the first page

I'm trying to add offline capabilities to my TMDB app. I've tried doing it with Room but RemoteMediator only loads the first page.
This is how I implemented the RemoteMediator class
#OptIn(ExperimentalPagingApi::class)
class MoviesPopularMediator(
private val service: ApiService,
private val database: PopularMoviesDatabase
) : RemoteMediator<Int, MoviesModel>() {
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, MoviesModel>
): MediatorResult {
return try {
val loadKey = when(loadType){
LoadType.REFRESH -> {
1
}
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND ->{
state.lastItemOrNull()
?: return MediatorResult.Success(endOfPaginationReached = true)
getMoviesPage()
}
}
val response = service.getPopular(
page = state.config.pageSize,
)
val listing = response.body()
val results = listing?.results
if (listing != null) {
database.withTransaction {
if (loadKey != null) {
database.popularMoviesPageDao().savePopularMoviesPage(MoviesPage(page = listing.page, results = listing.results, total_pages = listing.total_pages))
}
if (results != null) {
database.popularMoviesDao().savePopularMovies(results)
}
}
}
MediatorResult.Success(endOfPaginationReached = response.body()?.page == response.body()?.total_pages)
} catch (exception: IOException) {
MediatorResult.Error(exception)
} catch (exception: HttpException) {
MediatorResult.Error(exception)
}
}
private suspend fun getMoviesPage(): MoviesPage? {
return database.popularMoviesPageDao().getPopularMoviesPage().firstOrNull()
}
}
I get the data from this api: https://api.themoviedb.org/3/.
Any ideas on how I should change this RemoteMediator so that it will load all pages?
If you need more details please feel free to ask

Using emit to build a Kotlin flow runs indefinitely and doesnt complete

I use a java library with which I can subscribe to events from my eventstore db.
I can create a subscription according to the following SubscirptionListener
public abstract class SubscriptionListener {
public void onEvent(Subscription subscription, ResolvedEvent event) {
}
public void onError(Subscription subscription, Throwable throwable) {
}
public void onCancelled(Subscription subscription) {
}
}
I would like to emit ResolvedEvents as part of a flow each time the subscription is triggered. However, the call to emit doesn't finish.
fun flowSubscriptionListener(
streamName: String,
options: SubscribeToStreamOptions = SubscribeToStreamOptions.get(),
onError: (subscription: Subscription?, throwable: Throwable) -> Unit = { _, _ -> },
onCancelled: (subscription: Subscription) -> Unit = { _ -> }
): Flow<ResolvedEvent> {
return flow {
val listener = object : SubscriptionListener() {
override fun onEvent(subscription: Subscription, event: ResolvedEvent) {
logger.info {
"Received event ${event.originalEvent.streamRevision}#${event.originalEvent.streamId}"
}
runBlocking {
logger.info { "emitting event" }
this#flow.emit(event)
logger.info { "Event emitted" }
}
}
override fun onError(subscription: Subscription?, throwable: Throwable) {
logger.error {
"Received error with message: ${throwable.message ?: "No message"} on subscription ${subscription?.subscriptionId}"
}
onError(subscription, throwable)
}
override fun onCancelled(subscription: Subscription) {
logger.debug { "Subscription ${subscription.subscriptionId} cancelled" }
onCancelled(subscription)
}
}
client.subscribeToStream(streamName, listener).await()
}.buffer(10)
}
I have a sample setup where I await a flow with three events
flowSubscriptionListener(
streamName = "SampleTournament-adb517b8-62e9-4305-b3b6-c1e7193a6d19",
).map {
it.event.eventType
}.collect {
println(it)
}
However, I receive no events at all. The console output shows me that invocation of emit never terminates.
[grpc-default-executor-1] INFO lib.eventstoredb.wrapper.EskWrapperEsdb - Received event 0#SampleTournament-adb517b8-62e9-4305-b3b6-c1e7193a6d19
[grpc-default-executor-1] INFO lib.eventstoredb.wrapper.EskWrapperEsdb - emitting event
I am expecting the logging of "Event emitted"
In order to wrap callback-based API, you should use callbackFlow instead. It supports concurrent emissions, which I think is likely your problem here.
Also, it will properly handle the cancellation of the subscription when the flow itself is cancelled (via awaitClose()).
Here is one way to do it:
fun EventStoreDBClient.flowSubscription(
streamName: String,
options: SubscribeToStreamOptions = SubscribeToStreamOptions.get(),
): Flow<ResolvedEvent> = callbackFlow {
val listener = object : SubscriptionListener() {
override fun onEvent(subscription: Subscription, event: ResolvedEvent) {
logger.info { "Received event ${event.originalEvent.streamRevision}#${event.originalEvent.streamId}" }
logger.info { "Emitting event" }
trySendBlocking(event)
logger.info { "Event emitted" }
}
override fun onError(subscription: Subscription?, throwable: Throwable) {
logger.error {
"Received error with message: ${throwable.message ?: "No message"} on subscription ${subscription?.subscriptionId}"
}
close(throwable)
}
override fun onCancelled(subscription: Subscription) {
logger.debug { "Subscription ${subscription.subscriptionId} cancelled" }
close()
}
}
val subscription = subscribeToStream(streamName, listener, options).await()
awaitClose {
subscription.stop()
}
}.buffer(10)
Note that I also converted it to an extension function on EventStoreDBClient, which seems appropriate here. And I removed the error/cancellation callbacks because Flow already handles those (you can put them back if you need them)

Need help completing the kotlinlang suggested exercise supporting Webhooks with javafx

In the tutorial, they teach how to support real-time p2p command-line messaging using websockets by implementing both client and server. I'm trying to finish an exercise where I have the client input messages via a javafx gui and receive messages inside the gui in the form of a chat log (basically a chat room)
I'm having trouble simply starting up the gui and the websocket together. I tried GlobalScope.launch in hopes that both would get run, but only the GUI gets launched. If I use runBlocking instead, only the websocket is active.
Here's what I have so far.
Other issues:
Don't know how to reference the javafx label variable inside the outputMessages function, so that we can update the chatlog. I try placing the label variable in the global scope, but it only results in a compile error, so I put it back inside SAKApplication.
How to update the label field to move to the next line (tried adding "/n" but it literally added "\n")
import java.util.Queue
import java.util.LinkedList
//var a = Label("s")
val messagesToSend: Queue<String> = LinkedList<String>()
class SAKApplication : Application() {
val l = Label("no text")
override fun start(primaryStage: Stage) {
val btn = Button()
btn.text = "Say 'Hello World'"
btn.onAction = EventHandler<ActionEvent> { println("Hello World!") }
val root = StackPane()
root.children.add(btn)
val textField = TextField()
// a = l
// action event
val event: EventHandler<ActionEvent> =
EventHandler {
l.text += "/n" + textField.getText()
messagesToSend.add(textField.getText())
}
// when enter is pressed
textField.setOnAction(event)
// add textfield
root.children.add(textField)
root.children.add(l)
val scene = Scene(root, 300.0, 250.0)
if (primaryStage != null) {
primaryStage.title = "Hello World!"
primaryStage.scene = scene
primaryStage.show()
}
val client = HttpClient {
install(WebSockets)
}
GlobalScope.launch {
client.webSocket(method = HttpMethod.Get, host = "127.0.0.1", port = 8080, path = "/chat") {
while(true) {
val messageOutputRoutine = launch { outputMessages() }
val userInputRoutine = launch { inputMessages() }
userInputRoutine.join() // Wait for completion; either "exit" or error
messageOutputRoutine.cancelAndJoin()
}
}
}
client.close()
}
}
fun main(args: Array<String>) {
Application.launch(SAKApplication::class.java, *args)
}
suspend fun DefaultClientWebSocketSession.outputMessages() {
try {
for (message in incoming) {
message as? Frame.Text ?: continue
// a.text += "/n" + message.readText()
println(message.readText())
}
} catch (e: Exception) {
println("Error while receiving: " + e.localizedMessage)
}
}
suspend fun DefaultClientWebSocketSession.inputMessages() {
val name = readLine() ?: ""
send(name)
while (true) {
sleep(1)
if (messagesToSend.isEmpty()) { continue }
val message = messagesToSend.remove()
if (message.equals("exit", true)) return
try {
send(message)
} catch (e: Exception) {
println("Error while sending: " + e.localizedMessage)
return
}
}
}

Flutter - Get data with an Event Channel from Kotlin to Dart

I have the following problem that I am already working on for over 20 hours: I want to use an Event Channel to get a data stream from the Spotify SDK. On the native side, I can automatically display the status of a current song by subscribing to my PlayerState. My goal is to be able to access this data stream with my Flutter app. On the native side I can output the data flow without problems. But I also want to be able to access this data in my Flutter App. The problem is that I do not get the data from Kotlin to Dart. I can not execute the command mEventSink?.success(position) because the mEventSink is zero.
It would be really great if someone could help me with this problem.
//...
class Spotifysdk04Plugin(private var registrar: Registrar): MethodCallHandler, EventChannel.StreamHandler {
//...
private var mEventSink: EventChannel.EventSink? = null
companion object {
#JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "spotifysdk")
channel.setMethodCallHandler(Spotifysdk04Plugin(registrar))
val eventChannel = EventChannel(registrar.messenger(), "timerStream")
eventChannel.setStreamHandler(Spotifysdk04Plugin(registrar))
}
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "loginAppRemote") {
//...
} else if(call.method == "initEventStream") {
try {
spotifyAppRemote!!.playerApi.subscribeToPlayerState()
.setEventCallback { playerState: PlayerState? ->
Log.d("test", "test24")
var position = playerState!!.playbackPosition.toDouble()
Log.d("playbackPosition1", position.toString())
if(mEventSink != null) {
Log.d("test", "test25")
mEventSink?.success(position)
} else {
Log.d("test", "mEventSink == null")
}
}
} catch (err:Throwable) {
Log.v("initEventStreamError",err.message.toString())
result.success(false)
}
} else {
result.notImplemented()
}
}
override fun onCancel(arguments: Any?) {
mEventSink = null
}
override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink) {
mEventSink = eventSink
}
}
I found a solution:
override fun onListen(p0: Any?, p1: EventChannel.EventSink?) {
mEventSink = p1
Log.d("test", "test1")
if(spotifyAppRemote == null) {
Log.d("test", "test2")
}
val connectionParams = ConnectionParams.Builder(clientId)
.setRedirectUri(redirectUri)
.showAuthView(true)
.build()
SpotifyAppRemote.connect(registrar.context(), connectionParams, object : Connector.ConnectionListener {
override fun onConnected(appRemote: SpotifyAppRemote) {
spotifyAppRemote = appRemote
if(spotifyAppRemote != null) {
Log.d("test", "test3")
spotifyAppRemote!!.playerApi.subscribeToPlayerState()
.setEventCallback { playerState: PlayerState? ->
Log.d("test", "test24")
var position = playerState!!.playbackPosition.toDouble()
Log.d("playbackPosition1", position.toString())
if(mEventSink != null) {
Log.d("test", "test25")
mEventSink?.success(position)
} else {
Log.d("test", "mEventSink == null")
}
}
}
Log.d("Spotify App Remote Login", "Connected!")
}
override fun onFailure(throwable: Throwable) {
Log.e("Spotify App Remote Login", "Error!", throwable)
}
})
}

What's the right way to get permissions for phone call intent

How to request permissions using Kotlin.
I am trying to make a phone call function
fun buChargeEvent(view: View){
var number: Int = txtCharge.text.toString().toInt()
val intentChrage = Intent(Intent.ACTION_CALL)
intent.data = Uri.parse("tel:$number")
startActivity(intentChrage)
}
I added user permissions in manifest
but still having the same
error .
You need to add permission to your manifest first
<uses-permission android:name="android.permission.CALL_PHONE" />
After permission added in manifest following code would work fine for you "Number_to_call" will be youe number that is need to be replaced
val call = Intent(Intent.ACTION_DIAL)
call.setData(Uri.parse("tel:" +"Number_to_call"))
startActivity(call)
You need to add the run time permission. Download the source code from here
//Click function of layout:
rl_call.setOnClickListener {
if (boolean_call) {
phonecall()
}else {
fn_permission(Manifest.permission.CALL_PHONE,CALLMODE)
}
}
// Request permission response
fun fn_permission(permission:String,mode:Int){
requestPermissions(permission, object : PermissionCallBack {
override fun permissionGranted() {
super.permissionGranted()
Log.v("Call permissions", "Granted")
boolean_call=true
phonecall()
}
override fun permissionDenied() {
super.permissionDenied()
Log.v("Call permissions", "Denied")
boolean_call=false
}
})
}
// function to call intent
fun phonecall() {
val intent = Intent(Intent.ACTION_CALL);
intent.data = Uri.parse("tel:1234567890s")
startActivity(intent)
}
Thanks!
First you need to add permission to your manifest first :
<uses-permission android:name="android.permission.CALL_PHONE" />
This bit of code is used on the place of your method :
fun buChargeEvent(view: View) {
var number: Int = txtCharge.text.toString().toInt()
val callIntent = Intent(Intent.ACTION_CALL)
callIntent.data = Uri.parse("tel:$number")
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this as Activity,
Manifest.permission.CALL_PHONE)) {
} else {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.CALL_PHONE),
MY_PERMISSIONS_REQUEST_CALL_PHONE)
}
}
startActivity(callIntent)
}
You need to request the runtime permission, since Android 6.0 certain permissions require you to ask at install and again at runtime.
Following the instructions here explains how to ask for permission at runtime.
This is the complete code for runtime permissions for Call Phone
Step 1:- add permission in manifest
<uses-permission android:name="android.permission.CALL_PHONE" />
Step 2:- Call this method checkAndroidVersion() in onCreate()
fun checkAndroidVersion() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkAndRequestPermissions()) {
} else {
}
} else {
// do code for pre-lollipop devices
}
}
val REQUEST_ID_MULTIPLE_PERMISSIONS = 1
fun checkAndRequestPermissions(): Boolean {
val call = ContextCompat.checkSelfPermission(this#MainActivity, Manifest.permission.CALL_PHONE)
val listPermissionsNeeded = ArrayList<String>()
if (call != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.CALL_PHONE)
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this#MainActivity, listPermissionsNeeded.toTypedArray(), REQUEST_ID_MULTIPLE_PERMISSIONS)
return false
}
return true
}
fun checkAndRequestPermissions(): Boolean {
val call = ContextCompat.checkSelfPermission(this#MainActivity, Manifest.permission.CALL_PHONE)
val listPermissionsNeeded = ArrayList<String>()
if (call != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.CALL_PHONE)
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this#MainActivity, listPermissionsNeeded.toTypedArray(), REQUEST_ID_MULTIPLE_PERMISSIONS)
return false
}
return true
}
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<String>, grantResults: IntArray) {
Log.d("in fragment on request", "Permission callback called-------")
when (requestCode) {
REQUEST_ID_MULTIPLE_PERMISSIONS -> {
val perms = HashMap<String, Int>()
// Initialize the map with both permissions
perms[Manifest.permission.CALL_PHONE] = PackageManager.PERMISSION_GRANTED
// Fill with actual results from user
if (grantResults.size > 0) {
for (i in permissions.indices)
perms[permissions[i]] = grantResults[i]
// Check for both permissions
if (perms[Manifest.permission.CALL_PHONE] == PackageManager.PERMISSION_GRANTED
) {
print("Storage permissions are required")
// process the normal flow
//else any one or both the permissions are not granted
} else {
Log.d("in fragment on request", "Some permissions are not granted ask again ")
//permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
// // shouldShowRequestPermissionRationale will return true
//show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
if (ActivityCompat.shouldShowRequestPermissionRationale(this#MainActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE) || ActivityCompat.shouldShowRequestPermissionRationale(this#MainActivity, Manifest.permission.CAMERA) || ActivityCompat.shouldShowRequestPermissionRationale(this#MainActivity, Manifest.permission.READ_EXTERNAL_STORAGE) || ActivityCompat.shouldShowRequestPermissionRationale(this#MainActivity, Manifest.permission.ACCESS_FINE_LOCATION)) {
showDialogOK("Call permission is required for this app",
DialogInterface.OnClickListener { dialog, which ->
when (which) {
DialogInterface.BUTTON_POSITIVE -> checkAndRequestPermissions()
DialogInterface.BUTTON_NEGATIVE -> {
}
}// proceed with logic by disabling the related features or quit the app.
})
} else {
Toast.makeText(this#MainActivity, "Go to settings and enable permissions", Toast.LENGTH_LONG)
.show()
// //proceed with logic by disabling the related features or quit the app.
}//permission is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
}
}
}
}
}
fun showDialogOK(message: String, okListener: DialogInterface.OnClickListener) {
AlertDialog.Builder(this#MainActivity)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show()
}
**Step 3**:- On button click
fun buChargeEvent(view: View){
if(checkAndRequestPermissions(){
var number: Int = txtCharge.text.toString().toInt()
val intentChrage = Intent(Intent.ACTION_CALL)
intent.data = Uri.parse("tel:$number")
startActivity(intentChrage)
}
}