浏览代码

Refactoring of common adapter

sirekanyan 8 年之前
父节点
当前提交
447e8a38e9

+ 2 - 2
app/src/main/java/me/vadik/knigopis/MainActivity.kt

@@ -34,8 +34,8 @@ class MainActivity : AppCompatActivity() {
         getSharedPreferences("knigopis", MODE_PRIVATE)
     )
   }
-  private val finishedBooksAdapter by lazy { booksAdapter.create(finishedBooks) }
-  private val plannedBooksAdapter by lazy { booksAdapter.create(plannedBooks) }
+  private val finishedBooksAdapter by lazy { booksAdapter.build(finishedBooks) }
+  private val plannedBooksAdapter by lazy { booksAdapter.build(plannedBooks) }
   private lateinit var usersView: RecyclerView
   private lateinit var finishedBooksView: RecyclerView
   private lateinit var plannedBooksView: RecyclerView

+ 43 - 0
app/src/main/java/me/vadik/knigopis/adapters/Adapter.kt

@@ -0,0 +1,43 @@
+package me.vadik.knigopis.adapters
+
+import android.support.annotation.IdRes
+import android.support.annotation.LayoutRes
+import android.support.v7.widget.RecyclerView
+import android.view.View
+import android.view.ViewGroup
+import me.vadik.knigopis.inflate
+
+class Adapter<T>(
+    private val items: List<T>,
+    @LayoutRes private val itemLayout: Int
+) {
+
+  val binders = mutableMapOf<@IdRes Int, (View, T) -> Unit>()
+
+  inline fun <reified V : View> bind(@IdRes id: Int, crossinline binder: V.(T) -> Unit): Adapter<T> {
+    binders[id] = { view, model ->
+      binder(view as V, model)
+    }
+    return this
+  }
+
+  fun build() = object : RecyclerView.Adapter<ViewsHolder>() {
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
+        parent.inflate(itemLayout).let { rootView ->
+          ViewsHolder(rootView, binders.mapValues { (key, _) ->
+            rootView.findViewById<View>(key)
+          })
+        }
+
+    override fun onBindViewHolder(holder: ViewsHolder, position: Int) =
+        binders.forEach { (id, binder) ->
+          holder.views[id]?.let { view ->
+            binder(view, items[position])
+          }
+        }
+
+    override fun getItemCount() = items.size
+  }
+}
+
+class ViewsHolder(rootView: View, val views: Map<Int, View>) : RecyclerView.ViewHolder(rootView)

+ 15 - 14
app/src/main/java/me/vadik/knigopis/adapters/BooksAdapter.kt

@@ -1,7 +1,6 @@
 package me.vadik.knigopis.adapters
 
 import android.content.SharedPreferences
-import android.view.View
 import android.widget.ImageView
 import android.widget.TextView
 import com.bumptech.glide.Glide
@@ -19,14 +18,18 @@ class BooksAdapter(
     private val preferences: SharedPreferences
 ) {
 
-  fun create(books: List<Book>) = createAdapter<Book, View>(
-      books,
-      R.layout.book,
-      Adapter(R.id.book_image) { book ->
+  fun build(books: List<Book>) = Adapter(books, R.layout.book)
+      .bind<ImageView>(R.id.book_image) { book ->
         val cachedUrl = preferences.getString("book${book.id}", null)
         Single.defer {
           if (cachedUrl == null) {
-            imageEndpoint.searchImage("${book.title} ${book.author}")
+            val titleWordsCount = book.title.split(" ").size
+            val searchQuery = if (titleWordsCount < 2) {
+              "${book.title} ${book.author}"
+            } else {
+              book.title
+            }
+            imageEndpoint.searchImage(searchQuery)
                 .delay((Math.random() * 3000).toLong(), TimeUnit.MICROSECONDS)
                 .map { thumbnail ->
                   ("https:" + thumbnail.url).also {
@@ -41,22 +44,20 @@ class BooksAdapter(
               Glide.with(context)
                   .load(thumbnailUrl)
                   .apply(RequestOptions.circleCropTransform())
-                  .into(this as ImageView)
+                  .into(this)
             }, {
               logError("cannot load thumbnail", it)
             })
-      },
-      Adapter(R.id.book_title) {
-        this as TextView
+      }
+      .bind<TextView>(R.id.book_title) {
         text = it.title
-      },
-      Adapter(R.id.book_author) {
-        this as TextView
+      }
+      .bind<TextView>(R.id.book_author) {
         text = if (it.author.isEmpty()) {
           "(автор не указан)"
         } else {
           it.author
         }
       }
-  )
+      .build()
 }

+ 6 - 6
app/src/main/java/me/vadik/knigopis/adapters/UsersAdapter.kt

@@ -5,13 +5,13 @@ import me.vadik.knigopis.R
 import me.vadik.knigopis.model.User
 
 object UsersAdapter {
-  fun create(users: List<User>) = createAdapter<User, TextView>(
-      users,
-      R.layout.user,
-      Adapter(R.id.user_name) { text = it.nickname },
-      Adapter(R.id.book_count) {
+  fun create(users: List<User>) = Adapter(users, R.layout.user)
+      .bind<TextView>(R.id.user_name) {
+        text = it.nickname
+      }
+      .bind<TextView>(R.id.book_count) {
         text = it.booksCount.toString()
         setTextColor(it.color)
       }
-  )
+      .build()
 }

+ 0 - 33
app/src/main/java/me/vadik/knigopis/adapters/adapter.kt

@@ -1,33 +0,0 @@
-package me.vadik.knigopis.adapters
-
-import android.support.annotation.IdRes
-import android.support.annotation.LayoutRes
-import android.support.v7.widget.RecyclerView
-import android.view.View
-import android.view.ViewGroup
-import me.vadik.knigopis.inflate
-
-class Adapter<in T, in V : View>(@IdRes val id: Int, val bind: V.(T) -> Unit)
-
-class ViewHolder(rootView: View, val views: List<*>) : RecyclerView.ViewHolder(rootView)
-
-inline fun <T, reified V : View> createAdapter(
-    items: List<T>,
-    @LayoutRes itemLayout: Int,
-    vararg adapters: Adapter<T, V>
-) =
-    object : RecyclerView.Adapter<ViewHolder>() {
-      override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
-          parent.inflate(itemLayout).let { rootView ->
-            ViewHolder(rootView, adapters.map {
-              rootView.findViewById<View>(it.id) as V
-            })
-          }
-
-      override fun onBindViewHolder(holder: ViewHolder, position: Int) =
-          adapters.forEachIndexed { index, adapter ->
-            adapter.bind.invoke(holder.views[index] as V, items[position])
-          }
-
-      override fun getItemCount() = items.size
-    }