Open wbinarytree opened 6 years ago
I'm open to the idea of better Kotlin support, was thinking about it today ... but I'm not convinced making Items on the fly is a major use case for Groupie. In fact, I wrote it to encourage code reuse.
Do you normally make one-off Items like this? I never have ...
I totally understand that using a subclass of Item can reduce the boilerplate code to spamming Layout ID and other stuff every where. But for each item/type I need to create a new Class feels just another kind of boilerplate code for me.
There is a middle point of those 2 things. That is introducing annotation processor to generate those code and even for DSL style support. (That what exactly Epoxy did.) But it's a huge change of API which I don't really think you or even other user can accept including me.
Sorry For My Bad English. Hope you understand my words :smiley:
Your English is great! There are probably lots of ways I could make this less verbose in Kotlin. In particular, passing the layoutId in the Item constructor is a great idea.
I haven't spent much time looking at Kotlin support past an update to support the basics last year, but now I'm writing it regularly it's probably time to have a closer look!
I thought about this over the weekend and I changed my mind. I think you're totally right. And it would be useful for creating reusable Items too. :)
Great! Looking forward to those enhancements.
I like this idea as well. This would be helpful for me if I could create the GroupAdapter object and each of the sections I need ahead of time.
Are you actively or planning on working on this one, Lisa? I wouldn't mind giving this a shot if I have time this week, but only if you don't mind.
I'd love help on anything here! PRs welcomed :)
@wbinarytree thanks a lot for bringing me to the world of DSL. Didn't have any clue this existed. @TylerMcCraw a small working sample I created here.
@khatv911 If you already have a working sample, go for it. I'm in Portugal this week so I'm not going to touch a computer until I get back 😁
I don't feel like DSL works very well for this use case. It seems to be mostly useful for optional configuration, as you can not ensure that a function is given. Thus we can't ensure that an item gets a layout and a binder. Fell over this as I am writing my own library for handling RecyclerView.
Constructing a list of headers that expand to show children looks like this, adapted from @khatv911's code.
val expandables = groupData.rooms.asSequence().map { roomData ->
ExpandableGroup(
header = HeaderItem(
title = roomData.name,
subtitle = "%d".format(roomData.jobs.count())),
content = CompoundGroup(roomData.jobs.asSequence().map { jobData ->
GenericItem(
layout = R.layout.view_item_text_1,
binder = { viewHolder, payloads ->
with(viewHolder.itemView) {
tv_item_name.text = jobData.name
editText.text = jobData.id
}
})
})
).apply { expand() }
}
with(recyclerView) {
setHasFixedSize(true)
addItemDecoration(DividerItemDecoration(context, VERTICAL))
layoutManager = LinearLayoutManager(context)
adapter = GroupAdapter(CompoundGroup(expandables))
}
I am unsure how we would, for my case, or Groupie's, be able to use DSL in a secure way. As we are dependent on some arguments being passed. And item needs a layout and a binder, it makes sense to require this on a type level.
Is there a way to ensure that a function is called when using DSL?
I ended up quite liking this idea. What I have decided to do, in case groupie wants to implement similar, is to show a default item in case a setter method isn't called. As with the header of an expandable group.
I use group to open up a basic group builder which returns a single group.
I realize that I often display lists of data, so I created a method to allow us to map over a list, with the GroupBuilder.
fun <T> map(data: List<T>, init: GroupBuilder.(T) -> Unit): CompoundGroup
One of my issues has been calling methods on your parent, as with expanding a group upon touch of the header.
With the below implementation it becomes simple to get the parent instance: this@expandable.instance
I do this by having a public field which is set the moment the build method is called on the builder.
override fun build() = CompoundGroup(groups).also { _instance = it }
val foo = group {
map((0 until 10).toList()) { parentIndex ->
expandable {
header(R.layout.header) {
bind { viewHolder, _ ->
viewHolder.itemView.findViewById<TextView>(R.id.textView).text = "Parent #$parentIndex"
}
onClick {
this@expandable.instance.toggle()
}
}
content {
map((0 until 3).toList()) {
item(R.layout.item) {
bind { viewHolder, _ ->
viewHolder.itemView.findViewById<TextView>(R.id.textView).text =
"Child #$it of parent #$parentIndex"
}
}
}
}
}
}
}
Hi, Thanks for this great library. When using with kotlin, I feel it's a bit boilerplate can be remove by using kotlin DSL and Lambda feature. For example a GenericItem:
By that way I can just use a GenericItem without creating a new subclass of Item.
Even more with kotlin DSL style support. We can easily build a DSL style List for RecyclerView For example :