Introduce epoxy in demo app
This commit is contained in:
parent
e323c858ab
commit
06a5253fd9
Binary file not shown.
|
@ -1,6 +1,11 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
kapt {
|
||||
correctErrorTypes = true
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
@ -20,7 +25,20 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
configurations.all { strategy ->
|
||||
strategy.resolutionStrategy.eachDependency { details ->
|
||||
if (details.requested.group == 'com.android.support') {
|
||||
details.useVersion "28.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
def epoxy_version = "2.19.0"
|
||||
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation project(":matrix-sdk-android")
|
||||
|
||||
|
@ -30,6 +48,9 @@ dependencies {
|
|||
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
|
||||
implementation("com.airbnb.android:epoxy:$epoxy_version")
|
||||
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
|
||||
|
||||
implementation "org.koin:koin-android:$koin_version"
|
||||
implementation "org.koin:koin-android-scope:$koin_version"
|
||||
implementation "org.koin:koin-android-viewmodel:$koin_version"
|
||||
|
@ -38,3 +59,5 @@ dependencies {
|
|||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package im.vector.riotredesign.core.helpers
|
||||
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.EpoxyHolder
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* A pattern for easier view binding with an [EpoxyHolder]
|
||||
*
|
||||
* See [SampleKotlinModelWithHolder] for a usage example.
|
||||
*/
|
||||
abstract class KotlinEpoxyHolder : EpoxyHolder() {
|
||||
private lateinit var view: View
|
||||
|
||||
override fun bindView(itemView: View) {
|
||||
view = itemView
|
||||
}
|
||||
|
||||
protected fun <V : View> bind(id: Int): ReadOnlyProperty<KotlinEpoxyHolder, V> =
|
||||
Lazy { holder: KotlinEpoxyHolder, prop ->
|
||||
holder.view.findViewById(id) as V?
|
||||
?: throw IllegalStateException("View ID $id for '${prop.name}' not found.")
|
||||
}
|
||||
|
||||
/**
|
||||
* Taken from Kotterknife.
|
||||
* https://github.com/JakeWharton/kotterknife
|
||||
*/
|
||||
private class Lazy<V>(
|
||||
private val initializer: (KotlinEpoxyHolder, KProperty<*>) -> V
|
||||
) : ReadOnlyProperty<KotlinEpoxyHolder, V> {
|
||||
private object EMPTY
|
||||
|
||||
private var value: Any? = EMPTY
|
||||
|
||||
override fun getValue(thisRef: KotlinEpoxyHolder, property: KProperty<*>): V {
|
||||
if (value == EMPTY) {
|
||||
value = initializer(thisRef, property)
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return value as V
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package im.vector.riotredesign.core.helpers
|
||||
|
||||
import android.support.annotation.IdRes
|
||||
import android.support.annotation.LayoutRes
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.EpoxyModel
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
abstract class KotlinModel(
|
||||
@LayoutRes private val layoutRes: Int
|
||||
) : EpoxyModel<View>() {
|
||||
|
||||
private var view: View? = null
|
||||
|
||||
abstract fun bind()
|
||||
|
||||
override fun bind(view: View) {
|
||||
this.view = view
|
||||
bind()
|
||||
}
|
||||
|
||||
override fun unbind(view: View) {
|
||||
this.view = null
|
||||
}
|
||||
|
||||
override fun getDefaultLayout() = layoutRes
|
||||
|
||||
protected fun <V : View> bind(@IdRes id: Int) = object : ReadOnlyProperty<KotlinModel, V> {
|
||||
override fun getValue(thisRef: KotlinModel, property: KProperty<*>): V {
|
||||
// This is not efficient because it looks up the view by id every time (it loses
|
||||
// the pattern of a "holder" to cache that look up). But it is simple to use and could
|
||||
// be optimized with a map
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return view?.findViewById(id) as V?
|
||||
?: throw IllegalStateException("View ID $id for '${property.name}' not found.")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,5 +2,5 @@ package im.vector.riotredesign.core.platform
|
|||
|
||||
import android.support.v4.app.Fragment
|
||||
|
||||
class RiotFragment : Fragment() {
|
||||
open class RiotFragment : Fragment() {
|
||||
}
|
|
@ -1,31 +1,24 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import android.arch.lifecycle.Observer
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.RiotActivity
|
||||
import org.koin.android.ext.android.inject
|
||||
import timber.log.Timber
|
||||
|
||||
|
||||
class HomeActivity : RiotActivity() {
|
||||
|
||||
private val matrix by inject<Matrix>()
|
||||
private val currentSession = matrix.currentSession!!
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_home)
|
||||
currentSession.rooms().observe(this, Observer<List<Room>> { roomList ->
|
||||
if (roomList == null) {
|
||||
return@Observer
|
||||
}
|
||||
Timber.v("Observe rooms: %d", roomList.size)
|
||||
})
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
val roomListFragment = RoomListFragment.newInstance()
|
||||
val ft = supportFragmentManager.beginTransaction()
|
||||
ft.replace(R.id.homeFragmentContainer, roomListFragment)
|
||||
ft.commit()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
|
||||
class RoomController(private val callback: Callback? = null) : TypedEpoxyController<List<Room>>() {
|
||||
|
||||
override fun buildModels(data: List<Room>?) {
|
||||
data?.forEach {
|
||||
RoomItem(it.roomId, listener = { callback?.onRoomSelected(it) })
|
||||
.id(it.roomId)
|
||||
.addTo(this)
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onRoomSelected(room: Room)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import android.widget.TextView
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.helpers.KotlinModel
|
||||
|
||||
data class RoomItem(
|
||||
val title: String,
|
||||
val listener: (() -> Unit)? = null
|
||||
) : KotlinModel(R.layout.item_room) {
|
||||
|
||||
val titleView by bind<TextView>(R.id.titleView)
|
||||
|
||||
override fun bind() {
|
||||
titleView.setOnClickListener { listener?.invoke() }
|
||||
titleView.text = title
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import android.arch.lifecycle.Observer
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.RiotFragment
|
||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class RoomListFragment : RiotFragment(), RoomController.Callback {
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): RoomListFragment {
|
||||
return RoomListFragment()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val matrix by inject<Matrix>()
|
||||
private val currentSession = matrix.currentSession!!
|
||||
private val roomController = RoomController(this)
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_room_list, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
epoxyRecyclerView.setController(roomController)
|
||||
currentSession.rooms().observe(this, Observer<List<Room>> { renderRooms(it) })
|
||||
}
|
||||
|
||||
private fun renderRooms(rooms: List<Room>?) {
|
||||
roomController.setData(rooms)
|
||||
}
|
||||
|
||||
override fun onRoomSelected(room: Room) {
|
||||
Toast.makeText(context, "Room ${room.roomId} clicked", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,40 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".features.login.LoginActivity">
|
||||
|
||||
<Button
|
||||
android:id="@+id/startSyncButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Start sync"
|
||||
app:layout_constraintBottom_toTopOf="@+id/stopSyncButton"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/stopSyncButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="stop sync"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/startSyncButton" />
|
||||
<FrameLayout
|
||||
android:id="@+id/homeFragmentContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||
android:id="@+id/epoxyRecyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</FrameLayout>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/titleView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp"
|
||||
android:textSize="14sp"
|
||||
tools:text="Room name" />
|
Loading…
Reference in New Issue