Fixing Some Kotlin Syntax - kotlin

I just finish built a simple android music app with Java, then I convert the java files to Kotlin with Kotlin plugin for Android Studio.
There are some error, in MainActivity.kt
private fun display() {
val mySongs = findSong(Environment.getExternalStorageDirectory())
items = arrayOf(mySongs.size.toString())
for (i in mySongs.indices) {
items[i] = mySongs[i].name.toString().replace(".mp3", "").replace(".wav", "")
}
val adp = ArrayAdapter(this, android.R.layout.simple_list_item_1, items!!)
listView!!.adapter = adp
listView!!.onItemClickListener = AdapterView.OnItemClickListener { adapterView, view, position, l -> startActivity(Intent(applicationContext, PlayerActivity::class.java).putExtra("pos", position).putExtra("songs", mySongs)) }
}
this line : items[i] = mySongs[i].name.toString().replace(".mp3","").replace(".wav", "")
showing an error: Smart cast to 'Array' is a mutable property that could have been changed by this time.
and on the PlayerActivity.kt
val i = intent
val b = i.extras
mySongs = b.getParcelableArrayList<Parcelable>(mySongs.toString())
position = b.getInt("pos", 0)
val u = Uri.parse(mySongs!![position].toString())
mediaPlayer = MediaPlayer.create(applicationContext, u)
the b.getParcelableArrayList<Parcelable>(mySongs.toString()) has a problem says Type mismatch.
Anyone can help me fix this? Thank You

This line
items = arrayOf(mySongs.size.toString())
creates an array of 1 element containing a string with the size of my songs. ex: ["23"]
You could use this instead: arrayOfNulls(mySongs.size)
For the other question:
mySongs = b.getParcelableArrayList<Parcelable>(mySongs.toString())
should return the same type as (I assume that it was the same code than in main activity because they are in 2 differents files and the context of mySongs is not provided)
val mySongs = findSong(Environment.getExternalStorageDirectory())
mySongs will have be the same type as the result of findSong.
Also you should use var instead of val because val are immutable

Related

How to use Lucene's DistinctValuesCollector?

My objective is to collect distinct values of select fields to provided them as filter options for the frontend. DistinctValuesCollector seems to be the tool for this, however since I haven't found code sample and documentation except for the Javadocs I can't currently correctly construct this collector. Can anyone provide an example?
This is my attempt which doesn't deliver the desired distinct values of the field PROJEKTSTATUS.name.
val groupSelector = TermGroupSelector(PROJEKTSTATUS.name)
val searchGroup = SearchGroup<BytesRef>()
val valueSelector = TermGroupSelector(PROJEKTSTATUS.name)
val groups = mutableListOf(searchGroup)
val distinctValuesCollector = DistinctValuesCollector(groupSelector, groups, valueSelector)
That field is indexed as follows:
document.add(TextField(PROJEKTSTATUS.name, aggregat.projektstatus, YES))
document.add(SortedDocValuesField(PROJEKTSTATUS.name, BytesRef(aggregat.projektstatus)))
Thanks to #andrewJames's hint to a test class I could figure it out:
fun IndexSearcher.collectFilterOptions(query: Query, field: String, topNGroups: Int = 128, mapper: Function<String?, String?> = Function { it }): Set<String?> {
val firstPassGroupingCollector = FirstPassGroupingCollector(TermGroupSelector(field), Sort(), topNGroups)
search(query, firstPassGroupingCollector)
val topGroups = firstPassGroupingCollector.getTopGroups(0)
val groupSelector = firstPassGroupingCollector.groupSelector
val distinctValuesCollector = DistinctValuesCollector(groupSelector, topGroups, groupSelector)
search(query, distinctValuesCollector)
return distinctValuesCollector.groups.map { mapper.apply(it.groupValue.utf8ToString()) }.toSet()
}

Why RTFEditorKit parser can not find new line?

