Can I use the repeated binding data in the variable? - kotlin

Please understand my poor English :)
Can I use it as follows?
before
if (binding.heightEditText.text.isNotBlank() && binding.weightEditText.text.isNotBlank()) {
val intent = Intent(this, ResultActivity::class.java).apply {
putExtra("weight", binding.weightEditText.text.toString().toFloat())
putExtra("height", binding.heightEditText.text.toString().toFloat())
}
startActivity(intent)
}
after
val height = binding.heightEditText.text
val weight = binding.weightEditText.text
if (height.isNotBlank() && weight.isNotBlank()) {
val intent = Intent(this, ResultActivity::class.java).apply {
putExtra("weight", weight.toString().toFloat())
putExtra("height", height.toString().toFloat())
}
startActivity(intent)
}

Yes, you can use this way to define those variables.
Just make sure your variables are in the same method that you are calling to retrieve the updated values into defined variables.
I'm updating minor things in your code.
val height = binding.heightEditText.text.toString()
val weight = binding.weightEditText.text.toString()
if (height.isNotBlank() && weight.isNotBlank()) {
val intent = Intent(this, ResultActivity::class.java).apply {
putExtra("weight", weight.toFloat())
putExtra("height", height.toFloat())
}
startActivity(intent)
}
I hope it's helpful to you!

Related

how to add a points system to an app preferences DataStore Jetpack Compose

