How do I remove .0 from Float - android

Here is the code:
private fun setData(playerData: TreeMap<String, String>) {
val values = ArrayList<Entry>()
val graphData = java.util.ArrayList<Float>()
for (value in playerData.values) {
graphData.add(value.toInt().toFloat()) # <-- converting here
}
graphData.reverse()
for (i in 0 until graphData.size) {
val itemi = i.toFloat()
values.add(
Entry(
itemi, #<-- entering here directly
graphData[i],
resources.getDrawable(R.drawable.ic_cricket)
)
)
}
val set1: LineDataSet
set1 = LineDataSet(values, "Player Form Graph")
val dataSets = ArrayList<ILineDataSet>()
// Possible Solution?
val valueFormatter = IValueFormatter { value, _, _, _ ->
value.toInt().toString()
}
set1.valueFormatter = valueFormatter as ValueFormatter?
dataSets.add(set1)
val data = LineData(dataSets)
// set data
binding.chart1.data = data
}
Error: java.lang.ClassCastException: <id>DemoFragment$setData$valueFormatter$1 cannot be cast to com.github.mikephil.charting.formatter.ValueFormatter
The thing is some values are working without .0 and some are with .0

this is what I have used:
set1.valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return value.toInt().toString()
}
}
In case if there is a chance of value coming in decimal as well, say [1, 1.2, 3, 3.5] is your set, then go for:
set1.valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return DecimalFormat("#.#").format(value)
}
}
in above case #.# can be replaced with #.## if you want to show UPTO 2 decimal places and so on.

Use:
DecimalFormat df = new DecimalFormat( "0" );

Related

change value dispayed with onValueSelected - MPAndroidChart

I show percentage values in my pieChart. I want to change those values to real amounts when the user clicks on the slice. Is that possible by using onValueSelected()? I don't want to use IMarker as it's a bit complicated for me. I tried doing this but it didn't work:
override fun onValueSelected(e: Entry?, h: Highlight?) {
val amount = (e as PieEntry).value
e.y = amount
}
You can do this by setting a unique index attribute for each PieEntry, using a OnChartValueSelectedListener to keep track of which item is selected, and a ValueFormatter to choose how to render the item's value text based on whether it is the selected item or not.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val chart = findViewById<PieChart>(R.id.chart)
val myData = listOf(10f,20f,50f)
// Step 1: Create a list of PieEntry objects that uses
// the source data index as its "data" attribute
val entries = myData.mapIndexed { i, v -> PieEntry(v, i)}
val dataset = PieDataSet(entries, "Values")
dataset.isHighlightEnabled = true
dataset.valueTextSize = 14f
dataset.colors = listOf(
Color.parseColor("#FF32DA64"),
Color.parseColor("#FF32DAD4"),
Color.parseColor("#FFB853F2")
)
// Step 2: Create a value formatter that compares the pie entry data
// (aka index in the original list) with the selected index to choose
// what value to show
val myValueFormatter = object : ValueFormatter() {
override fun getPieLabel(value: Float, pieEntry: PieEntry?): String {
val idx = pieEntry?.data as? Int ?: -2
return if (idx == selectedIndex ) {
// Show the value for the selected item
"$value"
}
else {
// Show percentage for all the rest
"${value / myData.sum() * 100f} %"
}
}
}
dataset.valueFormatter = myValueFormatter
// Step 3: Add a value selected listener to change the selected index
chart.setOnChartValueSelectedListener(object : OnChartValueSelectedListener {
override fun onValueSelected(e: Entry?, h: Highlight?) {
selectedIndex = h?.x?.roundToInt() ?: -1
}
override fun onNothingSelected() {
selectedIndex = -1
}
})
chart.data = PieData(dataset)
chart.description.isEnabled = false
chart.legend.isEnabled = false
}
Which looks like (de-selected on the left, selected on the right):

how to show min and max value in linechart using mpchart in Android

