How to convert this AppInventor Blocks to Kotlin Code? Any Idea - kotlin

Hi there I want to convert those blocks from the AppInventor project to Android Studio Project Using Kotiln as my programing language but I am very new to android development can anyone help me with that?
What this app does is opening webview and reload my webpage URL at a randomly generated time.
What I tried so far!
package com.technosoftkpk.y_view
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myWebView: WebView = findViewById(R.id.webview)
myWebView.setWebViewClient(WebViewClient())
myWebView.loadUrl("https://technosoft.pk")
val webSettings = myWebView.settings
webSettings.displayZoomControls = true
webSettings.javaScriptEnabled = true
}
}

Would something like this work? This will randomly wait between 0 and 5 seconds. (Add the code at the end of onCreate):
import kotlin.concurrent.thread
import kotlin.random.Random
thread {
while (true) {
Thread.sleep(Random.nextLong(5000))
runOnUiThread { myWebView.reload() }
}
}
This might look complicated, but we need to make a new thread to avoid blocking the UI thread and allowing user input. But then the reloading needs to happen on the UI thread again. An alternative would be to use postDelayed.

Related

API data takes 2 button clicks in order to display data - Kotlin

I've tried searching stackoverflow, but couldn't find the answer to my issue. When the search button is clicked, I want the app to display the data from the API. The issue I'm having is that it is taking 2 clicks of the search button in order to display the data. The first click displays "null" and the second click displays all data correctly. What am I doing wrong? What do I need to change in order to process correctly on the first click? Thanks in advance!
Pairing Fragment
package com.example.winepairing.view.fragments
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.activityViewModels
import com.example.winepairing.databinding.FragmentPairingBinding
import com.example.winepairing.utils.hideKeyboard
import com.example.winepairing.viewmodel.PairingsViewModel
class PairingFragment : Fragment() {
private var _binding: FragmentPairingBinding? = null
private val binding get() = _binding!!
private val viewModel: PairingsViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentPairingBinding.inflate(inflater, container, false)
val view = binding.root
val toolbar = binding.toolbar
(activity as AppCompatActivity).setSupportActionBar(toolbar)
binding.searchBtn.setOnClickListener {
hideKeyboard()
if (binding.userItem.text.isNullOrEmpty()) {
Toast.makeText(this#PairingFragment.requireActivity(),
"Please enter a food, entree, or cuisine",
Toast.LENGTH_SHORT).show()
} else {
val foodItem = binding.userItem.text.toString()
getWinePairing(foodItem)
pairedWinesList()
pairingInfo()
}
}
return view
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun pairedWinesList() {
val pairedWines = viewModel.apiResponse.value?.pairedWines
var content = ""
if (pairedWines != null) {
for (i in 0 until pairedWines.size) {
//Append all the values to a string
content += pairedWines.get(i)
content += "\n"
}
}
binding.pairingWines.setText(content)
}
private fun pairingInfo() {
val pairingInfo = viewModel.apiResponse.value?.pairingText.toString()
binding.pairingInfo.setText(pairingInfo)
}
private fun getWinePairing(foodItem: String) {
viewModel.getWinePairings(foodItem.lowercase())
}
}
So, sorry!!! Here is the viewmodel
package com.example.winepairing.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.winepairing.BuildConfig
import com.example.winepairing.model.data.Wine
import com.example.winepairing.model.network.WineApi
import kotlinx.coroutines.launch
const val CLIENT_ID = BuildConfig.SPOONACULAR_ACCESS_KEY
class PairingsViewModel: ViewModel() {
private val _apiResponse = MutableLiveData<Wine>()
val apiResponse: LiveData<Wine> = _apiResponse
fun getWinePairings(food: String) {
viewModelScope.launch {
_apiResponse.value = WineApi.retrofitService.getWinePairing(food, CLIENT_ID)
}
}
}
Although you didn't share your ViewModel code, I'm guessing that your ViewModel's getWinePairings() function retrieves data asynchronously from an API and then updates a LiveData called apiResponse with the return value. Since the API response takes some time before it returns, your apiResponse LiveData is going to still be empty by the time you call the Fragment's pairedWinesList() function from the click listener.
Hint, any time you use the .value of a LiveData outside of the ViewModel that manages it, you are probably doing something wrong. The point of LiveData is to react to it's data when it arrives, so you should be calling observe() on it instead of trying to read its .value synchronously.
More information in this question about asynchronous calls.
You haven't posted your actual code for fetching data from the API (probably in viewModel#getWinePairings), but at a guess it's going like this in your button click listener:
you call getWinePairing - this kicks off an async call that will eventually complete and set data on viewModel.apiResponse, sometime in the future. It's initial value is null
you call pairedWinesList which references the current value of apiResponse - this is gonna be null until an API call sets a value on it. Since you're basically fetching the most recent completed search result, if you change your search data then you'll end up displaying the results of the previous search, while the API call runs in the background and updates apiResponse later
you call pairingInfo() which is the same as above, you're looking at a stale value before the API call returns with the new results
The problem here is you're doing async calls that take a while to complete, but you're trying to display the results immediately by reading the current value of your apiResponse LiveData. You shouldn't be doing that, you should be using a more reactive design that observes the LiveData, and updates your UI when something happens (i.e. when you get new results):
// in onCreateView, set everything up
viewModel.apiResponse.observe(viewLifeCycleOwner) { response ->
// this is called when a new 'response' comes in, so you can
// react to that by updating your UI as appropriate
binding.pairingInfo.setText(response.pairingInfo.toString())
// this is a way you can combine all your wine strings FYI
val wines = response.pairedWines?.joinToString(separator="\n") ?: ""
binding.pairingWines.setText(wines)
}
binding.searchBtn.setOnClickListener {
...
} else {
val foodItem = binding.userItem.text.toString()
// kick off the API request - we don't display anything here, the observing
// function above handles that when we get the results back
getWinePairing(foodItem)
}
}
Hopefully that makes sense - the button click listener just starts the async fetch operation (which could be a network call, or a slow database call, or a fast in-memory fetch that wouldn't block the thread - the fragment doesn't need to know the details!) and the observe function handles displaying the new state in the UI, whenever it arrives.
The advantage is you're separating everything out - the viewmodel handles state, the UI just handles things like clicks (updating the viewmodel) and displaying the new state (reacting to changes in the viewmodel). That way you can also do things like have the VM save its own state, and when it initialises, the UI will just react to that change and display it automatically. It doesn't need to know what caused that change, y'know?