I'm working on a Quiz app and I'm trying to add a points system to the app so that everytime the user gets a question right he gets a +1pts.
and for storing the points I use jetpack compose preferences Datastore.
the problem is whenever I want to add a point to the already saved points it doesn't work.
this is my PointsData
class PointsData(private val context: Context) {
//create the preference datastore
companion object{
private val Context.datastore : DataStore<Preferences> by preferencesDataStore("points")
val CURRENT_POINTS_KEY = intPreferencesKey("points")
}
//get the current points
val getpoints: Flow<Int> =context.datastore.data.map { preferences->
preferences[CURRENT_POINTS_KEY] ?: 0
}
// to save current points
suspend fun SaveCurrentPoints(numPoints : Int){
context.datastore.edit {preferences ->
preferences[PointsData.CURRENT_POINTS_KEY] = numPoints
}
}
}
save points methode
class SavePoints {
companion object {
#Composable
fun savepoints(numPointsToSave : Int) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val datastore = PointsData(context)
LaunchedEffect(1) {
scope.launch {
datastore.SaveCurrentPoints(numPointsToSave)
}
}
}
}
}
and whenever i want to get the number of points from my DataStore i use
val pointsdatastore = PointsData(context)
val currentpoints = pointsdatastore.getpoints.collectAsState(initial = 0)
//display it as text for example
Text(text = currentpoints.value.toString(), fontSize = 30.sp, fontWeight = FontWeight.Bold,
color = Color.White)
and to do the operation i want (add +1 o the already existing points i do this
val pointsdatastore = PointsData(context)
val currentpoints = pointsdatastore.getpoints.collectAsState(initial = 0)
SavePoints.savepoints(numPointsToSave = currentpoints.value + 1)
but it doesn't seem to work because the number of points always stays 1.
if you know whats the problem please help.
I found the answer my self but for anyone who is stuck in same situation the solution is to another method in PointsData(look at the question provided code)
the method is:
suspend fun incrementpoints(){
context.datastore.edit { preferences->
val currentpoints = preferences[CURRENT_POINTS_KEY] ?: 0
preferences[CURRENT_POINTS_KEY] = currentpoints + 1
}
}
(if you want decrement not increment you can just change + to - )
and now in the PointsMethod(look at the question provided code) you should add
#Composable
fun incrementpoints() {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val datastore = PointsData(context)
LaunchedEffect(key1 = 1) {
scope.launch {
datastore.incrementpoints()
}
}
}

Issues related to moving to MainActivity by pressing a button

If the user presses the positive button, they want to move it to MainActivity
fun setPositiveButtonClick(callback: (() -> Unit)?, view: View? = null) {
val intent = Intent(this#ErrorDialog, MainActivity::class.java)
startActivity(intent)
var view = view
if (view == null) view = this.view
this.positiveCallback = callback
view?.let { v ->
v.yes.setOnClickListener {
callback?.let { c ->
c()
}
dismiss()
}
}
}
Here is the error
I'm assuming this is in some sort of Dialog class, so I think you simply need to get the context of it by just replacing
val intent = Intent(this#ErrorDialog, MainActivity::class.java)
to
val intent = Intent(this.context, MainActivity::class.java)

How can I iterate through a gridView base adapter to check the text on it?

I have tried different ways, I've been stuck trying to do it for weeks.
I also tried to add the code in the adapter, I thought about using sqlite, but I just can't figure how to do it.
I just want to check a condition, if this string exists somewhere in gridview, boolean = true
Can I do something like that in the activity?
for (i in 0 until arrayList!!.size){
WordViewAdapter(this,arrayList).getView(i, convertView = null, parent = null).word.text
}
}
This is my grid view:
This is my Adapter:
private lateinit var mTTS : TextToSpeech
class WordViewAdapter(var ctx: Context, var array: ArrayList<Word_Item>?) : BaseAdapter() {
override fun getCount(): Int {
return array!!.size
}
override fun getItem(position: Int): Any {
return array!![position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var view : View = View.inflate(ctx, R.layout.grid_item_list,null)
var word:TextView = view.findViewById(R.id.tx_word)
var translation:TextView = view.findViewById(R.id.tx_transl)
var wordItem : Word_Item = array!![position]
word.text = wordItem.word
translation.text = wordItem.transl
Translate(ctx).question(word,translation)
view.setOnClickListener{
mTTS = TextToSpeech(ctx, TextToSpeech.OnInitListener { status ->
if (status != TextToSpeech.ERROR){
mTTS.setLanguage(Locale.US)
mTTS.setSpeechRate(0.7F)
mTTS.setPitch(0.7F)
mTTS.speak(word.text.toString(),TextToSpeech.QUEUE_FLUSH,null,null)
}
})
}
return view
}
}
Well guys, I did it. And I will post it here, maybe it help someone.
I've created another list:
var faladas = mutableListOf<String>()
And a function that check if it is equal, like that, if OK, then send to adapter, and update it:
private fun checkPalavra(str: String) {
var flip : Boolean = str.lowercase().trim().contains(binding.txPronunciar.text.toString().lowercase().trim().replace("!","").replace(".","").replace("?","").replace(",","") )
if (flip){
faladas.add(str.lowercase())
wordAdapter?.notifyDataSetChanged()
gridView?.invalidateViews()
gridView?.adapter = WordViewAdapter(this,arrayList,faladas)...
In the adapter, I just add it:
for (i in 0 until faladas.size){
if (faladas[i].lowercase() == word.text.toString().lowercase()){
view.setBackgroundColor(ctx.resources.getColor(R.color.green))
}
}

Kotlin, onActivityResult is deprecated scanning QR code, any ideas

"onActivityResult" is deprecated
I don't know how to replace with "StartActivityForResult" any ideas
please help, This is my code:
my code works fine but showme warning about deprecated method
this is my function QrScan code:
private fun scanQRCode() {
val integrator = IntentIntegrator(this).apply {
captureActivity = CaptureActivity::class.java
setOrientationLocked(false)
setDesiredBarcodeFormats(IntentIntegrator.ALL_CODE_TYPES)
setPrompt("Scanning Code")
}
integrator.initiateScan()
}
then
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
if (result != null) {
if (result.contents == null) Toast.makeText(this, "OperaciĆ³n Cancelada", Toast.LENGTH_LONG).show()
else {
resultado = result.contents.toString()
getlist()
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
I tried this new way but I can't get it works
the new way in Kotlin:
var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val data: Intent? = result.data
doSomeOperations()
}
}
fun openSomeActivityForResult() {
val intent = Intent(this, SomeActivity::class.java)
resultLauncher.launch(intent)
}
The initiateScan() method calls another method called createScanIntent() which returns the intent necessary for the resultLauncher to work. This way:
private fun scanQRCode() {
val integrator = IntentIntegrator(this).apply {
captureActivity = CaptureActivity::class.java
setOrientationLocked(false)
setDesiredBarcodeFormats(IntentIntegrator.ALL_CODE_TYPES)
setPrompt("Scanning Code")
}
resultLauncher.launch(integrator.createScanIntent())
}
Replacing integrator.initiateScan() with resultLauncher.launch (integrator.createScanIntent()) accesses the result of resultLauncher
In your new way of kotlin
replace StartActivityForResult() with ActivityResultContracts.StartActivityForResult() and instead of
resultLauncher.launch(intent) you can use
resultLauncher.launch(
IntentIntegrator(requireActivity())
.setOrientationLocked(true)
.setPrompt("scanning")
.createScanIntent()
)

How to simply add another source to MediatorLiveData in kotlin?

I want to combine multiple data sources in a MediatorLiveData. Unfortunately, there are not many examples yet. So in my ViewModel I have
//all lists have been declared before
val playerList = MediatorLiveData<List<Player>>()
init {
playerList.addSource(footballPlayerList) { value ->
playerList.value = value
}
playerList.addSource(basketballPlayerList) { value ->
playerList.value = value
}
}
But apparently this will always override the current value of playerList. I mean I could build some hacky workarounds with helper variables like _playerList but maybe there is an easier solution?
Having done quite some research.. I found it out. Here is an example
fun blogpostBoilerplateExample(newUser: String): LiveData<UserDataResult> {
val liveData1 = userOnlineDataSource.getOnlineTime(newUser)
val liveData2 = userCheckinsDataSource.getCheckins(newUser)
val result = MediatorLiveData<UserDataResult>()
result.addSource(liveData1) { value ->
result.value = combineLatestData(liveData1, liveData2)
}
result.addSource(liveData2) { value ->
result.value = combineLatestData(liveData1, liveData2)
}
return result
}
The actual combination of data is done in a separate combineLatestData method like so
private fun combineLatestData(
onlineTimeResult: LiveData<Long>,
checkinsResult: LiveData<CheckinsResult>
): UserDataResult {
val onlineTime = onlineTimeResult.value
val checkins = checkinsResult.value
// Don't send a success until we have both results
if (onlineTime == null || checkins == null) {
return UserDataLoading()
}
// TODO: Check for errors and return UserDataError if any.
return UserDataSuccess(timeOnline = onlineTime, checkins = checkins)
}
Here is a simple example
class MergeMultipleLiveData : ViewModel() {
private val fictionMenu: MutableLiveData<Resource<RssMenu>> = MutableLiveData()
private val nonFictionMenu: MutableLiveData<Resource<RssMenu>> = MutableLiveData()
val allCategoryMenus: MediatorLiveData<Resource<RssMenu>> = MediatorLiveData()
init {
getFictionMenus()
getNonFictionMenus()
getAllCategoryMenus()
}
private fun getAllCategoryMenus() = viewModelScope.launch(Dispatchers.IO) {
allCategoryMenus.addSource(fictionMenu) { value ->
allCategoryMenus.value = value
}
allCategoryMenus.addSource(nonFictionMenu) { value ->
allCategoryMenus.value = value
}
}
private fun getFictionMenus() = viewModelScope.launch(Dispatchers.IO) {
fictionMenu.postValue( // todo )
}
private fun getNonFictionMenus() = viewModelScope.launch(Dispatchers.IO) {
nonFictionMenu.postValue( // todo )
}
}
And in your fragment you can observer as;
viewModel.allCategoryMenus.observe(viewLifecycleOwner) {
// todo
}