Button doesn't set to Enabled even after "if conditions" are met - android

Below code is supposed to set "isEnabled" attribute of a button to true, but it doesn't.
I initialize a mutable list which adds a String when certain Switches are on, and remove them when are off.
I created an if condition where if the size of the list is equal to 2 then ok_button is enabled.
I can't see why the ok_button is not updated even when the conditions are met.
package com.example.malakes
import android.nfc.Tag
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.CompoundButton
import android.widget.Switch
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
import android.util.Log
import android.view.View
import android.widget.Button
class MainActivity : AppCompatActivity() {
companion object{ const val TAG = "MyActivity" } //define TAG
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val epilegmenoi: MutableList<String> = mutableListOf()
val tony = findViewById<Switch>(R.id.switchTony)
val giorgis = findViewById<Switch>(R.id.switchGiorgos)
val duke = findViewById<Switch>(R.id.switchDuke)
val nikolas = findViewById<Switch>(R.id.switchNikolas)
val dionisis = findViewById<Switch>(R.id.switchDionisis)
val grigoris = findViewById<Switch>(R.id.switchGrigoris)
val ok_button = findViewById<Button>(R.id.buttonOK)
val clear_button = findViewById<Button>(R.id.buttonCLEAR)
tony.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
epilegmenoi.add("Tony")
} else {
epilegmenoi.remove("Tony")
}
}
giorgis.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
epilegmenoi.add("Giorgis")
} else {
epilegmenoi.remove("Giorgis")
}
}
if (epilegmenoi.size == 2) {ok_button.isEnabled=true}
}
}

‍onCreate() is a Lifecycle method in your activity. It is only called when your Activity is being called for the first time or when phone configs change, e.g. Screen Rotation, Locale change, and ...
Setting if (epilegmenoi.size == 2) {ok_button.isEnabled=true} inside onCreate doesn't do anything for you.
Consider moving this line of code to some Event-based function.
fun updateButtonState() {
my_button.isEnabled = (myList.size == 2)
}
And inside your check box events:
tony.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
epilegmenoi.add("Tony")
} else {
epilegmenoi.remove("Tony")
}
updateButtonState()
}
giorgis.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
epilegmenoi.add("Giorgis")
} else {
epilegmenoi.remove("Giorgis")
}
updateButtonState()
}

Related

I encountered a problem while following a tutorial on building an app with Kotlin