how to have loading in Kotlin

my MainActivity contains a ViewPager that loads 4 fragments, each fragment should load lots of data from the server.
so when my app wants to be run for the first time, it almost takes more than 3 seconds and the other times(for example, if you exit the app but not clean it from your 'recently app' window and reopen it) it takes almost 1 second.
while it is loading, it shows a white screen.
is there any way instead of showing a white screen till data become ready, I show my own image?
something like the splash page?
If you do long-running actions on the main thread, you risk getting an ANR crash.
Your layout for each fragment should have a loading view that is initially visible, and your data view. Something like this:
(not code)
FrameLayout
loading_view (can show a progress spinner or something, size is match parent)
content_view (probably a RecyclerView, initial visibility=GONE, size is match parent)
/FrameLayout
You need to do your long running action on a background thread or coroutine, and then swap the visibility of these two views when the data is ready to show in the UI.
You should not be directly handling the loading of data in your Fragment code, as Fragment is a UI controller. The Android Jetpack libraries provide the ViewModel class for this purpose. You would set up your ViewModel something like this. In this example, MyData could be anything. In your case it's likely a List or Set of something.
class MyBigDataViewModel(application: Application): AndroidViewModel(application) {
private val _myBigLiveData = MutableLiveData<MyData>()
val myBigLiveData: LiveData<MyData>() = _myBigLiveData
init {
loadMyBigData()
}
private fun loadMyBigData() {
viewModelScope.launch { // start a coroutine in the main UI thread
val myData: MyData = withContext(Dispatchers.Default) {
// code in this block is done on background coroutine
// Calculate MyData here and return it from lambda
// If you have a big for-loop, you might want to call yield()
// inside the loop to allow this job to be cancelled early if
// the Activity is closed before loading was finished.
//...
return#withContext calculatedData
}
// LiveData can only be accessed from the main UI thread so
// we do it outside the withContext block
_myBigLiveData.value = myData
}
}
}
Then in your fragment, you observe the live data to update the UI when it is ready. The below uses the fragment-ktx library, which you need to add to your project. You definitely should read the documentation on ViewModel.
class MyFragment: Fragment() {
// ViewModels should not be instantiated directly, or they won't be scoped to the
// UI life cycle correctly. The activityViewModels delegate handles instantiation for us.
private val model: MyBigDataViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model.myBigLiveData.observe(this, Observer<MyData> { myData ->
loading_view.visibility = View.GONE
content_view.visibility = View.VISIBLE
// use myData to update the view content
})
}
}

Trying to create a load screen in Kotlin(Android)

I'm trying to make a simple load screen in a app using kotlin
Instead of just displaying a text, I want to play a sound and show an image for like, 3 seconds.
I created a layout to set for 3 seconds using Thread.sleep, but it didn't work.
Can anyone see what I'm missing?
Thank you!
class MatrixActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.loading_activity_matrix)
Thread.sleep(3000)
setContentView(R.layout.activity_matrix)
A00.setOnClickListener { sendCommand("00000")}
B00.setOnClickListener { sendCommand("00100")}
C00.setOnClickListener { sendCommand("00200")}
D00.setOnClickListener { sendCommand("00300")}
E00.setOnClickListener { sendCommand("00400")}
F00.setOnClickListener { sendCommand("00500")}
G00.setOnClickListener { sendCommand("00600")}
H00.setOnClickListener { sendCommand("00700")}
If you're using Kotlins coroutines, you can use
runBlocking {
delay(3000) //waits for 3s
}
in place of Thread.sleep(3000) to let a thread sleep for the given amount of milliseconds. If you need help setting up coroutines, or need further information, great explanations are on the Kotlin website: Your first coroutine with Kotlin.