I have a code which used javax.swing.text.rtf.RTFEditorKit
#Throws(IOException::class, BadLocationException::class)
fun readTextBlocks(`is`: InputStream?): List<TextBlock> {
val rtfParser = RTFEditorKit()
val document = rtfParser.createDefaultDocument()
rtfParser.read(`is`, document, 0)
var text = document.getText(0, document.length)
text = rtfDecoderText.decodeText(null, text)
val rootElement = document.defaultRootElement
val count = rootElement.elementCount
val blocks: MutableList<TextBlock> = ArrayList(count)
for (i in 0 until count) {
val block = TextBlock()
val childElement = rootElement.getElement(i)
if (childElement is BranchElement) {
val endOffset = childElement.getEndOffset()
if (endOffset >= text.length) {
continue
}
val substring = text.substring(childElement.getStartOffset(), endOffset)
val matchEntire = "(.*)\n".toRegex().matchEntire(substring)
and rtf text
Which produces following line (val substring )
Раздел VIIОценка соответствия объектов защиты (продукции) требованиям пожарной безопасности
I know for sure that this RTF document uses non standard spaces xA0 instead of x20 . Probably there is something wrong with new line codes and javax.swing.text.rtf.RTFEditorKit can't find them. I can see
VII\line
in the raw text. It should by "\par" instead as I understand. Could you help me to set up javax.swing.text.rtf.RTFEditorKit to parse such newlines?

How can I loop over an array of sets/maps with varying data types

I want to make it so that I keep my code dry and create 3 (or more, or less) buttons with somewhat the same structure. So I create a list of objects to loop over and put the data inside the object to use in several places in the AppButton.
I might think a bit too Pythonic, because that's my main language and I only recently started using Kotlin. What I normally do in Python:
app_buttons = [
dict(
text="....",
icon="....",
uri_string="....",
),
...
]
I've tried something similar in Kotlin with mapOf:
val appButtons = arrayOf(
mapOf(
"title" to getString(R.string.app_btn_example1),
"icon" to R.drawable.ic_some_icon_1_64,
"uriString" to "myapp://example1",
),
...
)
and then loop over them and getting from the map:
for (entry in appButtons) {
buttons.add(
AppButton(
entry.get("text"),
entry.get("icon"),
) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(entry.get("uriString"))).apply {
val name = getString(R.string.saved_account_key)
putExtra(name, sharedPref.getString(name, null))
}
startActivity(intent)
}
)
}
But then I get Type mismatch. Required String. Found {Comparable & java.io.Serializable}?. I don't know what types to put where...
Ok different approach, using setOf and destructuring:
val appButtons = arrayOf(
setOf(
getString(R.string.app_btn_example1),
R.drawable.ic_some_icon_1_64,
"myapp://example1",
),
...
)
for ((text, icon, uriString) in appButtons) {
buttons.add(
AppButton(
text,
icon
) {
...
}
)
}
But now I get the following:
Destructuring declaration initializer of type Set<{Comparable<*> & java.io.Serializable}> must have a 'component1()' function
Destructuring declaration initializer of type Set<{Comparable<*> & java.io.Serializable}> must have a 'component2()' function
Destructuring declaration initializer of type Set<{Comparable<*> & java.io.Serializable}> must have a 'component3()' function
How do I make this work? How do I create a basic list of objects and loop over them with the correct types? It feels so simple in Python. I'm clearly missing something.
Rather than using maps, you should create a data class. For example:
data class ButtonModel(
val title: String,
val icon: Int,
val uriString: String,
)
You can then create the array like this:
val appButtons = arrayOf(
ButtonModel(
title = getString(R.string.app_btn_example1),
icon = R.drawable.ic_some_icon_1_64,
uriString = "myapp://example1",
),
...
)
Or without the parameter labels if you prefer:
val appButtons = arrayOf(
ButtonModel(
getString(R.string.app_btn_example1),
R.drawable.ic_some_icon_1_64,
"myapp://example1",
),
...
)
Then, rather than getting them with get or [], you can just use the dot syntax:
buttons.add(
AppButton(
entry.text,
entry.icon,
) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(entry.uriString)).apply {
val name = getString(R.string.saved_account_key)
putExtra(name, sharedPref.getString(name, null))
}
startActivity(intent)
}
)