The error that appears is as follows "Type mismatch: inferred type is String? but String is expected". How can I solve this problem?
The source code is as follows:
package com.example.submission2.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.example.submission2.Adapter.AdapterSectionPager
import com.example.submission2.ViewModel.DetailVM
import com.example.submission2.databinding.ActivityDetailBinding
class DetailActivity : AppCompatActivity() {
companion object{
const val EXTRA_USERNAME = "extra_username"
}
private lateinit var binding: ActivityDetailBinding
private lateinit var viewModel: DetailVM
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setDisplayShowHomeEnabled(true)
}
val username = intent.getStringExtra(EXTRA_USERNAME)
viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(DetailVM::class.java)
viewModel.setPenggunaDetail(username)
viewModel.getPenggunaDetail().observe(this) {
if (it != null) {
binding.apply {
tvNamaDetail.text = it.name
tvUsernameDetail.text = it.login
tvCompanyDetail.text = it.company
tvEmailDetail.text = it.email
tvFollowersDetail.text = "${it.followers} Followers"
tvFollowingDetail.text = "${it.following} Follwing"
Glide.with(this#DetailActivity)
.load(it.avatar_url)
.transition(DrawableTransitionOptions.withCrossFade())
.centerCrop()
.into(ivDetailProfil)
}
}
}
val sectionPagerAdpter = AdapterSectionPager(this,supportFragmentManager)
binding.apply {
viewPager.adapter = sectionPagerAdpter
tabs.setupWithViewPager(viewPager)
}
}
}
error appears on the line "viewModel.set User Data(username)" username is used in extra_username which will be called in main
for main activity as follows:
package com.example.submission2.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.KeyEvent
import android.view.View
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.submission2.Adapter.AdapterPengguna
import com.example.submission2.DataBase.Pengguna
import com.example.submission2.R
import com.example.submission2.ViewModel.MainVM
import com.example.submission2.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: MainVM
private lateinit var adapter: AdapterPengguna
private fun searchPengguna(){
binding.apply {
val query = etSearch.text.toString()
if (query.isEmpty())return
showLoading(true)
viewModel.setSearchPengguna(query)
}
}
private fun showLoading(state: Boolean){
if (state){
binding.progressBarMain.visibility = View.VISIBLE
}else{
binding.progressBarMain.visibility = View.GONE
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
adapter = AdapterPengguna()
adapter.notifyDataSetChanged()
adapter.setOnItemClickCallback(object :AdapterPengguna.OnItemClickCallback{
override fun onItemCliked(data: Pengguna) {
Intent(this#MainActivity,DetailActivity::class.java).also {
it.putExtra(DetailActivity.EXTRA_USERNAME, data.login)
startActivity(it)
}
}
})
viewModel = ViewModelProvider(this,ViewModelProvider.NewInstanceFactory()).get(MainVM::class.java)
binding.apply {
rvPengguna.layoutManager = LinearLayoutManager(this#MainActivity)
rvPengguna.setHasFixedSize(true)
rvPengguna.adapter = adapter
btnSearch.setOnClickListener {
searchPengguna()
}
etSearch.setOnKeyListener { v, keyCode, event ->
if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER){
searchPengguna()
return#setOnKeyListener true
}
return#setOnKeyListener false
}
}
viewModel.getSearchPengguna().observe(this,{
if (it!= null){
adapter.setList(it)
showLoading(false
)
}
})
}
}
In your code there is no such line as viewModel.setUserData
I guess that the error occurs in the line viewModel.setPenggunaDetail(username)
In this case, you should pay attention to the fact that the all intent.getExtra calls returns nullable values.
Thus, if the setPenggunaDetail call expects a non-nullable argument, you must first check username value for null

Focus action button in SnackBar with TalkBack

I am creating a SnackBar with action using Android Jetpack Compose.
My requirement is, when accessibility TalkBack is enabled and snackBar is shown, action button should be focused, so that user can perform action (action button click) by clicking (double tap)anywhere.
I just provide my prototype. I added all code in one activity, to simplify example. I suspect you can improve and modify for your case. May be my example will inspire you)
package com.rollo.exampleandtests.composable
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_DOWN
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.rollo.exampleandtests.composable.ui.ComposeTutorialTheme
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
class ComposeActivity10 : AppCompatActivity() {
//must be moved to ViewModel
private var isShowed = false
private var action: MutableStateFlow<Boolean?> = MutableStateFlow(null)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeTutorialTheme {
val forceDismiss by action.collectAsState()
SnackBarDemo(forceDismiss) {
isShowed = it
}
}
}
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
return if (ev?.action == ACTION_DOWN && isShowed) {
action.value = !(action.value ?: false)
true
} else {
super.dispatchTouchEvent(ev)
}
}
}
#Composable
fun SnackBarDemo(action: Boolean?, callback: (Boolean) -> Unit) {
val coroutineScope = rememberCoroutineScope()
val scaffoldState = rememberScaffoldState()
Scaffold(
modifier = Modifier.fillMaxSize(),
scaffoldState = scaffoldState
) {
Button(
modifier = Modifier
.fillMaxWidth()
.padding(20.dp),
onClick = {
coroutineScope.launch {
callback(true)
val snackbarResult = scaffoldState.snackbarHostState.showSnackbar(
message = "This is your message",
actionLabel = "Do something."
)
callback(false)
when (snackbarResult) {
SnackbarResult.Dismissed -> Log.d("SnackbarDemo", "Dismissed")
SnackbarResult.ActionPerformed -> Log.d(
"SnackbarDemo",
"Snackbar's button clicked"
)
}
}
}
) {
Text(text = "A button that shows a Snackbar")
}
}
LaunchedEffect(key1 = action, block = {
if (action == true) {
scaffoldState.snackbarHostState.currentSnackbarData?.dismiss()
//HERE: do something
}
})
}

Can't detect key press with hardware keyboard on android app (Kotlin)