I want to show the Min and Max value on the line chart i am using the library MPChart Android library.
I want to show min max as like this.
My Code for the Line chart
val lineDataSet = LineDataSet(values, "")
lineDataSet.lineWidth = 2f
lineDataSet.setDrawValues(true)
lineDataSet.setDrawFilled(true)
// lineDataSet.fillAlpha = 85
lineDataSet.setDrawCircles(false)
// lineDataSet.setCircleColor(Color.BLACK)
lineDataSet.color = resources.getColor(R.color.green)
// lineDataSet.fillColor = resources.getColor(R.color.colorPrimary)
lineDataSet.highLightColor = resources.getColor(R.color.coral);
val elevationMarker = ChartMarkerView2(activity)
binding!!.chart.markerView = elevationMarker
lineDataSet.setDrawHighlightIndicators(true)
lineDataSet.setDrawHorizontalHighlightIndicator(false)
lineDataSet.setDrawCircleHole(true)
lineDataSet.circleHoleRadius = 5f
lineDataSet.setCircleColor(
resources.getColor(R.color.green)
)
val drawable = ContextCompat.getDrawable(requireContext(), R.drawable.fade_graph_bg)
lineDataSet.fillDrawable = drawable
lineDataSet.axisDependency = YAxis.AxisDependency.LEFT
// lineDataSet.cubicIntensity = 0f
// lineDataSet.mode = LineDataSet.Mode.HORIZONTAL_BEZIER;
val dataSets = ArrayList<ILineDataSet>()
dataSets.add(lineDataSet) // add the datasets
// create a data object with the datasets
val data = LineData(dataSets)
// data.setDrawValues(false)
// set data
binding!!.chart.data = data
// binding!!.chart.animateX(100)
binding!!.chart.invalidate()
you can get Max- Min your Dataset and in ValueFormatter Modify your value like this :
val numArr1 = intArrayOf(10000, 10100, 12200,12700, 9036, 11200, 10200)
val max = numArr1.maxOrNull() ?: 0
val min = numArr1.minOrNull() ?: 0
valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
if (value == min.toFloat() || value == max.toFloat())
{
return "$value $"
}
return ""
}
}
Here is the code snippet to set minimum and maximum value in Linechart using MPAndroidChart library.
val chartEntities: ArrayList<Entry> = ArrayList()
val values = Array(5) {0f}
values[0] = 5f
values[1] = 2.2f
values[2] = 7.2f
values[3] = 9.5f
values[4] = 4.5f
values[5] = 6.4f
var i = 0
for (entry in values) {
var value = values[i]
chartEntities.add(Entry(i.toFloat(), value))
i++
}
val lineDataSet = LineDataSet(chartEntities, "")
val max = values.maxOrNull() ?: 0
val min = values.minOrNull() ?: 0
val valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
if (value == min.toFloat() || value == max.toFloat())
{
return "$value"
}
return ""
}
}
lineDataSet.valueFormatter = valueFormatter
lineDataSet.setDrawValues(true)
With this sample snippet you can set minimum and maximum values in linechart using MPAndroidChart.
Create float array of items to display in the line chart
find out minimum and maximum values from the arraylist.
create ValueFormatter and set values there.
set valueFormatter property to lineDataSet
set setDrawValues(true) in lineDataSet
Hope this helps. Happy coding.

How to apply a mask date (mm/dd/yyyy) in TextField with Jetpack Compose?

