├── lib ├── consumer-rules.pro ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── ohyooo │ │ └── lib │ │ ├── mvvm │ │ ├── MVVMBaseFragment.kt │ │ ├── MVVMLifecycle.kt │ │ ├── MVVMBaseActivity.kt │ │ ├── MVVMBaseViewModel.kt │ │ └── MVVMViewModelFactory.kt │ │ ├── extension │ │ ├── ContextExtensions.kt │ │ ├── UnitExtensions.kt │ │ ├── FragmentExtensions.kt │ │ └── ActivityExtensions.kt │ │ ├── adapter │ │ └── ImageViewAdapter.kt │ │ └── livedata │ │ └── SingleLiveEvent.kt ├── proguard-rules.pro └── build.gradle.kts ├── app ├── .gitignore ├── signkey.jks ├── src │ └── main │ │ ├── kotlin │ │ └── com │ │ │ └── ohyooo │ │ │ └── demo │ │ │ ├── model │ │ │ └── MainUIItem.kt │ │ │ ├── viewmodel │ │ │ └── MainViewModel.kt │ │ │ ├── app │ │ │ └── App.kt │ │ │ └── ui │ │ │ ├── splash │ │ │ └── SplashActivity.kt │ │ │ ├── main │ │ │ └── MainActivity.kt │ │ │ └── list │ │ │ └── ListActivity.kt │ │ ├── res │ │ ├── values │ │ │ ├── strings.xml │ │ │ ├── colors.xml │ │ │ └── styles.xml │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ └── layout │ │ │ ├── activity_main.xml │ │ │ └── activity_list.xml │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle.kts ├── network ├── .gitignore ├── consumer-rules.pro ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── ohyooo │ │ └── network │ │ ├── model │ │ ├── BaseResponse.kt │ │ └── RateLimitResponse.kt │ │ ├── api │ │ └── GitHubAPIInterface.kt │ │ ├── repository │ │ ├── GithubAPIRepository.kt │ │ └── BaseRepository.kt │ │ └── factory │ │ └── ErrorConverterFactory.kt ├── proguard-rules.pro └── build.gradle.kts ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── gradle.properties ├── settings.gradle.kts ├── LICENSE ├── .github ├── workflows │ ├── update-gradle-wrapper.yml │ ├── auto-merge.yml │ └── android.yml └── dependabot.yml ├── README.md ├── .gitignore ├── gradlew.bat └── gradlew /lib/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /network/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /network/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class com.ohyooo.network.model.** { *; } -------------------------------------------------------------------------------- /lib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /network/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/signkey.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohyooo/MVVMBaseProject/HEAD/app/signkey.jks -------------------------------------------------------------------------------- /app/src/main/kotlin/com/ohyooo/demo/model/MainUIItem.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.demo.model 2 | 3 | 4 | class MainUIItem -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Demo 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohyooo/MVVMBaseProject/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohyooo/MVVMBaseProject/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohyooo/MVVMBaseProject/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /network/src/main/kotlin/com/ohyooo/network/model/BaseResponse.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.network.model 2 | 3 | 4 | open class BaseResponse(var errorCode: Int = 0, var errorMsg: String? = null) -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/ohyooo/lib/mvvm/MVVMBaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.lib.mvvm 2 | 3 | import androidx.annotation.LayoutRes 4 | import androidx.fragment.app.Fragment 5 | 6 | abstract class MVVMBaseFragment(@LayoutRes layoutId: Int) : Fragment(layoutId) -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/ohyooo/demo/viewmodel/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.demo.viewmodel 2 | 3 | import com.ohyooo.demo.model.MainUIItem 4 | import com.ohyooo.lib.mvvm.MVVMBaseViewModel 5 | 6 | class MainViewModel : MVVMBaseViewModel() { 7 | private val ui = MainUIItem() 8 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/ohyooo/lib/extension/ContextExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.lib.extension 2 | 3 | import android.content.Context 4 | import android.widget.Toast 5 | 6 | fun Context.showToast(text: String?) { 7 | text ?: return 8 | Toast.makeText(this, text, Toast.LENGTH_SHORT).show() 9 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /network/src/main/kotlin/com/ohyooo/network/api/GitHubAPIInterface.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.network.api 2 | 3 | import com.ohyooo.network.model.RateLimitResponse 4 | import retrofit2.http.GET 5 | 6 | interface GitHubAPIInterface { 7 | 8 | @GET("rate_limit") 9 | suspend fun getRateLimit(): RateLimitResponse 10 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableR8.fullMode=true 2 | android.useAndroidX=true 3 | # 4 | kapt.include.compile.classpath=false 5 | kapt.incremental.apt=true 6 | # 7 | org.gradle.caching=true 8 | org.gradle.configureondemand=true 9 | org.gradle.daemon=true 10 | org.gradle.jvmargs=-Xmx2048m 11 | org.gradle.parallel.threads=12 12 | org.gradle.parallel=true 13 | org.gradle.vfs.watch=true 14 | org.gradle.workers.max=12 -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/ohyooo/lib/adapter/ImageViewAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.lib.adapter 2 | 3 | import android.graphics.Bitmap 4 | import android.widget.ImageView 5 | import androidx.databinding.BindingAdapter 6 | 7 | object ImageViewAdapter { 8 | 9 | @JvmStatic 10 | @BindingAdapter("bitmap") 11 | fun setBitmap(iv: ImageView, bitmap: Bitmap?) { 12 | iv.setImageBitmap(bitmap) 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/ohyooo/demo/app/App.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.demo.app 2 | 3 | import android.app.Application 4 | import timber.log.Timber 5 | 6 | class App : Application() { 7 | init { 8 | instance = this 9 | } 10 | 11 | override fun onCreate() { 12 | super.onCreate() 13 | Timber.plant(Timber.DebugTree()) 14 | } 15 | 16 | companion object { 17 | lateinit var instance: App 18 | private set 19 | } 20 | } -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | pluginManagement { 4 | repositories { 5 | google() 6 | mavenCentral() 7 | gradlePluginPortal() 8 | } 9 | } 10 | 11 | dependencyResolutionManagement { 12 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | } 18 | 19 | rootProject.name = "Demo" 20 | include(":app", ":lib", ":network") -------------------------------------------------------------------------------- /app/src/main/kotlin/com/ohyooo/demo/ui/splash/SplashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.demo.ui.splash 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import com.ohyooo.demo.ui.main.MainActivity 7 | 8 | class SplashActivity : Activity() { 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | startActivity(Intent(this, MainActivity::class.java)) 12 | finish() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/ohyooo/lib/mvvm/MVVMLifecycle.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.lib.mvvm 2 | 3 | import androidx.lifecycle.Lifecycle 4 | import androidx.lifecycle.LifecycleObserver 5 | import androidx.lifecycle.OnLifecycleEvent 6 | 7 | interface MVVMLifecycle : LifecycleObserver { 8 | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) 9 | fun onCreate() 10 | 11 | @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) 12 | fun onPause() 13 | 14 | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) 15 | fun onResume() 16 | 17 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 18 | fun onDestroy() 19 | } -------------------------------------------------------------------------------- /.github/workflows/update-gradle-wrapper.yml: -------------------------------------------------------------------------------- 1 | name: Update Gradle Wrapper 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: "0 0 * * *" 7 | 8 | jobs: 9 | update-gradle-wrapper: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@main 14 | 15 | - name: Setup JDK 16 | uses: actions/setup-java@main 17 | with: 18 | distribution: 'zulu' 19 | java-version: '21' 20 | java-package: jdk 21 | cache: 'gradle' 22 | 23 | - name: Update Gradle Wrapper 24 | uses: gradle-update/update-gradle-wrapper-action@main 25 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/ohyooo/lib/mvvm/MVVMBaseActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.lib.mvvm 2 | 3 | import android.os.Bundle 4 | import androidx.annotation.LayoutRes 5 | import androidx.databinding.DataBindingUtil 6 | import androidx.databinding.ViewDataBinding 7 | import androidx.fragment.app.FragmentActivity 8 | 9 | abstract class MVVMBaseActivity(@LayoutRes val layoutId: Int = 0) : FragmentActivity() { 10 | 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | if (layoutId != 0) { 14 | DataBindingUtil.setContentView(this, layoutId) 15 | } 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directory: / 5 | schedule: 6 | interval: daily 7 | registries: 8 | - maven-google 9 | - gradle-plugin 10 | groups: 11 | maven-dependencies: 12 | patterns: 13 | - "*" 14 | 15 | - package-ecosystem: github-actions 16 | directory: / 17 | schedule: 18 | interval: daily 19 | groups: 20 | github-actions: 21 | patterns: 22 | - "*" 23 | 24 | registries: 25 | maven-google: 26 | type: maven-repository 27 | url: https://dl.google.com/dl/android/maven2/ 28 | gradle-plugin: 29 | type: maven-repository 30 | url: https://plugins.gradle.org/m2/ 31 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/ohyooo/lib/mvvm/MVVMBaseViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.lib.mvvm 2 | 3 | import android.os.Bundle 4 | import androidx.lifecycle.ViewModel 5 | import com.ohyooo.lib.livedata.SingleLiveEvent 6 | 7 | abstract class MVVMBaseViewModel : ViewModel(), MVVMLifecycle { 8 | 9 | var bundle: Bundle = Bundle() 10 | 11 | val toastLiveData = SingleLiveEvent() 12 | 13 | fun showToast(msg: String?) { 14 | toastLiveData.postValue(msg) 15 | } 16 | 17 | /** 18 | * Lifecycle Start 19 | */ 20 | override fun onCreate() {} 21 | 22 | override fun onPause() {} 23 | 24 | override fun onResume() {} 25 | 26 | override fun onDestroy() {} 27 | /** 28 | * Lifecycle End 29 | */ 30 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/ohyooo/lib/extension/UnitExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.ohyooo.lib.extension 2 | 3 | import android.content.Context 4 | import android.util.TypedValue 5 | 6 | fun Context.dp2px(dp: Float) = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics) 7 | 8 | fun Context.sp2px(sp: Float) = (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, resources.displayMetrics)) 9 | 10 | fun Context.pt2px(pt: Float) = (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, pt, resources.displayMetrics)) 11 | 12 | fun Context.in2px(inch: Float) = (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_IN, inch, resources.displayMetrics)) 13 | 14 | fun Context.mm2px(mm: Float) = (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, mm, resources.displayMetrics)) 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /lib/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.kts. 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 | -------------------------------------------------------------------------------- /network/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.kts. 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/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.kts.kts.kts. 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/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 18 | 19 |