├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── encodings.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── nextus │ │ └── baseapp │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── nextus │ │ │ └── baseapp │ │ │ ├── MyApplication.kt │ │ │ ├── data │ │ │ ├── RemoteClient.kt │ │ │ ├── api │ │ │ │ └── GitApi.kt │ │ │ ├── datasource │ │ │ │ ├── GitDataSource.kt │ │ │ │ └── GitRemoteDataSource.kt │ │ │ └── repository │ │ │ │ └── GitRepositoryImpl.kt │ │ │ ├── di │ │ │ └── AppModules.kt │ │ │ ├── domain │ │ │ ├── core │ │ │ │ └── Result.kt │ │ │ ├── model │ │ │ │ └── GistsPublic.kt │ │ │ ├── repository │ │ │ │ └── GitRepository.kt │ │ │ └── usecase │ │ │ │ └── GetGistsPublicUseCase.kt │ │ │ ├── ui │ │ │ ├── base │ │ │ │ ├── BaseActivity.kt │ │ │ │ ├── BaseFragment.kt │ │ │ │ ├── BaseRecyclerAdapter.kt │ │ │ │ ├── BaseViewHolder.kt │ │ │ │ └── BaseViewModel.kt │ │ │ ├── home │ │ │ │ ├── GistsAdapter.kt │ │ │ │ ├── HomeFragment.kt │ │ │ │ └── HomeViewModel.kt │ │ │ ├── main │ │ │ │ ├── MainActivity.kt │ │ │ │ └── MainViewModel.kt │ │ │ └── mypage │ │ │ │ ├── MyPageFragment.kt │ │ │ │ └── MyPageViewModel.kt │ │ │ └── utils │ │ │ ├── AppLogger.kt │ │ │ ├── BindingUtils.kt │ │ │ ├── CommonUtils.kt │ │ │ └── ViewUtils.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_apps_black_24dp.xml │ │ ├── ic_description_black_24dp.xml │ │ ├── ic_directions_run_black_24dp.xml │ │ ├── ic_launcher_background.xml │ │ └── selector_bottom_navigation.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_home.xml │ │ ├── fragment_mypage.xml │ │ ├── item_empty.xml │ │ └── item_gists.xml │ │ ├── menu │ │ └── menu_bottom_navigation_view.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── 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 │ │ ├── navigation │ │ └── navigation_graph.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── nextus │ └── baseapp │ └── ExampleUnitTest.kt ├── build.gradle ├── dependency.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | xmlns:android 18 | 19 | ^$ 20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 | xmlns:.* 29 | 30 | ^$ 31 | 32 | 33 | BY_NAME 34 | 35 |
36 |
37 | 38 | 39 | 40 | .*:id 41 | 42 | http://schemas.android.com/apk/res/android 43 | 44 | 45 | 46 |
47 |
48 | 49 | 50 | 51 | .*:name 52 | 53 | http://schemas.android.com/apk/res/android 54 | 55 | 56 | 57 |
58 |
59 | 60 | 61 | 62 | name 63 | 64 | ^$ 65 | 66 | 67 | 68 |
69 |
70 | 71 | 72 | 73 | style 74 | 75 | ^$ 76 | 77 | 78 | 79 |
80 |
81 | 82 | 83 | 84 | .* 85 | 86 | ^$ 87 | 88 | 89 | BY_NAME 90 | 91 |
92 |
93 | 94 | 95 | 96 | .* 97 | 98 | http://schemas.android.com/apk/res/android 99 | 100 | 101 | ANDROID_ATTRIBUTE_ORDER 102 | 103 |
104 |
105 | 106 | 107 | 108 | .* 109 | 110 | .* 111 | 112 | 113 | BY_NAME 114 | 115 |
116 |
117 |
118 |
119 | 120 | 122 |
123 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kotlin_MVVM 2 | 3 | Android Design Pattern 중 하나인 MVVM Pattern 을 적용한 예제입니다. 4 | 5 | ## 라이브러리 6 | > Android Databinding 7 | > Android Navigation 8 | > RxJava2 + Retrofit2 9 | > Koin 10 | > Coroutine ( Flow ) 11 | > Android LiveData 12 | 13 | ## 업데이트 예정 14 | > Android Navigation 심화 ( BackStack 관련 ) 15 | > 비동기 처리 방식 변경 ( 기존 Rx 에서 Coroutine 으로 ) 16 | > Room 예제 추가 17 | > 기존 ObservableField 에서 LiveData 이용으로 18 | 19 | ## 업데이트 내용 20 | 21 | * 2020.07.28 22 | > 일부 필요 없는 코드 제거 23 | > Coroutine Flow 적용 24 | > ExperimentalCoroutinesApi 관련 어노테이션 제거 25 | 26 | * 2020.06.25 27 | > Gradle Version 변경 28 | > Base 클래스들( BaseViewModel, BaseActivity, BaseFragment, BaseRecyclerAdapter, BaseViewHolder) 의 구조적 변화로 인한 전체 코드 수정 29 | > 네트워크 라이브러리 변경 (~~Android Fast Networking~~ => Retrofit2) 30 | > Clean Architecture 적용 ( Google Architecture Sample 참조 ) 31 | 32 | 33 | 블로그 34 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'kotlin-kapt' 5 | apply plugin: "androidx.navigation.safeargs.kotlin" 6 | 7 | android { 8 | compileSdkVersion build_versions.compile_sdk 9 | buildToolsVersion build_versions.build_tools 10 | defaultConfig { 11 | applicationId "com.nextus.baseapp" 12 | minSdkVersion build_versions.min_sdk 13 | targetSdkVersion build_versions.target_sdk 14 | versionCode 1 15 | versionName "1.0" 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | vectorDrawables.useSupportLibrary true 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_1_8 28 | targetCompatibility JavaVersion.VERSION_1_8 29 | } 30 | 31 | kotlinOptions { 32 | jvmTarget = JavaVersion.VERSION_1_8.toString() 33 | freeCompilerArgs += [ 34 | "-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi", 35 | "-Xuse-experimental=kotlinx.coroutines.ObsoleteCoroutinesApi" 36 | ] 37 | } 38 | 39 | dataBinding { 40 | enabled = true 41 | } 42 | } 43 | 44 | dependencies { 45 | 46 | implementation deps.kotlin.stdlib 47 | 48 | // Jetpack 49 | implementation deps.androidx.appcompat 50 | implementation deps.androidx.core_ktx 51 | implementation deps.androidx.constraintlayout 52 | implementation deps.androidx.lifecycle.runtime_ktx 53 | implementation deps.androidx.lifecycle.extensions 54 | implementation deps.androidx.lifecycle.viewmodel_ktx 55 | implementation deps.androidx.lifecycle.livedata_ktx 56 | implementation deps.androidx.navigation.fragment_ktx 57 | implementation deps.androidx.navigation.ui_ktx 58 | implementation deps.androidx.material 59 | implementation deps.androidx.swiperefresh 60 | 61 | // coroutine 62 | implementation deps.kotlin.coroutines.core 63 | implementation deps.kotlin.coroutines.android 64 | implementation deps.kotlin.coroutines.play_services 65 | 66 | // retrofit 67 | implementation deps.retrofit.core 68 | implementation deps.retrofit.converter_gson 69 | implementation deps.retrofit.adapter_rxjava2 70 | 71 | // koin 72 | implementation deps.koin.core 73 | implementation deps.koin.viewModel 74 | 75 | // okhttp 76 | implementation deps.okhttp.core 77 | implementation deps.okhttp.logging_interceptor 78 | 79 | // debugging 80 | implementation deps.debugging.timber 81 | 82 | // test 83 | testImplementation deps.atsl.junit 84 | androidTestImplementation deps.atsl.ext_junit 85 | androidTestImplementation deps.atsl.espresso_core 86 | testImplementation deps.kotlin.coroutines.test 87 | /* 88 | 89 | 90 | //implementation fileTree(dir: 'libs', include: ['*.jar']) 91 | kapt "androidx.room:room-compiler:$rootProject.roomVersion" 92 | kapt "com.github.bumptech.glide:compiler:$rootProject.glideVersion" 93 | //kapt "com.android.databinding:compiler:$rootProject.gradleVersion" 94 | 95 | implementation "androidx.appcompat:appcompat:$rootProject.supportLibraryVersion" 96 | implementation "androidx.constraintlayout:constraintlayout:$rootProject.constraintLayoutVersion" 97 | implementation "androidx.core:core-ktx:$rootProject.ktxVersion" 98 | implementation "androidx.fragment:fragment-ktx:$rootProject.fragmentVersion" 99 | implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.lifecycleVersion" 100 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:$rootProject.lifecycleVersion" 101 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion" 102 | //annotationProcessor "androidx.lifecycle:lifecycle-compiler:$rootProject.lifecycleVersion" 103 | implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.navigationVersion" 104 | implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion" 105 | implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerViewVersion" 106 | implementation "androidx.room:room-runtime:$rootProject.roomVersion" 107 | 108 | implementation "com.amitshekhar.android:rx2-android-networking:$rootProject.rx2FastAndroidNetworking" 109 | implementation "com.github.bumptech.glide:glide:$rootProject.glideVersion" 110 | implementation "com.google.android.material:material:$rootProject.materialVersion" 111 | implementation "com.jakewharton.timber:timber:$rootProject.timberVersion" 112 | 113 | implementation "io.reactivex.rxjava2:rxjava:$rootProject.rxjava2Version" 114 | implementation "io.reactivex.rxjava2:rxandroid:$rootProject.rxandroidVersion" 115 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$rootProject.kotlinVersion" 116 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$rootProject.coroutinesVersion" 117 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$rootProject.coroutinesVersion" 118 | implementation "org.koin:koin-androidx-scope:$rootProject.koinVersion" 119 | implementation "org.koin:koin-androidx-viewmodel:$rootProject.koinVersion" 120 | 121 | implementation "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion" 122 | implementation "com.squareup.retrofit2:converter-gson:$rootProject.retrofitVersion" 123 | implementation "com.squareup.retrofit2:converter-jackson:$rootProject.retrofitVersion" 124 | implementation "com.squareup.retrofit2:adapter-rxjava2:$rootProject.retrofitVersion" 125 | 126 | 127 | testImplementation 'junit:junit:4.12' 128 | androidTestImplementation 'androidx.test:runner:1.2.0' 129 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'*/ 130 | } 131 | -------------------------------------------------------------------------------- /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.gradle. 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/androidTest/java/com/nextus/baseapp/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp 2 | 3 | import androidx.test.InstrumentationRegistry 4 | import androidx.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("com.nextus.baseapp", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/MyApplication.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp 2 | 3 | import android.app.Application 4 | import com.nextus.baseapp.di.appModules 5 | import com.nextus.baseapp.utils.AppLogger 6 | import org.koin.android.ext.koin.androidContext 7 | import org.koin.core.context.startKoin 8 | import timber.log.Timber 9 | 10 | class MyApplication : Application() { 11 | 12 | override fun onCreate() { 13 | super.onCreate() 14 | 15 | if (BuildConfig.DEBUG) { 16 | AppLogger.init() 17 | Timber.plant(Timber.DebugTree()) 18 | } 19 | 20 | // start Koin! 21 | startKoin { 22 | // Android context 23 | androidContext(this@MyApplication) 24 | // modules 25 | modules(appModules) 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/data/RemoteClient.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.data 2 | 3 | import okhttp3.OkHttpClient 4 | import okhttp3.logging.HttpLoggingInterceptor 5 | import retrofit2.Retrofit 6 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory 7 | import retrofit2.converter.gson.GsonConverterFactory 8 | 9 | object RemoteClient { 10 | 11 | private const val baseUrl = "http://api.github.com/" 12 | 13 | fun createRetrofit(debug: Boolean): Retrofit { 14 | return Retrofit.Builder() 15 | .baseUrl(baseUrl) 16 | .client( 17 | provideOkHttpClient( 18 | provideLoggingInterceptor(debug) 19 | ) 20 | ) 21 | .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) 22 | .addConverterFactory(GsonConverterFactory.create()) 23 | .build() 24 | } 25 | 26 | // 네트워크 통신에 사용할 클라이언트 객체를 생성합니다. 27 | private fun provideOkHttpClient(interceptor: HttpLoggingInterceptor): OkHttpClient { 28 | val b = OkHttpClient.Builder() 29 | // 이 클라이언트를 통해 오고 가는 네트워크 요청/응답을 로그로 표시하도록 합니다. 30 | b.addInterceptor(interceptor) 31 | /* // header 에 정보를 추가해 준다. 32 | b.addInterceptor(AddHeaderInterceptor())*/ 33 | return b.build() 34 | } 35 | 36 | // 네트워크 요청/응답을 로그에 표시하는 Interceptor 객체를 생성합니다. 37 | private fun provideLoggingInterceptor(debug: Boolean): HttpLoggingInterceptor { 38 | val logging = HttpLoggingInterceptor() 39 | logging.level = if (debug) 40 | HttpLoggingInterceptor.Level.BODY 41 | else 42 | HttpLoggingInterceptor.Level.NONE 43 | return logging 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/data/api/GitApi.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.data.api 2 | 3 | import com.nextus.baseapp.domain.model.GistsPublic 4 | import retrofit2.Call 5 | import retrofit2.http.POST 6 | 7 | interface GitApi { 8 | 9 | @POST("gists/public") 10 | fun getGistsPublic(): Call> 11 | 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/data/datasource/GitDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.data.datasource 2 | 3 | import com.nextus.baseapp.domain.core.Result 4 | import com.nextus.baseapp.domain.model.GistsPublic 5 | 6 | interface GitDataSource { 7 | suspend fun getGistsPublic(): Result> 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/data/datasource/GitRemoteDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.data.datasource 2 | 3 | import com.nextus.baseapp.data.api.GitApi 4 | import com.nextus.baseapp.domain.core.Result 5 | import com.nextus.baseapp.domain.model.GistsPublic 6 | 7 | class GitRemoteDataSource(private val gitApi: GitApi): GitDataSource { 8 | 9 | override suspend fun getGistsPublic(): Result> { 10 | val response = gitApi.getGistsPublic().execute() 11 | 12 | return if(response.isSuccessful) { 13 | Result.Success(response.body() ?: ArrayList()) 14 | } else { 15 | Result.Error(Exception("Network Error")) 16 | } 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/data/repository/GitRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.data.repository 2 | 3 | import com.nextus.baseapp.data.datasource.GitDataSource 4 | import com.nextus.baseapp.domain.core.Result 5 | import com.nextus.baseapp.domain.model.GistsPublic 6 | import com.nextus.baseapp.domain.repository.GitRepository 7 | import kotlinx.coroutines.delay 8 | import kotlinx.coroutines.flow.Flow 9 | import kotlinx.coroutines.flow.flow 10 | 11 | class GitRepositoryImpl(private val gitDataSource: GitDataSource): GitRepository { 12 | override fun getGistsPublic() = flow { 13 | emit(Result.Loading) 14 | delay(1000) 15 | emit(gitDataSource.getGistsPublic()) 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/di/AppModules.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.di 2 | 3 | import com.nextus.baseapp.data.RemoteClient 4 | import com.nextus.baseapp.data.api.GitApi 5 | import com.nextus.baseapp.data.datasource.GitDataSource 6 | import com.nextus.baseapp.data.datasource.GitRemoteDataSource 7 | import com.nextus.baseapp.domain.repository.GitRepository 8 | import com.nextus.baseapp.data.repository.GitRepositoryImpl 9 | import com.nextus.baseapp.ui.home.HomeViewModel 10 | import com.nextus.baseapp.ui.main.MainViewModel 11 | import com.nextus.baseapp.ui.mypage.MyPageViewModel 12 | import com.nextus.baseapp.domain.usecase.GetGistsPublicUseCase 13 | import org.koin.androidx.viewmodel.dsl.viewModel 14 | import org.koin.dsl.module 15 | 16 | val viewModelModule = module { 17 | viewModel { MainViewModel(get()) } 18 | viewModel { HomeViewModel(get(), get()) } 19 | viewModel { MyPageViewModel(get()) } 20 | } 21 | 22 | val remoteModule = module { 23 | single { RemoteClient } 24 | } 25 | 26 | val dataSourceModule = module { 27 | single { GitRemoteDataSource(get()) as GitDataSource} 28 | } 29 | 30 | val apiModule = module { 31 | single { gitApi } 32 | } 33 | 34 | val repositoryModule = module { 35 | single { GitRepositoryImpl(get()) as GitRepository } 36 | } 37 | 38 | val useCaseModule = module { 39 | single { GetGistsPublicUseCase(get()) } 40 | } 41 | 42 | val retrofit = RemoteClient.createRetrofit(true) 43 | private val gitApi = retrofit.create(GitApi::class.java) 44 | 45 | val appModules = listOf( 46 | remoteModule, 47 | dataSourceModule, 48 | viewModelModule, 49 | apiModule, 50 | repositoryModule, 51 | useCaseModule 52 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/domain/core/Result.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.domain.core 2 | 3 | /** 4 | * @author ReStartAllKill 5 | * @created on 2020-02-12 6 | * @modified by 7 | * @updated on 8 | */ 9 | /** 10 | * A generic class that holds a value with its loading status. 11 | * @param 12 | */ 13 | sealed class Result { 14 | 15 | data class Success(val data: T) : Result() 16 | data class Error(val exception: Exception) : Result() 17 | object Loading : Result() 18 | 19 | override fun toString(): String { 20 | return when (this) { 21 | is Success<*> -> "Success[data=$data]" 22 | is Error -> "Error[exception=$exception]" 23 | Loading -> "Loading" 24 | } 25 | } 26 | } 27 | 28 | /** 29 | * `true` if [Result] is of type [Success] & holds non-null [Success.data]. 30 | */ 31 | val Result<*>.succeeded 32 | get() = this is Result.Success && data != null -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/domain/model/GistsPublic.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.domain.model 2 | 3 | data class GistsPublic(val url: String, val forks_url: String) -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/domain/repository/GitRepository.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.domain.repository 2 | 3 | import com.nextus.baseapp.domain.core.Result 4 | import com.nextus.baseapp.domain.model.GistsPublic 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | interface GitRepository { 8 | fun getGistsPublic(): Flow>> 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/domain/usecase/GetGistsPublicUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.domain.usecase 2 | 3 | import com.nextus.baseapp.domain.repository.GitRepository 4 | 5 | class GetGistsPublicUseCase(private val gitRepository: GitRepository) { 6 | operator fun invoke() = gitRepository.getGistsPublic() 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/base/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.base 2 | 3 | import android.os.Bundle 4 | import androidx.annotation.LayoutRes 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.databinding.DataBindingUtil 7 | import androidx.databinding.ViewDataBinding 8 | import androidx.lifecycle.ViewModel 9 | import org.koin.androidx.viewmodel.ext.android.viewModel 10 | import kotlin.reflect.KClass 11 | import com.nextus.baseapp.BR 12 | 13 | abstract class BaseActivity( 14 | @LayoutRes private val layoutResId: Int, 15 | clazz: KClass 16 | ) : AppCompatActivity(), BaseFragment.CallBack { 17 | 18 | protected lateinit var mViewDataBinding: B 19 | protected val viewModel : VM by viewModel(clazz) 20 | 21 | abstract fun onCreate() 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | performDataBinding() 26 | onCreate() 27 | } 28 | 29 | private fun performDataBinding() { 30 | mViewDataBinding = DataBindingUtil.setContentView(this, layoutResId) 31 | mViewDataBinding.lifecycleOwner = this 32 | mViewDataBinding.setVariable(BR.viewModel, viewModel) 33 | mViewDataBinding.executePendingBindings() 34 | } 35 | 36 | override fun onFragmentAttached() { 37 | 38 | } 39 | 40 | override fun onFragmentDetached(tag: String) { 41 | 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.base 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import androidx.annotation.LayoutRes 9 | import androidx.databinding.DataBindingUtil 10 | import androidx.databinding.ViewDataBinding 11 | import androidx.fragment.app.Fragment 12 | import androidx.lifecycle.ViewModel 13 | import com.nextus.baseapp.BR 14 | import org.koin.androidx.viewmodel.ext.android.viewModel 15 | import kotlin.reflect.KClass 16 | 17 | /** 18 | * @author ReStartAllKill 19 | * @created on 2019-05-27 20 | * @modified by 21 | * @updated on 22 | */ 23 | abstract class BaseFragment( 24 | @LayoutRes private val layoutResId: Int, 25 | clazz: KClass 26 | ) : Fragment() { 27 | 28 | private lateinit var mViewDataBinding: B 29 | protected val viewModel : VM by viewModel(clazz) 30 | private var mActivity: BaseActivity<*, *>? = null 31 | 32 | override fun onAttach(context: Context) { 33 | super.onAttach(context) 34 | if(context is BaseActivity<*, *>) { 35 | mActivity = context 36 | mActivity?.onFragmentAttached() 37 | } 38 | } 39 | 40 | abstract fun onCreate() 41 | 42 | override fun onCreate(savedInstanceState: Bundle?) { 43 | super.onCreate(savedInstanceState) 44 | setHasOptionsMenu(true) // Fragment Option Menu 사용 45 | } 46 | 47 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 48 | mViewDataBinding = DataBindingUtil.inflate(inflater, layoutResId, container, false) 49 | return mViewDataBinding.root 50 | } 51 | 52 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 53 | super.onViewCreated(view, savedInstanceState) 54 | mViewDataBinding.setVariable(BR.viewModel, viewModel) 55 | mViewDataBinding.lifecycleOwner = this 56 | mViewDataBinding.executePendingBindings() 57 | 58 | onCreate() 59 | } 60 | 61 | fun getBaseActivity() : BaseActivity<*, *>? { 62 | return mActivity 63 | } 64 | 65 | override fun onDetach() { 66 | mActivity = null 67 | super.onDetach() 68 | } 69 | 70 | interface CallBack { 71 | fun onFragmentAttached() 72 | fun onFragmentDetached(tag: String) 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/base/BaseRecyclerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.base 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.databinding.DataBindingUtil 7 | import androidx.databinding.ViewDataBinding 8 | import androidx.recyclerview.widget.DiffUtil 9 | import androidx.recyclerview.widget.ListAdapter 10 | 11 | abstract class BaseRecyclerAdapter(diffCallBack: DiffUtil.ItemCallback) 12 | : ListAdapter>(diffCallBack) { 13 | 14 | interface ItemClickListener { 15 | fun onClickItem(view: View, item: T, position: Int) 16 | } 17 | 18 | private var onItemClickListener : ItemClickListener? = null 19 | 20 | fun setOnItemClickListener(listener: (view: View, T, position: Int) -> Unit) { 21 | onItemClickListener = object: ItemClickListener { 22 | override fun onClickItem(view: View, item: T, position: Int) { 23 | listener(view, item, position) 24 | } 25 | } 26 | } 27 | 28 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { 29 | val layoutInflater = LayoutInflater.from(parent.context) 30 | val binding = DataBindingUtil.inflate(layoutInflater, viewType, parent, false) 31 | return BaseViewHolder(binding) 32 | } 33 | 34 | override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { 35 | holder.itemView.setOnClickListener { 36 | onItemClickListener?.onClickItem(holder.itemView, getItem(position), position) 37 | } 38 | return holder.bind(getItem(position)) 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/base/BaseViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.base 2 | 3 | import androidx.databinding.ViewDataBinding 4 | import androidx.recyclerview.widget.RecyclerView 5 | import com.nextus.baseapp.BR 6 | 7 | class BaseViewHolder(private val binding: ViewDataBinding): RecyclerView.ViewHolder(binding.root) { 8 | 9 | fun bind(item: T) { 10 | binding.setVariable(BR.item, item) 11 | binding.executePendingBindings() 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/base/BaseViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.base 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.AndroidViewModel 5 | 6 | abstract class BaseViewModel(application: Application) : AndroidViewModel(application) { 7 | 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/home/GistsAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.home 2 | 3 | import androidx.recyclerview.widget.DiffUtil 4 | import com.nextus.baseapp.R 5 | import com.nextus.baseapp.domain.model.GistsPublic 6 | import com.nextus.baseapp.ui.base.BaseRecyclerAdapter 7 | 8 | class GistsAdapter : BaseRecyclerAdapter(DiffCallback()) { 9 | 10 | class DiffCallback : DiffUtil.ItemCallback() { 11 | override fun areItemsTheSame(oldItem: GistsPublic, newItem: GistsPublic): Boolean { 12 | return oldItem.url == newItem.url 13 | } 14 | 15 | override fun areContentsTheSame(oldItem: GistsPublic, newItem: GistsPublic): Boolean { 16 | return oldItem == newItem 17 | } 18 | } 19 | 20 | override fun getItemViewType(position: Int) = R.layout.item_gists 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/home/HomeFragment.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.home 2 | 3 | import android.widget.Toast 4 | import androidx.lifecycle.Observer 5 | import androidx.navigation.findNavController 6 | import androidx.recyclerview.widget.LinearLayoutManager 7 | import androidx.recyclerview.widget.RecyclerView 8 | import com.nextus.baseapp.R 9 | import com.nextus.baseapp.databinding.FragmentHomeBinding 10 | import com.nextus.baseapp.ui.base.BaseFragment 11 | import kotlinx.android.synthetic.main.fragment_home.* 12 | import kotlinx.coroutines.ExperimentalCoroutinesApi 13 | 14 | /** 15 | * @author ReStartAllKill 16 | * @created on 2019-05-28 17 | * @modified by 18 | * @updated on 19 | */ 20 | 21 | class HomeFragment : BaseFragment( 22 | R.layout.fragment_home, 23 | HomeViewModel::class 24 | ) { 25 | 26 | private val gistsAdapter = GistsAdapter() 27 | 28 | override fun onCreate() { 29 | initView() 30 | initGistsObserve() 31 | } 32 | 33 | private fun initView() { 34 | gistsAdapter.apply { 35 | setOnItemClickListener { view, gistsPublic, i -> 36 | Toast.makeText(view.context, "$i) $gistsPublic", Toast.LENGTH_SHORT).show() 37 | 38 | val directions = HomeFragmentDirections.actionHomeFragmentToMyPageFragment(gistsPublic.url) 39 | view.findNavController().navigate(directions) 40 | } 41 | } 42 | 43 | gistsPublicRecycler.apply { 44 | adapter = gistsAdapter 45 | layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false) 46 | } 47 | } 48 | 49 | private fun initGistsObserve() { 50 | viewModel.gistsPublicDataList.observe(this, Observer { 51 | it.let(gistsAdapter::submitList) 52 | }) 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/home/HomeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.home 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.* 5 | import com.nextus.baseapp.domain.core.Result 6 | import com.nextus.baseapp.domain.model.GistsPublic 7 | import com.nextus.baseapp.domain.usecase.GetGistsPublicUseCase 8 | import com.nextus.baseapp.ui.base.BaseViewModel 9 | import kotlinx.coroutines.Dispatchers 10 | import kotlinx.coroutines.flow.flowOn 11 | import kotlinx.coroutines.flow.map 12 | 13 | /** 14 | * @author ReStartAllKill 15 | * @created on 2019-05-28 16 | * @modified by 17 | * @updated on 18 | */ 19 | 20 | class HomeViewModel( 21 | application: Application, 22 | private val getGistsPublicUseCase: GetGistsPublicUseCase 23 | ): BaseViewModel(application) { 24 | 25 | private val _refreshEvent = MutableLiveData() 26 | val refreshEvent: LiveData = _refreshEvent 27 | 28 | private val _gistsPublicDataList = refreshEvent.switchMap { 29 | getGistsPublicUseCase() 30 | .flowOn(Dispatchers.IO) 31 | .map { 32 | when (it) { 33 | is Result.Success -> it.data 34 | is Result.Loading -> ArrayList() 35 | is Result.Error -> ArrayList() 36 | } 37 | } 38 | .asLiveData() 39 | } 40 | 41 | var gistsPublicDataList: LiveData> = _gistsPublicDataList 42 | 43 | val isRefreshing: LiveData = gistsPublicDataList.map { it.isEmpty() } 44 | 45 | init { 46 | _refreshEvent.value = Unit 47 | } 48 | 49 | fun getGistsPublic() { 50 | _refreshEvent.value = Unit 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/main/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.main 2 | 3 | import androidx.navigation.fragment.NavHostFragment 4 | import androidx.navigation.ui.NavigationUI 5 | import com.nextus.baseapp.R 6 | import com.nextus.baseapp.databinding.ActivityMainBinding 7 | import com.nextus.baseapp.ui.base.BaseActivity 8 | import kotlinx.android.synthetic.main.activity_main.* 9 | 10 | class MainActivity : BaseActivity( 11 | R.layout.activity_main, 12 | MainViewModel::class 13 | ) { 14 | 15 | override fun onCreate() { 16 | val host = supportFragmentManager.findFragmentById(R.id.navHostfragment) as NavHostFragment 17 | NavigationUI.setupWithNavController(bottomNavigation, host.navController) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/main/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.main 2 | 3 | import android.app.Application 4 | import com.nextus.baseapp.data.RemoteClient 5 | import com.nextus.baseapp.ui.base.BaseViewModel 6 | 7 | class MainViewModel(application: Application): BaseViewModel(application) { 8 | 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/mypage/MyPageFragment.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.mypage 2 | 3 | import com.nextus.baseapp.R 4 | import com.nextus.baseapp.databinding.FragmentMypageBinding 5 | import com.nextus.baseapp.ui.base.BaseFragment 6 | import kotlinx.android.synthetic.main.fragment_mypage.* 7 | 8 | /** 9 | * @author ReStartAllKill 10 | * @created on 2019-05-28 11 | * @modified by 12 | * @updated on 13 | */ 14 | 15 | class MyPageFragment : BaseFragment( 16 | R.layout.fragment_mypage, 17 | MyPageViewModel::class 18 | ) { 19 | 20 | override fun onCreate() { 21 | arguments?.let { 22 | val arguments = MyPageFragmentArgs.fromBundle(it) 23 | text.text = arguments.testString 24 | } 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/ui/mypage/MyPageViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.ui.mypage 2 | 3 | import android.app.Application 4 | import com.nextus.baseapp.data.RemoteClient 5 | import com.nextus.baseapp.ui.base.BaseViewModel 6 | 7 | /** 8 | * @author ReStartAllKill 9 | * @created on 2019-05-28 10 | * @modified by 11 | * @updated on 12 | */ 13 | class MyPageViewModel(application: Application) : BaseViewModel(application) { 14 | 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/utils/AppLogger.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.utils 2 | 3 | import com.nextus.baseapp.BuildConfig 4 | import timber.log.Timber 5 | 6 | /** 7 | * @author ReStartAllKill 8 | * @created on 2018-09-20 9 | * @modified by 10 | * @updated on 11 | */ 12 | 13 | object AppLogger { 14 | fun d(s: String, vararg objects: Any) { 15 | Timber.d(s, objects) 16 | } 17 | 18 | fun d(throwable: Throwable, s: String, vararg objects: Any) { 19 | Timber.d(throwable, s, objects) 20 | } 21 | 22 | fun e(s: String, vararg objects: Any) { 23 | Timber.e(s, objects) 24 | } 25 | 26 | fun e(throwable: Throwable, s: String, vararg objects: Any) { 27 | Timber.e(throwable, s, objects) 28 | } 29 | 30 | fun i(s: String, vararg objects: Any) { 31 | Timber.i(s, objects) 32 | } 33 | 34 | fun i(throwable: Throwable, s: String, vararg objects: Any) { 35 | Timber.i(throwable, s, objects) 36 | } 37 | 38 | fun init() { 39 | Timber.plant(Timber.DebugTree()) 40 | } 41 | 42 | fun w(s: String, vararg objects: Any) { 43 | Timber.w(s, objects) 44 | } 45 | 46 | fun w(throwable: Throwable, s: String, vararg objects: Any) { 47 | Timber.w(throwable, s, objects) 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/utils/BindingUtils.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.utils 2 | 3 | import androidx.databinding.BindingAdapter 4 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout 5 | 6 | /** 7 | * @author ReStartAllKill 8 | * @created on 2019-05-27 9 | * @modified by 10 | * @updated on 11 | */ 12 | object BindingUtils { 13 | @JvmStatic 14 | @BindingAdapter("isRefreshing") 15 | fun SwipeRefreshLayout.bindRefreshing(isRefreshing: Boolean) { 16 | this.isRefreshing = isRefreshing 17 | } 18 | 19 | @JvmStatic 20 | @BindingAdapter("onRefresh") 21 | fun SwipeRefreshLayout.bindRefreshListener(onRefreshListener: SwipeRefreshLayout.OnRefreshListener) = 22 | setOnRefreshListener(onRefreshListener) 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/utils/CommonUtils.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.utils 2 | 3 | import android.util.Patterns 4 | import java.text.SimpleDateFormat 5 | import java.util.* 6 | 7 | /** 8 | * @author ReStartAllKill 9 | * @created on 2019-05-27 10 | * @modified by 11 | * @updated on 12 | */ 13 | object CommonUtils { 14 | 15 | fun getTimeStamp(format: String) : String { 16 | return SimpleDateFormat(format, Locale.KOREA).format(Date()) 17 | } 18 | 19 | fun getTime() : Long { 20 | return System.currentTimeMillis() 21 | } 22 | 23 | fun isEmailValid(email: String) : Boolean { 24 | return Patterns.EMAIL_ADDRESS.matcher(email).matches() 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/nextus/baseapp/utils/ViewUtils.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp.utils 2 | 3 | import android.content.res.Resources 4 | 5 | /** 6 | * @author ReStartAllKill 7 | * @created on 2019-05-27 8 | * @modified by 9 | * @updated on 10 | */ 11 | object ViewUtils { 12 | 13 | fun dpToPx(dp: Float) : Int { 14 | val density = Resources.getSystem().displayMetrics.density 15 | return Math.round(dp * density) 16 | } 17 | 18 | fun pxToDp(px: Float) : Float { 19 | val densityDpi = Resources.getSystem().displayMetrics.densityDpi 20 | return px / (densityDpi / 160f) 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_description_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_directions_run_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_bottom_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 23 | 24 | 27 | 28 | 29 | 38 | 39 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | 13 | 14 | 20 | 21 | 26 | 27 | 28 | 29 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_mypage.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 12 | 13 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_empty.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_gists.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 12 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_bottom_navigation_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 12 | 16 | -------------------------------------------------------------------------------- /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/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/navigation/navigation_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 15 | 16 | 17 | 22 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FFC107 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | My Application 3 | 4 | TAB1 5 | TAB2 6 | TAB3 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/nextus/baseapp/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.nextus.baseapp 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | apply from: 'dependency.gradle' 5 | addRepos(repositories) 6 | 7 | dependencies { 8 | classpath gradlePlugin.android 9 | classpath gradlePlugin.kotlin 10 | classpath gradlePlugin.navigation_safe_args 11 | } 12 | /*ext { 13 | constraintLayoutVersion = '2.0.0-beta4' 14 | coroutinesVersion = "1.3.5" 15 | 16 | fragmentVersion = '1.2.5' 17 | 18 | gradleVersion = '4.0.0' 19 | glideVersion = '4.11.0' 20 | 21 | kotlinVersion = '1.3.72' 22 | koinVersion = '2.1.0-alpha-3' 23 | ktxVersion = '1.2.0' 24 | 25 | lifecycleVersion = '2.2.0' 26 | 27 | materialVersion = '1.1.0' 28 | 29 | navigationVersion = '2.3.0-alpha01' 30 | 31 | recyclerViewVersion = '1.2.0-alpha01' 32 | retrofitVersion = '2.7.1' 33 | rxandroidVersion = '2.1.1' 34 | rxjava2Version = '2.2.13' 35 | rx2FastAndroidNetworking = '1.0.2' 36 | roomVersion = '2.2.5' 37 | 38 | supportLibraryVersion = '1.2.0-alpha02' 39 | 40 | timberVersion = '4.7.1' 41 | } 42 | 43 | dependencies { 44 | classpath "com.android.tools.build:gradle:$gradleVersion" 45 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" 46 | classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion" 47 | // NOTE: Do not place your application dependencies here; they belong 48 | // in the individual module build.gradle files 49 | }*/ 50 | } 51 | 52 | allprojects { 53 | addRepos(repositories) 54 | } 55 | 56 | task clean(type: Delete) { 57 | delete rootProject.buildDir 58 | } 59 | -------------------------------------------------------------------------------- /dependency.gradle: -------------------------------------------------------------------------------- 1 | /** 2 | * Shared file between builds so that they can all use the same dependencies and 3 | * maven repositories. 4 | **/ 5 | ext.deps = [:] 6 | 7 | // version 8 | def versions = [:] 9 | versions.kotlin = "1.3.72" 10 | versions.lifecycle = "2.2.0" 11 | versions.coroutine = "1.3.5" 12 | versions.navigation = "2.3.0-alpha01" 13 | versions.timber = "4.7.1" 14 | versions.retrofit = "2.7.1" 15 | versions.koin = "2.1.0-alpha-3" 16 | versions.okhttp = "4.4.0" 17 | deps.versions = versions 18 | 19 | // dependency 20 | def deps = [:] 21 | 22 | // androidx 23 | def androidx = [:] 24 | androidx.appcompat = "androidx.appcompat:appcompat:1.2.0-alpha02" 25 | androidx.core_ktx = "androidx.core:core-ktx:1.2.0" 26 | androidx.constraintlayout = "androidx.constraintlayout:constraintlayout:2.0.0-beta4" 27 | androidx.lifecycle = [ 28 | runtime_ktx : "androidx.lifecycle:lifecycle-runtime-ktx:$versions.lifecycle", 29 | extensions : "androidx.lifecycle:lifecycle-extensions:$versions.lifecycle", 30 | viewmodel_ktx: "androidx.lifecycle:lifecycle-viewmodel-ktx:$versions.lifecycle", 31 | livedata_ktx : "androidx.lifecycle:lifecycle-livedata-ktx:$versions.lifecycle" 32 | ] 33 | androidx.navigation = [ 34 | fragment_ktx: "androidx.navigation:navigation-fragment-ktx:$versions.navigation", 35 | ui_ktx : "androidx.navigation:navigation-ui-ktx:$versions.navigation" 36 | ] 37 | androidx.material = "com.google.android.material:material:1.1.0" 38 | androidx.swiperefresh = "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" 39 | deps.androidx = androidx 40 | 41 | // kotlin 42 | def kotlin = [:] 43 | kotlin.stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin" 44 | kotlin.coroutines = [ 45 | core : "org.jetbrains.kotlinx:kotlinx-coroutines-core:$versions.coroutine", 46 | android : "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.coroutine", 47 | play_services: "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$versions.coroutine", 48 | test : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$versions.coroutine" 49 | ] 50 | deps.kotlin = kotlin 51 | 52 | // koin 53 | deps.koin = [ 54 | core : "org.koin:koin-androidx-scope:$versions.koin", 55 | viewModel: "org.koin:koin-androidx-viewmodel:$versions.koin" 56 | ] 57 | 58 | // okhttp 59 | deps.okhttp = [ 60 | core : "com.squareup.okhttp3:okhttp:$versions.okhttp", 61 | logging_interceptor : "com.squareup.okhttp3:logging-interceptor:$versions.okhttp" 62 | ] 63 | 64 | // retrofit 65 | deps.retrofit = [ 66 | core : "com.squareup.retrofit2:retrofit:$versions.retrofit", 67 | converter_gson : "com.squareup.retrofit2:converter-gson:$versions.retrofit", 68 | adapter_rxjava2 : "com.squareup.retrofit2:adapter-rxjava2:$versions.retrofit" 69 | ] 70 | 71 | deps.google = [ 72 | gson: 'com.google.code.gson:gson:2.8.6' 73 | ] 74 | 75 | // debugging 76 | deps.debugging = [ 77 | timber : "com.jakewharton.timber:timber:$versions.timber" 78 | ] 79 | 80 | // test 81 | deps.atsl = [ 82 | junit : "junit:junit:4.12", 83 | ext_junit : "androidx.test.ext:junit:1.1.1", 84 | espresso_core: "androidx.test.espresso:espresso-core:3.2.0" 85 | ] 86 | 87 | ext.deps = deps 88 | 89 | // build gradle plugin 90 | def gradlePlugin = [ 91 | android : "com.android.tools.build:gradle:4.0.1", 92 | kotlin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin", 93 | play_services: "com.google.gms:google-services:4.3.3", 94 | navigation_safe_args: "androidx.navigation:navigation-safe-args-gradle-plugin:$versions.navigation" 95 | ] 96 | ext.gradlePlugin = gradlePlugin 97 | 98 | // build_versions 99 | ext.build_versions = [ 100 | compile_sdk: 29, 101 | build_tools: "29.0.2", 102 | min_sdk : 15, 103 | target_sdk : 29 104 | ] 105 | 106 | // repository 107 | def static addRepos(RepositoryHandler handler) { 108 | handler.google() 109 | handler.jcenter() 110 | } 111 | 112 | ext.addRepos = this.&addRepos -------------------------------------------------------------------------------- /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 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chosw1029/Kotlin_MVVM/c54db6b4e877b8f71fcc1eedd850b2050a53e4b0/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jun 24 15:30:07 KST 2020 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-6.1.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------