I am creating a simple application for my android tv box, which uses a webview object to show some streaming urls and choose beetween them with PGup and PGdown of a remote control (an hardware keyboard).
I am overriding method onKeyUp, but unfortunately my app seem not to detect any key press.
This is some code excerpt:
package com.dm.tutorialwebview
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.KeyEvent
import android.view.Menu
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import android.util.Log
import android.view.MotionEvent
class MainActivity : AppCompatActivity() {
var webview: WebView? = null
data class Channel(val number: Int, val name:String, val url: String )
object ChannelList {
private val list = mutableListOf<Channel>()
private var curChannel: Int = 0
[..]
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ChannelList.addItem(Channel(1,"channel1","https://...3"))
ChannelList.addItem(Channel(2,"channel2","https://..."))
ChannelList.addItem(Channel(3,"channel3","https://..."))
webview = findViewById(R.id.myweb)
webview!!.webViewClient = WebViewClient()
webview!!.settings.javaScriptEnabled = false
webview!!.webChromeClient = WebChromeClient()
webview!!.settings.domStorageEnabled = true
webview!!.settings.builtInZoomControls = false
webview!!.settings.setSupportZoom(false)
webview!!.overScrollMode = WebView.OVER_SCROLL_NEVER
webview!!.settings.useWideViewPort = true
webview!!.setInitialScale(1)
webview!!.loadUrl(ChannelList.getChannelUrl())
}
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
Log.i("TAG", "onKeyUp is been called");
return when (keyCode) {
KeyEvent.KEYCODE_PAGE_UP -> {
ChannelList.nextChannel()
webview!!.loadUrl(ChannelList.getChannelUrl())
true
}
KeyEvent.KEYCODE_PAGE_DOWN -> {
ChannelList.prevChannel()
webview!!.loadUrl(ChannelList.getChannelUrl())
true
}
KeyEvent.KEYCODE_1 -> {
ChannelList.setChannel(1)
webview!!.loadUrl(ChannelList.getChannelUrl())
true
}
else -> super.onKeyUp(keyCode, event)
}
}
}
Method onKeyUp doesn't seem to be triggered at all.
Any hints on what could be wrong with this code?
Thanks and regards
Thanks #Ashwini-violet, I replaced onKeyUp with dispathKeyEvent.
I used a workaround to limit inputs to one every 250ms; not very polite but it's working.
var lastclick : Long = 0
var keyDelay : Int = 250
[..]
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
return when (event!!.keyCode) {
KeyEvent.KEYCODE_PAGE_UP , KeyEvent.KEYCODE_DPAD_UP -> {
if ((SystemClock.currentThreadTimeMillis() - lastclick) < keyDelay) true
else {
ChannelList.nextChannel()
webview!!.clearHistory()
webview!!.clearCache(true)
showChannelName()
webview!!.loadUrl(ChannelList.getChannelUrl())
lastclick = SystemClock.currentThreadTimeMillis()
true
}
}

How to change a single value in firebase database multiple times?

Im trying to change value of true and false to the opposite, so if the value in the database is true then it needs to be changed to false and if false then to true.
It works the first time i press the button but if i press the button again then it keeps changing nonstop until the app crashes.
Here is the code i use to change the value:
package com.example.myapplication.adapters
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication.Model.CategoryModel
import com.example.myapplication.R
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
class Category(private val listCategory: MutableList<CategoryModel>) :
RecyclerView.Adapter<Category.ViewHolder>() {
val mAuth = FirebaseAuth.getInstance()
val database = FirebaseDatabase.getInstance()
var currentUid = mAuth.currentUser?.uid
val myRef = database.getReference("User-following").child(currentUid!!)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val v = inflater.inflate(R.layout.category_layout, parent, false)
return ViewHolder(v)
}
private fun fetchNotificationStatus(category: String, b: Boolean) {
var status = if (b) {
"true"
} else {
"false"
}
myRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (childSnapshot in snapshot.children) {
val key = childSnapshot.key
if (childSnapshot.child("category").value == category) {
myRef.child(key!!).child("notifications").setValue(status)
return
}
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("Database Error", error.toString())
}
})
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var category: TextView = itemView.findViewById(R.id.category)
var remove: Button = itemView.findViewById(R.id.remove)
val alert: CheckBox = itemView.findViewById(R.id.alert)
init {
alert.setOnCheckedChangeListener { _: CompoundButton, _: Boolean ->
val cat = category.text
if (alert.isChecked) {
Snackbar.make(itemView,
"${category.text} has been added to your notifications list",
Snackbar.LENGTH_LONG)
.show()
fetchNotificationStatus(cat as String, true)
} else {
Snackbar.make(itemView,
"${category.text} has been removed from your notifications list",
Snackbar.LENGTH_LONG)
.show()
fetchNotificationStatus(cat as String, false)
}
}
}
}
So when you press the check box the first time it changes either from
false -> True or from true -> false
but if you press the check box again it keeps changing
(false -> true -> false -> true -> false ...)
and doesn't stop changing until you close the app or until you press another button which causes the app to crash
How do i fix this so that it only changes to the opposite everytime the checkbox is pressed?
The simple fix is to use addListenerForSingleValueEvent instead of addValueEventListener in fetchNotificationStatus. Using addListenerForSingleValueEvent ensures that the listener only gets one value and then stops listening. Your current addValueEventListener keeps listening to the data, so that it gets retriggered by your own write, which then writes it again, and again, and again...
In addition, I recommend using a query to find the node(s) that you want to modify:
private fun fetchNotificationStatus(category: String, b: Boolean) {
var status = if (b) {
"true"
} else {
"false"
}
Query query = myRef.orderByChild("category").equalTo(category);
query.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (childSnapshot in snapshot.children) {
childSnapshot.getRef().child("notifications").setValue(status)
// might be able to do .ref. instead of .getRef().
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("Database Error", error.toString())
}
})
}
Using a query like this reduces the amount of data that your app reads and this reduces the bandwidth usage/cost both on the client and on the server.

