Skip to content
5 changes: 5 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ android {

dependencies {
def ktx_version = "2.0.0"
def kotlin_coroutines_version = "1.0.1"

implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
Expand All @@ -39,6 +40,10 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$ktx_version"
implementation project (':ktandroidarchitecturecore')
testImplementation 'junit:junit:4.12'

implementation 'androidx.paging:paging-runtime-ktx:2.1.0'

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}
Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/com/sysdata/kt/ktandroidarchitecture/DIUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.sysdata.kt.ktandroidarchitecture

import com.sysdata.kt.ktandroidarchitecture.ui.Note
import it.sysdata.ktandroidarchitecturecore.interactor.Channel

class DIUtils {

private object Holder {
val INSTANCE = Channel<Note>()
}

companion object {
val channel: Channel<Note> by lazy {
Holder.INSTANCE
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package com.sysdata.kt.ktandroidarchitecture.ui

import android.app.Activity
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import android.os.Bundle

import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModelProviders
import androidx.paging.PagedList
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.sysdata.kt.ktandroidarchitecture.R
import com.sysdata.kt.ktandroidarchitecture.repository.model.UIUserLogged
import com.sysdata.kt.ktandroidarchitecture.repository.model.UserLogged
import com.sysdata.kt.ktandroidarchitecture.usecase.LoginActionParams
import com.sysdata.kt.ktandroidarchitecture.viewmodel.LoginViewModel
import it.sysdata.ktandroidarchitecturecore.exception.Failure
Expand All @@ -20,6 +21,7 @@ import kotlinx.android.synthetic.main.activity_login.*
class LoginActivity : FragmentActivity(), View.OnClickListener, TextWatcher {

private var viewModel : LoginViewModel? = null
private var adapter: PagedListAdapterImpl? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -37,6 +39,28 @@ class LoginActivity : FragmentActivity(), View.OnClickListener, TextWatcher {

viewModel?.actionLogin?.observe(this, ::onUserLoggged)
viewModel?.actionLogin?.observeFailure(this, ::onLoginFailed)

viewModel?.channelNotes?.initDatasource(pageSize = 10)

adapter = PagedListAdapterImpl {
viewModel?.channelPostNotes?.postData(it)
}

recycler_view.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
recycler_view.adapter = adapter

viewModel?.channelNotes?.observe(this,::onPostNote)
viewModel?.channelPostNotes?.observe(this, ::onReceivePost)
}

private fun onReceivePost(note: Note?) {
Toast.makeText(this, "note : $note", Toast.LENGTH_SHORT).show()
}

private fun onPostNote(list: PagedList<Note>?) {
list?.let {
adapter?.submitList(list)
}
}

private fun onLoginFailed(failure: Failure?) {
Expand Down
18 changes: 18 additions & 0 deletions app/src/main/java/com/sysdata/kt/ktandroidarchitecture/ui/Note.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.sysdata.kt.ktandroidarchitecture.ui

import androidx.recyclerview.widget.DiffUtil
import java.util.*

data class Note(val index:Int, val noteId: String = UUID.randomUUID().toString()) {
companion object {
val DiffCallback = object : DiffUtil.ItemCallback<Note>() {
override fun areItemsTheSame(oldItem: Note, newItem: Note): Boolean
= oldItem.noteId == newItem.noteId

override fun areContentsTheSame(oldItem: Note, newItem: Note): Boolean
= oldItem.noteId == newItem.noteId && oldItem.title == newItem.title && oldItem.content == newItem.content
}
}
var title: String = ""
var content: String = ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.sysdata.kt.ktandroidarchitecture.ui

import it.sysdata.ktandroidarchitecturecore.BasePositionalDatasource

class NoteDataSource: BasePositionalDatasource<Note>()
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.sysdata.kt.ktandroidarchitecture.ui

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.sysdata.kt.ktandroidarchitecture.R

class PagedListAdapterImpl(val onClick: (Note) -> Unit) : PagedListAdapter<Note, PagedListAdapterImpl.ListItemViewHolder>(Note.DiffCallback) {
class ListItemViewHolder(val view: View): RecyclerView.ViewHolder(view) {
var note: Note? = null
set(value) {
if(value != null){
val tv: TextView = view.findViewById(R.id.itemText)
tv.text = value.toString()
}
field = value
}
}

companion object {
private val TAG = this::class.java.simpleName
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListItemViewHolder
= ListItemViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.note_list_item, parent, false))

override fun onBindViewHolder(holder: ListItemViewHolder, position: Int) {
Log.d(TAG, "Binding view holder at position $position")
holder.note = getItem(position)
holder.view.setOnClickListener { onClick(holder.note!!) }
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.sysdata.kt.ktandroidarchitecture.ui

import androidx.paging.ItemKeyedDataSource

class TestDataSource: ItemKeyedDataSource<Int, Note>(){

private val datas = listOf(Note(1), Note(2), Note(3), Note(4), Note(5))

override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Note>) {
val requestedLoadSize = params.requestedLoadSize
val requestedInitialKey = params.requestedInitialKey ?: 0

val initItem = datas.firstOrNull { it.index == requestedInitialKey }
val initIndex = initItem?.let {datas.indexOf(initItem)} ?: 0
val newData = getSubList(initIndex, initIndex + requestedLoadSize)
callback.onResult(newData)
}

private fun getSubList(initIndex: Int, finalIndex: Int): MutableList<Note> {
val newData = mutableListOf<Note>()
for (i in initIndex until finalIndex) {
newData.add(datas[i % datas.size])
}
return newData
}

override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Note>) {
val key = params.key
val requestedLoadSize = params.requestedLoadSize

val initItem = datas.firstOrNull { it.index == key }
val initIndex = initItem?.let {datas.indexOf(initItem)} ?: 0
val newData = getSubList(initIndex, initIndex + requestedLoadSize)
callback.onResult(newData)
}

override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Note>) {
val key = params.key
val requestedLoadSize = params.requestedLoadSize

val initItem = datas.firstOrNull { it.index == key }
var initIndex = initItem?.let {datas.indexOf(initItem)} ?: 0
var finalIndex = initIndex
if(initIndex - requestedLoadSize >= 0){
initIndex -= requestedLoadSize
} else {
initIndex = 0
finalIndex = initIndex + requestedLoadSize
}
val newData = getSubList(initIndex, finalIndex)
callback.onResult(newData)
}

override fun getKey(item: Note): Int {
return item.index
}

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
package com.sysdata.kt.ktandroidarchitecture.viewmodel

import com.sysdata.kt.ktandroidarchitecture.DIUtils
import com.sysdata.kt.ktandroidarchitecture.repository.model.UIUserLogged
import com.sysdata.kt.ktandroidarchitecture.repository.model.UserLogged
import com.sysdata.kt.ktandroidarchitecture.ui.Note
import com.sysdata.kt.ktandroidarchitecture.ui.NoteDataSource
import com.sysdata.kt.ktandroidarchitecture.ui.TestDataSource
import com.sysdata.kt.ktandroidarchitecture.usecase.LoginActionParams
import com.sysdata.kt.ktandroidarchitecture.usecase.LoginUseCase
import it.sysdata.ktandroidarchitecturecore.interactor.Action
import it.sysdata.ktandroidarchitecturecore.interactor.*
import it.sysdata.ktandroidarchitecturecore.platform.BaseViewModel

class LoginViewModel: BaseViewModel() {

val actionLogin = Action.Builder<LoginActionParams,UserLogged, UIUserLogged>()
.useCase(LoginUseCase::class.java)
.buildWithUiModel { UIUserLogged(it.username) }

val channelNotes = DataSourceChannel.Builder<Int, Note>()
.dataSource(TestDataSource::class.java)
.build()

val channelPostNotes = DIUtils.channel
}
10 changes: 9 additions & 1 deletion app/src/main/res/layout/activity_login.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:padding="50dp"
Expand Down Expand Up @@ -40,4 +42,10 @@
android:layout_marginTop="10dp"
android:background="@android:drawable/btn_default" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/note_list_item" />

</LinearLayout>
15 changes: 15 additions & 0 deletions app/src/main/res/layout/note_list_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/itemText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:padding="8dp"
android:textColor="#000"
/>

</LinearLayout>
1 change: 1 addition & 0 deletions ktandroidarchitecturecore/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.paging:paging-runtime-ktx:2.1.0'
}

repositories {
Expand Down
Loading