├── app ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── menu │ │ │ └── search_menu.xml │ │ ├── layout │ │ │ ├── list_users_item.xml │ │ │ └── activity_list_users.xml │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ └── drawable │ │ │ └── ic_launcher_background.xml │ │ ├── java │ │ └── br │ │ │ └── com │ │ │ └── wellingtoncosta │ │ │ └── coroutines │ │ │ ├── domain │ │ │ ├── model │ │ │ │ └── User.kt │ │ │ └── repository │ │ │ │ └── UserRepository.kt │ │ │ ├── resources │ │ │ ├── remote │ │ │ │ ├── response │ │ │ │ │ └── UserResponse.kt │ │ │ │ └── api │ │ │ │ │ └── GithubApi.kt │ │ │ └── repository │ │ │ │ └── UserDataRepository.kt │ │ │ └── app │ │ │ ├── App.kt │ │ │ ├── config │ │ │ ├── koinModules.kt │ │ │ └── retrofitConfig.kt │ │ │ └── ui │ │ │ ├── ListUsersAdapter.kt │ │ │ ├── ListUsersViewModel.kt │ │ │ └── ListUsersActivity.kt │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle.kts ├── settings.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── README.md ├── .gitignore ├── gradle.properties ├── LICENSE ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "android-kotlin-coroutines" 2 | 3 | include(":app") 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wellingtoncosta/android-kotlin-coroutines/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/java/br/com/wellingtoncosta/coroutines/domain/model/User.kt: -------------------------------------------------------------------------------- 1 | package br.com.wellingtoncosta.coroutines.domain.model 2 | 3 | /** 4 | * @author Wellington Costa on 22/04/18. 5 | */ 6 | data class User (val avatarUrl: String, val username: String) -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 03 06:04:29 BRT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #212121 8 | #757575 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # android-kotlin-coroutines 2 | 3 | A simple Android project using asynchronous programming with Kotlin Coroutines. 4 | 5 | This project uses the following stack: 6 | 7 | - Android Jetpack Live Data 8 | - Android Jetpack View Model 9 | - Fresco 10 | - Google Material Design for Android 11 | - Koin 12 | - Kotlin 13 | - Kotlin Coroutines 14 | - Moshi 15 | - Retrofit -------------------------------------------------------------------------------- /app/src/main/res/menu/search_menu.xml: -------------------------------------------------------------------------------- 1 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Android Kotlin Coroutines 3 | GitHub Users 4 | Search Users 5 | Could not connect to server 6 | Could not get the users 7 | User not found 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/br/com/wellingtoncosta/coroutines/domain/repository/UserRepository.kt: -------------------------------------------------------------------------------- 1 | package br.com.wellingtoncosta.coroutines.domain.repository 2 | 3 | import br.com.wellingtoncosta.coroutines.domain.model.User 4 | import kotlinx.coroutines.Deferred 5 | 6 | /** 7 | * @author Wellington Costa on 23/04/18 8 | */ 9 | interface UserRepository { 10 | 11 | suspend fun getAll(): List 12 | 13 | suspend fun getByUsername(username: String): User 14 | 15 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | 5 | # IDEA config files 6 | .idea/ 7 | /.idea/workspace.xml 8 | /.idea/libraries 9 | /.idea/misc.xml 10 | .idea/modules.xml 11 | /.idea/vcs.xml 12 | 13 | # Java class files 14 | *.class 15 | 16 | # Legacy Eclipse project files 17 | .classpath 18 | .project 19 | 20 | ### Eclipse ### 21 | 22 | .metadata 23 | tmp/ 24 | *.tmp 25 | *.bak 26 | *~.nib 27 | .settings/ 28 | .loadpath 29 | .recommenders 30 | 31 | 32 | 33 | /build 34 | /captures 35 | .externalNativeBuild -------------------------------------------------------------------------------- /app/src/main/java/br/com/wellingtoncosta/coroutines/resources/remote/response/UserResponse.kt: -------------------------------------------------------------------------------- 1 | package br.com.wellingtoncosta.coroutines.resources.remote.response 2 | 3 | import br.com.wellingtoncosta.coroutines.domain.model.User 4 | import com.squareup.moshi.Json 5 | 6 | /** 7 | * @author Wellington Costa on 03/12/18 8 | */ 9 | data class UserResponse( 10 | @Json(name = "avatar_url") val avatarUrl: String, 11 | @Json(name = "login") val username: String 12 | ) 13 | 14 | fun UserResponse.toModel() = User(this.avatarUrl, this.username) -------------------------------------------------------------------------------- /app/src/main/java/br/com/wellingtoncosta/coroutines/resources/remote/api/GithubApi.kt: -------------------------------------------------------------------------------- 1 | package br.com.wellingtoncosta.coroutines.resources.remote.api 2 | 3 | import br.com.wellingtoncosta.coroutines.resources.remote.response.UserResponse 4 | import kotlinx.coroutines.Deferred 5 | import retrofit2.http.GET 6 | import retrofit2.http.Path 7 | 8 | /** 9 | * @author Wellington Costa on 22/04/18. 10 | */ 11 | interface GithubApi { 12 | 13 | @GET("users") 14 | fun getAll(): Deferred> 15 | 16 | @GET("users/{username}") 17 | fun getByUsername(@Path("username") username: String): Deferred 18 | 19 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.old. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/java/br/com/wellingtoncosta/coroutines/app/App.kt: -------------------------------------------------------------------------------- 1 | package br.com.wellingtoncosta.coroutines.app 2 | 3 | import android.app.Application 4 | import br.com.wellingtoncosta.coroutines.app.config.remoteModule 5 | import br.com.wellingtoncosta.coroutines.app.config.repositoryModule 6 | import br.com.wellingtoncosta.coroutines.app.config.uiModule 7 | import com.facebook.drawee.backends.pipeline.Fresco 8 | import org.koin.android.ext.android.startKoin 9 | 10 | /** 11 | * @author Wellington Costa on 22/04/18. 12 | */ 13 | open class App : Application() { 14 | 15 | private val appModules by lazy { 16 | listOf(remoteModule, repositoryModule, uiModule) 17 | } 18 | 19 | override fun onCreate() { 20 | super.onCreate() 21 | 22 | startKoin(this, appModules) 23 | 24 | Fresco.initialize(this) 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | kotlin.code.style=official 15 | android.useAndroidX=true 16 | android.enableJetifier=true -------------------------------------------------------------------------------- /app/src/main/java/br/com/wellingtoncosta/coroutines/app/config/koinModules.kt: -------------------------------------------------------------------------------- 1 | package br.com.wellingtoncosta.coroutines.app.config 2 | 3 | import br.com.wellingtoncosta.coroutines.resources.repository.UserDataRepository 4 | import br.com.wellingtoncosta.coroutines.resources.remote.api.GithubApi 5 | import br.com.wellingtoncosta.coroutines.domain.repository.UserRepository 6 | import br.com.wellingtoncosta.coroutines.app.ui.ListUsersViewModel 7 | import org.koin.androidx.viewmodel.ext.koin.viewModel 8 | import org.koin.dsl.module.module 9 | 10 | val uiModule = module { 11 | viewModel { ListUsersViewModel(get()) } 12 | } 13 | 14 | val repositoryModule = module { 15 | single { UserDataRepository(get()) } 16 | } 17 | 18 | val remoteModule = module { 19 | single { provideOkHttpClient() } 20 | single { provideRetrofit(get()) } 21 | single { createApi(get()) } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/br/com/wellingtoncosta/coroutines/resources/repository/UserDataRepository.kt: -------------------------------------------------------------------------------- 1 | package br.com.wellingtoncosta.coroutines.resources.repository 2 | 3 | import br.com.wellingtoncosta.coroutines.domain.repository.UserRepository 4 | import br.com.wellingtoncosta.coroutines.resources.remote.api.GithubApi 5 | import br.com.wellingtoncosta.coroutines.resources.remote.response.toModel 6 | import kotlinx.coroutines.Dispatchers.IO 7 | import kotlinx.coroutines.withContext 8 | 9 | /** 10 | * @author Wellington Costa on 23/04/18 11 | */ 12 | class UserDataRepository( 13 | private val api: GithubApi 14 | ) : UserRepository { 15 | 16 | override suspend fun getAll() = withContext(IO) { 17 | api.getAll().await().map { it.toModel() } 18 | } 19 | 20 | override suspend fun getByUsername(username: String) = withContext(IO) { 21 | api.getByUsername(username).await().toModel() 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 |