Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
vantuan88291 committed Dec 15, 2019
0 parents commit 30cdb3e
Showing 97 changed files with 2,840 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
*.iml
.gradle
/local.properties
/.idea
.DS_Store
/build
/captures
.externalNativeBuild
.idea
app/release

38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# MVVM with databinding

Library: DI with koin, RXjava, room, mvvm, Rx retrofit

This app has a small example about chat with socket io using MVVM

## Explanation of folder structure

```
packagename
├── data
│   ├── local
│   │ ├──entity
│   │ ├──model
│   │ └──room
│   │
│   ├── remote
├── di
│   ├── AppModule.kt
├── utils
├── view
│ ├──activity
│ ├──adapter
│ ├──components
│ └──fragment
├── App.kt
├── BaseActivity.kt
├── BaseContract.kt
├── BaseFragment.kt
└── BaseView.kt
```


All lib in ```dependencies.gradle```


To use socket demo, clone project and setup node server: https://github.com/vantuan88291/SocketServer
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
77 changes: 77 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

apply plugin: 'kotlin-kapt'
apply from: rootProject.file("dependencies.gradle")
android {
kotlinOptions {
jvmTarget = "1.8"
}
compileSdkVersion versions.compile_sdk
defaultConfig {
applicationId versions.package
minSdkVersion versions.min_sdk
targetSdkVersion versions.compile_sdk
versionCode versions.publish_version_code
versionName versions.publish_version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation deps.support.kotlin
implementation deps.support.app_compat
implementation deps.support.core
implementation deps.support.material
implementation deps.support.constraint_layout
testImplementation deps.test.junit
androidTestImplementation deps.test.runner
androidTestImplementation deps.test.core
implementation deps.support.sdp
implementation deps.perfomance.multidex
implementation deps.perfomance.rxjava
implementation deps.perfomance.rxandroid
implementation deps.resful.converter
implementation deps.resful.rx_retrofit
implementation deps.resful.retrofit2
implementation deps.resful.logd
implementation deps.resful.logging
implementation deps.db.runtime
kapt deps.db.compiler
androidTestImplementation deps.db.test
implementation deps.lifecycler.extension
implementation deps.lifecycler.viewmodel
implementation deps.lifecycler.java8
implementation deps.resful.gson
kapt deps.support.databinding
implementation deps.di.koin
implementation deps.di.koin_androix
implementation deps.di.koin_viewmodel
implementation (deps.resful.socket){
exclude group: 'org.json', module: 'json'
}
implementation deps.webrtc
}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.tuan88291.mvvmpattern

import androidx.test.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
assertEquals("com.tuan88291.mvppatternkotlin", appContext.packageName)
}
}
30 changes: 30 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tuan88291.mvvmpattern">
<uses-permission android:name="android.permission.INTERNET"/>

<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<uses-library
android:name="org.apache.http.legacy"
android:required="false"/>
<activity
android:name=".view.activity.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>

<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>

</manifest>
44 changes: 44 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/App.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.tuan88291.mvvmpattern

import android.content.Context
import androidx.multidex.MultiDex
import androidx.multidex.MultiDexApplication
import com.google.gson.Gson
import com.tuan88291.mvvmpattern.di.RetrofitModule
import com.tuan88291.mvvmpattern.di.dbModule
import com.tuan88291.mvvmpattern.di.mvvmModule
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidFileProperties
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import org.koin.core.logger.Level

class App : MultiDexApplication() {
init {
instance = this
gSon = Gson()
}
override fun onCreate() {
super.onCreate()
MultiDex.install(this)
startKoin {
androidLogger(Level.DEBUG)
androidContext(this@App)
androidFileProperties()
modules(listOf(dbModule, mvvmModule, RetrofitModule))
}
}

companion object {
private var instance: App? = null
private var gSon: Gson? = null

fun applicationContext() : Context {
return instance!!.applicationContext
}
fun getGson() : Gson {
return gSon!!
}
}
}

41 changes: 41 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/BaseActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.tuan88291.mvvmpattern

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment

open class BaseActivity : AppCompatActivity(), BaseView {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}

override fun onDestroy() {
super.onDestroy()
}

override fun onResume() {
super.onResume()
}

override fun onStart() {
super.onStart()
}

protected fun addFragment(fragment: Fragment?) {
if (fragment != null) {
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.setCustomAnimations(
android.R.anim.fade_in,
android.R.anim.fade_out
)
fragmentTransaction.replace(R.id.contentHome, fragment)
fragmentTransaction.addToBackStack(fragment.javaClass.simpleName)
fragmentTransaction.commitAllowingStateLoss()
}
}

override fun setErrorParent(data: Any) {

}
}
7 changes: 7 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/BaseContract.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.tuan88291.mvvmpattern

interface BaseContract : BaseView {
fun onLoading()
fun onLoadComplete()
fun onError(mess: String)
}
49 changes: 49 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/BaseFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.tuan88291.mvvmpattern

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import com.tuan88291.mvvmpattern.view.activity.MainActivity

abstract class BaseFragment : Fragment(), BaseView {
private var context: MainActivity? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}

override fun setErrorParent(data: Any) {
AlertDialog.Builder(context!!)
.setTitle("Your Alert")
.setMessage(data.toString())
.setCancelable(false)
.setPositiveButton("ok") { dialog, which ->

}.show()
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return setView(inflater, container, savedInstanceState)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewCreated(view, savedInstanceState)

}

override fun onAttach(context: Context) {
super.onAttach(context)
this.context = context as MainActivity?
}

protected abstract fun setView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
protected abstract fun viewCreated(view: View, savedInstanceState: Bundle?)
protected fun mContext(): MainActivity? {
return this.context
}

}
5 changes: 5 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/BaseView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.tuan88291.mvvmpattern

interface BaseView {
fun setErrorParent(data: Any)
}
4 changes: 4 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/data/DataMain.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tuan88291.mvvmpattern.data