import kotlinx is impossible in IntelliJ IDEA

I`m testing coroutine example code on IntelliJ IDEA. But I cannot import library which needs for coroutine.
I created project as Kotlin - "JVM | IDEA". I tried simple print hello world code and succeesfully done. But coroutine example don`t even execute.
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
fun main()
{
runBlocking {
var counter = 0
val lock = Mutex()
val coroutines = List(3) {
launch {
repeat(1_000) {
lock.withLock {
counter++
}
}
}
}
coroutines.forEach { it.join() }
println("Final counter: $counter")
}
}
This Code runs on https://play.kotlinlang.org. But in IDEA, they cannot understand it, showing 'Unresolved reference'.
I`ve searched but no answer found. How can I run this on IDEA project?
it would be a good idea to switch to a Gradle-based build, which will automatically be imported by IntelliJ IDEA.
you can set IntelliJ to automatically stay in sync with your Gradle files, or you can opt to "sync" IntelliJ to Gradle's structure on demand.
you have two syntax options with Gradle: Groovy and Kotlin. make sure if you are new to Gradle that you use a consistent syntax, otherwise it can be hard to follow the guides. obviously if you are working in Kotlin, it's a great idea to use Kotlin in your build files, too.

Kotlin native - Execute an executable

I am trying to execute a command via bash, for example konanc.
In KotlinJVM this would just be using Runtime.getRuntime().exec("..."), or creating a Process using the ProcessBuilder, however, none of those classes are available in Kotlin-Native, as they are part of the Java libraries.
I tried searching for example code in the documentation and the kotlin-native GitHub repository, but haven't found anything.
tl;dr No, there is no standard process api for kotlin-native
Well the kotlin std for native is still under development, and i don't think process api will be there anytime soon.
However you could use interoperability with some C process library such as https://github.com/eidheim/tiny-process-library
How-to you will find here https://github.com/JetBrains/kotlin-native/blob/master/INTEROP.md
However there are also POSIX's exec/fork calls you could use to spawn and create new process and i think kotlin-native does include POSIX for linux/windows. https://github.com/JetBrains/kotlin-native/tree/master/platformLibs/src/platform see posix.def for platforms.
Example:
import platform.posix.*
fun main(arguments: Array<String>) {
println("${arguments[0]}")
execlp("touch", "touch", "${arguments[0]}")
}
Calling it with ./file <name> will create a file that is named after the parameter name in your current directory.
IMHO, this is the killer app for Kotlin native. And here is part of the solution using the standard Kotlin API; This solution still needs the buffering of the dir or date command output, but generally works on Windows yea!
import kotlin.native.OsFamily.*
import platform.posix.*
fun main(arguments: Array<String>) {
println("running")
if (arguments.size >= 1) {
arguments.forEach { a -> println(a) }
}
val platform = Platform
val os = platform.osFamily
println("os is " + os)
when (os) {
WINDOWS -> runWindows()
else -> runUnix()
}
}
fun runWindows() {
val result = execlp("dir", "","")
println("Ran on windows $result");
}
fun runUnix() {
execlp("date", "","")
println("Ran on UNIX")
}
Finally one that reads from the called process yea!
Only tested on Windows, I will do unix (aka mac :) ) tomorrow.
import kotlin.native.OsFamily.*
import platform.posix.*
import kotlinx.cinterop.refTo
import kotlinx.cinterop.toKString
fun main(arguments: Array<String>) {
println("running")
if (arguments.size >= 1) {
arguments.forEach { a -> println(a) }
}
val platform = Platform
val os = platform.osFamily
println("os is " + os)
when (os) {
WINDOWS -> runWindows()
else -> runUnix()
}
}
fun runWindows() {
val result = execl("dir", "","")
//hmm emulate https://gist.github.com/a-cordier/33211eda92b8084a9e7e
//https://www.youtube.com/watch?v=6xbLgZpOBi8
val fp = _popen("dir", "r") ?: error("Failed to run command: dir")
val buffer = ByteArray(4096)
var counter = 0
println("hmm")
while (true) {
val input = fgets(buffer.refTo(0), buffer.size, fp) ?: break
print(input.toKString())
//println(counter++)
}
println("Ran on windows $result");
}
fun runUnix() {
execlp("date", "","")
println("Ran on UNIX")
}