Why Can't I Say: val list = properties.map((key,value) -> "$key = $value")

In Kotlin I can say
//sweet
for ((key,value) in System.getProperties())
println("$key = $value")
but I cannot say
//sour
val properties = System.getProperties()
val list = properties.map((key,value) -> "$key = $value")
What is the Kotlin equivalent to properties.map{case (key, value) => s"$key = $value"} in Scala?
In Kotlin 1.0 you can say:
val properties = System.getProperties()
val list = properties.map { "${it.key} = ${it.value}" }
And if you prefer to unpack the map entries to separate values you can say:
val properties = System.getProperties()
val list = properties.map { val (key, value) = it; "$key = $value" }
In Kotlin 1.1 "you can now use the destructuring declaration syntax to unpack the arguments passed to a lambda" (What's New in Kotlin 1.1 - Kotlin Programming Language):
val properties = System.getProperties()
val list = properties.map { (key,value) -> "$key = $value" }
Your question has absolutely nothing with inference.
In scala you doc:
import collection.JavaConversions._
val properties = System.getProperties()
val list = properties.map{case (key,value) => s"$key = $value"}
As for your comments.
Having gone from years of Scala, to now exploring Kotlin, I tend to like Kotlin better in its power and simplicity, however, it would be nice to be able to infer things better, given that I am still in learning mode.
The issues in your code have nothing to do with type inference. Not even the syntax was right.
Please correct your syntax for lambda expressions and unpacking:
val properties = mapOf(1 to "First", 2 to "Second")
val list = properties.map {val (value, key) = it; "$key = $value"}
There is a Kotlin feature that is planned but will not be available in 1.0 which will allow writing {(key,value) -> "$key = $value"} to unpack a value type like a Pair – cypressious
Thanks #cypressious that was exactly what I was hoping for. Basically the answer is that Kotlin is still evolving and people are still getting around to polishing off cool stuff.
For now I have found that
//savory
val properties = System.getProperties()
val list = properties.map {property -> "${property.key} = ${property.value}"}
comes pretty close.

ReactiveMongo : How to write macros handler to Enumeration object?

I use ReactiveMongo 0.10.0, and I have following user case class and gender Enumeration object:
case class User(
_id: Option[BSONObjectID] = None,
name: String,
gender: Option[Gender.Gender] = None)
object Gender extends Enumeration {
type Gender = Value
val MALE = Value("male")
val FEMALE = Value("female")
val BOTH = Value("both")
}
And I declare two implicit macros handler:
implicit val genderHandler = Macros.handler[Gender.Gender]
implicit val userHandler = Macros.handler[User]
but, when I run application, I get following error:
Error:(123, 48) No apply function found for reactive.userservice.Gender.Gender
implicit val genderHandler = Macros.handler[Gender.Gender]
^
Error:(125, 46) Implicit reactive.userservice.Gender.Gender for 'value gender' not found
implicit val userHandler = Macros.handler[User]
^
Anybody know how to write macros handler to Enumeration object?
Thanks in advance!
I stumbled upon your question a few times searching for the same answer. I did it this way:
import myproject.utils.EnumUtils
import play.api.libs.json.{Reads, Writes}
import reactivemongo.bson._
object DBExecutionStatus extends Enumeration {
type DBExecutionStatus = Value
val Error = Value("Error")
val Started = Value("Success")
val Created = Value("Running")
implicit val enumReads: Reads[DBExecutionStatus] = EnumUtils.enumReads(DBExecutionStatus)
implicit def enumWrites: Writes[DBExecutionStatus] = EnumUtils.enumWrites
implicit object BSONEnumHandler extends BSONHandler[BSONString, DBExecutionStatus] {
def read(doc: BSONString) = DBExecutionStatus.Value(doc.value)
def write(stats: DBExecutionStatus) = BSON.write(stats.toString)
}
}
You have to create a read/write pair by hand and populate with your values.
Hope you already solved this issue given the question age :D