data class DataMain(val name: String, val age: Int) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.tuan88291.mvvmpattern.data.local.entity

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "user")
data class DataRoom( @ColumnInfo(name = "name") var Name: String = "", @ColumnInfo(name = "age") var Age: Int = 0) {
@ColumnInfo(name = "id")
@PrimaryKey(autoGenerate = true)
var mId: Long = 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.tuan88291.mvvmpattern.data.local.model

import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName

class CommonData<T: Any> {
@SerializedName("data")
@Expose
var data: T? = null
@SerializedName("status_code")
@Expose
var code: Int = 0
@SerializedName("message")
@Expose
lateinit var message: String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.tuan88291.mvvmpattern.data.local.model

import androidx.lifecycle.ViewModel

class Data : ViewModel() {
var example: String = ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.tuan88291.mvvmpattern.data.local.model

data class DataChat (var id: Int, var name: String, var content: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.tuan88291.mvvmpattern.data.local.model

import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName

class DataUser {
@SerializedName("data")
@Expose
var data: MutableList<DetailUser>? = null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.tuan88291.mvvmpattern.data.local.model

import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName

class DetailUser {
@SerializedName("id")
@Expose
var id: Int? = null
@SerializedName("email")
@Expose
var email: String? = null
@SerializedName("first_name")
@Expose
var firstName: String? = null
@SerializedName("last_name")
@Expose
var lastName: String? = null
@SerializedName("avatar")
@Expose
var avatar: String? = null

constructor(id: Int?, email: String?, firstName: String?, lastName: String?, avatar: String?) {
this.id = id
this.email = email
this.firstName = firstName
this.lastName = lastName
this.avatar = avatar
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tuan88291.mvvmpattern.data.local.room

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.tuan88291.mvvmpattern.data.local.entity.DataRoom

@Database(entities = [DataRoom::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {

abstract fun queries() : QueriesDao
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.tuan88291.mvvmpattern.data.local.room

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.tuan88291.mvvmpattern.data.local.entity.DataRoom
import io.reactivex.Completable

@Dao
interface QueriesDao {

@Query("select * from user ORDER BY id DESC")
fun getAll(): LiveData<MutableList<DataRoom>>

@Insert
fun insertData(item: DataRoom) : Completable

@Query("SELECT * FROM user where id = (SELECT MAX(id) FROM user) LIMIT 1")
fun getLast(): LiveData<DataRoom>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.tuan88291.mvvmpattern.data.local.room.livedata

import android.annotation.SuppressLint
import androidx.lifecycle.LiveData
import com.tuan88291.mvvmpattern.data.local.entity.DataRoom
import com.tuan88291.mvvmpattern.data.local.room.QueriesDao
import com.tuan88291.mvvmpattern.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@SuppressLint("CheckResult")
class DBRepository internal constructor(val mQueries: QueriesDao): iDBRepository {
override fun getAll(): LiveData<MutableList<DataRoom>> {
return mQueries.getAll()
}

override fun getLast(): LiveData<DataRoom> {
return mQueries.getLast()
}

override fun insertData(item: DataRoom) {
mQueries.insertData(item)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ Utils.log("Insert db success", item) },
{ Utils.log("Insert db Fail", item) }
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.tuan88291.mvvmpattern.data.local.room.livedata

import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import com.tuan88291.mvvmpattern.data.local.entity.DataRoom
import com.tuan88291.mvvmpattern.data.local.room.QueriesDao

class DBmodel(val mRepository: iDBRepository) : ViewModel() {
fun getAll(): LiveData<MutableList<DataRoom>> {
return mRepository.getAll()
}
fun getLast(): LiveData<DataRoom> {
return mRepository.getLast()
}
fun insertData(item: DataRoom) {
mRepository.insertData(item)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.tuan88291.mvvmpattern.data.local.room.livedata

import androidx.lifecycle.LiveData
import com.tuan88291.mvvmpattern.data.local.entity.DataRoom

interface iDBRepository {
fun getAll(): LiveData<MutableList<DataRoom>>
fun getLast(): LiveData<DataRoom>
fun insertData(item: DataRoom)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tuan88291.mvvmpattern.data.remote

import com.tuan88291.mvvmpattern.data.remote.service.iServiceApi

class ApiGenerator(val service: iServiceApi) {
fun createApi(): CallApi {
return service.createService(CallApi::class.java)
}

fun createTokenApi(): CallApi {
return service.createServiceToken(CallApi::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.tuan88291.mvvmpattern.data.remote

interface BaseInteractor {
val callAPi: CallApi
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/data/remote/CallApi.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.tuan88291.mvvmpattern.data.remote


import com.tuan88291.mvvmpattern.data.local.model.DataUser
import io.reactivex.Observable
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query

@JvmSuppressWildcards
interface CallApi {
@GET("users")
fun getList(@Query("page") page: Int): Observable<DataUser>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.tuan88291.mvvmpattern.data.remote.customcallback

import com.blankj.utilcode.util.LogUtils
import com.google.gson.Gson
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException
import com.tuan88291.mvvmpattern.utils.observe.AutoDisposable
import com.tuan88291.mvvmpattern.utils.observe.addTo
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.observers.DisposableObserver
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.Response
import java.io.IOException
import java.net.SocketTimeoutException

abstract class BaseRetrofit<T>(callback: Observable<T>) {

init {
getRetrofit(callback)
}

private fun getRetrofit(callback: Observable<T>) {
onLoading()
if (callback != null) {
val dis = callback.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribeWith(object : DisposableObserver<T>() {
override fun onComplete() {
onLoadComplete()
}
override fun onNext(t: T) {
try {
onGetApiComplete(t)
} catch (e: Exception) {
if (e.localizedMessage == null) {
onFail("Have some trouble, please try again")
} else {
onFail(e.localizedMessage)
}
LogUtils.a("Exeption fire: $e")
}
onLoadComplete()
}

override fun onError(e: Throwable) {
try {
if (e is HttpException) {
val responseBody = e.response().errorBody()
onFail(getMessage(responseBody!!))
} else if (e is SocketTimeoutException) {
onFail("Server not response, please try again")
} else if (e is IOException) {
onFail("Check your network please!")
} else {
if (e.localizedMessage == null) {
onFail("Have some trouble, please try again")
} else {
onFail(e.localizedMessage)
}

}

}catch (e1: Exception){
onFail(e1.localizedMessage)

}
LogUtils.a("onError: $e")
onLoadComplete()
}

})
if (getDispose() != null) {
dis.addTo(getDispose()!!)
}

}else{
onFail("callback can not be null")
LogUtils.a("callback null")
onLoadComplete()
}
}


private fun getMessage(response: ResponseBody): String {
var mess: String
try {
val errorBody = response.string()
val jObjError = JSONObject(errorBody)
mess = jObjError.getString("message")
} catch (e: Exception) {
mess = "Have some trouble, please try again!"
LogUtils.a("Can not get message!", response.toString())
}
return mess
}
protected abstract fun getDispose(): AutoDisposable?
protected abstract fun onGetApiComplete(t: T)

protected open fun onLoading() {

}

protected open fun onLoadComplete() {

}

protected abstract fun onFail(err: String)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.tuan88291.mvvmpattern.data.remote.service

import com.google.gson.GsonBuilder
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import com.tuan88291.mvvmpattern.BuildConfig
import com.tuan88291.mvvmpattern.utils.Common
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

class ServiceApi: iServiceApi {
private val logging = HttpLoggingInterceptor()
private val httpClient: OkHttpClient.Builder by lazy { OkHttpClient.Builder() }
private val builder = Retrofit.Builder()
.baseUrl(Common.DOMAIN)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())

// service have not token
override fun <S> createService(serviceClass: Class<S>): S {
httpClient.apply {
readTimeout(3, TimeUnit.MINUTES)
connectTimeout(3, TimeUnit.MINUTES)
addInterceptor { chain ->
val requestBuilder = chain.request().newBuilder()
.addHeader("Content-Type", "application/json; charset=utf-8")
.addHeader("Accept", "application/json")
.method(chain.request().method, chain.request().body)
val request = requestBuilder.build()
chain.proceed(request)
}
if (BuildConfig.DEBUG) {
logging.level = HttpLoggingInterceptor.Level.BODY
addInterceptor(logging)
}
}

val gson = GsonBuilder()
.setLenient()
.create()
val client = httpClient.build()
val retrofit = builder.client(client).addConverterFactory(
GsonConverterFactory.create(gson)).build()
return retrofit.create(serviceClass)
}

override fun <S> createServiceToken(serviceClass: Class<S>): S {
httpClient.apply {
readTimeout(3, TimeUnit.MINUTES)
connectTimeout(3, TimeUnit.MINUTES)
addInterceptor { chain ->
val requestBuilder = chain.request().newBuilder()
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.method(chain.request().method, chain.request().body).build()
chain.proceed(requestBuilder)
}
if (BuildConfig.DEBUG) {
logging.level = HttpLoggingInterceptor.Level.BODY
addInterceptor(logging)
}
}
val client = httpClient.build()
val retrofit = builder.client(client).build()
return retrofit.create(serviceClass)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.tuan88291.mvvmpattern.data.remote.service

interface iServiceApi {
fun <S> createService(serviceClass: Class<S>): S
fun <S> createServiceToken(serviceClass: Class<S>): S
}
29 changes: 29 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/di/AppModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.tuan88291.mvvmpattern.di

import androidx.room.Room
import com.tuan88291.mvvmpattern.data.local.room.AppDatabase
import com.tuan88291.mvvmpattern.data.local.room.livedata.DBRepository
import com.tuan88291.mvvmpattern.data.local.room.livedata.DBmodel
import com.tuan88291.mvvmpattern.data.local.room.livedata.iDBRepository
import com.tuan88291.mvvmpattern.data.remote.ApiGenerator
import com.tuan88291.mvvmpattern.data.remote.service.ServiceApi
import com.tuan88291.mvvmpattern.data.remote.service.iServiceApi
import com.tuan88291.mvvmpattern.view.fragment.chat.ChatViewModel
import com.tuan88291.mvvmpattern.view.fragment.homefragment.HomeViewModel
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module

val dbModule = module {
single { Room.databaseBuilder(get(), AppDatabase::class.java, "user-database").build() }
single { get<AppDatabase>().queries() }
single<iDBRepository> { DBRepository(get()) }
viewModel { DBmodel(get()) }
}
val mvvmModule = module {
viewModel { HomeViewModel(get()) }
viewModel { ChatViewModel() }
}
val RetrofitModule = module {
single<iServiceApi> { ServiceApi() }
single { ApiGenerator(get()) }
}
6 changes: 6 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/utils/Common.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.tuan88291.mvvmpattern.utils

object Common {
val DOMAIN = "https://reqres.in/api/"
val SHARED_PREFERENCE_NAME = "AppName"
}
49 changes: 49 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/utils/SharedPrefs.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.tuan88291.mvvmpattern.utils

import android.content.Context
import android.content.SharedPreferences
import com.tuan88291.mvvmpattern.App

import com.tuan88291.mvvmpattern.utils.Common.SHARED_PREFERENCE_NAME


class SharedPrefs private constructor(){
private val mSharedPreferences: SharedPreferences by lazy{ App.applicationContext().getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE) }
fun <T> get(key: String, anonymousClass: Class<T>): T {

return when (anonymousClass) {
String::class.java -> mSharedPreferences.getString(key, "") as T
Boolean::class.java -> mSharedPreferences.getBoolean(key, false) as T
Float::class.java -> mSharedPreferences.getFloat(key, 0f) as T
Int::class.java -> mSharedPreferences.getInt(key, 0) as T
Long::class.java -> mSharedPreferences.getLong(key, 0) as T
else -> App.getGson().fromJson(mSharedPreferences.getString(key, ""), anonymousClass)
}
}

fun <T> put(key: String, data: T) {
val editor = mSharedPreferences.edit()
when(data) {
is String -> editor.putString(key, data as String)
is Boolean -> editor.putBoolean(key, data as Boolean)
is Float -> editor.putFloat(key, data as Float)
is Int -> editor.putInt(key, data as Int)
is Long -> editor.putLong(key, data as Long)
else -> editor.putString(key, App.getGson().toJson(data))
}
editor.apply()
}
fun clear() {
mSharedPreferences.edit().clear().apply()
}
companion object {
private var mInstance: SharedPrefs? = null
val instance: SharedPrefs?
get() {
if (mInstance == null) {
mInstance = SharedPrefs()
}
return mInstance!!
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/tuan88291/mvvmpattern/utils/Utils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.tuan88291.mvvmpattern.utils

import com.blankj.utilcode.util.LogUtils
import com.google.gson.Gson

object Utils {
fun log(msg: String, data: Any) {
try {
LogUtils.e("$msg: --->" + Gson().toJson(data))
} catch (e: Exception) {
LogUtils.e("$msg: --->" + e.message)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.tuan88291.mvvmpattern.utils.observe

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import com.blankj.utilcode.util.LogUtils
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable

class AutoDisposable(lifecycle: Lifecycle?) : LifecycleObserver {
var compositeDisposable: CompositeDisposable? = null
init {
lifecycle?.addObserver(this)
compositeDisposable = CompositeDisposable()
}

fun add(disposable: Disposable) {
if (compositeDisposable != null) {
compositeDisposable?.add(disposable)
} else {
throw NotImplementedError("must bind AutoDisposable to a Lifecycle first")
}
}

@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
compositeDisposable?.dispose()
LogUtils.a("Destroy this task success----->")
}
fun onDismiss() {
compositeDisposable?.dispose()
LogUtils.a("Cancel this task success----->")
}
}

fun Disposable.addTo(autoDisposable: AutoDisposable) {
autoDisposable.add(this)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.tuan88291.mvvmpattern.utils.observe

import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.observers.DisposableObserver
import io.reactivex.schedulers.Schedulers

abstract class ObserveEasy
protected constructor() {
init {
onLoading()
val doWork = Observable.fromCallable { doBackground() }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object : DisposableObserver<Any>() {

override fun onNext(o: Any) {
try {
onSuccess(o)
} catch (e: Exception) {
onFail(e.message!!)
}

}

override fun onError(e: Throwable) {
onFail(e.message!!)
onComplete()
}

override fun onComplete() {
onLoadComplete()
}
})
if (getDispose() != null)
doWork.addTo(getDispose()!!)

}

protected abstract fun getDispose(): AutoDisposable?
protected abstract fun doBackground(): Any?

protected open fun onSuccess(result: Any?) {}

protected open fun onLoading() {}

protected open fun onLoadComplete() {}

protected open fun onFail(err: String) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package com.tuan88291.mvvmpattern.view.activity

import android.os.Bundle
import com.google.android.material.navigation.NavigationView
import androidx.core.view.GravityCompat
import androidx.appcompat.app.ActionBarDrawerToggle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProviders
import com.tuan88291.mvvmpattern.BaseActivity
import com.tuan88291.mvvmpattern.R
import com.tuan88291.mvvmpattern.data.local.model.Data
import com.tuan88291.mvvmpattern.databinding.ActivityMainBinding
import com.tuan88291.mvvmpattern.utils.observe.AutoDisposable
import com.tuan88291.mvvmpattern.utils.observe.addTo
import com.tuan88291.mvvmpattern.view.fragment.chat.ChatFragment
import com.tuan88291.mvvmpattern.view.fragment.homefragment.HomeFragment
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.TimeUnit

class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {

var binding: ActivityMainBinding? = null
private var item: Data? = null
private var autodis: AutoDisposable? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
autodis = AutoDisposable(this.lifecycle)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
setSupportActionBar(binding?.appBar?.toolbar)
item = ViewModelProviders.of(this).get(Data::class.java)

val toggle = ActionBarDrawerToggle(
this, binding?.drawerLayout, binding?.appBar?.toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
)
binding?.drawerLayout?.addDrawerListener(toggle)
toggle.syncState()

binding?.navView?.setNavigationItemSelectedListener(this)
binding?.appBar?.title?.text = "Call API"
addFragment(HomeFragment())
}

override fun onBackPressed() {
if (binding?.drawerLayout!!.isDrawerOpen(GravityCompat.START)) {
binding?.drawerLayout?.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}

fun setItem(it: String) {
item?.example = it
}

fun getItem(): String {
return item!!.example
}
fun setTyping(msg: String) {
binding?.appBar?.typing?.visibility = View.VISIBLE
binding?.appBar?.typing?.text = "$msg is typing..."
setUpTyping()
}

fun setUpTyping() {
Observable.just(true).delay(3000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map {
binding?.appBar?.typing?.visibility = View.GONE
}
.subscribe().addTo(autodis!!)

}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
when (item.itemId) {
R.id.action_settings -> return true
else -> return super.onOptionsItemSelected(item)
}
}

override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
when (item.itemId) {
R.id.nav_camera -> {
binding?.appBar?.title?.text = "Call API"
addFragment(HomeFragment())
}
R.id.nav_gallery -> {
binding?.appBar?.title?.text = "Chat socket"
addFragment(ChatFragment())

}
R.id.nav_slideshow -> {

}
R.id.nav_manage -> {

}
R.id.nav_share -> {

}
R.id.nav_send -> {

}
}

binding?.drawerLayout?.closeDrawer(GravityCompat.START)
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.tuan88291.mvvmpattern.view.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.tuan88291.mvvmpattern.BR
import com.tuan88291.mvvmpattern.data.local.model.DataChat
import com.tuan88291.mvvmpattern.databinding.ItemChatFriendBinding
import com.tuan88291.mvvmpattern.databinding.ItemChatYouBinding

class AdapterChat(private val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

private val inflater: LayoutInflater
internal var data = mutableListOf<DataChat>()
private var name: String? = null
init {
inflater = LayoutInflater.from(context)
}
fun setId(name: String) {
this.name = name
}
fun setData(item: DataChat) {
this.data.add(item)
notifyItemInserted(this.data.size - 1)
}
fun addAllData(data: MutableList<DataChat>) {
this.data = data
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (this.data[viewType].name == name) {
return MyHolder(ItemChatYouBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
return FriendHolder(ItemChatFriendBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = data.getOrElse(position) { data.getOrNull(0) }
if (holder is MyHolder) {
holder.bind(item!!)
} else {
val mHolder = holder as FriendHolder
mHolder.bind(item!!)
}
}

override fun getItemViewType(position: Int): Int {
return position
}

override fun getItemCount(): Int {
return data.size
}

internal inner class MyHolder(binding: ItemChatYouBinding) : RecyclerView.ViewHolder(binding.root) {
var binding: ItemChatYouBinding? = null
init {
this.binding = binding
}
fun bind(item: Any) {
this.binding?.setVariable(BR.userChat, item)
}
}
internal inner class FriendHolder(binding: ItemChatFriendBinding) : RecyclerView.ViewHolder(binding.root) {
var binding: ItemChatFriendBinding? = null
init {
this.binding = binding
}
fun bind(item: Any) {
this.binding?.setVariable(BR.userChat, item)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.tuan88291.mvvmpattern.view.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.tuan88291.mvvmpattern.BR
import com.tuan88291.mvvmpattern.data.local.entity.DataRoom
import com.tuan88291.mvvmpattern.databinding.ItemDbBinding

class DBApdapter(private val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

private val inflater: LayoutInflater
internal var data = mutableListOf<DataRoom>()
private var binding: ItemDbBinding? = null

init {
inflater = LayoutInflater.from(context)
}
fun setData(data: MutableList<DataRoom>) {
this.data = data
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
binding = ItemDbBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MyHolder(binding!!)
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = data.getOrElse(position) { data.getOrNull(0) }
val mHolder = holder as MyHolder
mHolder.bind(item!!)
}

override fun getItemCount(): Int {
return data.size
}

internal inner class MyHolder(binding: ItemDbBinding) : RecyclerView.ViewHolder(binding.root) {
var binding: ItemDbBinding? = null
init {
this.binding = binding
}
fun bind(item: Any) {
this.binding?.setVariable(BR.userDB, item)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.tuan88291.mvvmpattern.view.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.tuan88291.mvvmpattern.BR
import com.tuan88291.mvvmpattern.data.local.model.DetailUser
import com.tuan88291.mvvmpattern.databinding.ItemHomeBinding


class HomeAdapter(private val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

private val inflater: LayoutInflater
internal var data = mutableListOf<DetailUser>()
private var binding: ItemHomeBinding? = null

init {
inflater = LayoutInflater.from(context)
}
fun setData(data: MutableList<DetailUser>) {
this.data.addAll(data)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
binding = ItemHomeBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MyHolder(binding!!)
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = data.getOrElse(position) { data.getOrNull(0) }
val mHolder = holder as MyHolder
mHolder.bind(item!!)
}

override fun getItemCount(): Int {
return data.size
}

internal inner class MyHolder(binding: ItemHomeBinding) : RecyclerView.ViewHolder(binding.root) {
var binding: ItemHomeBinding? = null
init {
this.binding = binding
}
fun bind(item: Any) {
this.binding?.setVariable(BR.user, item)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.tuan88291.mvvmpattern.view.components

import android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.tuan88291.mvvmpattern.data.local.model.DataChat
import com.tuan88291.mvvmpattern.view.adapter.AdapterChat

class ListChatSocket(context: Context, attrs: AttributeSet) : RecyclerView(context, attrs) {
private var mLayoutManager: LinearLayoutManager? = null
private var mAdapter: AdapterChat? = null

init {
setUpList(context)
}

private fun setUpList(context: Context) {
mLayoutManager = LinearLayoutManager(context)
mAdapter = AdapterChat(context)
this.apply {
adapter = mAdapter
layoutManager = mLayoutManager
}
}
fun setmId(name: String) {
mAdapter?.setId(name)
}
fun setData(item: DataChat) {
mAdapter?.setData(item)
this.smoothScrollToPosition(mAdapter!!.itemCount - 1)
}
fun addAllData(data: MutableList<DataChat>) {
mAdapter?.addAllData(data)
this.scrollToEnd()
}
fun scrollToEnd() {
try {
this.smoothScrollToPosition(mAdapter!!.itemCount - 1)
}catch (e: Exception) {

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.tuan88291.mvvmpattern.view.components

import android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.tuan88291.mvvmpattern.data.local.entity.DataRoom
import com.tuan88291.mvvmpattern.view.adapter.DBApdapter

class ListItemDB(context: Context, attrs: AttributeSet) : RecyclerView(context, attrs) {
private var mLayoutManager: LinearLayoutManager? = null
private var mAdapter: DBApdapter? = null

init {
setUpList(context)
}

private fun setUpList(context: Context) {
mLayoutManager = LinearLayoutManager(context)
mAdapter = DBApdapter(context)
this.apply {
adapter = mAdapter
layoutManager = mLayoutManager
}
}
fun setData(data: MutableList<DataRoom>) {
mAdapter?.setData(data)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.tuan88291.mvvmpattern.view.components

import android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.tuan88291.mvvmpattern.data.local.model.DetailUser
import com.tuan88291.mvvmpattern.view.adapter.HomeAdapter

class ListItemUser(context: Context, attrs: AttributeSet) : RecyclerView(context, attrs) {
private var mLayoutManager: LinearLayoutManager? = null
private var mAdapter: HomeAdapter? = null

init {
setUpList(context)
}

private fun setUpList(context: Context) {
mLayoutManager = LinearLayoutManager(context)
mAdapter = HomeAdapter(context)
this.apply {
adapter = mAdapter
layoutManager = mLayoutManager
}
}
fun setData(data: MutableList<DetailUser>) {
mAdapter?.setData(data)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.tuan88291.mvvmpattern.view.fragment.chat

import android.os.Build
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import com.tuan88291.mvvmpattern.BaseFragment
import com.tuan88291.mvvmpattern.R
import com.tuan88291.mvvmpattern.data.local.model.DataChat
import com.tuan88291.mvvmpattern.databinding.AboutFragmentBinding
import com.tuan88291.mvvmpattern.utils.observe.AutoDisposable
import com.tuan88291.mvvmpattern.utils.observe.addTo
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
import org.koin.androidx.viewmodel.ext.android.viewModel
import java.util.concurrent.TimeUnit


class ChatFragment : BaseFragment() {
private var binding: AboutFragmentBinding? = null
private val chatViewModel: ChatViewModel by viewModel()
override fun setView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(inflater, R.layout.about_fragment, container, false)
return binding!!.getRoot()
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(chatViewModel)
}

override fun viewCreated(view: View, savedInstanceState: Bundle?) {
binding?.list?.setmId(Build.MODEL)
chatViewModel.getTyping().observe(this, Observer<String> { this.onTyping(it) })
chatViewModel.getLoading().observe(this, Observer<Boolean> { this.loading(it) })
chatViewModel.getDataChat().observe(this, Observer<DataChat> { this.processData(it) })
chatViewModel.getAllDataChat().observe(this, Observer<MutableList<DataChat>> { this.processAllData(it) })
binding?.send?.setOnClickListener {
if (binding?.input?.text?.toString()!! == "") return@setOnClickListener
chatViewModel.sendMsg(binding?.input?.text?.toString()!!)
binding?.input?.setText("")
}
binding?.input?.addTextChangedListener(object : TextWatcher{
override fun afterTextChanged(p0: Editable?) {

}

override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}

override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
chatViewModel.emitTyping()
}

})
mContext()?.setUpTyping()
}

private fun processData(item: DataChat) {
binding?.list?.setData(item)
}
private fun processAllData(data: MutableList<DataChat>) {
binding?.list?.addAllData(data)
}
private fun loading(load: Boolean) {
binding?.loading?.visibility = if (load) View.VISIBLE else View.GONE
}
private fun onTyping(typings: String) {
if (typings !== "") {
mContext()?.setTyping(typings)
}
}
override fun onDestroy() {
super.onDestroy()
lifecycle.removeObserver(chatViewModel)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package com.tuan88291.mvvmpattern.view.fragment.chat

import android.os.Build
import androidx.lifecycle.*
import com.tuan88291.mvvmpattern.data.local.model.DataChat
import io.socket.client.IO
import io.socket.client.Socket
import io.socket.emitter.Emitter
import org.json.JSONArray
import org.json.JSONObject


class ChatViewModel: ViewModel(), LifecycleObserver {
private val isLoading: MutableLiveData<Boolean> by lazy { MutableLiveData<Boolean>() }
private val listTyping: MutableLiveData<String> by lazy { MutableLiveData<String>() }
private val data: MutableLiveData<DataChat> by lazy { MutableLiveData<DataChat>() }
private val allData: MutableLiveData<MutableList<DataChat>> by lazy { MutableLiveData<MutableList<DataChat>>() }
// private val mSocket: Socket by lazy { IO.socket("http://192.168.31.196:3000") }
private val mSocket: Socket by lazy { IO.socket("http://35.227.150.67:3000") }
val mId: Int = (0..10).random()

@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreateSocket() {
mSocket.connect()
mSocket.on("newmsg", onNewMsg)
mSocket.on("allData", getAllData)
mSocket.on("isTyping", onTyping)
mSocket.emit("getAllData")

}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun reConnectSocket() {
if (!mSocket.connected()) {
mSocket.connect()
}
}
fun sendMsg(msg: String) {
val jsonObject = JSONObject()
jsonObject.put("id", mId)
jsonObject.put("name", Build.MODEL)
jsonObject.put("message", msg)
mSocket.emit("sendmsg", jsonObject)
}
private val onNewMsg = object : Emitter.Listener {

override fun call(vararg args: Any?) {
val datas = args[0] as JSONObject
val item = DataChat(datas.getInt("id"), datas.getString("name"), datas.getString("message"))
data.postValue(item)
}
}
private val getAllData = object : Emitter.Listener {

override fun call(vararg args: Any?) {
val datas = args[0] as JSONArray
if (datas.length() > 0) {
val data = mutableListOf<DataChat>()
for (i in 0..datas.length() - 1) {
val jsObject = datas[i] as JSONObject
data.add(DataChat(jsObject.getInt("id"), jsObject.getString("name"), jsObject.getString("message")))
}
allData.postValue(data)
}
isLoading.postValue(false)
}
}
private val onTyping = object : Emitter.Listener {

override fun call(vararg args: Any?) {
val datas = args[0].toString()
var listUser = ""
if (datas != Build.MODEL) {
listUser = "$datas"
}
listTyping.postValue(listUser)
}
}
fun emitTyping() {
mSocket.emit("typing", Build.MODEL)
}
fun getDataChat(): MutableLiveData<DataChat>{
return this.data
}
fun getLoading(): MutableLiveData<Boolean>{
return this.isLoading
}
fun getTyping(): MutableLiveData<String>{
return this.listTyping
}
fun getAllDataChat(): MutableLiveData<MutableList<DataChat>>{
return this.allData
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onDestroySocket() {
mSocket.disconnect()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.tuan88291.mvvmpattern.view.fragment.homefragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import com.tuan88291.mvvmpattern.BaseFragment
import com.tuan88291.mvvmpattern.R
import com.tuan88291.mvvmpattern.data.local.entity.DataRoom
import com.tuan88291.mvvmpattern.data.local.model.DataUser
import com.tuan88291.mvvmpattern.data.local.model.DetailUser
import com.tuan88291.mvvmpattern.data.local.room.livedata.DBmodel
import com.tuan88291.mvvmpattern.databinding.HomeFragmentBinding
import org.koin.androidx.viewmodel.ext.android.viewModel

class HomeFragment : BaseFragment() {
private val homeViewModel: HomeViewModel by viewModel()
private var binding: HomeFragmentBinding? = null
private val db: DBmodel by viewModel()

override fun setView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = DataBindingUtil.inflate(inflater, R.layout.home_fragment, container, false)
return binding!!.getRoot()
}

override fun viewCreated(view: View, savedInstanceState: Bundle?) {

homeViewModel.getData().observe(this, Observer<DataUser> { this.processData(it) })
homeViewModel.loading().observe(this, Observer<Boolean> { this.loading(it) })
homeViewModel.error().observe(this, Observer<String> { this.error(it) })

db.getAll().observe(this, Observer<MutableList<DataRoom>> { this.onDataChange(it) })

binding?.button?.setOnClickListener{
homeViewModel.loadData()
}
binding?.btn?.setOnClickListener {
db.insertData(DataRoom("tuan", (0..10).random()))
}
}
private fun onDataChange(data: MutableList<DataRoom>) {
binding?.list?.visibility = View.GONE
binding?.listDb?.visibility = View.VISIBLE
binding?.listDb?.setData(data)
}
private fun processData(data: DataUser) {
binding?.list?.visibility = View.VISIBLE
binding?.listDb?.visibility = View.GONE
try {
binding?.list?.setData(data.data!!)
}catch (e: Exception) {
}
}
private fun loading(isLoading: Boolean) {
binding?.progressBar?.visibility = if (isLoading) View.VISIBLE else View.GONE
}
private fun error(msg: String) {
}
fun toast(msg: String) {
Toast.makeText(mContext(), msg, Toast.LENGTH_LONG).show()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.tuan88291.mvvmpattern.view.fragment.homefragment

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.tuan88291.mvvmpattern.data.local.model.DataUser
import com.tuan88291.mvvmpattern.data.remote.ApiGenerator
import com.tuan88291.mvvmpattern.data.remote.BaseInteractor
import com.tuan88291.mvvmpattern.data.remote.CallApi
import com.tuan88291.mvvmpattern.data.remote.customcallback.BaseRetrofit
import com.tuan88291.mvvmpattern.utils.observe.AutoDisposable

class HomeViewModel(api: ApiGenerator): ViewModel(), BaseInteractor {
override val callAPi: CallApi = api.createApi()

private val dataServer: MutableLiveData<DataUser> by lazy { MutableLiveData<DataUser>() }
private val isLoading: MutableLiveData<Boolean> by lazy { MutableLiveData<Boolean>() }
private val error: MutableLiveData<String> by lazy { MutableLiveData<String>() }
private val autodis = AutoDisposable(null)
fun getData(): MutableLiveData<DataUser>{
return this.dataServer
}
fun loading(): MutableLiveData<Boolean>{
return this.isLoading
}
fun error(): MutableLiveData<String>{
return this.error
}
fun loadData(){
object : BaseRetrofit<DataUser>(callAPi.getList(1)) {
override fun onFail(err: String) {
error.postValue(err)
}

override fun onLoading() {
super.onLoading()
isLoading.postValue(true)
}

override fun onLoadComplete() {
super.onLoadComplete()
isLoading.postValue(false)
}

override fun getDispose(): AutoDisposable? {
return autodis
}

override fun onGetApiComplete(t: DataUser) {
dataServer.postValue(t)
}
}
}
fun dispose() {
autodis.onDismiss()
}
}
12 changes: 12 additions & 0 deletions app/src/main/res/drawable-v21/ic_menu_camera.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
<path
android:fillColor="#FF000000"
android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zm3,15c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable-v21/ic_menu_gallery.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M22,16V4c0,-1.1 -0.9,-2 -2,-2H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zm-11,-4l2.03,2.71L16,11l4,5H8l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2H4V6H2z"/>
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable-v21/ic_menu_manage.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z"/>
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable-v21/ic_menu_send.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable-v21/ic_menu_share.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable-v21/ic_menu_slideshow.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M4,6H2v14c0,1.1 0.9,2 2,2h14v-2H4V6zm16,-4H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zm-8,12.5v-9l6,4.5 -6,4.5z"/>
</vector>
34 changes: 34 additions & 0 deletions app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
<item
android:color="#00000000"
android:offset="1.0"/>
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1"/>
</vector>
21 changes: 21 additions & 0 deletions app/src/main/res/drawable/bg_chat.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<solid
android:color="#0b8bf4" >
</solid>

<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" >
</padding>

<corners
android:radius="15dp" >
</corners>

</shape>
20 changes: 20 additions & 0 deletions app/src/main/res/drawable/bg_text.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<solid
android:color="#e0ecf9" >
</solid>
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" >
</padding>

<corners
android:radius="15dp" >
</corners>

</shape>
74 changes: 74 additions & 0 deletions app/src/main/res/drawable/ic_launcher_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/side_nav_bar.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="135"
android:centerColor="#009688"
android:endColor="#00695C"
android:startColor="#4DB6AC"
android:type="linear"/>
</shape>
64 changes: 64 additions & 0 deletions app/src/main/res/layout/about_fragment.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">

<data></data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">


<EditText
android:id="@+id/input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:background="#E6E4E4"
android:ems="10"
android:hint="Enter message..."
android:inputType="textMultiLine"
android:padding="@dimen/_10sdp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/send"
app:layout_constraintStart_toStartOf="parent" />

<ImageButton
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/_10sdp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/ic_menu_send" />

<com.tuan88291.mvvmpattern.view.components.ListChatSocket
android:id="@+id/list"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/input"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.6"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

</com.tuan88291.mvvmpattern.view.components.ListChatSocket>

<ProgressBar
android:id="@+id/loading"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
31 changes: 31 additions & 0 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">

<data></data>

<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">

<include
android:id="@+id/appBar"
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"/>

</androidx.drawerlayout.widget.DrawerLayout>
</layout>
52 changes: 52 additions & 0 deletions app/src/main/res/layout/app_bar_main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">

<data></data>

<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.activity.MainActivity">

<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/_16sdp"
android:textColor="#fff"/>
<TextView
android:id="@+id/typing"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/_9sdp"
android:textColor="#fff"/>
</LinearLayout>
</androidx.appcompat.widget.Toolbar>

</com.google.android.material.appbar.AppBarLayout>

<include
android:id="@+id/contentMain"
layout="@layout/content_main" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
19 changes: 19 additions & 0 deletions app/src/main/res/layout/content_main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">

<data></data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".view.activity.MainActivity"
tools:showIn="@layout/app_bar_main">
<FrameLayout
android:id="@+id/contentHome"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
77 changes: 77 additions & 0 deletions app/src/main/res/layout/home_fragment.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">

<data>
</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="8dp"
android:text="api"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="db"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.tuan88291.mvvmpattern.view.components.ListItemUser
android:id="@+id/list"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />
<com.tuan88291.mvvmpattern.view.components.ListItemDB
android:id="@+id/listDb"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:visibility="gone"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
52 changes: 52 additions & 0 deletions app/src/main/res/layout/item_chat_friend.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<data>
<variable
name="userChat"
type="com.tuan88291.mvvmpattern.data.local.model.DataChat" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:padding="@dimen/_6sdp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="5dp"
android:text="@{userChat.name}"
android:textColor="#2b3840"
android:textStyle="normal|bold" />

<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/name"
android:layout_marginTop="5dp"
android:background="@drawable/bg_text"
android:gravity="left"
android:text="@{userChat.content}"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="@android:color/black" />

</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
52 changes: 52 additions & 0 deletions app/src/main/res/layout/item_chat_you.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<data>
<variable
name="userChat"
type="com.tuan88291.mvvmpattern.data.local.model.DataChat" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:padding="@dimen/_6sdp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:textStyle="normal|bold"
android:visibility="gone" />

<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/name"
android:layout_alignParentRight="true"
android:layout_marginTop="5dp"
android:background="@drawable/bg_chat"
android:gravity="left"
android:text="@{userChat.content}"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="#ffffff" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
35 changes: 35 additions & 0 deletions app/src/main/res/layout/item_db.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<data>
<variable
name="userDB"
type="com.tuan88291.mvvmpattern.data.local.entity.DataRoom" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:padding="@dimen/_10sdp"
android:layout_marginVertical="@dimen/_5sdp"
android:background="#CDE9CD"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`Age:` + userDB.age}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`name:` + userDB.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/age" />
</androidx.constraintlayout.widget.ConstraintLayout>

</layout>
53 changes: 53 additions & 0 deletions app/src/main/res/layout/item_home.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<data>
<variable
name="user"
type="com.tuan88291.mvvmpattern.data.local.model.DetailUser" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:padding="@dimen/_10sdp"
android:layout_marginVertical="@dimen/_5sdp"
android:background="#E0E0E0"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`id:` + user.id}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`email:` + user.email}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/id" />

<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@{user.firstName}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/email" />

<TextView
android:id="@+id/last"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@{user.lastName}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/name" />
</androidx.constraintlayout.widget.ConstraintLayout>

</layout>
37 changes: 37 additions & 0 deletions app/src/main/res/layout/nav_header_main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
android:orientation="vertical"
android:gravity="bottom">

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
app:srcCompat="@mipmap/ic_launcher_round"
android:contentDescription="@string/nav_header_desc"
android:id="@+id/imageView"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="@string/nav_header_title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nav_header_subtitle"
android:id="@+id/textView"/>

</LinearLayout>
38 changes: 38 additions & 0 deletions app/src/main/res/menu/activity_main_drawer.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">

<group android:checkableBehavior="single">
<item
android:id="@+id/nav_camera"
android:icon="@drawable/ic_menu_camera"
android:title="Call Data"/>
<item
android:id="@+id/nav_gallery"
android:icon="@drawable/ic_menu_gallery"
android:title="Chat socket"/>
<item
android:id="@+id/nav_slideshow"
android:icon="@drawable/ic_menu_slideshow"
android:title="Slideshow"/>
<item
android:id="@+id/nav_manage"
android:icon="@drawable/ic_menu_manage"
android:title="Tools"/>
</group>

<item android:title="Communicate">
<menu>
<item
android:id="@+id/nav_share"
android:icon="@drawable/ic_menu_share"
android:title="Share"/>
<item
android:id="@+id/nav_send"
android:icon="@drawable/ic_menu_send"
android:title="Send"/>
</menu>
</item>

</menu>
8 changes: 8 additions & 0 deletions app/src/main/res/menu/main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:orderInCategory="100"
app:showAsAction="never"/>
</menu>
5 changes: 5 additions & 0 deletions app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
5 changes: 5 additions & 0 deletions app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
Binary file added app/src/main/res/mipmap-hdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/mipmap-mdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/mipmap-xhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions app/src/main/res/values-v21/styles.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<resources>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
6 changes: 6 additions & 0 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>
8 changes: 8 additions & 0 deletions app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="nav_header_vertical_spacing">8dp</dimen>
<dimen name="nav_header_height">176dp</dimen>
<dimen name="fab_margin">16dp</dimen>
</resources>
8 changes: 8 additions & 0 deletions app/src/main/res/values/drawables.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item name="ic_menu_camera" type="drawable">@android:drawable/ic_menu_camera</item>
<item name="ic_menu_gallery" type="drawable">@android:drawable/ic_menu_gallery</item>
<item name="ic_menu_slideshow" type="drawable">@android:drawable/ic_menu_slideshow</item>
<item name="ic_menu_manage" type="drawable">@android:drawable/ic_menu_manage</item>
<item name="ic_menu_share" type="drawable">@android:drawable/ic_menu_share</item>
<item name="ic_menu_send" type="drawable">@android:drawable/ic_menu_send</item>
</resources>
20 changes: 20 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<resources>
<string name="app_name">MVVM sample</string>
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
<string name="nav_header_title">Android Studio</string>
<string name="nav_header_subtitle">android.studio@android.com</string>
<string name="nav_header_desc">Navigation header</string>
<string name="action_settings">Settings</string>
<string name="title_activity_login">Sign in</string>
<!-- Strings related to login -->
<string name="prompt_email">Email</string>
<string name="prompt_password">Password (optional)</string>
<string name="action_sign_in">Sign in or register</string>
<string name="action_sign_in_short">Sign in</string>
<string name="error_invalid_email">This email address is invalid</string>
<string name="error_invalid_password">This password is too short</string>
<string name="error_incorrect_password">This password is incorrect</string>
<string name="error_field_required">This field is required</string>
<string name="permission_rationale">"Contacts permissions are needed for providing email completions."</string>
</resources>
17 changes: 17 additions & 0 deletions app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<resources>

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>

</resources>
17 changes: 17 additions & 0 deletions app/src/test/java/com/tuan88291/mvvmpattern/ExampleUnitTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.tuan88291.mvvmpattern

import org.junit.Test

import org.junit.Assert.*

/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
30 changes: 30 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
apply from: "dependencies.gradle"
repositories {
google()
jcenter()

}
dependencies {
classpath deps.gradle_plugins.android
classpath deps.gradle_plugins.kotlin
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }


}
}

task clean(type: Delete) {
delete rootProject.buildDir
}
67 changes: 67 additions & 0 deletions dependencies.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
ext.versions = [
min_sdk: 16,
compile_sdk: 29,
publish_version: "1.0",
publish_version_code: 1,
package: "com.tuan88291.mvvmpattern",
kotlin_version: "1.3.61"
]
ext.arch = [
koin: '2.0.1',
room: '2.2.2',
retrofit: '2.6.2',
lifecycler: '2.1.0'
]
ext.deps = [
gradle_plugins: [
android: "com.android.tools.build:gradle:3.5.2",
kotlin: "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin_version"
],

di: [
koin: "org.koin:koin-android:$arch.koin",
koin_androix: "org.koin:koin-androidx-scope:$arch.koin",
koin_viewmodel: "org.koin:koin-androidx-viewmodel:$arch.koin"
],
resful: [
gson: "com.google.code.gson:gson:2.8.6",
logd: "com.blankj:utilcode:1.5.1",
retrofit2: "com.squareup.retrofit2:retrofit:$arch.retrofit",
rx_retrofit: "com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0",
converter: "com.squareup.retrofit2:converter-gson:$arch.retrofit",
logging: "com.squareup.okhttp3:logging-interceptor:4.2.2",
socket: "io.socket:socket.io-client:1.0.0"

],
webrtc: "org.webrtc:google-webrtc:1.0.+",
perfomance: [
rxandroid: "io.reactivex.rxjava2:rxandroid:2.1.1",
rxjava: "io.reactivex.rxjava2:rxjava:2.2.12",
multidex: "androidx.multidex:multidex:2.0.1",
],
lifecycler: [
java8: "androidx.lifecycle:lifecycle-common-java8:$arch.lifecycler",
viewmodel: "androidx.lifecycle:lifecycle-viewmodel:$arch.lifecycler",
extension: "android.arch.lifecycle:extensions:1.1.1",
],
db: [
test: "androidx.room:room-testing:$arch.room",
compiler: "androidx.room:room-compiler:$arch.room",
runtime: "androidx.room:room-runtime:$arch.room",
],
support: [
app_compat: "androidx.appcompat:appcompat:1.1.0",
constraint_layout: "androidx.constraintlayout:constraintlayout:1.1.3",
material: "com.google.android.material:material:1.0.0",
core: "androidx.core:core-ktx:1.2.0-rc01",
kotlin: "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin_version",
databinding: "com.android.databinding:compiler:3.3.1",
sdp: "com.intuit.sdp:sdp-android:1.0.6",
],

test: [
runner: "androidx.test:runner:1.3.0-alpha02",
core: "androidx.test.espresso:espresso-core:3.3.0-alpha02",
junit: "junit:junit:4.12",
]
]
21 changes: 21 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
6 changes: 6 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#Fri Nov 08 10:34:39 ICT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
172 changes: 172 additions & 0 deletions gradlew
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#!/usr/bin/env sh

##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn () {
echo "$*"
}

die () {
echo
echo "$*"
echo
exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`

# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option

if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi

# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi

exec "$JAVACMD" "$@"
84 changes: 84 additions & 0 deletions gradlew.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windows variants

if not "%OS%" == "Windows_NT" goto win9xME_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ':app'

0 comments on commit 30cdb3e

Please sign in to comment.