From e3cdc2af2b50e23310be5f8154fd2052958cb4ee Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Sun, 2 Feb 2020 10:54:43 -0300 Subject: [PATCH 01/12] reestructure gradle config so modules can implement a base configuration --- app/src/main/AndroidManifest.xml | 19 ++++++++++-- .../com/hako/friendlists/MainApplication.kt | 7 +++++ .../com/hako/friendlists/home/HomeActivity.kt | 7 +++++ app/src/main/res/values/colors.xml | 7 +++-- core.gradle | 29 +++++++++++++++++++ settings.gradle | 2 +- userlist/.gitignore | 1 + userlist/build.gradle | 6 ++++ userlist/consumer-rules.pro | 0 userlist/proguard-rules.pro | 21 ++++++++++++++ .../ExampleInstrumentedTest.kt | 24 +++++++++++++++ userlist/src/main/AndroidManifest.xml | 2 ++ userlist/src/main/res/values/strings.xml | 3 ++ .../friendlist_userlist/ExampleUnitTest.kt | 17 +++++++++++ 14 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/hako/friendlists/MainApplication.kt create mode 100644 app/src/main/java/com/hako/friendlists/home/HomeActivity.kt create mode 100644 core.gradle create mode 100644 userlist/.gitignore create mode 100644 userlist/build.gradle create mode 100644 userlist/consumer-rules.pro create mode 100644 userlist/proguard-rules.pro create mode 100644 userlist/src/androidTest/java/com/hako/friendlist_userlist/ExampleInstrumentedTest.kt create mode 100644 userlist/src/main/AndroidManifest.xml create mode 100644 userlist/src/main/res/values/strings.xml create mode 100644 userlist/src/test/java/com/hako/friendlist_userlist/ExampleUnitTest.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cfc8478..5322f2e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,10 +2,25 @@ package="com.hako.friendlists"> + android:supportsRtl="false" + android:theme="@style/AppTheme"> + + + + + + + + + + + diff --git a/app/src/main/java/com/hako/friendlists/MainApplication.kt b/app/src/main/java/com/hako/friendlists/MainApplication.kt new file mode 100644 index 0000000..4e58a5a --- /dev/null +++ b/app/src/main/java/com/hako/friendlists/MainApplication.kt @@ -0,0 +1,7 @@ +package com.hako.friendlists + +import android.app.Application + +class MainApplication : Application() { + +} \ No newline at end of file diff --git a/app/src/main/java/com/hako/friendlists/home/HomeActivity.kt b/app/src/main/java/com/hako/friendlists/home/HomeActivity.kt new file mode 100644 index 0000000..9147d3e --- /dev/null +++ b/app/src/main/java/com/hako/friendlists/home/HomeActivity.kt @@ -0,0 +1,7 @@ +package com.hako.friendlists.home + +import androidx.appcompat.app.AppCompatActivity + +class HomeActivity : AppCompatActivity() { + +} \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 69b2233..3743e89 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,6 +1,7 @@ - #008577 - #00574B - #D81B60 + #37474F + #324047 + #CBCFD1 + #D32F2F diff --git a/core.gradle b/core.gradle new file mode 100644 index 0000000..e0be423 --- /dev/null +++ b/core.gradle @@ -0,0 +1,29 @@ +apply from: '../versions.gradle' +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion build_versions.target_sdk + buildToolsVersion build_versions.build_tools + + defaultConfig { + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + testOptions { + unitTests.returnDefaultValues = true + } + + lintOptions { + abortOnError false + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index c723749..0e9eb61 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ -include ':app', ':base' +include ':app', ':base', ':userlist' rootProject.name='Friendlists' diff --git a/userlist/.gitignore b/userlist/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/userlist/.gitignore @@ -0,0 +1 @@ +/build diff --git a/userlist/build.gradle b/userlist/build.gradle new file mode 100644 index 0000000..298aaa6 --- /dev/null +++ b/userlist/build.gradle @@ -0,0 +1,6 @@ +apply plugin: 'com.android.library' +apply from: '../core.gradle' + +dependencies { + implementation project(':base') +} diff --git a/userlist/consumer-rules.pro b/userlist/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/userlist/proguard-rules.pro b/userlist/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/userlist/proguard-rules.pro @@ -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 diff --git a/userlist/src/androidTest/java/com/hako/friendlist_userlist/ExampleInstrumentedTest.kt b/userlist/src/androidTest/java/com/hako/friendlist_userlist/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..fe782da --- /dev/null +++ b/userlist/src/androidTest/java/com/hako/friendlist_userlist/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.hako.friendlist_userlist + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.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.getInstrumentation().targetContext + assertEquals("com.hako.friendlist_userlist.test", appContext.packageName) + } +} diff --git a/userlist/src/main/AndroidManifest.xml b/userlist/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d577ea7 --- /dev/null +++ b/userlist/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/userlist/src/main/res/values/strings.xml b/userlist/src/main/res/values/strings.xml new file mode 100644 index 0000000..1d5d98a --- /dev/null +++ b/userlist/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + userlist + diff --git a/userlist/src/test/java/com/hako/friendlist_userlist/ExampleUnitTest.kt b/userlist/src/test/java/com/hako/friendlist_userlist/ExampleUnitTest.kt new file mode 100644 index 0000000..fc064f1 --- /dev/null +++ b/userlist/src/test/java/com/hako/friendlist_userlist/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.hako.friendlist_userlist + +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) + } +} From 744a2773f000a21b7dfd2a2e123547e146997313 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Sun, 2 Feb 2020 11:14:30 -0300 Subject: [PATCH 02/12] delete example tests --- .../ExampleInstrumentedTest.kt | 24 ------------------- .../friendlist_userlist/ExampleUnitTest.kt | 17 ------------- 2 files changed, 41 deletions(-) delete mode 100644 userlist/src/androidTest/java/com/hako/friendlist_userlist/ExampleInstrumentedTest.kt delete mode 100644 userlist/src/test/java/com/hako/friendlist_userlist/ExampleUnitTest.kt diff --git a/userlist/src/androidTest/java/com/hako/friendlist_userlist/ExampleInstrumentedTest.kt b/userlist/src/androidTest/java/com/hako/friendlist_userlist/ExampleInstrumentedTest.kt deleted file mode 100644 index fe782da..0000000 --- a/userlist/src/androidTest/java/com/hako/friendlist_userlist/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.hako.friendlist_userlist - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.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.getInstrumentation().targetContext - assertEquals("com.hako.friendlist_userlist.test", appContext.packageName) - } -} diff --git a/userlist/src/test/java/com/hako/friendlist_userlist/ExampleUnitTest.kt b/userlist/src/test/java/com/hako/friendlist_userlist/ExampleUnitTest.kt deleted file mode 100644 index fc064f1..0000000 --- a/userlist/src/test/java/com/hako/friendlist_userlist/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.hako.friendlist_userlist - -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) - } -} From 5ba028de3c19e1413a156da47d97b1912888a216 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Sun, 2 Feb 2020 11:14:47 -0300 Subject: [PATCH 03/12] create POJO --- .../friendlist/feature/UserlistFragment.kt | 4 ++ .../com/hako/friendlist/model/UserModels.kt | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt create mode 100644 userlist/src/main/java/com/hako/friendlist/model/UserModels.kt diff --git a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt new file mode 100644 index 0000000..509c2e1 --- /dev/null +++ b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt @@ -0,0 +1,4 @@ +package com.hako.friendlist.feature + +class UserlistFragment { +} \ No newline at end of file diff --git a/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt b/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt new file mode 100644 index 0000000..f2d3428 --- /dev/null +++ b/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt @@ -0,0 +1,44 @@ +package com.hako.friendlist.model + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class User( + @SerializedName("id") val id: Int, + @SerializedName("name") val realName: String, + @SerializedName("username") val userName: String, + @SerializedName("email") val email: String, + @SerializedName("amount") val balance: Address, + @SerializedName("phone") val phone: String, + @SerializedName("website") val website: String, + @SerializedName("company") val company: Company +) : Parcelable { + + @Parcelize + data class Address( + @SerializedName("street") val street: String, + @SerializedName("suite") val realName: String, + @SerializedName("city") val userName: String, + @SerializedName("zipcode") val email: String, + @SerializedName("geo") val geoLocation: GeoLocation + ) : Parcelable { + + @Parcelize + data class GeoLocation( + @SerializedName("lat") val latitude: String, + @SerializedName("lng") val longitude: String + ) : Parcelable + } + + @Parcelize + data class Company( + @SerializedName("name") val name: String, + @SerializedName("catchPhrase") val catchPhrase: String, + @SerializedName("bs") val keywords: String + ) : Parcelable { + fun getKeywordList() = keywords.split(" ") + } +} + From 46be4aca108f012955e431241c18a9cf87bfed58 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Sun, 2 Feb 2020 13:44:51 -0300 Subject: [PATCH 04/12] add room entities and daos --- .../{home => view}/HomeActivity.kt | 0 .../main/java/com/hako/base/room/Database.kt | 17 ++++++++++++ .../java/com/hako/base/room/dao/AlbumDao.kt | 27 +++++++++++++++++++ .../java/com/hako/base/room/dao/PhotoDao.kt | 27 +++++++++++++++++++ .../java/com/hako/base/room/dao/UserDao.kt | 27 +++++++++++++++++++ .../java/com/hako/base/room/entities/Album.kt | 17 ++++++++++++ .../com/hako/base/room/entities/Photos.kt | 19 +++++++++++++ .../java/com/hako/base/room/entities/User.kt | 20 ++++++++++++++ 8 files changed, 154 insertions(+) rename app/src/main/java/com/hako/friendlists/{home => view}/HomeActivity.kt (100%) create mode 100644 base/src/main/java/com/hako/base/room/Database.kt create mode 100644 base/src/main/java/com/hako/base/room/dao/AlbumDao.kt create mode 100644 base/src/main/java/com/hako/base/room/dao/PhotoDao.kt create mode 100644 base/src/main/java/com/hako/base/room/dao/UserDao.kt create mode 100644 base/src/main/java/com/hako/base/room/entities/Album.kt create mode 100644 base/src/main/java/com/hako/base/room/entities/Photos.kt create mode 100644 base/src/main/java/com/hako/base/room/entities/User.kt diff --git a/app/src/main/java/com/hako/friendlists/home/HomeActivity.kt b/app/src/main/java/com/hako/friendlists/view/HomeActivity.kt similarity index 100% rename from app/src/main/java/com/hako/friendlists/home/HomeActivity.kt rename to app/src/main/java/com/hako/friendlists/view/HomeActivity.kt diff --git a/base/src/main/java/com/hako/base/room/Database.kt b/base/src/main/java/com/hako/base/room/Database.kt new file mode 100644 index 0000000..0358461 --- /dev/null +++ b/base/src/main/java/com/hako/base/room/Database.kt @@ -0,0 +1,17 @@ +package com.hako.base.room + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.hako.base.room.dao.AlbumDao +import com.hako.base.room.dao.PhotoDao +import com.hako.base.room.dao.UserDao +import com.hako.base.room.entities.AlbumEntity +import com.hako.base.room.entities.PhotoEntity +import com.hako.base.room.entities.UserEntity + +@Database(entities = [UserEntity::class, AlbumEntity::class, PhotoEntity::class], version = 1, exportSchema = false) +abstract class Database : RoomDatabase() { + abstract fun userDao(): UserDao + abstract fun albumDao(): AlbumDao + abstract fun photoDao(): PhotoDao +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/room/dao/AlbumDao.kt b/base/src/main/java/com/hako/base/room/dao/AlbumDao.kt new file mode 100644 index 0000000..9988b89 --- /dev/null +++ b/base/src/main/java/com/hako/base/room/dao/AlbumDao.kt @@ -0,0 +1,27 @@ +package com.hako.base.room.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.hako.base.room.entities.AlbumEntity + +@Dao +interface AlbumDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun save(entity: AlbumEntity) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun saveAll(entities: List) + + @get:Query("SELECT * FROM ${AlbumEntity.TABLE_NAME}") + val all: List + + @Query("SELECT COUNT(*) FROM ${AlbumEntity.TABLE_NAME}") + fun count(page: Int): Int + + @Query("DELETE FROM ${AlbumEntity.TABLE_NAME}") + fun nukeDatabase() + +} diff --git a/base/src/main/java/com/hako/base/room/dao/PhotoDao.kt b/base/src/main/java/com/hako/base/room/dao/PhotoDao.kt new file mode 100644 index 0000000..2f696de --- /dev/null +++ b/base/src/main/java/com/hako/base/room/dao/PhotoDao.kt @@ -0,0 +1,27 @@ +package com.hako.base.room.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.hako.base.room.entities.PhotoEntity + +@Dao +interface PhotoDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun save(entity: PhotoEntity) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun saveAll(entities: List) + + @get:Query("SELECT * FROM ${PhotoEntity.TABLE_NAME}") + val all: List + + @Query("SELECT COUNT(*) FROM ${PhotoEntity.TABLE_NAME}") + fun count(page: Int): Int + + @Query("DELETE FROM ${PhotoEntity.TABLE_NAME}") + fun nukeDatabase() + +} diff --git a/base/src/main/java/com/hako/base/room/dao/UserDao.kt b/base/src/main/java/com/hako/base/room/dao/UserDao.kt new file mode 100644 index 0000000..3546001 --- /dev/null +++ b/base/src/main/java/com/hako/base/room/dao/UserDao.kt @@ -0,0 +1,27 @@ +package com.hako.base.room.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.hako.base.room.entities.UserEntity + +@Dao +interface UserDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun save(entity: UserEntity) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun saveAll(entities: List) + + @get:Query("SELECT * FROM ${UserEntity.TABLE_NAME}") + val all: List + + @Query("SELECT COUNT(*) FROM ${UserEntity.TABLE_NAME}") + fun count(page: Int): Int + + @Query("DELETE FROM ${UserEntity.TABLE_NAME}") + fun nukeDatabase() + +} diff --git a/base/src/main/java/com/hako/base/room/entities/Album.kt b/base/src/main/java/com/hako/base/room/entities/Album.kt new file mode 100644 index 0000000..48d664a --- /dev/null +++ b/base/src/main/java/com/hako/base/room/entities/Album.kt @@ -0,0 +1,17 @@ +package com.hako.base.room.entities + +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity(tableName = AlbumEntity.TABLE_NAME, indices = [Index(value = ["id"], unique = true)]) +data class AlbumEntity( + @PrimaryKey + val id: Int, + val userId: Int, + val title: String +) { + companion object { + const val TABLE_NAME = "albums" + } +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/room/entities/Photos.kt b/base/src/main/java/com/hako/base/room/entities/Photos.kt new file mode 100644 index 0000000..01c840a --- /dev/null +++ b/base/src/main/java/com/hako/base/room/entities/Photos.kt @@ -0,0 +1,19 @@ +package com.hako.base.room.entities + +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity(tableName = PhotoEntity.TABLE_NAME, indices = [Index(value = ["id"], unique = true)]) +data class PhotoEntity( + @PrimaryKey + val id: Int, + val albumId: Int, + val title: String, + val photoUrl: String, + val thumbnailUrl: String +) { + companion object { + const val TABLE_NAME = "photos" + } +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/room/entities/User.kt b/base/src/main/java/com/hako/base/room/entities/User.kt new file mode 100644 index 0000000..7f847bc --- /dev/null +++ b/base/src/main/java/com/hako/base/room/entities/User.kt @@ -0,0 +1,20 @@ +package com.hako.base.room.entities + +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity(tableName = UserEntity.TABLE_NAME, indices = [Index(value = ["id"], unique = true)]) +data class UserEntity( + @PrimaryKey + val id: Int, + val realName: String, + val userName: String, + val email: String, + val phone: String, + val website: String +) { + companion object { + const val TABLE_NAME = "users" + } +} \ No newline at end of file From 14e9eff32596c55e4f863ee39d642ae92cd132a9 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Sun, 2 Feb 2020 14:03:11 -0300 Subject: [PATCH 05/12] add base room implementation --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 2 +- .../com/hako/friendlists/MainApplication.kt | 25 +++++++++++++++++++ .../com/hako/friendlists/view/HomeActivity.kt | 2 +- base/build.gradle | 2 ++ .../main/java/com/hako/base/di/BaseModules.kt | 16 ++++++++++++ .../room/{Database.kt => BaseDatabase.kt} | 2 +- .../java/com/hako/base/room/dao/AlbumDao.kt | 2 +- .../java/com/hako/base/room/dao/PhotoDao.kt | 2 +- .../java/com/hako/base/room/dao/UserDao.kt | 2 +- 10 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 base/src/main/java/com/hako/base/di/BaseModules.kt rename base/src/main/java/com/hako/base/room/{Database.kt => BaseDatabase.kt} (92%) diff --git a/app/build.gradle b/app/build.gradle index 0b27de6..552d861 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,4 +45,5 @@ android { dependencies { implementation project(":base") + implementation project(":userlist") } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5322f2e..a241d9b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ android:theme="@style/AppTheme"> diff --git a/app/src/main/java/com/hako/friendlists/MainApplication.kt b/app/src/main/java/com/hako/friendlists/MainApplication.kt index 4e58a5a..c2b26db 100644 --- a/app/src/main/java/com/hako/friendlists/MainApplication.kt +++ b/app/src/main/java/com/hako/friendlists/MainApplication.kt @@ -1,7 +1,32 @@ package com.hako.friendlists import android.app.Application +import com.hako.base.di.baseModule +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin +import timber.log.Timber +@Suppress("unused") class MainApplication : Application() { + override fun onCreate() { + super.onCreate() + setupLogger() + setupDi() + } + private fun setupLogger() { + Timber.plant(Timber.DebugTree()) + } + + private fun setupDi() { + startKoin { + androidContext(this@MainApplication) + + modules( + listOf( + baseModule + ) + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/hako/friendlists/view/HomeActivity.kt b/app/src/main/java/com/hako/friendlists/view/HomeActivity.kt index 9147d3e..3b3e7ed 100644 --- a/app/src/main/java/com/hako/friendlists/view/HomeActivity.kt +++ b/app/src/main/java/com/hako/friendlists/view/HomeActivity.kt @@ -1,4 +1,4 @@ -package com.hako.friendlists.home +package com.hako.friendlists.view import androidx.appcompat.app.AppCompatActivity diff --git a/base/build.gradle b/base/build.gradle index 75c9e33..817b5e5 100644 --- a/base/build.gradle +++ b/base/build.gradle @@ -12,6 +12,8 @@ android { minSdkVersion build_versions.min_sdk targetSdkVersion build_versions.target_sdk testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + buildConfigField "String", "DB_NAME", '"friendlists.db"' } compileOptions { diff --git a/base/src/main/java/com/hako/base/di/BaseModules.kt b/base/src/main/java/com/hako/base/di/BaseModules.kt new file mode 100644 index 0000000..e535755 --- /dev/null +++ b/base/src/main/java/com/hako/base/di/BaseModules.kt @@ -0,0 +1,16 @@ +package com.hako.base.di + +import androidx.room.Room +import com.hako.base.BuildConfig +import com.hako.base.room.BaseDatabase +import org.koin.dsl.module + +val baseModule = module { + + // Room database + single { Room.databaseBuilder(get(), BaseDatabase::class.java, BuildConfig.DB_NAME).build() } + factory { get().userDao() } + factory { get().albumDao() } + factory { get().photoDao() } + +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/room/Database.kt b/base/src/main/java/com/hako/base/room/BaseDatabase.kt similarity index 92% rename from base/src/main/java/com/hako/base/room/Database.kt rename to base/src/main/java/com/hako/base/room/BaseDatabase.kt index 0358461..47648b7 100644 --- a/base/src/main/java/com/hako/base/room/Database.kt +++ b/base/src/main/java/com/hako/base/room/BaseDatabase.kt @@ -10,7 +10,7 @@ import com.hako.base.room.entities.PhotoEntity import com.hako.base.room.entities.UserEntity @Database(entities = [UserEntity::class, AlbumEntity::class, PhotoEntity::class], version = 1, exportSchema = false) -abstract class Database : RoomDatabase() { +abstract class BaseDatabase : RoomDatabase() { abstract fun userDao(): UserDao abstract fun albumDao(): AlbumDao abstract fun photoDao(): PhotoDao diff --git a/base/src/main/java/com/hako/base/room/dao/AlbumDao.kt b/base/src/main/java/com/hako/base/room/dao/AlbumDao.kt index 9988b89..5d452c4 100644 --- a/base/src/main/java/com/hako/base/room/dao/AlbumDao.kt +++ b/base/src/main/java/com/hako/base/room/dao/AlbumDao.kt @@ -19,7 +19,7 @@ interface AlbumDao { val all: List @Query("SELECT COUNT(*) FROM ${AlbumEntity.TABLE_NAME}") - fun count(page: Int): Int + fun count(): Int @Query("DELETE FROM ${AlbumEntity.TABLE_NAME}") fun nukeDatabase() diff --git a/base/src/main/java/com/hako/base/room/dao/PhotoDao.kt b/base/src/main/java/com/hako/base/room/dao/PhotoDao.kt index 2f696de..b61d826 100644 --- a/base/src/main/java/com/hako/base/room/dao/PhotoDao.kt +++ b/base/src/main/java/com/hako/base/room/dao/PhotoDao.kt @@ -19,7 +19,7 @@ interface PhotoDao { val all: List @Query("SELECT COUNT(*) FROM ${PhotoEntity.TABLE_NAME}") - fun count(page: Int): Int + fun count(): Int @Query("DELETE FROM ${PhotoEntity.TABLE_NAME}") fun nukeDatabase() diff --git a/base/src/main/java/com/hako/base/room/dao/UserDao.kt b/base/src/main/java/com/hako/base/room/dao/UserDao.kt index 3546001..69879cc 100644 --- a/base/src/main/java/com/hako/base/room/dao/UserDao.kt +++ b/base/src/main/java/com/hako/base/room/dao/UserDao.kt @@ -19,7 +19,7 @@ interface UserDao { val all: List @Query("SELECT COUNT(*) FROM ${UserEntity.TABLE_NAME}") - fun count(page: Int): Int + fun count(): Int @Query("DELETE FROM ${UserEntity.TABLE_NAME}") fun nukeDatabase() From 6a2722177ee4d70adb6d0fef3c7762ba6189857e Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Sun, 2 Feb 2020 14:59:33 -0300 Subject: [PATCH 06/12] implement navigation --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 2 +- .../com/hako/friendlists/view/HomeActivity.kt | 7 ---- .../com/hako/friendlists/view/MainActivity.kt | 22 +++++++++++++ app/src/main/res/layout/activity_main.xml | 8 +++++ .../main/res/navigation/main_navigation.xml | 9 +++++ app/versions.gradle | 33 ------------------- base/build.gradle | 2 ++ .../base/extensions/NavigationExtensions.kt | 19 +++++++++++ base/versions.gradle | 3 ++ .../friendlist/feature/UserlistFragment.kt | 12 ++++++- .../src/main/res/layout/fragment_userlist.xml | 15 +++++++++ .../res/navigation/userlist_navigation.xml | 14 ++++++++ 13 files changed, 105 insertions(+), 43 deletions(-) delete mode 100644 app/src/main/java/com/hako/friendlists/view/HomeActivity.kt create mode 100644 app/src/main/java/com/hako/friendlists/view/MainActivity.kt create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/navigation/main_navigation.xml delete mode 100644 app/versions.gradle create mode 100644 base/src/main/java/com/hako/base/extensions/NavigationExtensions.kt create mode 100644 userlist/src/main/res/layout/fragment_userlist.xml create mode 100644 userlist/src/main/res/navigation/userlist_navigation.xml diff --git a/app/build.gradle b/app/build.gradle index 552d861..4a238fd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,4 @@ -apply from: 'versions.gradle' +apply from: '../versions.gradle' apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a241d9b..779efa4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ android:theme="@style/AppTheme"> diff --git a/app/src/main/java/com/hako/friendlists/view/HomeActivity.kt b/app/src/main/java/com/hako/friendlists/view/HomeActivity.kt deleted file mode 100644 index 3b3e7ed..0000000 --- a/app/src/main/java/com/hako/friendlists/view/HomeActivity.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.hako.friendlists.view - -import androidx.appcompat.app.AppCompatActivity - -class HomeActivity : AppCompatActivity() { - -} \ No newline at end of file diff --git a/app/src/main/java/com/hako/friendlists/view/MainActivity.kt b/app/src/main/java/com/hako/friendlists/view/MainActivity.kt new file mode 100644 index 0000000..3652198 --- /dev/null +++ b/app/src/main/java/com/hako/friendlists/view/MainActivity.kt @@ -0,0 +1,22 @@ +package com.hako.friendlists.view + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.findNavController +import com.hako.friendlists.R + +class MainActivity : AppCompatActivity() { + + private val navController by lazy { findNavController(R.id.main_fragment_container) } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + setupNavigation() + } + + private fun setupNavigation() { + navController.setGraph(R.navigation.main_navigation) + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..cf47f54 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/app/src/main/res/navigation/main_navigation.xml b/app/src/main/res/navigation/main_navigation.xml new file mode 100644 index 0000000..4befeb8 --- /dev/null +++ b/app/src/main/res/navigation/main_navigation.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/versions.gradle b/app/versions.gradle deleted file mode 100644 index 1c984d7..0000000 --- a/app/versions.gradle +++ /dev/null @@ -1,33 +0,0 @@ -ext.deps = [:] - -def versions = [:] -versions.kotlin = "1.3.41" -versions.gradle = "3.5.3" - -def deps = [:] - -def project = [:] -project.kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin" -project.gradle = "com.android.tools.build:gradle:$versions.gradle" -deps.project = project - -def build_versions = [:] -build_versions.min_sdk = 21 -build_versions.target_sdk = 29 -build_versions.build_tools = "29.0.3" -ext.build_versions = build_versions - -def kotlin = [:] -kotlin.version = "$versions.kotlin" -kotlin.std_lib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin" -deps.kotlin = kotlin - -ext.deps = deps - -def addRepos(RepositoryHandler handler) { - handler.google() - handler.jcenter() - handler.maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } -} - -ext.addRepos = this.&addRepos diff --git a/base/build.gradle b/base/build.gradle index 817b5e5..b6dffda 100644 --- a/base/build.gradle +++ b/base/build.gradle @@ -39,6 +39,8 @@ dependencies { api deps.androidx.lifecycle_ext api deps.androidx.lifecycle_viewmodel api deps.androidx.recycler_view + api deps.androidx.navigation_fragment + api deps.androidx.navigation_ui api deps.retrofit.runtime api deps.retrofit.gson api deps.retrofit.rx diff --git a/base/src/main/java/com/hako/base/extensions/NavigationExtensions.kt b/base/src/main/java/com/hako/base/extensions/NavigationExtensions.kt new file mode 100644 index 0000000..0045856 --- /dev/null +++ b/base/src/main/java/com/hako/base/extensions/NavigationExtensions.kt @@ -0,0 +1,19 @@ +package com.hako.base.extensions + +import androidx.annotation.IdRes +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.NavHostFragment + +fun AppCompatActivity.findNavHostFragment(@IdRes id: Int) = + supportFragmentManager.findFragmentById(id) as NavHostFragment + +fun Fragment.findNavHostFragment(@IdRes id: Int) = + childFragmentManager.findFragmentById(id) as NavHostFragment + +fun Fragment.findNavController(@IdRes id: Int) = + androidx.navigation.Navigation.findNavController(view?.findViewById(id) ?: viewNotFound(id, this)) + +private fun viewNotFound(@IdRes id: Int, fragment: Fragment): Nothing = throw IllegalStateException( + "View ID $id at '${fragment::class.java.simpleName}' not found." +) \ No newline at end of file diff --git a/base/versions.gradle b/base/versions.gradle index b8ac739..be2f710 100644 --- a/base/versions.gradle +++ b/base/versions.gradle @@ -7,6 +7,7 @@ versions.androidx_core = "1.1.0" versions.androidx_constraint_layout = "1.1.3" versions.androidx_lifecycle = "2.2.0" versions.androidx_recycler_view = "1.1.0" +versions.androidx_navigation = "2.2.0" versions.okhttp_logging_interceptor = "4.3.1" versions.retrofit = "2.7.1" versions.timber = "4.7.1" @@ -33,6 +34,8 @@ androidx.constraint_layout = "androidx.constraintlayout:constraintlayout:$versio androidx.lifecycle_ext = "androidx.lifecycle:lifecycle-extensions:$versions.androidx_lifecycle" androidx.lifecycle_viewmodel = "androidx.lifecycle:lifecycle-viewmodel-ktx:$versions.androidx_lifecycle" androidx.recycler_view = "androidx.recyclerview:recyclerview:$versions.androidx_recycler_view" +androidx.navigation_fragment = "androidx.navigation:navigation-fragment-ktx:$versions.androidx_navigation" +androidx.navigation_ui = "androidx.navigation:navigation-ui-ktx:$versions.androidx_navigation" deps.androidx = androidx def retrofit = [:] diff --git a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt index 509c2e1..05c0fbf 100644 --- a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt +++ b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt @@ -1,4 +1,14 @@ package com.hako.friendlist.feature -class UserlistFragment { +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.hako.friendlist_userlist.R + +class UserlistFragment : Fragment() { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return inflater.inflate(R.layout.fragment_userlist, container, false) + } } \ No newline at end of file diff --git a/userlist/src/main/res/layout/fragment_userlist.xml b/userlist/src/main/res/layout/fragment_userlist.xml new file mode 100644 index 0000000..6c7bfe6 --- /dev/null +++ b/userlist/src/main/res/layout/fragment_userlist.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/userlist/src/main/res/navigation/userlist_navigation.xml b/userlist/src/main/res/navigation/userlist_navigation.xml new file mode 100644 index 0000000..2343782 --- /dev/null +++ b/userlist/src/main/res/navigation/userlist_navigation.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file From 451d14ad9565a0a3ff40a4cb25665e7a8258fde5 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Sun, 2 Feb 2020 18:46:51 -0300 Subject: [PATCH 07/12] integrate lottie and create view for users --- app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/values/styles.xml | 3 +- base/build.gradle | 1 + .../hako/base/extensions/ViewExtensions.kt | 10 ++++ .../java/com/hako/base/widgets/LikeButton.kt | 46 +++++++++++++++++++ base/src/main/res/drawable/bg_card.xml | 9 ++++ base/src/main/res/layout/like_button.xml | 19 ++++++++ base/src/main/res/raw/like_animation.json | 1 + base/src/main/res/values/colors.xml | 8 ++++ base/versions.gradle | 2 + build.gradle | 4 -- .../friendlist/feature/UserlistFragment.kt | 8 +++- .../src/main/res/layout/fragment_userlist.xml | 15 +++--- .../src/main/res/layout/item_user_card.xml | 40 ++++++++++++++++ 14 files changed, 152 insertions(+), 16 deletions(-) create mode 100644 base/src/main/java/com/hako/base/extensions/ViewExtensions.kt create mode 100644 base/src/main/java/com/hako/base/widgets/LikeButton.kt create mode 100644 base/src/main/res/drawable/bg_card.xml create mode 100644 base/src/main/res/layout/like_button.xml create mode 100644 base/src/main/res/raw/like_animation.json create mode 100644 base/src/main/res/values/colors.xml create mode 100644 userlist/src/main/res/layout/item_user_card.xml diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index cf47f54..dd69f9f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,4 +5,4 @@ android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" - app:defaultNavHost="true" /> \ No newline at end of file + app:defaultNavHost="true"/> \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 5885930..f69921a 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,11 +1,10 @@ - diff --git a/base/build.gradle b/base/build.gradle index b6dffda..57e4157 100644 --- a/base/build.gradle +++ b/base/build.gradle @@ -52,6 +52,7 @@ dependencies { api deps.rx.android api deps.okhttp_logging_interceptor api deps.timber + api deps.lottie //Testing api deps.testing.junit api deps.testing.koin diff --git a/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt b/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt new file mode 100644 index 0000000..93700d1 --- /dev/null +++ b/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt @@ -0,0 +1,10 @@ +package com.hako.base.extensions + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.LayoutRes + +fun ViewGroup.inflate(@LayoutRes layout: Int, attachToRoot: Boolean = false) = + LayoutInflater + .from(context) + .inflate(layout, this, attachToRoot) diff --git a/base/src/main/java/com/hako/base/widgets/LikeButton.kt b/base/src/main/java/com/hako/base/widgets/LikeButton.kt new file mode 100644 index 0000000..357dbe1 --- /dev/null +++ b/base/src/main/java/com/hako/base/widgets/LikeButton.kt @@ -0,0 +1,46 @@ +package com.hako.base.widgets + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout +import com.hako.base.R +import com.hako.base.extensions.inflate +import kotlinx.android.synthetic.main.like_button.view.* + +private const val LIKE_MIN_FRAME = 0 +private const val LIKE_MAX_FRAME = 28 +private const val LIKE_ANIM_SPEED = 1f +private const val DISLIKE_MIN_FRAME = 28 +private const val DISLIKE_MAX_FRAME = 70 +private const val DISLIKE_ANIM_SPEED = 2f + +class LikeButton @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + init { + inflate(R.layout.like_button, true) + } + + fun like() { + like_button_animation_view.frame = LIKE_MAX_FRAME + } + + fun dislike() { + like_button_animation_view.frame = LIKE_MIN_FRAME + } + + fun playLike() { + like_button_animation_view.setMinAndMaxFrame(LIKE_MIN_FRAME, LIKE_MAX_FRAME) + like_button_animation_view.speed = LIKE_ANIM_SPEED + like_button_animation_view.playAnimation() + } + + fun playDislike() { + like_button_animation_view.setMinAndMaxFrame(DISLIKE_MIN_FRAME, DISLIKE_MAX_FRAME) + like_button_animation_view.speed = DISLIKE_ANIM_SPEED + like_button_animation_view.playAnimation() + } +} \ No newline at end of file diff --git a/base/src/main/res/drawable/bg_card.xml b/base/src/main/res/drawable/bg_card.xml new file mode 100644 index 0000000..a7029e8 --- /dev/null +++ b/base/src/main/res/drawable/bg_card.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/base/src/main/res/layout/like_button.xml b/base/src/main/res/layout/like_button.xml new file mode 100644 index 0000000..29c09f0 --- /dev/null +++ b/base/src/main/res/layout/like_button.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/base/src/main/res/raw/like_animation.json b/base/src/main/res/raw/like_animation.json new file mode 100644 index 0000000..28a586a --- /dev/null +++ b/base/src/main/res/raw/like_animation.json @@ -0,0 +1 @@ +{"v":"5.5.1","fr":30,"ip":0,"op":70,"w":160,"h":160,"nm":"Love and Unlove","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"crack-L/love Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[79,127,0],"ix":2},"a":{"a":0,"k":[99,147,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[9.19,3.12],[-4.54,-21.16],[-6.73,-7.61],[-14.68,-9.59],[-0.53,-0.35],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[-4.52,-8.61],[-21.01,-7.14],[2.14,9.93],[11.62,13.14],[0.32,0.21],[0,0],[0,0],[0,0]],"v":[[15.875,30.375],[40.875,21.375],[8.875,8.375],[34.875,-4.625],[11.875,-13.625],[20.875,-24.135],[-0.305,-43.235],[-36.335,-10.415],[-21.345,15.735],[18.745,49.565],[19.875,50.375],[19.875,43.375],[24.875,37.375]],"c":true}]},{"t":16,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[9.19,3.12],[-4.54,-21.16],[-6.73,-7.61],[-14.68,-9.59],[-0.53,-0.35],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[-4.52,-8.61],[-21.01,-7.14],[2.14,9.93],[11.62,13.14],[0.32,0.21],[0,0],[0,0],[0,0]],"v":[[15.875,30.375],[24.494,20.732],[8.875,8.375],[22.795,-3.103],[11.875,-13.625],[20.875,-24.135],[-0.305,-43.235],[-36.335,-10.415],[-21.345,15.735],[18.745,49.565],[19.875,50.375],[19.875,43.375],[24.875,37.375]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.83,0.18,0.18,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[98.568,146.527],"ix":2},"a":{"a":0,"k":[19.443,49.902],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[-10.469]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[-5.938]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[-9.942]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[-4.716]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[-8.401]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[-4.873]},{"t":19,"s":[-15]}],"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[100]},{"t":26,"s":[1]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"crack-R/love Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[79,127,0],"ix":2},"a":{"a":0,"k":[99,147,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[4.55,-21.16],[6.729,-7.61],[14.68,-9.59],[0,0],[0.32,0.21],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.04,1.44],[-9.229,3.13]],"o":[[-2.13,9.93],[-11.611,13.14],[-0.51,0.33],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[4.51,-8.64],[21.01,-7.14]],"v":[[32.365,-10.715],[17.375,15.435],[-22.715,49.265],[-24.875,50.675],[-25.435,50.315],[-25.915,43.075],[-20.915,37.075],[-29.915,30.075],[-4.915,21.075],[-36.915,8.075],[-10.915,-4.925],[-33.915,-13.925],[-24.875,-24.365],[-3.656,-43.535]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[4.55,-21.16],[6.729,-7.61],[14.68,-9.59],[0,0],[0.32,0.21],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.592,2.962],[-9.229,3.13]],"o":[[-2.13,9.93],[-11.611,13.14],[-0.51,0.33],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[3.978,-7.912],[21.01,-7.14]],"v":[[32.365,-10.715],[17.375,15.435],[-22.715,49.265],[-24.875,50.675],[-25.435,50.315],[-25.915,43.075],[-20.915,37.075],[-27.419,29.73],[-6.748,20.272],[-33.29,9.53],[-11.387,-3.666],[-28.853,-14.095],[-24.875,-24.365],[-3.656,-43.535]],"c":true}]},{"t":16,"s":[{"i":[[4.55,-21.16],[6.729,-7.61],[14.68,-9.59],[0,0],[0.32,0.21],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.152,-0.028],[-2.807,6.31],[-9.229,3.13]],"o":[[-2.13,9.93],[-11.611,13.14],[-0.51,0.33],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.026,-3.877],[2.807,-6.31],[21.01,-7.14]],"v":[[32.365,-10.715],[17.375,15.435],[-22.715,49.265],[-24.875,50.675],[-25.435,50.315],[-25.915,43.075],[-20.915,37.075],[-21.929,28.97],[-10.78,18.505],[-25.315,12.731],[-12.424,-0.897],[-28.309,-12.321],[-24.875,-24.365],[-3.656,-43.535]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.83,0.18,0.18,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[98.993,147.034],"to":[0,0],"ti":[0,0]},{"t":14,"s":[98.993,147.034]}],"ix":2},"a":{"a":0,"k":[-25.922,50.109],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[10.938]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0.208]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[4.265]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0.091]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[9.333]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[4.848]},{"t":16,"s":[15]}],"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[100]},{"t":26,"s":[1]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"love/love disable","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7,"s":[34]},{"t":14,"s":[99]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[-5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[-3]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[3]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[-2]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[2]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":17,"s":[-1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":19,"s":[1]},{"t":21,"s":[0]}],"ix":10},"p":{"a":0,"k":[80,127.607,0],"ix":2},"a":{"a":0,"k":[99.038,147.6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6,"x":"var $bm_rt;\nvar maxDev, spd, decay, t, x, y;\nmaxDev = 10;\nspd = 30;\ndecay = 3;\nt = $bm_sub(time, inPoint);\nx = $bm_sum($bm_transform.scale[0], $bm_div($bm_mul(maxDev, Math.sin($bm_mul(spd, t))), Math.exp($bm_mul(decay, t))));\ny = $bm_div($bm_mul($bm_transform.scale[0], $bm_transform.scale[1]), x);\n$bm_rt = [\n x,\n y\n];"}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.509,0.333],[11.614,13.14],[2.134,9.936],[-21.012,-7.139],[-4.515,-8.635],[-9.227,3.135],[4.543,-21.158],[6.73,-7.616],[14.683,-9.592]],"o":[[0,0],[-14.682,-9.592],[-6.73,-7.616],[-4.542,-21.158],[9.227,3.135],[4.515,-8.635],[21.011,-7.139],[-2.133,9.936],[-11.614,13.14],[-0.508,0.333]],"v":[[0,50.676],[-2.165,49.266],[-42.255,15.439],[-57.246,-10.717],[-21.221,-43.537],[0,-24.365],[21.221,-43.537],[57.245,-10.717],[42.255,15.439],[2.164,49.266]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.793550848961,0.793550848961,0.793550848961,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[99.038,108.457],"ix":2},"a":{"a":0,"k":[0,11.274],"ix":1},"s":{"a":0,"k":[100,100],"ix":3,"x":"var $bm_rt;\nvar maxDev, spd, decay, t, x, y;\nmaxDev = 10;\nspd = 30;\ndecay = 6;\nt = $bm_sub(time, inPoint);\nx = $bm_sum($bm_transform.scale[0], $bm_div($bm_mul(maxDev, Math.sin($bm_mul(spd, t))), Math.exp($bm_mul(decay, t))));\ny = $bm_div($bm_mul($bm_transform.scale[0], $bm_transform.scale[1]), x);\n$bm_rt = [\n x,\n y\n];"},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"love/love enable","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[80,98.107,0],"ix":2},"a":{"a":0,"k":[99.038,117.735,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6,"x":"var $bm_rt;\nvar maxDev, spd, decay, t, x, y;\nmaxDev = 10;\nspd = 40;\ndecay = 4.5;\nt = $bm_sub(time, inPoint);\nx = $bm_sum($bm_transform.scale[0], $bm_div($bm_mul(maxDev, Math.sin($bm_mul(spd, t))), Math.exp($bm_mul(decay, t))));\ny = $bm_div($bm_mul($bm_transform.scale[0], $bm_transform.scale[1]), x);\n$bm_rt = [\n x,\n y\n];"}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.509,0.333],[11.614,13.14],[2.134,9.936],[-21.012,-7.139],[-4.515,-8.635],[-9.227,3.135],[4.543,-21.158],[6.73,-7.616],[14.683,-9.592]],"o":[[0,0],[-14.682,-9.592],[-6.73,-7.616],[-4.542,-21.158],[9.227,3.135],[4.515,-8.635],[21.011,-7.139],[-2.133,9.936],[-11.614,13.14],[-0.508,0.333]],"v":[[0,50.676],[-2.165,49.266],[-42.255,15.439],[-57.246,-10.717],[-21.221,-43.537],[0,-24.365],[21.221,-43.537],[57.245,-10.717],[42.255,15.439],[2.164,49.266]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0.793550848961,0.793550848961,0.793550848961,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[0.792156875134,0.792156875134,0.792156875134,1]},{"t":2,"s":[0.798314929008,0.04177454859,0.258352786303,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[99.038,91.234],"ix":2},"a":{"a":0,"k":[0,-5.949],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[107,107]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":2,"s":[91,91]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":4,"s":[107,107]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[91,91]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[107,107]},{"t":11,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"dislike","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[80,80,0],"ix":2},"a":{"a":0,"k":[80,80,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":160,"h":160,"ip":30,"op":90,"st":30,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"like","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[80,80,0],"ix":2},"a":{"a":0,"k":[80,80,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":160,"h":160,"ip":0,"op":30,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/base/src/main/res/values/colors.xml b/base/src/main/res/values/colors.xml new file mode 100644 index 0000000..2a9146f --- /dev/null +++ b/base/src/main/res/values/colors.xml @@ -0,0 +1,8 @@ + + + #EEEEEE + + #00000000 + + #FFFFFF + \ No newline at end of file diff --git a/base/versions.gradle b/base/versions.gradle index be2f710..050b956 100644 --- a/base/versions.gradle +++ b/base/versions.gradle @@ -19,6 +19,7 @@ versions.junit = "4.13" versions.test = "1.2.0" versions.test_ext = "1.1.1" versions.espresso = "3.2.0" +versions.lottie = "3.3.1" def deps = [:] @@ -75,5 +76,6 @@ deps.testing = testing deps.okhttp_logging_interceptor = "com.squareup.okhttp3:logging-interceptor:$versions.okhttp_logging_interceptor" deps.timber = "com.jakewharton.timber:timber:$versions.timber" +deps.lottie = "com.airbnb.android:lottie:$versions.lottie" ext.deps = deps diff --git a/build.gradle b/build.gradle index 46f5087..155de55 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,3 @@ detekt { task clean(type: Delete) { delete rootProject.buildDir } - -repositories { - google() -} diff --git a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt index 05c0fbf..ad27523 100644 --- a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt +++ b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt @@ -8,7 +8,13 @@ import androidx.fragment.app.Fragment import com.hako.friendlist_userlist.R class UserlistFragment : Fragment() { - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { return inflater.inflate(R.layout.fragment_userlist, container, false) } + } \ No newline at end of file diff --git a/userlist/src/main/res/layout/fragment_userlist.xml b/userlist/src/main/res/layout/fragment_userlist.xml index 6c7bfe6..d67170b 100644 --- a/userlist/src/main/res/layout/fragment_userlist.xml +++ b/userlist/src/main/res/layout/fragment_userlist.xml @@ -1,15 +1,14 @@ - + + \ No newline at end of file diff --git a/userlist/src/main/res/layout/item_user_card.xml b/userlist/src/main/res/layout/item_user_card.xml new file mode 100644 index 0000000..f838949 --- /dev/null +++ b/userlist/src/main/res/layout/item_user_card.xml @@ -0,0 +1,40 @@ + + + + + + + + + + \ No newline at end of file From 7d4432278ef5819d293b7a038f0253a875917163 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Sun, 2 Feb 2020 22:35:44 -0300 Subject: [PATCH 08/12] implement recycler view for userlist --- .../base/extensions/ApplicationExtension.kt | 8 +++ .../hako/base/extensions/ListExtensions.kt | 23 +++++++ .../hako/base/extensions/ViewExtensions.kt | 3 +- .../friendlist/feature/UserlistFragment.kt | 57 +++++++++++++-- .../com/hako/friendlist/model/UserModels.kt | 38 +++------- .../hako/friendlist/widget/UserlistAdapter.kt | 69 +++++++++++++++++++ .../src/main/res/layout/fragment_userlist.xml | 10 ++- .../src/main/res/layout/item_user_card.xml | 4 ++ 8 files changed, 176 insertions(+), 36 deletions(-) create mode 100644 base/src/main/java/com/hako/base/extensions/ApplicationExtension.kt create mode 100644 base/src/main/java/com/hako/base/extensions/ListExtensions.kt create mode 100644 userlist/src/main/java/com/hako/friendlist/widget/UserlistAdapter.kt diff --git a/base/src/main/java/com/hako/base/extensions/ApplicationExtension.kt b/base/src/main/java/com/hako/base/extensions/ApplicationExtension.kt new file mode 100644 index 0000000..cd7e477 --- /dev/null +++ b/base/src/main/java/com/hako/base/extensions/ApplicationExtension.kt @@ -0,0 +1,8 @@ +package com.hako.base.extensions + +import android.content.Context +import android.widget.Toast + +fun Context.toast(message: String) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show() +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/extensions/ListExtensions.kt b/base/src/main/java/com/hako/base/extensions/ListExtensions.kt new file mode 100644 index 0000000..61a3ded --- /dev/null +++ b/base/src/main/java/com/hako/base/extensions/ListExtensions.kt @@ -0,0 +1,23 @@ +package com.hako.base.extensions + +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView + +fun RecyclerView.Adapter<*>.autoNotify(oldList: List, newList: List, compare: (T, T) -> Boolean) { + val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() { + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return compare(oldList[oldItemPosition], newList[newItemPosition]) + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldList[oldItemPosition] == newList[newItemPosition] + } + + override fun getOldListSize() = oldList.size + + override fun getNewListSize() = newList.size + }) + + diff.dispatchUpdatesTo(this) +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt b/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt index 93700d1..5bd84f8 100644 --- a/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt +++ b/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt @@ -1,10 +1,11 @@ package com.hako.base.extensions import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.annotation.LayoutRes -fun ViewGroup.inflate(@LayoutRes layout: Int, attachToRoot: Boolean = false) = +fun ViewGroup.inflate(@LayoutRes layout: Int, attachToRoot: Boolean = false): View = LayoutInflater .from(context) .inflate(layout, this, attachToRoot) diff --git a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt index ad27523..f83776b 100644 --- a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt +++ b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt @@ -5,16 +5,63 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.hako.base.extensions.toast +import com.hako.friendlist.model.UserViewable +import com.hako.friendlist.widget.UserlistAdapter import com.hako.friendlist_userlist.R +import kotlinx.android.synthetic.main.fragment_userlist.* class UserlistFragment : Fragment() { + private val chatAdapter by lazy { UserlistAdapter() } + override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - return inflater.inflate(R.layout.fragment_userlist, container, false) + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View = inflater.inflate(R.layout.fragment_userlist, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setRecycler() } + private fun setRecycler() { + fragment_userlist_recycler_container.apply { + layoutManager = LinearLayoutManager(context) + adapter = chatAdapter.apply { + addAll( + listOf( + UserViewable(1, "Carlos Martinez", "carlitos"), + UserViewable(2, "Carlos Martinez", "carlitos"), + UserViewable(3, "Carlos Martinez", "carlitos"), + UserViewable(4, "Carlos Martinez", "carlitos"), + UserViewable(5, "Carlos Martinez", "carlitos"), + UserViewable(6, "Carlos Martinez", "carlitos"), + UserViewable(7, "Carlos Martinez", "carlitos"), + UserViewable(8, "Carlos Martinez", "carlitos"), + UserViewable(9, "Carlos Martinez", "carlitos"), + UserViewable(10, "Carlos Martinez", "carlitos"), + UserViewable(11, "Carlos Martinez", "carlitos"), + UserViewable(12, "Carlos Martinez", "carlitos"), + UserViewable(13, "Carlos Martinez", "carlitos"), + UserViewable(14, "Carlos Martinez", "carlitos"), + UserViewable(15, "Carlos Martinez", "carlitos"), + UserViewable(16, "Carlos Martinez", "carlitos"), + UserViewable(17, "Carlos Martinez", "carlitos"), + UserViewable(18, "Carlos Martinez", "carlitos"), + UserViewable(19, "Carlos Martinez", "carlitos"), + UserViewable(20, "Carlos Martinez", "carlitos") + ) + ) + + onItemClick = { + context.toast(it.realName) + } + + onFavoriteClick = { + context.toast(it.userName) + } + } + } + } } \ No newline at end of file diff --git a/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt b/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt index f2d3428..6c6992a 100644 --- a/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt +++ b/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt @@ -2,6 +2,7 @@ package com.hako.friendlist.model import android.os.Parcelable import com.google.gson.annotations.SerializedName +import com.hako.base.room.entities.UserEntity import kotlinx.android.parcel.Parcelize @Parcelize @@ -10,35 +11,18 @@ data class User( @SerializedName("name") val realName: String, @SerializedName("username") val userName: String, @SerializedName("email") val email: String, - @SerializedName("amount") val balance: Address, @SerializedName("phone") val phone: String, - @SerializedName("website") val website: String, - @SerializedName("company") val company: Company -) : Parcelable { + @SerializedName("website") val website: String +) : Parcelable - @Parcelize - data class Address( - @SerializedName("street") val street: String, - @SerializedName("suite") val realName: String, - @SerializedName("city") val userName: String, - @SerializedName("zipcode") val email: String, - @SerializedName("geo") val geoLocation: GeoLocation - ) : Parcelable { +data class UserViewable( + val id: Int, + val realName: String, + val userName: String, + var isFavorite: Boolean = false +) { + fun User.toUserViewable() = UserViewable(this.id, this.realName, this.userName) - @Parcelize - data class GeoLocation( - @SerializedName("lat") val latitude: String, - @SerializedName("lng") val longitude: String - ) : Parcelable - } - - @Parcelize - data class Company( - @SerializedName("name") val name: String, - @SerializedName("catchPhrase") val catchPhrase: String, - @SerializedName("bs") val keywords: String - ) : Parcelable { - fun getKeywordList() = keywords.split(" ") - } + fun UserEntity.toUserViewable() = UserViewable(this.id, this.realName, this.userName) } diff --git a/userlist/src/main/java/com/hako/friendlist/widget/UserlistAdapter.kt b/userlist/src/main/java/com/hako/friendlist/widget/UserlistAdapter.kt new file mode 100644 index 0000000..a6bfe05 --- /dev/null +++ b/userlist/src/main/java/com/hako/friendlist/widget/UserlistAdapter.kt @@ -0,0 +1,69 @@ +package com.hako.friendlist.widget + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.hako.base.extensions.autoNotify +import com.hako.friendlist.model.UserViewable +import com.hako.friendlist_userlist.R +import kotlinx.android.synthetic.main.item_user_card.view.* +import kotlin.properties.Delegates + +class UserlistAdapter : RecyclerView.Adapter() { + + private var items by Delegates.observable(emptyList()) { _, oldList, newList -> + autoNotify(oldList, newList) { old, new -> old.id == new.id } + notifyDataSetChanged() + } + + var onItemClick: (UserViewable) -> Unit = { } + var onFavoriteClick: (UserViewable) -> Unit = { } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = + UserViewHolder( + LayoutInflater + .from(parent.context) + .inflate(R.layout.item_user_card, parent, false), + onItemClick, + onFavoriteClick + ) + + fun getItem(position: Int) = items[position] + + fun addAll(list: List) { + items = list + } + + override fun getItemCount() = items.size + + override fun onBindViewHolder(viewholder: RecyclerView.ViewHolder, position: Int) = + when (viewholder) { + is UserViewHolder -> viewholder.bind(items[position]) + else -> throw NoWhenBranchMatchedException("Undefined viewholder") + } +} + +class UserViewHolder(private val view: View, + private val onItemClick: (UserViewable) -> Unit, + private val onFavoriteClick: (UserViewable) -> Unit) : + RecyclerView.ViewHolder(view) { + + fun bind(user: UserViewable) = with(view) { + item_user_card_real_name.text = user.realName + item_user_card_user_name.text = user.userName + item_user_card_container.setOnClickListener { + onItemClick(user) + } + item_user_card_like_button.setOnClickListener { + onFavoriteClick(user) + } + } + + private fun setFavorite(status: Boolean) { + when (status) { + true -> view.item_user_card_like_button.like() + false -> view.item_user_card_like_button.dislike() + } + } +} \ No newline at end of file diff --git a/userlist/src/main/res/layout/fragment_userlist.xml b/userlist/src/main/res/layout/fragment_userlist.xml index d67170b..a208918 100644 --- a/userlist/src/main/res/layout/fragment_userlist.xml +++ b/userlist/src/main/res/layout/fragment_userlist.xml @@ -3,10 +3,14 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical"> + android:orientation="vertical" + android:id="@+id/fragment_userlist_base"> - diff --git a/userlist/src/main/res/layout/item_user_card.xml b/userlist/src/main/res/layout/item_user_card.xml index f838949..524ef91 100644 --- a/userlist/src/main/res/layout/item_user_card.xml +++ b/userlist/src/main/res/layout/item_user_card.xml @@ -2,8 +2,12 @@ From 259955ed5db3c94631790a8648a5556974deda0f Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Mon, 3 Feb 2020 13:01:55 -0300 Subject: [PATCH 09/12] implement viewmodel, domain layer and view layer for userlist --- app/build.gradle | 3 + app/src/main/AndroidManifest.xml | 2 + .../com/hako/friendlists/MainApplication.kt | 6 +- .../com/hako/friendlists/di/AppModules.kt | 18 ++++++ base/build.gradle | 2 - .../main/java/com/hako/base/di/BaseModules.kt | 16 ------ .../main/java/com/hako/base/domain/Either.kt | 33 +++++++++++ .../main/java/com/hako/base/domain/UseCase.kt | 5 ++ .../base/domain/database/DatabaseClient.kt | 17 ++++++ .../{room => domain/database}/dao/AlbumDao.kt | 4 +- .../{room => domain/database}/dao/PhotoDao.kt | 4 +- .../{room => domain/database}/dao/UserDao.kt | 7 ++- .../database}/entities/Album.kt | 2 +- .../database}/entities/Photos.kt | 2 +- .../database}/entities/User.kt | 2 +- .../hako/base/domain/network/RemoteClient.kt | 35 ++++++++++++ .../hako/base/domain/network/RequestStatus.kt | 7 +++ .../base/extensions/LiveDataExtensions.kt | 13 +++++ .../java/com/hako/base/room/BaseDatabase.kt | 17 ------ .../com/hako/friendlist/di/UserlistModules.kt | 17 ++++++ .../domain/datasource/UserlistDatasource.kt | 13 +++++ .../domain/datasource/UserlistRemoteApi.kt | 11 ++++ .../friendlist/domain/usecase/GetUsers.kt | 43 ++++++++++++++ .../friendlist/feature/UserlistFragment.kt | 56 ++++++++++--------- .../com/hako/friendlist/model/UserModels.kt | 10 ++-- .../friendlist/viewmodel/UserlistViewmodel.kt | 36 ++++++++++++ 26 files changed, 305 insertions(+), 76 deletions(-) create mode 100644 app/src/main/java/com/hako/friendlists/di/AppModules.kt delete mode 100644 base/src/main/java/com/hako/base/di/BaseModules.kt create mode 100644 base/src/main/java/com/hako/base/domain/Either.kt create mode 100644 base/src/main/java/com/hako/base/domain/UseCase.kt create mode 100644 base/src/main/java/com/hako/base/domain/database/DatabaseClient.kt rename base/src/main/java/com/hako/base/{room => domain/database}/dao/AlbumDao.kt (85%) rename base/src/main/java/com/hako/base/{room => domain/database}/dao/PhotoDao.kt (85%) rename base/src/main/java/com/hako/base/{room => domain/database}/dao/UserDao.kt (75%) rename base/src/main/java/com/hako/base/{room => domain/database}/entities/Album.kt (88%) rename base/src/main/java/com/hako/base/{room => domain/database}/entities/Photos.kt (89%) rename base/src/main/java/com/hako/base/{room => domain/database}/entities/User.kt (90%) create mode 100644 base/src/main/java/com/hako/base/domain/network/RemoteClient.kt create mode 100644 base/src/main/java/com/hako/base/domain/network/RequestStatus.kt create mode 100644 base/src/main/java/com/hako/base/extensions/LiveDataExtensions.kt delete mode 100644 base/src/main/java/com/hako/base/room/BaseDatabase.kt create mode 100644 userlist/src/main/java/com/hako/friendlist/di/UserlistModules.kt create mode 100644 userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistDatasource.kt create mode 100644 userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistRemoteApi.kt create mode 100644 userlist/src/main/java/com/hako/friendlist/domain/usecase/GetUsers.kt create mode 100644 userlist/src/main/java/com/hako/friendlist/viewmodel/UserlistViewmodel.kt diff --git a/app/build.gradle b/app/build.gradle index 4a238fd..2f3e31f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,6 +15,9 @@ android { versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + buildConfigField "String", "DB_NAME", '"friendlists.db"' + buildConfigField "String", "BASE_ENDPOINT", '"https://jsonplaceholder.typicode.com/"' } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 779efa4..c89e347 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ + + ().userDao() } + factory { get().albumDao() } + factory { get().photoDao() } + + // Retrofit + single { RemoteClient(BuildConfig.BASE_ENDPOINT) } +} \ No newline at end of file diff --git a/base/build.gradle b/base/build.gradle index 57e4157..88cc65c 100644 --- a/base/build.gradle +++ b/base/build.gradle @@ -12,8 +12,6 @@ android { minSdkVersion build_versions.min_sdk targetSdkVersion build_versions.target_sdk testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - - buildConfigField "String", "DB_NAME", '"friendlists.db"' } compileOptions { diff --git a/base/src/main/java/com/hako/base/di/BaseModules.kt b/base/src/main/java/com/hako/base/di/BaseModules.kt deleted file mode 100644 index e535755..0000000 --- a/base/src/main/java/com/hako/base/di/BaseModules.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.hako.base.di - -import androidx.room.Room -import com.hako.base.BuildConfig -import com.hako.base.room.BaseDatabase -import org.koin.dsl.module - -val baseModule = module { - - // Room database - single { Room.databaseBuilder(get(), BaseDatabase::class.java, BuildConfig.DB_NAME).build() } - factory { get().userDao() } - factory { get().albumDao() } - factory { get().photoDao() } - -} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/domain/Either.kt b/base/src/main/java/com/hako/base/domain/Either.kt new file mode 100644 index 0000000..2c90b33 --- /dev/null +++ b/base/src/main/java/com/hako/base/domain/Either.kt @@ -0,0 +1,33 @@ +package com.hako.base.domain + +sealed class Either { + + data class Left(val a: L) : Either() + data class Right(val b: R) : Either() + + val isRight get() = this is Right + val isLeft get() = this is Left + + fun left(a: L) = Left(a) + fun right(b: R) = Right(b) + + fun either(fnL: (L) -> Any, fnR: (R) -> Any): Any = + when (this) { + is Left -> fnL(a) + is Right -> fnR(b) + } +} + +fun ((A) -> B).c(f: (B) -> C): (A) -> C = { + f(this(it)) +} + +fun Either.flatMap(fn: (R) -> Either): Either = + when (this) { + is Either.Left -> Either.Left( + a + ) + is Either.Right -> fn(b) + } + +fun Either.map(fn: (R) -> (T)): Either = this.flatMap(fn.c(::right)) diff --git a/base/src/main/java/com/hako/base/domain/UseCase.kt b/base/src/main/java/com/hako/base/domain/UseCase.kt new file mode 100644 index 0000000..d9e178c --- /dev/null +++ b/base/src/main/java/com/hako/base/domain/UseCase.kt @@ -0,0 +1,5 @@ +package com.hako.base.domain + +interface UseCase { + fun execute(onSuccess: (List) -> Unit, onError: (Throwable) -> Unit, onLoading: () -> Unit) +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/domain/database/DatabaseClient.kt b/base/src/main/java/com/hako/base/domain/database/DatabaseClient.kt new file mode 100644 index 0000000..b78a001 --- /dev/null +++ b/base/src/main/java/com/hako/base/domain/database/DatabaseClient.kt @@ -0,0 +1,17 @@ +package com.hako.base.domain.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.hako.base.domain.database.dao.AlbumDao +import com.hako.base.domain.database.dao.PhotoDao +import com.hako.base.domain.database.dao.UserDao +import com.hako.base.domain.database.entities.AlbumEntity +import com.hako.base.domain.database.entities.PhotoEntity +import com.hako.base.domain.database.entities.UserEntity + +@Database(entities = [UserEntity::class, AlbumEntity::class, PhotoEntity::class], version = 1, exportSchema = false) +abstract class DatabaseClient : RoomDatabase() { + abstract fun userDao(): UserDao + abstract fun albumDao(): AlbumDao + abstract fun photoDao(): PhotoDao +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/room/dao/AlbumDao.kt b/base/src/main/java/com/hako/base/domain/database/dao/AlbumDao.kt similarity index 85% rename from base/src/main/java/com/hako/base/room/dao/AlbumDao.kt rename to base/src/main/java/com/hako/base/domain/database/dao/AlbumDao.kt index 5d452c4..3a395de 100644 --- a/base/src/main/java/com/hako/base/room/dao/AlbumDao.kt +++ b/base/src/main/java/com/hako/base/domain/database/dao/AlbumDao.kt @@ -1,10 +1,10 @@ -package com.hako.base.room.dao +package com.hako.base.domain.database.dao import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import com.hako.base.room.entities.AlbumEntity +import com.hako.base.domain.database.entities.AlbumEntity @Dao interface AlbumDao { diff --git a/base/src/main/java/com/hako/base/room/dao/PhotoDao.kt b/base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt similarity index 85% rename from base/src/main/java/com/hako/base/room/dao/PhotoDao.kt rename to base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt index b61d826..0fc562b 100644 --- a/base/src/main/java/com/hako/base/room/dao/PhotoDao.kt +++ b/base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt @@ -1,10 +1,10 @@ -package com.hako.base.room.dao +package com.hako.base.domain.database.dao import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import com.hako.base.room.entities.PhotoEntity +import com.hako.base.domain.database.entities.PhotoEntity @Dao interface PhotoDao { diff --git a/base/src/main/java/com/hako/base/room/dao/UserDao.kt b/base/src/main/java/com/hako/base/domain/database/dao/UserDao.kt similarity index 75% rename from base/src/main/java/com/hako/base/room/dao/UserDao.kt rename to base/src/main/java/com/hako/base/domain/database/dao/UserDao.kt index 69879cc..217fe87 100644 --- a/base/src/main/java/com/hako/base/room/dao/UserDao.kt +++ b/base/src/main/java/com/hako/base/domain/database/dao/UserDao.kt @@ -1,10 +1,10 @@ -package com.hako.base.room.dao +package com.hako.base.domain.database.dao import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import com.hako.base.room.entities.UserEntity +import com.hako.base.domain.database.entities.UserEntity @Dao interface UserDao { @@ -18,6 +18,9 @@ interface UserDao { @get:Query("SELECT * FROM ${UserEntity.TABLE_NAME}") val all: List + @Query("SELECT * FROM ${UserEntity.TABLE_NAME}") + fun getAllUsers(): List + @Query("SELECT COUNT(*) FROM ${UserEntity.TABLE_NAME}") fun count(): Int diff --git a/base/src/main/java/com/hako/base/room/entities/Album.kt b/base/src/main/java/com/hako/base/domain/database/entities/Album.kt similarity index 88% rename from base/src/main/java/com/hako/base/room/entities/Album.kt rename to base/src/main/java/com/hako/base/domain/database/entities/Album.kt index 48d664a..a6174ad 100644 --- a/base/src/main/java/com/hako/base/room/entities/Album.kt +++ b/base/src/main/java/com/hako/base/domain/database/entities/Album.kt @@ -1,4 +1,4 @@ -package com.hako.base.room.entities +package com.hako.base.domain.database.entities import androidx.room.Entity import androidx.room.Index diff --git a/base/src/main/java/com/hako/base/room/entities/Photos.kt b/base/src/main/java/com/hako/base/domain/database/entities/Photos.kt similarity index 89% rename from base/src/main/java/com/hako/base/room/entities/Photos.kt rename to base/src/main/java/com/hako/base/domain/database/entities/Photos.kt index 01c840a..68432f7 100644 --- a/base/src/main/java/com/hako/base/room/entities/Photos.kt +++ b/base/src/main/java/com/hako/base/domain/database/entities/Photos.kt @@ -1,4 +1,4 @@ -package com.hako.base.room.entities +package com.hako.base.domain.database.entities import androidx.room.Entity import androidx.room.Index diff --git a/base/src/main/java/com/hako/base/room/entities/User.kt b/base/src/main/java/com/hako/base/domain/database/entities/User.kt similarity index 90% rename from base/src/main/java/com/hako/base/room/entities/User.kt rename to base/src/main/java/com/hako/base/domain/database/entities/User.kt index 7f847bc..c359911 100644 --- a/base/src/main/java/com/hako/base/room/entities/User.kt +++ b/base/src/main/java/com/hako/base/domain/database/entities/User.kt @@ -1,4 +1,4 @@ -package com.hako.base.room.entities +package com.hako.base.domain.database.entities import androidx.room.Entity import androidx.room.Index diff --git a/base/src/main/java/com/hako/base/domain/network/RemoteClient.kt b/base/src/main/java/com/hako/base/domain/network/RemoteClient.kt new file mode 100644 index 0000000..e24863d --- /dev/null +++ b/base/src/main/java/com/hako/base/domain/network/RemoteClient.kt @@ -0,0 +1,35 @@ +package com.hako.base.domain.network + +import com.hako.base.BuildConfig +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.converter.gson.GsonConverterFactory +import timber.log.Timber + +class RemoteClient(endpoint: String) { + private val logger = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger { + override fun log(message: String) { + Timber.d(message) + } + }).setLevel(getLoggerLevel()) + + private val client = OkHttpClient.Builder() + .addInterceptor(logger) + .build() + + private val retrofit: Retrofit = Retrofit.Builder() + .baseUrl(endpoint) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .client(client) + .build() + + fun getClient(api: Class): T = retrofit.create(api) + + private fun getLoggerLevel() = when (BuildConfig.DEBUG) { + true -> HttpLoggingInterceptor.Level.BASIC + false -> HttpLoggingInterceptor.Level.NONE + } +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/domain/network/RequestStatus.kt b/base/src/main/java/com/hako/base/domain/network/RequestStatus.kt new file mode 100644 index 0000000..d34b084 --- /dev/null +++ b/base/src/main/java/com/hako/base/domain/network/RequestStatus.kt @@ -0,0 +1,7 @@ +package com.hako.base.domain.network + +sealed class RequestStatus { + object Ready : RequestStatus() + object Loading : RequestStatus() + object Errored : RequestStatus() +} diff --git a/base/src/main/java/com/hako/base/extensions/LiveDataExtensions.kt b/base/src/main/java/com/hako/base/extensions/LiveDataExtensions.kt new file mode 100644 index 0000000..8aa5111 --- /dev/null +++ b/base/src/main/java/com/hako/base/extensions/LiveDataExtensions.kt @@ -0,0 +1,13 @@ +package com.hako.base.extensions + +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer + +fun LiveData.observeNonNull(owner: LifecycleOwner, func: (T) -> Unit) { + observe(owner, Observer { + it?.let { + func(it) + } + }) +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/room/BaseDatabase.kt b/base/src/main/java/com/hako/base/room/BaseDatabase.kt deleted file mode 100644 index 47648b7..0000000 --- a/base/src/main/java/com/hako/base/room/BaseDatabase.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.hako.base.room - -import androidx.room.Database -import androidx.room.RoomDatabase -import com.hako.base.room.dao.AlbumDao -import com.hako.base.room.dao.PhotoDao -import com.hako.base.room.dao.UserDao -import com.hako.base.room.entities.AlbumEntity -import com.hako.base.room.entities.PhotoEntity -import com.hako.base.room.entities.UserEntity - -@Database(entities = [UserEntity::class, AlbumEntity::class, PhotoEntity::class], version = 1, exportSchema = false) -abstract class BaseDatabase : RoomDatabase() { - abstract fun userDao(): UserDao - abstract fun albumDao(): AlbumDao - abstract fun photoDao(): PhotoDao -} \ No newline at end of file diff --git a/userlist/src/main/java/com/hako/friendlist/di/UserlistModules.kt b/userlist/src/main/java/com/hako/friendlist/di/UserlistModules.kt new file mode 100644 index 0000000..ccb1b20 --- /dev/null +++ b/userlist/src/main/java/com/hako/friendlist/di/UserlistModules.kt @@ -0,0 +1,17 @@ +package com.hako.friendlist.di + +import com.hako.base.domain.network.RemoteClient +import com.hako.friendlist.domain.datasource.UserlistDatasource +import com.hako.friendlist.domain.datasource.UserlistRemoteApi +import com.hako.friendlist.domain.usecase.GetUsers +import com.hako.friendlist.viewmodel.UserlistViewmodel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module + +val userlistModules = module { + factory { get().getClient(UserlistRemoteApi::class.java) } + factory { UserlistDatasource() } + factory { GetUsers(get()) } + + viewModel { UserlistViewmodel() } +} \ No newline at end of file diff --git a/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistDatasource.kt b/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistDatasource.kt new file mode 100644 index 0000000..b7ebfa2 --- /dev/null +++ b/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistDatasource.kt @@ -0,0 +1,13 @@ +package com.hako.friendlist.domain.datasource + +import com.hako.friendlist.model.User +import io.reactivex.Single +import org.koin.core.KoinComponent +import org.koin.core.get + +class UserlistDatasource : KoinComponent, UserlistRemoteApi { + + private val api: UserlistRemoteApi = get() + + override fun getUsers(): Single> = api.getUsers() +} \ No newline at end of file diff --git a/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistRemoteApi.kt b/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistRemoteApi.kt new file mode 100644 index 0000000..00ff807 --- /dev/null +++ b/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistRemoteApi.kt @@ -0,0 +1,11 @@ +package com.hako.friendlist.domain.datasource + +import com.hako.friendlist.model.User +import io.reactivex.Single +import retrofit2.http.GET + +interface UserlistRemoteApi { + + @GET("/users") + fun getUsers(): Single> +} \ No newline at end of file diff --git a/userlist/src/main/java/com/hako/friendlist/domain/usecase/GetUsers.kt b/userlist/src/main/java/com/hako/friendlist/domain/usecase/GetUsers.kt new file mode 100644 index 0000000..bf5e094 --- /dev/null +++ b/userlist/src/main/java/com/hako/friendlist/domain/usecase/GetUsers.kt @@ -0,0 +1,43 @@ +package com.hako.friendlist.domain.usecase + +import com.hako.base.domain.UseCase +import com.hako.base.domain.database.dao.UserDao +import com.hako.friendlist.domain.datasource.UserlistDatasource +import com.hako.friendlist.model.UserViewable +import com.hako.friendlist.model.toUserEntity +import com.hako.friendlist.model.toUserViewable +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers +import org.koin.core.KoinComponent +import org.koin.core.get + +class GetUsers(private val dao: UserDao) : KoinComponent, + UseCase { + + private val api: UserlistDatasource = get() + + override fun execute( + onSuccess: (List) -> Unit, + onError: (Throwable) -> Unit, + onLoading: () -> Unit + ) { + Single.fromCallable { dao.getAllUsers() } + .subscribeOn(Schedulers.io()) + .doOnError { onError(it) } + .doOnSuccess { dbUsers -> + if (dbUsers.isEmpty() || dbUsers.count() == 0) { + api.getUsers() + .doOnSuccess { + dao.saveAll(it.map { user -> user.toUserEntity() }) + onSuccess(dao.getAllUsers().map { user -> user.toUserViewable() }) + } + .doOnSubscribe { onLoading() } + .subscribeOn(Schedulers.io()) + .subscribe({}, { onError(it) }) + } else { + onSuccess(dbUsers.map { it.toUserViewable() }) + } + } + .subscribe() + } +} diff --git a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt index f83776b..9d2f4c3 100644 --- a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt +++ b/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt @@ -6,14 +6,20 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager +import com.hako.base.domain.network.RequestStatus +import com.hako.base.extensions.observeNonNull import com.hako.base.extensions.toast import com.hako.friendlist.model.UserViewable +import com.hako.friendlist.viewmodel.UserlistViewmodel import com.hako.friendlist.widget.UserlistAdapter import com.hako.friendlist_userlist.R import kotlinx.android.synthetic.main.fragment_userlist.* +import org.koin.androidx.viewmodel.ext.android.viewModel +import timber.log.Timber class UserlistFragment : Fragment() { + private val viewModel: UserlistViewmodel by viewModel() private val chatAdapter by lazy { UserlistAdapter() } override fun onCreateView( @@ -23,37 +29,37 @@ class UserlistFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setRecycler() + setObservers() + viewModel.fetchUsers() + } + + private fun setObservers() { + viewModel.data.observeNonNull(this) { + it.either(::handleFetchError, ::handleFetchSuccess) + } + + viewModel.requestStatus.observeNonNull(this) { + when (it) { + RequestStatus.Ready -> { context?.toast("Ready") } + RequestStatus.Loading -> { context?.toast("Loading") } + RequestStatus.Errored -> { context?.toast("Errored") } + } + } + } + + private fun handleFetchError(throwable: Throwable) { + context?.toast("Could't get data") + Timber.e(throwable) + } + + private fun handleFetchSuccess(users: List) { + chatAdapter.addAll(users) } private fun setRecycler() { fragment_userlist_recycler_container.apply { layoutManager = LinearLayoutManager(context) adapter = chatAdapter.apply { - addAll( - listOf( - UserViewable(1, "Carlos Martinez", "carlitos"), - UserViewable(2, "Carlos Martinez", "carlitos"), - UserViewable(3, "Carlos Martinez", "carlitos"), - UserViewable(4, "Carlos Martinez", "carlitos"), - UserViewable(5, "Carlos Martinez", "carlitos"), - UserViewable(6, "Carlos Martinez", "carlitos"), - UserViewable(7, "Carlos Martinez", "carlitos"), - UserViewable(8, "Carlos Martinez", "carlitos"), - UserViewable(9, "Carlos Martinez", "carlitos"), - UserViewable(10, "Carlos Martinez", "carlitos"), - UserViewable(11, "Carlos Martinez", "carlitos"), - UserViewable(12, "Carlos Martinez", "carlitos"), - UserViewable(13, "Carlos Martinez", "carlitos"), - UserViewable(14, "Carlos Martinez", "carlitos"), - UserViewable(15, "Carlos Martinez", "carlitos"), - UserViewable(16, "Carlos Martinez", "carlitos"), - UserViewable(17, "Carlos Martinez", "carlitos"), - UserViewable(18, "Carlos Martinez", "carlitos"), - UserViewable(19, "Carlos Martinez", "carlitos"), - UserViewable(20, "Carlos Martinez", "carlitos") - ) - ) - onItemClick = { context.toast(it.realName) } diff --git a/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt b/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt index 6c6992a..5dfa108 100644 --- a/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt +++ b/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt @@ -2,7 +2,7 @@ package com.hako.friendlist.model import android.os.Parcelable import com.google.gson.annotations.SerializedName -import com.hako.base.room.entities.UserEntity +import com.hako.base.domain.database.entities.UserEntity import kotlinx.android.parcel.Parcelize @Parcelize @@ -20,9 +20,9 @@ data class UserViewable( val realName: String, val userName: String, var isFavorite: Boolean = false -) { - fun User.toUserViewable() = UserViewable(this.id, this.realName, this.userName) +) - fun UserEntity.toUserViewable() = UserViewable(this.id, this.realName, this.userName) -} +fun User.toUserEntity() = UserEntity(this.id, this.realName, this.userName, this.email, this.phone, this.website) + +fun UserEntity.toUserViewable() = UserViewable(this.id, this.realName, this.userName) diff --git a/userlist/src/main/java/com/hako/friendlist/viewmodel/UserlistViewmodel.kt b/userlist/src/main/java/com/hako/friendlist/viewmodel/UserlistViewmodel.kt new file mode 100644 index 0000000..dd6b938 --- /dev/null +++ b/userlist/src/main/java/com/hako/friendlist/viewmodel/UserlistViewmodel.kt @@ -0,0 +1,36 @@ +package com.hako.friendlist.viewmodel + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.hako.base.domain.network.RequestStatus +import com.hako.base.domain.network.RequestStatus.Ready +import com.hako.base.domain.network.RequestStatus.Loading +import com.hako.base.domain.network.RequestStatus.Errored +import com.hako.base.domain.Either +import com.hako.friendlist.domain.usecase.GetUsers +import com.hako.friendlist.model.UserViewable +import org.koin.core.KoinComponent +import org.koin.core.get + +class UserlistViewmodel : ViewModel(), KoinComponent { + + val data = MutableLiveData>>() + val requestStatus = MutableLiveData() + + private val getUsers: GetUsers = get() + + fun fetchUsers() { + getUsers.execute( + onSuccess = { + requestStatus.postValue(Ready) + data.postValue(Either.Right(it)) + }, + onLoading = { + requestStatus.postValue(Loading) + }, + onError = { + requestStatus.postValue(Errored) + data.postValue(Either.Left(it)) + }) + } +} From 83d243ec580873687e5fef0ee091acef9a1f69ee Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Mon, 3 Feb 2020 13:04:35 -0300 Subject: [PATCH 10/12] rename package --- .../main/java/com/hako/friendlists/MainApplication.kt | 2 +- .../{friendlist => userlist}/di/UserlistModules.kt | 10 +++++----- .../domain/datasource/UserlistDatasource.kt | 4 ++-- .../domain/datasource/UserlistRemoteApi.kt | 4 ++-- .../domain/usecase/GetUsers.kt | 10 +++++----- .../feature/UserlistFragment.kt | 8 ++++---- .../hako/{friendlist => userlist}/model/UserModels.kt | 2 +- .../viewmodel/UserlistViewmodel.kt | 6 +++--- .../{friendlist => userlist}/widget/UserlistAdapter.kt | 4 ++-- .../src/main/res/navigation/userlist_navigation.xml | 2 +- 10 files changed, 26 insertions(+), 26 deletions(-) rename userlist/src/main/java/com/hako/{friendlist => userlist}/di/UserlistModules.kt (56%) rename userlist/src/main/java/com/hako/{friendlist => userlist}/domain/datasource/UserlistDatasource.kt (76%) rename userlist/src/main/java/com/hako/{friendlist => userlist}/domain/datasource/UserlistRemoteApi.kt (63%) rename userlist/src/main/java/com/hako/{friendlist => userlist}/domain/usecase/GetUsers.kt (84%) rename userlist/src/main/java/com/hako/{friendlist => userlist}/feature/UserlistFragment.kt (92%) rename userlist/src/main/java/com/hako/{friendlist => userlist}/model/UserModels.kt (96%) rename userlist/src/main/java/com/hako/{friendlist => userlist}/viewmodel/UserlistViewmodel.kt (88%) rename userlist/src/main/java/com/hako/{friendlist => userlist}/widget/UserlistAdapter.kt (96%) diff --git a/app/src/main/java/com/hako/friendlists/MainApplication.kt b/app/src/main/java/com/hako/friendlists/MainApplication.kt index 0b5aa8e..92db1b3 100644 --- a/app/src/main/java/com/hako/friendlists/MainApplication.kt +++ b/app/src/main/java/com/hako/friendlists/MainApplication.kt @@ -1,7 +1,7 @@ package com.hako.friendlists import android.app.Application -import com.hako.friendlist.di.userlistModules +import com.hako.userlist.di.userlistModules import com.hako.friendlists.di.appModules import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin diff --git a/userlist/src/main/java/com/hako/friendlist/di/UserlistModules.kt b/userlist/src/main/java/com/hako/userlist/di/UserlistModules.kt similarity index 56% rename from userlist/src/main/java/com/hako/friendlist/di/UserlistModules.kt rename to userlist/src/main/java/com/hako/userlist/di/UserlistModules.kt index ccb1b20..a69b104 100644 --- a/userlist/src/main/java/com/hako/friendlist/di/UserlistModules.kt +++ b/userlist/src/main/java/com/hako/userlist/di/UserlistModules.kt @@ -1,10 +1,10 @@ -package com.hako.friendlist.di +package com.hako.userlist.di import com.hako.base.domain.network.RemoteClient -import com.hako.friendlist.domain.datasource.UserlistDatasource -import com.hako.friendlist.domain.datasource.UserlistRemoteApi -import com.hako.friendlist.domain.usecase.GetUsers -import com.hako.friendlist.viewmodel.UserlistViewmodel +import com.hako.userlist.domain.datasource.UserlistDatasource +import com.hako.userlist.domain.datasource.UserlistRemoteApi +import com.hako.userlist.domain.usecase.GetUsers +import com.hako.userlist.viewmodel.UserlistViewmodel import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module diff --git a/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistDatasource.kt b/userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistDatasource.kt similarity index 76% rename from userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistDatasource.kt rename to userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistDatasource.kt index b7ebfa2..c9a6710 100644 --- a/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistDatasource.kt +++ b/userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistDatasource.kt @@ -1,6 +1,6 @@ -package com.hako.friendlist.domain.datasource +package com.hako.userlist.domain.datasource -import com.hako.friendlist.model.User +import com.hako.userlist.model.User import io.reactivex.Single import org.koin.core.KoinComponent import org.koin.core.get diff --git a/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistRemoteApi.kt b/userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistRemoteApi.kt similarity index 63% rename from userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistRemoteApi.kt rename to userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistRemoteApi.kt index 00ff807..8ffd5b5 100644 --- a/userlist/src/main/java/com/hako/friendlist/domain/datasource/UserlistRemoteApi.kt +++ b/userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistRemoteApi.kt @@ -1,6 +1,6 @@ -package com.hako.friendlist.domain.datasource +package com.hako.userlist.domain.datasource -import com.hako.friendlist.model.User +import com.hako.userlist.model.User import io.reactivex.Single import retrofit2.http.GET diff --git a/userlist/src/main/java/com/hako/friendlist/domain/usecase/GetUsers.kt b/userlist/src/main/java/com/hako/userlist/domain/usecase/GetUsers.kt similarity index 84% rename from userlist/src/main/java/com/hako/friendlist/domain/usecase/GetUsers.kt rename to userlist/src/main/java/com/hako/userlist/domain/usecase/GetUsers.kt index bf5e094..939394d 100644 --- a/userlist/src/main/java/com/hako/friendlist/domain/usecase/GetUsers.kt +++ b/userlist/src/main/java/com/hako/userlist/domain/usecase/GetUsers.kt @@ -1,11 +1,11 @@ -package com.hako.friendlist.domain.usecase +package com.hako.userlist.domain.usecase import com.hako.base.domain.UseCase import com.hako.base.domain.database.dao.UserDao -import com.hako.friendlist.domain.datasource.UserlistDatasource -import com.hako.friendlist.model.UserViewable -import com.hako.friendlist.model.toUserEntity -import com.hako.friendlist.model.toUserViewable +import com.hako.userlist.domain.datasource.UserlistDatasource +import com.hako.userlist.model.UserViewable +import com.hako.userlist.model.toUserEntity +import com.hako.userlist.model.toUserViewable import io.reactivex.Single import io.reactivex.schedulers.Schedulers import org.koin.core.KoinComponent diff --git a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt b/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt similarity index 92% rename from userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt rename to userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt index 9d2f4c3..08f15e7 100644 --- a/userlist/src/main/java/com/hako/friendlist/feature/UserlistFragment.kt +++ b/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt @@ -1,4 +1,4 @@ -package com.hako.friendlist.feature +package com.hako.userlist.feature import android.os.Bundle import android.view.LayoutInflater @@ -9,9 +9,9 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.hako.base.domain.network.RequestStatus import com.hako.base.extensions.observeNonNull import com.hako.base.extensions.toast -import com.hako.friendlist.model.UserViewable -import com.hako.friendlist.viewmodel.UserlistViewmodel -import com.hako.friendlist.widget.UserlistAdapter +import com.hako.userlist.model.UserViewable +import com.hako.userlist.viewmodel.UserlistViewmodel +import com.hako.userlist.widget.UserlistAdapter import com.hako.friendlist_userlist.R import kotlinx.android.synthetic.main.fragment_userlist.* import org.koin.androidx.viewmodel.ext.android.viewModel diff --git a/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt b/userlist/src/main/java/com/hako/userlist/model/UserModels.kt similarity index 96% rename from userlist/src/main/java/com/hako/friendlist/model/UserModels.kt rename to userlist/src/main/java/com/hako/userlist/model/UserModels.kt index 5dfa108..b89a2aa 100644 --- a/userlist/src/main/java/com/hako/friendlist/model/UserModels.kt +++ b/userlist/src/main/java/com/hako/userlist/model/UserModels.kt @@ -1,4 +1,4 @@ -package com.hako.friendlist.model +package com.hako.userlist.model import android.os.Parcelable import com.google.gson.annotations.SerializedName diff --git a/userlist/src/main/java/com/hako/friendlist/viewmodel/UserlistViewmodel.kt b/userlist/src/main/java/com/hako/userlist/viewmodel/UserlistViewmodel.kt similarity index 88% rename from userlist/src/main/java/com/hako/friendlist/viewmodel/UserlistViewmodel.kt rename to userlist/src/main/java/com/hako/userlist/viewmodel/UserlistViewmodel.kt index dd6b938..abe56e5 100644 --- a/userlist/src/main/java/com/hako/friendlist/viewmodel/UserlistViewmodel.kt +++ b/userlist/src/main/java/com/hako/userlist/viewmodel/UserlistViewmodel.kt @@ -1,4 +1,4 @@ -package com.hako.friendlist.viewmodel +package com.hako.userlist.viewmodel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -7,8 +7,8 @@ import com.hako.base.domain.network.RequestStatus.Ready import com.hako.base.domain.network.RequestStatus.Loading import com.hako.base.domain.network.RequestStatus.Errored import com.hako.base.domain.Either -import com.hako.friendlist.domain.usecase.GetUsers -import com.hako.friendlist.model.UserViewable +import com.hako.userlist.domain.usecase.GetUsers +import com.hako.userlist.model.UserViewable import org.koin.core.KoinComponent import org.koin.core.get diff --git a/userlist/src/main/java/com/hako/friendlist/widget/UserlistAdapter.kt b/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt similarity index 96% rename from userlist/src/main/java/com/hako/friendlist/widget/UserlistAdapter.kt rename to userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt index a6bfe05..3a5294e 100644 --- a/userlist/src/main/java/com/hako/friendlist/widget/UserlistAdapter.kt +++ b/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt @@ -1,11 +1,11 @@ -package com.hako.friendlist.widget +package com.hako.userlist.widget import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.hako.base.extensions.autoNotify -import com.hako.friendlist.model.UserViewable +import com.hako.userlist.model.UserViewable import com.hako.friendlist_userlist.R import kotlinx.android.synthetic.main.item_user_card.view.* import kotlin.properties.Delegates diff --git a/userlist/src/main/res/navigation/userlist_navigation.xml b/userlist/src/main/res/navigation/userlist_navigation.xml index 2343782..20c9258 100644 --- a/userlist/src/main/res/navigation/userlist_navigation.xml +++ b/userlist/src/main/res/navigation/userlist_navigation.xml @@ -7,7 +7,7 @@ From c1bb08ee8fa7a54055d0d8050199f15c4dc606e7 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Mon, 3 Feb 2020 13:52:11 -0300 Subject: [PATCH 11/12] add loading and error status, with a simple implementation --- .../hako/base/extensions/ViewExtensions.kt | 28 ++++++++++++++++ .../com/hako/base/widgets/LoadingOverlay.kt | 18 ++++++++++ .../hako/base/widgets/NetworkErrorOverlay.kt | 18 ++++++++++ base/src/main/res/layout/loading_overlay.xml | 21 ++++++++++++ .../main/res/layout/network_error_overlay.xml | 33 +++++++++++++++++++ base/src/main/res/raw/loading_animation.json | 1 + base/src/main/res/raw/network_animation.json | 1 + .../hako/userlist/feature/UserlistFragment.kt | 18 +++++++--- .../src/main/res/layout/fragment_userlist.xml | 20 +++++++++++ 9 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 base/src/main/java/com/hako/base/widgets/LoadingOverlay.kt create mode 100644 base/src/main/java/com/hako/base/widgets/NetworkErrorOverlay.kt create mode 100644 base/src/main/res/layout/loading_overlay.xml create mode 100644 base/src/main/res/layout/network_error_overlay.xml create mode 100644 base/src/main/res/raw/loading_animation.json create mode 100644 base/src/main/res/raw/network_animation.json diff --git a/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt b/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt index 5bd84f8..39105ff 100644 --- a/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt +++ b/base/src/main/java/com/hako/base/extensions/ViewExtensions.kt @@ -5,6 +5,34 @@ import android.view.View import android.view.ViewGroup import androidx.annotation.LayoutRes +fun View.enable() { + isEnabled = true +} + +fun View.disable() { + isEnabled = false +} + +fun View.visible() { + visibility = View.VISIBLE +} + +fun View.invisible() { + visibility = View.INVISIBLE +} + +fun View.transparent() { + alpha = 0f +} + +fun View.opaque() { + alpha = 1f +} + +fun View.gone() { + visibility = View.GONE +} + fun ViewGroup.inflate(@LayoutRes layout: Int, attachToRoot: Boolean = false): View = LayoutInflater .from(context) diff --git a/base/src/main/java/com/hako/base/widgets/LoadingOverlay.kt b/base/src/main/java/com/hako/base/widgets/LoadingOverlay.kt new file mode 100644 index 0000000..8f021f6 --- /dev/null +++ b/base/src/main/java/com/hako/base/widgets/LoadingOverlay.kt @@ -0,0 +1,18 @@ +package com.hako.base.widgets + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout +import com.hako.base.R +import com.hako.base.extensions.inflate + +class LoadingOverlay @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + init { + inflate(R.layout.loading_overlay, true) + } +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/widgets/NetworkErrorOverlay.kt b/base/src/main/java/com/hako/base/widgets/NetworkErrorOverlay.kt new file mode 100644 index 0000000..01b6cc2 --- /dev/null +++ b/base/src/main/java/com/hako/base/widgets/NetworkErrorOverlay.kt @@ -0,0 +1,18 @@ +package com.hako.base.widgets + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout +import com.hako.base.R +import com.hako.base.extensions.inflate + +class NetworkErrorOverlay @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + init { + inflate(R.layout.network_error_overlay, true) + } +} \ No newline at end of file diff --git a/base/src/main/res/layout/loading_overlay.xml b/base/src/main/res/layout/loading_overlay.xml new file mode 100644 index 0000000..b9d5a46 --- /dev/null +++ b/base/src/main/res/layout/loading_overlay.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/base/src/main/res/layout/network_error_overlay.xml b/base/src/main/res/layout/network_error_overlay.xml new file mode 100644 index 0000000..72ee319 --- /dev/null +++ b/base/src/main/res/layout/network_error_overlay.xml @@ -0,0 +1,33 @@ + + + + + + + + \ No newline at end of file diff --git a/base/src/main/res/raw/loading_animation.json b/base/src/main/res/raw/loading_animation.json new file mode 100644 index 0000000..ad2269b --- /dev/null +++ b/base/src/main/res/raw/loading_animation.json @@ -0,0 +1 @@ +{"v":"5.1.6","fr":30,"ip":0,"op":94,"w":300,"h":300,"nm":"Comp 2","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,59.26,0],"ix":2},"a":{"a":0,"k":[-30,-6.544,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.651,0.667,0.667],"y":[0.998,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p651_0p998_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":9,"s":[0,75.476,100],"e":[110,75.476,100]},{"i":{"x":[0.524,0.833,0.833],"y":[0.97,1,1]},"o":{"x":[0.379,0.167,0.167],"y":[0.013,0,0]},"n":["0p524_0p97_0p379_0p013","0p833_1_0p167_0","0p833_1_0p167_0"],"t":21,"s":[110,75.476,100],"e":[100,75.476,100]},{"t":29}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[85.26,14.271],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.792156862745098,0.792156862745098,0.792156862745098,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.63,-8.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":118,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,41.26,0],"ix":2},"a":{"a":0,"k":[-30,-6.544,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.651,0.667,0.667],"y":[0.997,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p651_0p997_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":3,"s":[0,75.476,100],"e":[90,75.476,100]},{"i":{"x":[0.524,0.833,0.833],"y":[0.94,1,1]},"o":{"x":[0.379,0.167,0.167],"y":[0.027,0,0]},"n":["0p524_0p94_0p379_0p027","0p833_1_0p167_0","0p833_1_0p167_0"],"t":15,"s":[90,75.476,100],"e":[85,75.476,100]},{"t":23}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[85.26,14.271],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.8549019607843137,0.8549019607843137,0.8549019607843137,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.63,-8.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":166,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[48.961,49.211,0],"ix":2},"a":{"a":0,"k":[-66.789,-32.789,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.044,0.044,0.667],"y":[0.991,0.991,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p044_0p991_0p333_0","0p044_0p991_0p333_0","0p667_1_0p333_0"],"t":0,"s":[0,0,100],"e":[93,93,100]},{"t":12}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[38.422,38.422],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.7294117647058823,0.7294117647058823,0.7294117647058823,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-66.789,-32.789],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":166,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,175,0],"ix":2},"a":{"a":0,"k":[100,50,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":200,"h":100,"ip":62,"op":152,"st":62,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":62,"s":[100],"e":[60]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":76,"s":[60],"e":[60]},{"t":94}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.182,"y":1},"o":{"x":0.333,"y":0},"n":"0p182_1_0p333_0","t":62,"s":[150,175,0],"e":[150,123.5,0],"to":[0,-8.58333301544189,0],"ti":[0,8.58333301544189,0]},{"i":{"x":0.182,"y":0.182},"o":{"x":0.167,"y":0.167},"n":"0p182_0p182_0p167_0p167","t":76,"s":[150,123.5,0],"e":[150,123.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":94}],"ix":2},"a":{"a":0,"k":[100,50,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.069,0.069,0.667],"y":[0.995,0.995,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p069_0p995_0p333_0","0p069_0p995_0p333_0","0p667_1_0p333_0"],"t":62,"s":[100,100,100],"e":[80,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_1_0p333_0","0p833_1_0p333_0","0p833_1_0p333_0"],"t":76,"s":[80,80,100],"e":[80,80,100]},{"t":94}],"ix":6}},"ao":0,"w":200,"h":100,"ip":30,"op":120,"st":30,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":30,"s":[100],"e":[60]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":44,"s":[60],"e":[60]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":62,"s":[60],"e":[0]},{"t":76}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.182,"y":1},"o":{"x":0.333,"y":0},"n":"0p182_1_0p333_0","t":30,"s":[150,175,0],"e":[150,123.5,0],"to":[0,-8.58333301544189,0],"ti":[0,8.58333301544189,0]},{"i":{"x":0.182,"y":0.182},"o":{"x":0.167,"y":0.167},"n":"0p182_0p182_0p167_0p167","t":44,"s":[150,123.5,0],"e":[150,123.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.182,"y":1},"o":{"x":0.167,"y":0},"n":"0p182_1_0p167_0","t":62,"s":[150,123.5,0],"e":[150,86.5,0],"to":[0,-6.16666650772095,0],"ti":[0,6.16666650772095,0]},{"t":76}],"ix":2},"a":{"a":0,"k":[100,50,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.069,0.069,0.667],"y":[0.995,0.995,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p069_0p995_0p333_0","0p069_0p995_0p333_0","0p667_1_0p333_0"],"t":30,"s":[100,100,100],"e":[80,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_1_0p333_0","0p833_1_0p333_0","0p833_1_0p333_0"],"t":44,"s":[80,80,100],"e":[80,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"n":["0p833_1_0p167_0","0p833_1_0p167_0","0p833_1_0p167_0"],"t":62,"s":[80,80,100],"e":[50,50,100]},{"t":76}],"ix":6}},"ao":0,"w":200,"h":100,"ip":-2,"op":88,"st":-2,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":-1,"s":[100],"e":[60]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":13,"s":[60],"e":[60]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":31,"s":[60],"e":[0]},{"t":45}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.182,"y":1},"o":{"x":0.333,"y":0},"n":"0p182_1_0p333_0","t":-1,"s":[150,175,0],"e":[150,123.5,0],"to":[0,-8.58333301544189,0],"ti":[0,8.58333301544189,0]},{"i":{"x":0.182,"y":0.182},"o":{"x":0.167,"y":0.167},"n":"0p182_0p182_0p167_0p167","t":13,"s":[150,123.5,0],"e":[150,123.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.182,"y":1},"o":{"x":0.167,"y":0},"n":"0p182_1_0p167_0","t":31,"s":[150,123.5,0],"e":[150,86.5,0],"to":[0,-6.16666650772095,0],"ti":[0,6.16666650772095,0]},{"t":45}],"ix":2},"a":{"a":0,"k":[100,50,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.069,0.069,0.667],"y":[0.995,0.995,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p069_0p995_0p333_0","0p069_0p995_0p333_0","0p667_1_0p333_0"],"t":-1,"s":[100,100,100],"e":[80,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_1_0p333_0","0p833_1_0p333_0","0p833_1_0p333_0"],"t":13,"s":[80,80,100],"e":[80,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"n":["0p833_1_0p167_0","0p833_1_0p167_0","0p833_1_0p167_0"],"t":31,"s":[80,80,100],"e":[50,50,100]},{"t":45}],"ix":6}},"ao":0,"w":200,"h":100,"ip":-33,"op":57,"st":-33,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":-35,"s":[100],"e":[60]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":-21,"s":[60],"e":[60]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":-1,"s":[60],"e":[0]},{"t":13}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.182,"y":1},"o":{"x":0.333,"y":0},"n":"0p182_1_0p333_0","t":-35,"s":[150,175,0],"e":[150,123.5,0],"to":[0,-8.58333301544189,0],"ti":[0,8.58333301544189,0]},{"i":{"x":0.182,"y":0.182},"o":{"x":0.167,"y":0.167},"n":"0p182_0p182_0p167_0p167","t":-21,"s":[150,123.5,0],"e":[150,123.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.182,"y":1},"o":{"x":0.167,"y":0},"n":"0p182_1_0p167_0","t":-1,"s":[150,123.5,0],"e":[150,86.5,0],"to":[0,-6.16666650772095,0],"ti":[0,6.16666650772095,0]},{"t":13}],"ix":2},"a":{"a":0,"k":[100,50,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.069,0.069,0.667],"y":[0.995,0.995,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p069_0p995_0p333_0","0p069_0p995_0p333_0","0p667_1_0p333_0"],"t":-35,"s":[100,100,100],"e":[80,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_1_0p333_0","0p833_1_0p333_0","0p833_1_0p333_0"],"t":-21,"s":[80,80,100],"e":[80,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"n":["0p833_1_0p167_0","0p833_1_0p167_0","0p833_1_0p167_0"],"t":-1,"s":[80,80,100],"e":[50,50,100]},{"t":13}],"ix":6}},"ao":0,"w":200,"h":100,"ip":-76,"op":14,"st":-76,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/base/src/main/res/raw/network_animation.json b/base/src/main/res/raw/network_animation.json new file mode 100644 index 0000000..2f268ac --- /dev/null +++ b/base/src/main/res/raw/network_animation.json @@ -0,0 +1 @@ +{"ip":0,"fr":60,"v":"5.1.20","assets":[{"id":"precomp_1","layers":[{"ty":4,"nm":"Fill-67-Copy","ip":0,"st":0,"ind":15,"hix":4,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[11.560674667358398,2.8008460998535156,0]},"p":{"s":true,"x":{"a":0,"k":136.78967466735838},"y":{"a":0,"k":59.93284609985351}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-67-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[46.7294343,62.2339406],[69.8507811,62.2339406],[69.8507811,56.6322499],[46.7294343,56.6322499]],"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.21568627450980393,0.2784313725490196,0.30980392156862746,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-171.958,-107.196]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-66-Copy","ip":0,"st":0,"ind":14,"hix":3,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[11.560674667358398,11.607135772705078,0]},"p":{"s":true,"x":{"a":0,"k":136.78967466735838},"y":{"a":0,"k":68.73913577270508}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-66-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[46.7294343,56.6322499],[69.8507811,56.6322499],[69.8507811,68.2393858],[58.2901077,79.8465217],[46.7294343,68.2393858]],"i":[[0,0],[0,0],[0,0],[6.384348499999994,0],[0,6.410007300000004]],"o":[[0,0],[0,0],[0,6.410007300000004],[-6.3851528,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.19607843137254902,0.25098039215686274,0.2784313725490196,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-171.958,-107.196]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Combined-Shape","ip":0,"st":0,"ind":12,"hix":2,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[8.197591781616211,3.335012435913086,0]},"p":{"s":true,"x":{"a":0,"k":136.8685917816162},"y":{"a":0,"k":53.899012435913086}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Combined-Shape shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[53.977576,56.7339961],[50.1709343,56.7339961],[50.1709343,51.9745374],[52.0746573,50.0639709],[53.977576,51.9745374]],"i":[[0,0],[0,0],[0,0],[-1.051189700000002,0],[0,-1.0546069000000031]],"o":[[0,0],[0,0],[0,-1.0546069000000031],[1.0503854000000032,0],[0,0]]}}},{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[66.5661151,56.7339961],[62.7602777,56.7339961],[62.7602777,51.9745374],[64.6631964,50.0639709],[66.5661151,51.9745374]],"i":[[0,0],[0,0],[0,0],[-1.051189700000002,0],[0,-1.0546069000000031]],"o":[[0,0],[0,0],[0,-1.0546069000000031],[1.050385300000002,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.796078431372549,0.8117647058823529,0.8196078431372549,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-175.4,-100.628]},"r":{"a":0,"k":0}}]}],"op":152}]},{"id":"precomp_2","layers":[{"ty":4,"nm":"Fill-72-Copy","ip":0,"st":0,"ind":18,"hix":7,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[11.560673713684082,2.801248550415039,0]},"p":{"s":true,"x":{"a":0,"k":136.79},"y":{"a":0,"k":38.024}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-72-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[5.86197757e-14,40.3253897],[23.1213468,40.3253897],[23.1213468,34.7228916],[5.86197757e-14,34.7228916]],"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.21568627450980393,0.2784313725490196,0.30980392156862746,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-125.229,-52.181]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-71-Copy","ip":0,"st":0,"ind":17,"hix":6,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[11.560673713684082,11.607135772705078,0]},"p":{"s":true,"x":{"a":0,"k":136.79},"y":{"a":0,"k":29.065}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-71-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[23.1213468,40.171963],[5.86197757e-14,40.171963],[5.86197757e-14,28.5648271],[11.5606734,16.9576912],[23.1213468,28.5648271]],"i":[[0,0],[0,0],[0,0],[-6.38515277,0],[0,-6.410814799999997]],"o":[[0,0],[0,0],[0,-6.410814799999997],[6.3843485,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.19607843137254902,0.25098039215686274,0.2784313725490196,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-125.229,-34.416]},"r":{"a":0,"k":0}}]}],"op":152}]}],"layers":[{"ty":0,"nm":"instance:precomp_2","refId":"precomp_2","ind":15,"ip":0,"st":0,"hix":5,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[11.560673713684082,11.683692161560058,0]},"p":{"s":true,"x":{"a":0,"k":70.198},"y":{"a":1,"k":[{"t":0,"s":[38.142],"e":[38.142],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":35,"s":[38.142],"e":[29.142],"i":{"x":[0.367],"y":[0.556]},"o":{"x":[0.4],"y":[2.5]}},{"t":50,"s":[29.142],"e":[28.987199999999998],"i":{"x":[0.565],"y":[1]},"o":{"x":[0.39],"y":[0.575]}},{"t":52,"s":[28.987199999999998],"e":[29.142],"i":{"x":[0.745],"y":[0.715]},"o":{"x":[0.47],"y":[0]}},{"t":56,"s":[29.142],"e":[29.1807],"i":{"x":[0.565],"y":[1]},"o":{"x":[0.39],"y":[0.575]}},{"t":58,"s":[29.1807],"e":[29.142],"i":{"x":[0.745],"y":[0.715]},"o":{"x":[0.47],"y":[0]}},{"t":65,"s":[29.142],"e":[29.142],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":127,"s":[29.142],"e":[37.142],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":135,"s":[37.142],"e":[38.142],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":152}]}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"w":23,"h":23,"op":152},{"ty":0,"nm":"instance:precomp_1","refId":"precomp_1","ind":14,"ip":0,"st":0,"hix":1,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[11.560674667358398,14.89113577270508,0]},"p":{"s":true,"x":{"a":0,"k":70.19767466735838},"y":{"a":1,"k":[{"t":0,"s":[57.455],"e":[57.455],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":35,"s":[57.455],"e":[65.31140939331054],"i":{"x":[0.367],"y":[0.556]},"o":{"x":[0.4],"y":[2.5]}},{"t":50,"s":[65.31140939331054],"e":[65.44653963487548],"i":{"x":[0.565],"y":[1]},"o":{"x":[0.39],"y":[0.575]}},{"t":52,"s":[65.44653963487548],"e":[65.31140939331054],"i":{"x":[0.745],"y":[0.715]},"o":{"x":[0.47],"y":[0]}},{"t":56,"s":[65.31140939331054],"e":[65.27762683291931],"i":{"x":[0.565],"y":[1]},"o":{"x":[0.39],"y":[0.575]}},{"t":58,"s":[65.27762683291931],"e":[65.31140939331054],"i":{"x":[0.745],"y":[0.715]},"o":{"x":[0.47],"y":[0]}},{"t":65,"s":[65.31140939331054],"e":[65.31140939331054],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":127,"s":[65.31140939331054],"e":[57.455],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":135}]}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"w":23,"h":30,"op":152},{"ty":4,"nm":"Fill-70-Copy","ip":0,"st":0,"ind":13,"hix":8,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[1.608553409576416,9.685667991638184,0]},"p":{"s":true,"x":{"a":0,"k":69.897},"y":{"a":0,"k":18.053}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,201.9]}},"shapes":[{"ty":"gr","nm":"Fill-70-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[9.65132051,19.3713359],[12.8684274,19.3713359],[12.8684274,-1.95399252e-13],[9.65132051,-1.95399252e-13]],"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.23921568627450981,0.30980392156862746,0.44313725490196076,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-9.651,0]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-65-Copy","ip":0,"st":0,"ind":12,"hix":9,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[1.6085529327392578,10.430999755859375,0]},"p":{"s":true,"x":{"a":0,"k":69.89655293273925},"y":{"a":0,"k":82.703}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,175.29999999999998]}},"shapes":[{"ty":"gr","nm":"Fill-65-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[56.3807548,98.4894844],[59.5978616,98.4894844],[59.5978616,77.6274867],[56.3807548,77.6274867]],"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.23921568627450981,0.30980392156862746,0.44313725490196076,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-56.381,-77.627]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-80-Copy","ip":0,"st":0,"ind":11,"hix":10,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[6.337699890136719,6.3631744384765625,0]},"p":{"s":true,"x":{"a":0,"k":99.034},"y":{"a":0,"k":86.913}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":1,"k":[{"t":0,"s":[0],"e":[183.34649444186343],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":152}]},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-80-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[90.3083635,86.412682],[93.4635411,83.2448238],[90.2818224,80.0495102],[87.1258406,83.218176],[83.970663,80.0495102],[80.7881401,83.2448238],[83.9441219,86.412682],[80.7881401,89.5813477],[83.970663,92.7758537],[87.1258406,89.6079955],[90.2818224,92.7758537],[93.4635411,89.5813477],[90.3083635,86.412682]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.7843137254901961,0.796078431372549,0.8156862745098039,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-80.788,-80.05]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-79-Copy","ip":0,"st":0,"ind":10,"hix":11,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[6.337700843811035,6.362766265869141,0]},"p":{"s":true,"x":{"a":0,"k":24.245999999999988},"y":{"a":0,"k":88.863}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":1,"k":[{"t":0,"s":[0],"e":[94.53803619658584],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":152}]},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-79-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[15.5202234,88.3631718],[18.6754009,85.194506],[15.4936823,82],[12.3377005,85.1678582],[9.18252294,82],[6,85.194506],[9.15598181,88.3631718],[6,91.5302225],[9.18252294,94.7247285],[12.3377005,91.5576778],[15.4936823,94.725536],[18.6754009,91.5302225],[15.5202234,88.3631718]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.7843137254901961,0.796078431372549,0.8156862745098039,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-6,-82]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-78-Copy","ip":0,"st":0,"ind":9,"hix":12,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[6.337700843811035,6.363171577453613,0]},"p":{"s":true,"x":{"a":0,"k":19.041000000000004},"y":{"a":0,"k":21.235}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":1,"k":[{"t":0,"s":[183.34649444186343],"e":[272.154952687141],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":152}]},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-78-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[10.3154041,20.7352648],[13.4705817,17.566599],[10.288863,14.372093],[7.13288119,17.5399512],[3.97770366,14.372093],[0.795180723,17.566599],[3.95116253,20.7352648],[0.795180723,23.903123],[3.97770366,27.0984365],[7.13288119,23.9297708],[10.288863,27.0984365],[13.4705817,23.903123],[10.3154041,20.7352648]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.7843137254901961,0.796078431372549,0.8156862745098039,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-0.795,-14.372]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-77-Copy","ip":0,"st":0,"ind":8,"hix":13,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[0],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":27,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":30,"s":[100],"e":[100],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":129,"s":[100],"e":[0],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":134}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[8.125606536865234,6.429790496826172,0]},"p":{"s":true,"x":{"a":0,"k":106.17299999999999},"y":{"a":0,"k":56.487}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-77-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[100.02483,53.7239059],[95.8063991,56.1682359],[102.390208,59.7253135],[97.7439017,62.4167414],[87.0976909,56.6559714],[91.7391718,53.9669661],[86.1389931,49.5571589],[100.02483,53.7239059]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.9529411764705882,0.6666666666666666,0,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-86.139,-49.557]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-76-Copy","ip":0,"st":0,"ind":7,"hix":14,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[0],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":10,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":19,"s":[100],"e":[100],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":129,"s":[100],"e":[0],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":134}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[7,4.5,0]},"p":{"s":true,"x":{"a":0,"k":37.908},"y":{"a":0,"k":45}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-76-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[24.5935437,44.9333587],[19,42.9542509],[22.2243422,40],[31.2707297,43.2081586],[28.0501854,46.1589783],[33,49],[21.6654309,47.6151735]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.9529411764705882,0.6666666666666666,0,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-19,-40]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-75-Copy","ip":0,"st":0,"ind":6,"hix":15,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[0],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":3,"s":[0],"e":[1.5599999999999998],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":4,"s":[1.5599999999999998],"e":[0],"i":{"x":[0.45],"y":[0.94]},"o":{"x":[0.25],"y":[0.46]}},{"t":5,"s":[0],"e":[6.25],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":7,"s":[6.25],"e":[0],"i":{"x":[0.45],"y":[0.94]},"o":{"x":[0.25],"y":[0.46]}},{"t":10,"s":[0],"e":[25],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":15,"s":[25],"e":[0],"i":{"x":[0.45],"y":[0.94]},"o":{"x":[0.25],"y":[0.46]}},{"t":20,"s":[0],"e":[100],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":30,"s":[100],"e":[100],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":129,"s":[100],"e":[0],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":133}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[7.5,10,0]},"p":{"s":true,"x":{"a":0,"k":44.117000000000004},"y":{"a":0,"k":13.921}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-75-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[24.7093689,11.181303],[30.4364682,11.0344267],[25.6228981,3.58373029],[31.929724,3.42099412],[39.7093689,15.4793309],[33.408674,15.6413775],[36.7289883,23.4209941],[24.7093689,11.181303]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.9529411764705882,0.6666666666666666,0,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-24.709,-3.421]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-74-Copy","ip":0,"st":0,"ind":5,"hix":16,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[0],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":22,"s":[0],"e":[1.5599999999999998],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":23,"s":[1.5599999999999998],"e":[0],"i":{"x":[0.45],"y":[0.94]},"o":{"x":[0.25],"y":[0.46]}},{"t":24,"s":[0],"e":[6.25],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":26,"s":[6.25],"e":[0],"i":{"x":[0.45],"y":[0.94]},"o":{"x":[0.25],"y":[0.46]}},{"t":28,"s":[0],"e":[25],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":32,"s":[25],"e":[0],"i":{"x":[0.45],"y":[0.94]},"o":{"x":[0.25],"y":[0.46]}},{"t":36,"s":[0],"e":[100],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":44,"s":[100],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":129,"s":[100],"e":[0],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":134}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[11.382123947143555,9.07196044921875,0]},"p":{"s":true,"x":{"a":0,"k":26.29},"y":{"a":0,"k":65.572}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-74-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[12.7389867,74.1439221],[11.995835,67.3939535],[3.81714514,73.8168809],[3,66.3837596],[16.2359818,56],[17.0531269,63.4266612],[25.764248,58.7342258],[12.7389867,74.1439221]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.9529411764705882,0.6666666666666666,0,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-3,-56]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-73-Copy","ip":0,"st":0,"ind":4,"hix":17,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[0],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":15,"s":[0],"e":[1.5599999999999998],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":16,"s":[1.5599999999999998],"e":[0],"i":{"x":[0.45],"y":[0.94]},"o":{"x":[0.25],"y":[0.46]}},{"t":17,"s":[0],"e":[6.25],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":19,"s":[6.25],"e":[0],"i":{"x":[0.45],"y":[0.94]},"o":{"x":[0.25],"y":[0.46]}},{"t":21,"s":[0],"e":[25],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":25,"s":[25],"e":[0],"i":{"x":[0.45],"y":[0.94]},"o":{"x":[0.25],"y":[0.46]}},{"t":29,"s":[0],"e":[100],"i":{"x":[0.68],"y":[0.53]},"o":{"x":[0.55],"y":[0.085]}},{"t":38,"s":[100],"e":[100],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":129,"s":[100],"e":[0],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":134}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[10.698890686035156,9.536684036254883,0]},"p":{"s":true,"x":{"a":0,"k":100.70299999999999},"y":{"a":0,"k":25.877}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":0,"k":[100,100,100]}},"shapes":[{"ty":"gr","nm":"Fill-73-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[96.8712615,27.6258868],[90.7643884,24.7035113],[99.4940078,19.0582152],[92.7702545,15.8402914],[78.654394,24.980487],[85.3717131,28.1959882],[78.096226,34.9136565],[96.8712615,27.6258868]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.9529411764705882,0.6666666666666666,0,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-78.096,-15.84]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-63-Copy","ip":0,"st":0,"ind":3,"hix":18,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[2.473957061767578,2.483494281768799,0]},"p":{"s":true,"x":{"a":0,"k":92.599},"y":{"a":0,"k":6.983}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[100,100],"e":[120,120],"i":{"x":[0.515,0.515],"y":[0.955,0.955]},"o":{"x":[0.455,0.455],"y":[0.03,0.03]}},{"t":97,"s":[120,120],"e":[100,100],"i":{"x":[0.515,0.515],"y":[0.955,0.955]},"o":{"x":[0.455,0.455],"y":[0.03,0.03]}},{"t":152}]}},"shapes":[{"ty":"gr","nm":"Fill-63-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[83.1647778,6.4830905],[80.6900184,8.96698851],[78.2168675,6.4830905],[80.6900184,4]],"i":[[0,-1.37115046],[1.3672703999999953,0],[0,1.3719579699999995],[-1.3656619000000063,0]],"o":[[0,1.3719579699999995],[-1.3656619000000063,0],[0,-1.37115046],[1.3672703999999953,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.24313725490196078,0.5137254901960784,0.7529411764705882,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-78.217,-4]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-62-Copy","ip":0,"st":0,"ind":2,"hix":19,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[2.473957061767578,2.4834938049316406,0]},"p":{"s":true,"x":{"a":0,"k":132.069},"y":{"a":0,"k":74.472}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[100,100],"e":[70,70],"i":{"x":[0.515,0.515],"y":[0.955,0.955]},"o":{"x":[0.455,0.455],"y":[0.03,0.03]}},{"t":51,"s":[70,70],"e":[100,100],"i":{"x":[0.515,0.515],"y":[0.955,0.955]},"o":{"x":[0.455,0.455],"y":[0.03,0.03]}},{"t":152}]}},"shapes":[{"ty":"gr","nm":"Fill-62-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[122.634657,73.9714626],[120.160702,76.4553606],[117.686747,73.9714626],[120.160702,71.4883721]],"i":[[0,-1.3711504999999988],[1.3664660000000026,0],[0,1.3719580000000065],[-1.3664660000000026,0]],"o":[[0,1.3719580000000065],[-1.3664660000000026,0],[0,-1.3711504999999988],[1.3664660000000026,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.24313725490196078,0.5137254901960784,0.7529411764705882,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-117.687,-71.488]},"r":{"a":0,"k":0}}]}],"op":152},{"ty":4,"nm":"Fill-61-Copy","ip":0,"st":0,"ind":1,"hix":20,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[2.473552703857422,2.4834938049316406,0]},"p":{"s":true,"x":{"a":0,"k":49.382000000000005},"y":{"a":0,"k":85.983}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[100,100],"e":[150,150],"i":{"x":[0.515,0.515],"y":[0.955,0.955]},"o":{"x":[0.455,0.455],"y":[0.03,0.03]}},{"t":73,"s":[150,150],"e":[100,100],"i":{"x":[0.515,0.515],"y":[0.955,0.955]},"o":{"x":[0.455,0.455],"y":[0.03,0.03]}},{"t":152}]}},"shapes":[{"ty":"gr","nm":"Fill-61-Copy shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[39.947106,85.4830905],[37.4731509,87.9669885],[35,85.4830905],[37.4731509,83]],"i":[[0,-1.3711504999999988],[1.3664660999999967,0],[0,1.3719579999999922],[-1.3656618999999992,0]],"o":[[0,1.3719579999999922],[-1.3656618999999992,0],[0,-1.3711504999999988],[1.3664660999999967,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.24313725490196078,0.5137254901960784,0.7529411764705882,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-35,-83]},"r":{"a":0,"k":0}}]}],"op":152}],"op":152,"w":140,"h":100} \ No newline at end of file diff --git a/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt b/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt index 08f15e7..7f02c67 100644 --- a/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt +++ b/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt @@ -7,8 +7,10 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import com.hako.base.domain.network.RequestStatus +import com.hako.base.extensions.gone import com.hako.base.extensions.observeNonNull import com.hako.base.extensions.toast +import com.hako.base.extensions.visible import com.hako.userlist.model.UserViewable import com.hako.userlist.viewmodel.UserlistViewmodel import com.hako.userlist.widget.UserlistAdapter @@ -40,15 +42,23 @@ class UserlistFragment : Fragment() { viewModel.requestStatus.observeNonNull(this) { when (it) { - RequestStatus.Ready -> { context?.toast("Ready") } - RequestStatus.Loading -> { context?.toast("Loading") } - RequestStatus.Errored -> { context?.toast("Errored") } + RequestStatus.Ready -> { + fragment_userlist_error_overlay.gone() + fragment_userlist_loading_overlay.gone() + } + RequestStatus.Loading -> { + fragment_userlist_error_overlay.gone() + fragment_userlist_loading_overlay.visible() + } + RequestStatus.Errored -> { + fragment_userlist_error_overlay.visible() + fragment_userlist_loading_overlay.gone() + } } } } private fun handleFetchError(throwable: Throwable) { - context?.toast("Could't get data") Timber.e(throwable) } diff --git a/userlist/src/main/res/layout/fragment_userlist.xml b/userlist/src/main/res/layout/fragment_userlist.xml index a208918..ef7295d 100644 --- a/userlist/src/main/res/layout/fragment_userlist.xml +++ b/userlist/src/main/res/layout/fragment_userlist.xml @@ -15,4 +15,24 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + \ No newline at end of file From fb754d1c994d2c1152c60d586279ded2ea16a97c Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Mon, 3 Feb 2020 15:30:13 -0300 Subject: [PATCH 12/12] fix detekt issues --- tools/detekt.yml | 2 +- .../main/java/com/hako/userlist/widget/UserlistAdapter.kt | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/tools/detekt.yml b/tools/detekt.yml index 58e7062..0d5938a 100644 --- a/tools/detekt.yml +++ b/tools/detekt.yml @@ -63,7 +63,7 @@ complexity: threshold: 150 LongMethod: active: true - threshold: 20 + threshold: 40 LongParameterList: active: false threshold: 6 diff --git a/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt b/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt index 3a5294e..fe5f979 100644 --- a/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt +++ b/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt @@ -59,11 +59,4 @@ class UserViewHolder(private val view: View, onFavoriteClick(user) } } - - private fun setFavorite(status: Boolean) { - when (status) { - true -> view.item_user_card_like_button.like() - false -> view.item_user_card_like_button.dislike() - } - } } \ No newline at end of file