I have a TextField in which there cannot be more than 10 characters, and the user is required to enter date in the format "mm/dd/yyyy". Whenever user types first 2 characters I append "/", when the user types next 2 characters I append "/" again.
I did the following to achieve this:
var maxCharDate = 10
TextField(
value = query2,
onValueChange = {
if (it.text.length <= maxCharDate) {
if (it.text.length == 2 || it.text.length == 5)
query2 = TextFieldValue(it.text + "/", selection = TextRange(it.text.length+1))
else
query2 = it
}
emailErrorVisible.value = false
},
label = {
Text(
"Date of Birth (mm/dd/yyyy)",
color = colorResource(id = R.color.bright_green),
fontFamily = FontFamily(Font(R.font.poppins_regular)),
fontSize = with(LocalDensity.current) { dimensionResource(id = R.dimen._12ssp).toSp() })
},
.
.
.
It's working except that the appended "/" doesn't get deleted on pressing backspace, while other characters do get deleted.
How do I make it such that "/" is deleted too on pressing backspace?
You can do something different using the onValueChange to define a max number of characters and using visualTransformation to display your favorite format without changing the value in TextField.
val maxChar = 8
TextField(
singleLine = true,
value = text,
onValueChange = {
if (it.length <= maxChar) text = it
},
visualTransformation = DateTransformation()
)
where:
class DateTransformation() : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
return dateFilter(text)
}
}
fun dateFilter(text: AnnotatedString): TransformedText {
val trimmed = if (text.text.length >= 8) text.text.substring(0..7) else text.text
var out = ""
for (i in trimmed.indices) {
out += trimmed[i]
if (i % 2 == 1 && i < 4) out += "/"
}
val numberOffsetTranslator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
if (offset <= 1) return offset
if (offset <= 3) return offset +1
if (offset <= 8) return offset +2
return 10
}
override fun transformedToOriginal(offset: Int): Int {
if (offset <=2) return offset
if (offset <=5) return offset -1
if (offset <=10) return offset -2
return 8
}
}
return TransformedText(AnnotatedString(out), numberOffsetTranslator)
}
The / is being deleted but as soon as you delete, the length of the text becomes 2 or 5. So it checks the condition,
if (it.text.length == 2 || it.text.length == 5)
Since the condition is true now, the / appends again into the text. So it seems like it is not at all being deleted.
One way to solve this is by storing the previous text length and checking if the text length now is greater than the previous text length.
To achieve this, declare a variable below maxCharDate as
var previousTextLength = 0
And change the nested if condition to,
if ((it.text.length == 2 || it.text.length == 5) && it.text.length > previousTextLength)
And at last update the previousTextLength variable. Below the emailErrorVisible.value = false add
previousTextLength = it.text.length;
Implementation of VisualTranformation that accepts any type of mask for Jetpack Compose TextField:
class MaskVisualTransformation(private val mask: String) : VisualTransformation {
private val specialSymbolsIndices = mask.indices.filter { mask[it] != '#' }
override fun filter(text: AnnotatedString): TransformedText {
var out = ""
var maskIndex = 0
text.forEach { char ->
while (specialSymbolsIndices.contains(maskIndex)) {
out += mask[maskIndex]
maskIndex++
}
out += char
maskIndex++
}
return TransformedText(AnnotatedString(out), offsetTranslator())
}
private fun offsetTranslator() = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
val offsetValue = offset.absoluteValue
if (offsetValue == 0) return 0
var numberOfHashtags = 0
val masked = mask.takeWhile {
if (it == '#') numberOfHashtags++
numberOfHashtags < offsetValue
}
return masked.length + 1
}
override fun transformedToOriginal(offset: Int): Int {
return mask.take(offset.absoluteValue).count { it == '#' }
}
}
}
How to use it:
#Composable
fun DateTextField() {
var date by remember { mutableStateOf("") }
TextField(
value = date,
onValueChange = {
if (it.length <= DATE_LENGTH) {
date = it
}
},
visualTransformation = MaskVisualTransformation(DATE_MASK)
)
}
object DateDefaults {
const val DATE_MASK = "##/##/####"
const val DATE_LENGTH = 8 // Equals to "##/##/####".count { it == '#' }
}
I would suggest not only a date mask, but a simpler and generic solution for inputs masking.
A general formatter interface in order to implement any kind of mask.
interface MaskFormatter {
fun format(textToFormat: String): String
}
Implement our own formatters.
object DateFormatter : MaskFormatter {
override fun format(textToFormat: String): String {
TODO("Format '01212022' into '01/21/2022'")
}
}
object CreditCardFormatter : MaskFormatter {
override fun format(textToFormat: String): String {
TODO("Format '1234567890123456' into '1234 5678 9012 3456'")
}
}
And finally use this generic extension function for transforming your text field inputs and you won't need to care about the offsets at all.
internal fun MaskFormatter.toVisualTransformation(): VisualTransformation =
VisualTransformation {
val output = format(it.text)
TransformedText(
AnnotatedString(output),
object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int = output.length
override fun transformedToOriginal(offset: Int): Int = it.text.length
}
)
}
Some example usages:
// Date Example
private const val MAX_DATE_LENGTH = 8
#Composable
fun DateTextField() {
var date by remember { mutableStateOf("") }
TextField(
value = date,
onValueChange = {
if (it.matches("^\\d{0,$MAX_DATE_LENGTH}\$".toRegex())) {
date = it
}
},
visualTransformation = DateFormatter.toVisualTransformation()
)
}
// Credit Card Example
private const val MAX_CREDIT_CARD_LENGTH = 16
#Composable
fun CreditCardTextField() {
var creditCard by remember { mutableStateOf("") }
TextField(
value = creditCard,
onValueChange = {
if (it.matches("^\\d{0,$MAX_CREDIT_CARD_LENGTH}\$".toRegex())) {
creditCard = it
}
},
visualTransformation = CreditCardFormatter.toVisualTransformation()
)
}
It is because you are checking for the length of the string. Whenever the length is two, you insert a slash. Hence the slash gets deleted, and re-inserted.
Why don't you just create three TextFields and insert Slashes as Texts in between. Such logic can be very hard to perfect. Keen users can use it to crash your app, and also devs can insert malicious stuff, and exploit this flaw because the handling logic can have loopholes as well, so... It is better in my opinion to just go with the simplest (and what I think is more elegant) way of constructing.

