Skip to content

Commit

Permalink
Koin Dependency Injection, Navigation component
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Imperato committed Feb 24, 2021
1 parent 39c8467 commit accca81
Show file tree
Hide file tree
Showing 22 changed files with 316 additions and 53 deletions.
23 changes: 22 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'androidx.navigation.safeargs'
}

android {
Expand Down Expand Up @@ -53,10 +54,15 @@ android {
}

dependencies {
def room_version = "2.2.6"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
// def room_version = "2.2.6"
def room_version = "2.3.0-alpha01"

def lifecycle_version = "2.3.0"
def activity_version = "1.2.0"
def work_version = "2.5.0"
def nav_version = "2.3.3"
def koin_version = '2.2.2'

implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
Expand All @@ -81,7 +87,22 @@ dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"
//Navigation kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

// Koin
implementation "org.koin:koin-core:$koin_version"
// Koin for Android
implementation "org.koin:koin-android:$koin_version"
// Koin AndroidX Scope features
implementation "org.koin:koin-androidx-scope:$koin_version"
// Koin AndroidX ViewModel features
implementation "org.koin:koin-androidx-viewmodel:$koin_version"
// Koin AndroidX Experimental features
implementation "org.koin:koin-androidx-ext:$koin_version"
// Testing
testImplementation "org.koin:koin-test:$koin_version"

testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'com.google.truth:truth:1.1.2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import androidx.test.espresso.matcher.ViewMatchers.hasChildCount
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.macoev.roomsample.activity.MainActivity
import com.macoev.roomsample.adapter.UserViewHolder
import com.macoev.roomsample.data.repository.Repository
import org.hamcrest.Matcher
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name=".application.App"
android:theme="@style/Theme.RoomSample">
<activity android:name=".MainActivity">

<activity android:name=".activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand Down
12 changes: 0 additions & 12 deletions app/src/main/java/com/macoev/roomsample/RecyclerViewBindings.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
package com.macoev.roomsample
package com.macoev.roomsample.activity

import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.macoev.roomsample.R
import com.macoev.roomsample.databinding.ActivityMainBinding
import com.macoev.roomsample.viewmodel.UserViewModel
import com.macoev.roomsample.work.DownloadWork
import com.macoev.roomsample.work.RequestManager
import org.koin.androidx.viewmodel.ext.android.viewModel
import java.time.Duration

class MainActivity : AppCompatActivity() {

private val model: UserViewModel by viewModels()
private val model: UserViewModel by viewModel()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.viewModel = model

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
syncServer()
}
Expand All @@ -32,10 +32,15 @@ class MainActivity : AppCompatActivity() {
RequestManager(applicationContext).run {
periodic<DownloadWork>(interval = Duration.ofMinutes(15))
.onError {
Toast.makeText(this@MainActivity, "onError called", Toast.LENGTH_SHORT).show()
Toast.makeText(applicationContext, "onError called", Toast.LENGTH_SHORT).show()
}.onSuccess {
Toast.makeText(this@MainActivity, "onSuccess called", Toast.LENGTH_SHORT).show()
Toast.makeText(applicationContext, "onSuccess called", Toast.LENGTH_SHORT)
.show()
}
}
}

override fun onBackPressed() {
super.onBackPressed()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import com.macoev.roomsample.R
import com.macoev.roomsample.data.User
import com.macoev.roomsample.data.repository.Repository

class UserAdapter(val repository: Repository) : RecyclerView.Adapter<UserViewHolder>() {
class UserAdapter(val repository: Repository, val tap: (User) -> Unit) : RecyclerView.Adapter<UserViewHolder>() {

private var data: ArrayList<User> = arrayListOf()

Expand All @@ -31,13 +31,13 @@ class UserAdapter(val repository: Repository) : RecyclerView.Adapter<UserViewHol
val u = data[position]
holder.run {
fullName.text = u.fullName
delete.setOnClickListener {
repository.delete(u)
}
delete.setOnClickListener { repository.delete(u) }
itemView.setOnClickListener { tap(u) }
}
}

override fun getItemCount() = data.size

}

class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/com/macoev/roomsample/application/App.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.macoev.roomsample.application

import android.app.Application
import com.macoev.roomsample.viewmodel.UserViewModel
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import org.koin.dsl.module

class App : Application() {

override fun onCreate() {
super.onCreate()
startKoin {
androidLogger()
androidContext(this@App)
modules(listOf(viewModelModule))
}
}
}
val viewModelModule = module {
factory { UserViewModel( get()) }
}
4 changes: 2 additions & 2 deletions app/src/main/java/com/macoev/roomsample/data/AppDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ internal abstract class AppDatabase : RoomDatabase() {
override fun onOpen(db: SupportSQLiteDatabase) {
scope.launch {
INSTANCE?.userDao()?.run {
if (getAll().value?.isNullOrEmpty() == true) {
if (findAll().value?.isNullOrEmpty() == true) {
deleteAll()
for (i in 0..10) {
insertAll(User.createRandom())
insertOrUpdate(User.createRandom())
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/java/com/macoev/roomsample/data/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ data class User(@PrimaryKey(autoGenerate = true) val id: Int? = null, @ColumnInf
fullName = "Utente ${System.currentTimeMillis()}"
}
}

override fun toString(): String {
return "User(id=$id, fullName='$fullName')"
}

}
13 changes: 8 additions & 5 deletions app/src/main/java/com/macoev/roomsample/data/UserDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ import androidx.room.*
interface UserDao {

@Query("SELECT * FROM user")
fun getAll(): LiveData<List<User>>
fun findAll(): LiveData<List<User>>

@Query("SELECT * FROM user WHERE id IN (:userIds)")
fun loadAllByIds(userIds: IntArray): LiveData<List<User>>
fun findByIds(userIds: IntArray): LiveData<List<User>>

@Query("SELECT * FROM user WHERE full_name LIKE :fullName LIMIT 1")
fun findFirstByName(fullName: String): LiveData<User?>

@Query("SELECT * FROM user WHERE full_name LIKE :fullName")
fun findByName(fullName: String): LiveData<List<User>>
fun findAllByName(fullName: String): LiveData<List<User>>

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg users: User)
@Insert(onConflict = OnConflictStrategy.REPLACE) //AUTO GENERATED IDS WILL CHANGE WHEN ROWS GET REPLACED
fun insertOrUpdate(vararg users: User)

//@Update
//fun update(user: User)

@Delete
fun delete(user: User)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import kotlinx.coroutines.*
class UserRepository(private val dao: UserDao) : Repository {
private val scope = CoroutineScope(Job() + Dispatchers.IO)

override fun getAllUsers() = dao.getAll()
override fun getAllUsers() = dao.findAll()

override fun insert(vararg users: User) = scope.launch { dao.insertAll(*users) }
override fun insert(vararg users: User) = scope.launch { dao.insertOrUpdate(*users) }

override fun delete(user: User) = scope.launch { dao.delete(user) }

override fun findBy(name: String) = dao.findByName(name)
override fun findBy(name: String) = dao.findAllByName(name)

override fun findByIds(vararg ids: Int) = dao.loadAllByIds(ids)
override fun findByIds(vararg ids: Int) = dao.findByIds(ids)

override fun deleteAll() = runBlocking { dao.deleteAll() }
}
45 changes: 45 additions & 0 deletions app/src/main/java/com/macoev/roomsample/fragment/MainFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.macoev.roomsample.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.distinctUntilChanged
import androidx.navigation.fragment.findNavController
import com.macoev.roomsample.R
import com.macoev.roomsample.databinding.MainFragmentBinding
import com.macoev.roomsample.viewmodel.UserViewModel
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import org.koin.core.parameter.parametersOf

class MainFragment : Fragment() {

private var binding: MainFragmentBinding?=null
private val model: UserViewModel by sharedViewModel()

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = MainFragmentBinding.inflate(inflater, container, false)
return binding!!.root
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding!!.viewModel = model
model.selectedUser.distinctUntilChanged().observe(requireActivity(), {
it?.let {
findNavController().navigate(MainFragmentDirections.actionMainFragmentToUserDetailFragment())
}
})
}

companion object {
fun newInstance() = MainFragment()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.macoev.roomsample.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.macoev.roomsample.databinding.UserDetailFragmentBinding
import com.macoev.roomsample.viewmodel.UserViewModel
import org.koin.androidx.viewmodel.ext.android.sharedViewModel

class UserDetailFragment : Fragment() {

companion object {
fun newInstance() = UserDetailFragment()
}

private lateinit var binding: UserDetailFragmentBinding
private val viewModel: UserViewModel by sharedViewModel()
// private val args: UserDetailFragmentArguments by navArgs()

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = UserDetailFragmentBinding.inflate(inflater, container, false)
return binding.root
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding.viewModel = viewModel
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.macoev.roomsample.utils

import android.view.MotionEvent
import androidx.databinding.BindingAdapter
import androidx.recyclerview.widget.RecyclerView

object RecyclerViewBindings {
@JvmStatic
@BindingAdapter("adapter")
fun <VH : RecyclerView.ViewHolder> adapter(
recyclerView: RecyclerView,
adapter: RecyclerView.Adapter<VH>
) {
recyclerView.adapter = adapter
}

@JvmStatic
@BindingAdapter("itemTap")
fun itemTap(recyclerView: RecyclerView, click: (Int) -> Boolean) {
recyclerView.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() {
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
val child = recyclerView.findChildViewUnder(e.x, e.y)
child?.let {
val pos = rv.getChildAdapterPosition(it)
return click(pos)
}
return false
}

})
}
}
Loading

0 comments on commit accca81

Please sign in to comment.