Login functionality: Shared preferences

package com.example.myapplication
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.icu.util.VersionInfo
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.renderscript.Sampler
import android.text.LoginFilter
import android.util.Log
import android.view.View
import android.widget.*
import kotlinx.android.synthetic.main.activity_main.*
import java.util.concurrent.LinkedBlockingDeque
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val username = findViewById<EditText>(R.id.ET1).toString()
val password = findViewById<EditText>(R.id.ET2).toString()
val username1 = getSharedPreferences("username", Context.MODE_PRIVATE)
username1.edit().putString("username","").apply()
val password1 = getSharedPreferences("password", Context.MODE_PRIVATE)
password1.edit().putString("password", "").apply()
val rememberme = findViewById<CheckBox>(R.id.checkBox)
val loginbutton = findViewById<Button>(R.id.LoginButton)
val register = findViewById<TextView>(R.id.textView2)
if(username.equals("admin")){
val a = username1.getString(username,"").toString()
Log.i("Usernmae is ", a)
loginbutton.setOnClickListener {
val intent = Intent(this, ListActivity::class.java)
startActivity(intent)
}
}
else{
Toast.makeText(this,"Invalid Credentials",Toast.LENGTH_SHORT).show()
}
rememberme.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
val pf = getSharedPreferences("checkbox", Context.MODE_PRIVATE)
val ed = pf.edit()
ed.putString("remember", "True")
ed.apply()
Toast.makeText(this, "Checked", Toast.LENGTH_LONG).show()
} else if (!isChecked) {
val pf = getSharedPreferences("checkbox", Context.MODE_PRIVATE)
val ed = pf.edit()
ed.putString("remember", "False")
ed.apply()
Toast.makeText(this, "Unchecked", Toast.LENGTH_LONG).show()
}
}
/*register.setOnClickListener {
val intent =Intent(this, Registration:: class.java)
startActivity(intent)
}*/
}
}
/*val pf = getSharedPreferences("checkbox", Context.MODE_PRIVATE)
val checkbox = pf.getString("remember", "")
}*/
/*
}
}
}*/
I am trying to add login functionality to my app.
Where user can register and his/her data is kept at their device only. Once they check the 'Remember Me' button they need not to login every time.
However,the code doesn't read the 'if' part of the code and always displays the message from 'else' section
Please help me.

Categories

Resources