Password generator displays kotlin.Unit

I'm trying to make random password generator based on user input and everything is fine until i use .toCharArray().shuffle() function, but without shuffling it's too predictable beacuse it puts letters in pre-determined positions. Is there any way this code would work? Any workaround? I already tried stringbuilder but it bypasses user input so I don't know what to do now.
val chars= "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~##$%^&*()!"
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if (fromUser)
{
when(seekBar)
{
sbNumberOfLetters ->
{
tvLetterCount.text = progress.toString()
smallLetters = progress
}
sbNumberOfCapitalLetters ->
{
tvCapitalsCount.text = progress.toString()
capitalLetterNumber = progress
}
sbNumberOfNumerals ->
{
tvNumeralsCount.text = progress.toString()
numeralsNumber = progress
}
sbNumberOfSpecialChars ->
{
tvSpecialCharsCount.text = progress.toString()
specialCharNumber = progress
}
}
}
}
private fun generatePassword() {
for (y in 1..numeralsNumber)
{
var randomLetter = Random.nextInt(0, 9)
listOfLetters.add(chars[randomLetter].toString())
}
for (w in 1..smallLetters)
{
var randomLetter = Random.nextInt(10, 36)
listOfLetters.add(chars[randomLetter].toString())
}
for (x in 1..capitalLetterNumber)
{
var randomLetter = Random.nextInt(36, 62)
listOfLetters.add(chars[randomLetter].toString())
}
for (z in 1..specialCharNumber)
{
var randomLetter = Random.nextInt(63, 73)
listOfLetters.add(chars[randomLetter].toString())
}
password = (listOfLetters.joinToString(separator = "",)).toCharArray().shuffle().toString()
tvGeneratedPassword.text = password
listOfLetters.clear()
}
shuffle returns Unit, so calling toString() on Unit will return kotlin.Unit which is defined in Unit. Try this:
listOfLetters.shuffle()
val password = listOfLetters.joinToString(separator = "")
tvGeneratedPassword.text = password
Might as well use the tools that Kotlin provides to write expressive and maintainable code ( are the indexes for Random.nextInt in the code you provided correct? ) . Here is one alternative (here lists and not arrays are used and shuffled() returns a new list ) :
abstract sealed class RandomChars {
open val chars: CharArray = charArrayOf()
fun get(count: Int) = (1..count).map { chars[Random.nextInt(0, chars.size)] }
}
object RandomDigits : RandomChars() {
override val chars = "0123456789".toCharArray()
}
object RandomLowerCase : RandomChars() {
override val chars = "abcdefghijklmnopqrstuvwxyz".toCharArray()
}
object RandomUpperCase : RandomChars() {
override val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()
}
object RandomSpecial : RandomChars() {
override val chars = "~##$%^&*()!".toCharArray()
}
fun main() {
val password =
(RandomDigits.get(1) + RandomLowerCase.get(2) + RandomUpperCase.get(2) + RandomSpecial.get(1))
.shuffled()
.joinToString(separator = "")
println(password) // e.g. %Oa7Mt
}
Here is another, more functional approach:
val charGenerator =
{ alphabet: CharArray -> { count: Int -> (1..count).map { alphabet[Random.nextInt(0, alphabet.size)] } } }
val randomDigits = charGenerator("0123456789".toCharArray())
val randomLowecase = charGenerator("abcdefghijklmnopqrstuvwxyz".toCharArray())
val randomUppercase = charGenerator("ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray())
val randomSpecial = charGenerator("~##$%^&*()!".toCharArray())
fun main() {
val password =
(randomDigits(1) + randomLowecase(2) + randomUppercase(2) + randomSpecial(1))
.shuffled()
.joinToString(separator = "")
println(password) // e.g. %Oa7Mt
}

Get the returned list from firestore based on condition when a value is passed to firestore function

I am trying to return a list from inside firestore function based on if a condition is true.I want to return different lists when different categories are selected.
I tried:
putting the return statement out of firestore function which did not work and returned empty list due to firestore async behaviour.
creating my own callback to wait for Firestore to return the data using interface as I saw in some other questions but in that case how am i supposed to access it as my function has a Int value(i.e.private fun getRandomPeople(num: Int): List<String>)?
What could be the way of returning different lists for different categories based on firestore conditions?
My code(Non Activity class):
class Board// Create new game
(private val context: Context, private val board: GridLayout) {
fun newBoard(size: Int) {
val squares = size * size
val people = getRandomPeople(squares)
createBoard(context, board, size, people)
}
fun createBoard(context: Context, board: GridLayout, size: Int, people: List<String>) {
destroyBoard()
board.columnCount = size
board.rowCount = size
var iterator = 0
for(col in 1..size) {
for (row in 1..size) {
cell = RelativeLayout(context)
val cellSpec = { GridLayout.spec(GridLayout.UNDEFINED, GridLayout.FILL, 1f) }
val params = GridLayout.LayoutParams(cellSpec(), cellSpec())
params.width = 0
cell.layoutParams = params
cell.setBackgroundResource(R.drawable.bordered_rectangle)
cell.gravity = Gravity.CENTER
cell.setPadding(5, 0, 5, 0)
text = TextView(context)
text.text = people[iterator++]
words.add(text.text as String)
text.maxLines = 5
text.setSingleLine(false)
text.gravity = Gravity.CENTER
text.setTextColor(0xFF000000.toInt())
cell.addView(text)
board.addView(cell)
cells.add(GameCell(cell, text, false, row, col) { })
}
}
}
private fun getRandomPeople(num: Int): List<String> {
val mFirestore: FirebaseFirestore=FirebaseFirestore.getInstance()
val mAuth: FirebaseAuth=FirebaseAuth.getInstance()
val currentUser: FirebaseUser=mAuth.currentUser!!
var validIndexes :MutableList<Int>
var chosenIndexes = mutableListOf<Int>()
var randomPeople = mutableListOf<String>()
mFirestore.collection("Names").document(gName).get().addOnSuccessListener(OnSuccessListener<DocumentSnapshot>(){ queryDocumentSnapshot->
var categorySelected:String=""
if (queryDocumentSnapshot.exists()) {
categorySelected= queryDocumentSnapshot.getString("selectedCategory")!!
print("categoryselected is:$categorySelected")
Toast.makeText(context, "Got sel category from gameroom:$categorySelected", Toast.LENGTH_LONG).show()
when(categorySelected){
"CardWords"->{
for (i in 1..num) {
validIndexes=(0..CardWords.squares.lastIndex).toMutableList()
val validIndexIndex = (0..validIndexes.lastIndex).random()
val peopleIndex = validIndexes[validIndexIndex]
chosenIndexes.add(peopleIndex)
val person = CardWords.squares[peopleIndex]
randomPeople.add(person)
validIndexes.remove(peopleIndex)
peopleIndexes = chosenIndexes.toList()
}
}
else->{}
}
}
else {
Toast.makeText(context, "Sel category does not exist", Toast.LENGTH_LONG).show()
}
}).addOnFailureListener(OnFailureListener { e->
val error=e.message
Toast.makeText(context,"Error:"+error, Toast.LENGTH_LONG).show()
})
return randomPeople.toList()
}
}
Activity A:
Board(this, gridLay!!)

Categories

Resources