├── sample
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values-land
│ │ │ │ └── dimens.xml
│ │ │ ├── values-w1240dp
│ │ │ │ └── dimens.xml
│ │ │ ├── values-w600dp
│ │ │ │ └── dimens.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── xml
│ │ │ │ └── network_security_config.xml
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── themes.xml
│ │ │ │ └── strings.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── drawable
│ │ │ │ ├── ic_home_black_24dp.xml
│ │ │ │ ├── ic_dashboard_black_24dp.xml
│ │ │ │ ├── ic_notifications_black_24dp.xml
│ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── mipmap-anydpi-v33
│ │ │ │ └── ic_launcher.xml
│ │ │ ├── menu
│ │ │ │ └── bottom_nav_menu.xml
│ │ │ ├── values-night
│ │ │ │ └── themes.xml
│ │ │ ├── layout
│ │ │ │ ├── fragment_home.xml
│ │ │ │ ├── fragment_dashboard.xml
│ │ │ │ ├── fragment_notifications.xml
│ │ │ │ ├── dialog_loading.xml
│ │ │ │ ├── activity_bottom_navigation_acitvity.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── activity_net_work.xml
│ │ │ │ ├── activity_login.xml
│ │ │ │ └── activity_detail.xml
│ │ │ ├── navigation
│ │ │ │ └── mobile_navigation.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── layout-w1240dp
│ │ │ │ └── activity_login.xml
│ │ │ └── layout-w936dp
│ │ │ │ └── activity_login.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── fastmvvm
│ │ │ │ └── sample
│ │ │ │ ├── repository
│ │ │ │ └── MainRepository.kt
│ │ │ │ ├── view
│ │ │ │ └── activity
│ │ │ │ │ ├── ui
│ │ │ │ │ ├── login
│ │ │ │ │ │ ├── LoginResult.kt
│ │ │ │ │ │ ├── LoggedInUserView.kt
│ │ │ │ │ │ ├── LoginFormState.kt
│ │ │ │ │ │ ├── LoginViewModelFactory.kt
│ │ │ │ │ │ └── LoginViewModel.kt
│ │ │ │ │ ├── home
│ │ │ │ │ │ ├── HomeViewModel.kt
│ │ │ │ │ │ └── HomeFragment.kt
│ │ │ │ │ ├── dashboard
│ │ │ │ │ │ ├── DashboardViewModel.kt
│ │ │ │ │ │ └── DashboardFragment.kt
│ │ │ │ │ └── notifications
│ │ │ │ │ │ ├── NotificationsViewModel.kt
│ │ │ │ │ │ └── NotificationsFragment.kt
│ │ │ │ │ ├── data
│ │ │ │ │ ├── model
│ │ │ │ │ │ └── LoggedInUser.kt
│ │ │ │ │ ├── Result.kt
│ │ │ │ │ ├── LoginDataSource.kt
│ │ │ │ │ └── LoginRepository.kt
│ │ │ │ │ ├── BaseActivity.kt
│ │ │ │ │ ├── BottomNavigationAcitvity.kt
│ │ │ │ │ ├── DetailActivity.kt
│ │ │ │ │ ├── MainActivity.kt
│ │ │ │ │ ├── NetworkActivity.kt
│ │ │ │ │ └── LoginActivity.kt
│ │ │ │ ├── network
│ │ │ │ ├── ApiResponse.kt
│ │ │ │ ├── Api.kt
│ │ │ │ ├── Banner.kt
│ │ │ │ ├── NetworkClient.kt
│ │ │ │ ├── LoginInfo.kt
│ │ │ │ └── User.kt
│ │ │ │ └── App.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── fastmvvm
│ │ │ └── sample
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── fastmvvm
│ │ └── sample
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── easyAndroid
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── yeqiu
│ │ │ └── easyandroid
│ │ │ ├── Common.kt
│ │ │ ├── ActivityStarter.kt
│ │ │ ├── AppInfo.kt
│ │ │ └── Logger.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── yeqiu
│ │ │ └── easyandroid
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── yeqiu
│ │ └── easyandroid
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── fastMvvm
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── yeqiu
│ │ │ └── fastmvvm
│ │ │ ├── view
│ │ │ ├── BaseFragment.kt
│ │ │ ├── ViewModelUtil.kt
│ │ │ ├── ViewModelDataBindingActivity.kt
│ │ │ └── ViewModelDataBindingFragment.kt
│ │ │ ├── network
│ │ │ ├── NetworkResponse.kt
│ │ │ ├── HeadInterceptor.kt
│ │ │ ├── NetworkConfig.kt
│ │ │ └── BaseNetworkClient.kt
│ │ │ ├── exception
│ │ │ ├── GenerateViewDataBindingException.kt
│ │ │ └── NetWorkException.kt
│ │ │ ├── viewmodel
│ │ │ └── BaseViewModel.kt
│ │ │ └── ext
│ │ │ └── BaseViewModelExt.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── yeqiu
│ │ │ └── fastmvvm
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── yeqiu
│ │ └── fastmvvm
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── todo.txt
├── README.md
├── settings.gradle
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── config.gradle
└── gradlew
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/easyAndroid/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/fastMvvm/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/fastMvvm/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/easyAndroid/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/sample/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 48dp
3 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-w1240dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 200dp
3 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-w600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 48dp
3 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeqiu/HailHydra/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/easyAndroid/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/fastMvvm/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/todo.txt:
--------------------------------------------------------------------------------
1 |
2 | 1.封装网络请求,自动联动到 activity 的loading
3 | 2.处理多个请求loading可能失效的问题
4 | 详情页面
5 | 登录页面
6 | 列表页面
7 | 单activity
8 |
9 |
10 | 主页面
11 |
12 | api基本使用
13 |
14 |
15 | 测试同步
--------------------------------------------------------------------------------
/sample/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/view/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.view
2 |
3 | /**
4 | * @project:FastMvvm
5 | * @author:小卷子
6 | * @date 2023/7/8
7 | * @describe:
8 | * @fix:
9 | */
10 | open class BaseFragment {
11 | }
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/repository/MainRepository.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.repository
2 |
3 | /**
4 | * @project:FastMvvm
5 | * @author:小卷子
6 | * @date 2023/7/8
7 | * @describe:
8 | * @fix:
9 | */
10 | class MainRepository {
11 |
12 |
13 |
14 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jul 05 21:41:36 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/login/LoginResult.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.login
2 |
3 | /**
4 | * Authentication result : success (user details) or error message.
5 | */
6 | data class LoginResult(
7 | val success: LoggedInUserView? = null,
8 | val error: Int? = null
9 | )
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/data/model/LoggedInUser.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.data.model
2 |
3 | /**
4 | * Data class that captures user information for logged in users retrieved from LoginRepository
5 | */
6 | data class LoggedInUser(
7 | val userId: String,
8 | val displayName: String
9 | )
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/login/LoggedInUserView.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.login
2 |
3 | /**
4 | * User details post authentication that is exposed to the UI
5 | */
6 | data class LoggedInUserView(
7 | val displayName: String
8 | //... other data fields that may be accessible to the UI
9 | )
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/login/LoginFormState.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.login
2 |
3 | /**
4 | * Data validation state of the login form.
5 | */
6 | data class LoginFormState(
7 | val usernameError: Int? = null,
8 | val passwordError: Int? = null,
9 | val isDataValid: Boolean = false
10 | )
--------------------------------------------------------------------------------
/easyAndroid/src/main/java/com/yeqiu/easyandroid/Common.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.easyandroid
2 |
3 | import android.content.Context
4 | import android.widget.Toast
5 |
6 | /**
7 | * @project:FastMvvm
8 | * @author:小卷子
9 | * @date 2023/7/9
10 | * @describe:
11 | * @fix:
12 | */
13 |
14 | fun Context.showToast(msg:String){
15 | Toast.makeText(this,msg,Toast.LENGTH_SHORT).show()
16 | }
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/ic_home_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-anydpi-v33/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## FastMvvm
2 |
3 | > master分支已修改为FastMvvm,原来HailHydra见分支[HailHydra](https://github.com/yeqiu/HailHydra/tree/HailHydra)
4 |
5 |
6 |
7 |
8 |
9 | **使用lifecycle+ViewModel+LiveData+DataBinding,快速实现MVVM架构**
10 |
11 | **使用kotlin扩展函数制作大量工具类,简化代码**
12 |
13 | **使用Retrofit+Moshi+协程,实现快速网络请求**
14 |
15 | **网络请求自动触发页面的loading,可配置统一错误处理**
16 |
17 | **可配置网络请求的脱壳数据**
18 |
19 | **详细使用见sample**
20 |
21 |
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/network/NetworkResponse.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.network
2 |
3 | /**
4 | * @project:FastMvvm
5 | * @author:小卷子
6 | * @date 2023/7/11
7 | * @describe:
8 | * @fix:
9 | */
10 | abstract class NetworkResponse {
11 |
12 | abstract fun isSuccess():Boolean
13 | abstract fun getCode():Int
14 | abstract fun getResponse():T?
15 | abstract fun getErrorMessage():String
16 |
17 | }
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/ic_dashboard_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/fastMvvm/src/test/java/com/yeqiu/fastmvvm/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm
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 | }
--------------------------------------------------------------------------------
/sample/src/test/java/com/fastmvvm/sample/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample
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 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/home/HomeViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.home
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 |
7 | class HomeViewModel : ViewModel() {
8 |
9 | private val _text = MutableLiveData().apply {
10 | value = "This is home Fragment"
11 | }
12 | val text: LiveData = _text
13 | }
--------------------------------------------------------------------------------
/easyAndroid/src/test/java/com/yeqiu/easyandroid/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.easyandroid
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 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/dashboard/DashboardViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.dashboard
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 |
7 | class DashboardViewModel : ViewModel() {
8 |
9 | private val _text = MutableLiveData().apply {
10 | value = "This is dashboard Fragment"
11 | }
12 | val text: LiveData = _text
13 | }
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/exception/GenerateViewDataBindingException.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.exception
2 |
3 |
4 | /**
5 | * @project:FastMvvm
6 | * @author:小卷子
7 | * @date 2023/7/8
8 | * @describe:
9 | * @fix:
10 | */
11 | class GenerateViewDataBindingException : RuntimeException {
12 | constructor(message: String?) : super(message)
13 | constructor(message: String?, cause: Throwable?) : super(message, cause)
14 | constructor(cause: Throwable?) : super(cause)
15 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/notifications/NotificationsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.notifications
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 |
7 | class NotificationsViewModel : ViewModel() {
8 |
9 | private val _text = MutableLiveData().apply {
10 | value = "This is notifications Fragment"
11 | }
12 | val text: LiveData = _text
13 | }
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/ic_notifications_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | maven { url 'https://jitpack.io' }
7 | jcenter()
8 | }
9 | }
10 | dependencyResolutionManagement {
11 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
12 | repositories {
13 | google()
14 | mavenCentral()
15 | maven { url 'https://jitpack.io' }
16 | jcenter()
17 | }
18 | }
19 | rootProject.name = "FastMvvm"
20 | include ':fastMvvm'
21 | include ':sample'
22 | include ':easyAndroid'
23 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/data/Result.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.data
2 |
3 | /**
4 | * A generic class that holds a value with its loading status.
5 | * @param
6 | */
7 | sealed class Result {
8 |
9 | data class Success(val data: T) : Result()
10 | data class Error(val exception: Exception) : Result()
11 |
12 | override fun toString(): String {
13 | return when (this) {
14 | is Success<*> -> "Success[data=$data]"
15 | is Error -> "Error[exception=$exception]"
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/network/HeadInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.network
2 |
3 | import okhttp3.Interceptor
4 | import okhttp3.Response
5 |
6 | /**
7 | * @project:FastMvvm
8 | * @author:小卷子
9 | * @date 2023/7/10
10 | * @describe:
11 | * @fix:
12 | */
13 | class HeadInterceptor: Interceptor {
14 | override fun intercept(chain: Interceptor.Chain): Response {
15 | val builder = chain.request().newBuilder()
16 |
17 | NetworkConfig.commonHead.forEach{
18 | builder.addHeader(it.key,it.value)
19 | }
20 | return chain.proceed(builder.build())
21 | }
22 | }
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/viewmodel/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.viewmodel
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import androidx.lifecycle.ViewModel
5 |
6 | /**
7 | * @project:FastMvvm
8 | * @author:小卷子
9 | * @date 2023/7/9
10 | * @describe:
11 | * @fix:
12 | */
13 | open class BaseViewModel : ViewModel() {
14 |
15 | val loadingStatus: OnLoadingEvent by lazy { OnLoadingEvent() }
16 |
17 |
18 | inner class OnLoadingEvent {
19 | //显示加载框
20 | val show by lazy { MutableLiveData() }
21 |
22 | //隐藏
23 | val dismiss by lazy { MutableLiveData() }
24 | }
25 | }
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/network/NetworkConfig.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.network
2 |
3 | import com.yeqiu.fastmvvm.BuildConfig
4 | import com.yeqiu.fastmvvm.exception.NetworkException
5 |
6 |
7 | /**
8 | * @project:FastMvvm
9 | * @author:小卷子
10 | * @date 2023/7/8
11 | * @describe:
12 | * @fix:
13 | */
14 | object NetworkConfig {
15 |
16 | var enableLog = BuildConfig.DEBUG
17 | val commonHead = HashMap()
18 | var onNetworkError: (NetworkException) -> Unit = {}
19 |
20 | fun addCommonHead(vararg head: Pair) {
21 | head.forEach {
22 | commonHead[it.first] = it.second
23 | }
24 |
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/sample/src/main/res/menu/bottom_nav_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/network/ApiResponse.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.network
2 |
3 | import com.yeqiu.fastmvvm.network.NetworkResponse
4 |
5 | /**
6 | * @project:FastMvvm
7 | * @author:小卷子
8 | * @date 2023/7/11
9 | * @describe:
10 | * @fix:
11 | */
12 | data class ApiResponse(val errorCode:Int, val errorMsg:String, val data:T?):NetworkResponse(){
13 |
14 | override fun isSuccess(): Boolean {
15 | return errorCode == 0
16 | }
17 |
18 | override fun getCode(): Int {
19 | return errorCode
20 | }
21 |
22 | override fun getResponse(): T? {
23 | return data
24 | }
25 |
26 | override fun getErrorMessage(): String {
27 | return errorMsg
28 | }
29 |
30 |
31 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 | .idea/
38 |
39 | # Keystore files
40 | *.jks
41 |
42 | # External native build folder generated in Android Studio 2.2 and later
43 | .externalNativeBuild
44 | //build.gradle
--------------------------------------------------------------------------------
/sample/src/androidTest/java/com/fastmvvm/sample/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.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.getInstrumentation().targetContext
22 | assertEquals("com.fastmvvm.sample", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/fastMvvm/src/androidTest/java/com/yeqiu/fastmvvm/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.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.getInstrumentation().targetContext
22 | assertEquals("com.yeqiu.fasemvvm.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/easyAndroid/src/androidTest/java/com/yeqiu/easyandroid/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.easyandroid
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.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.getInstrumentation().targetContext
22 | assertEquals("com.yeqiu.easyandroid.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/fastMvvm/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
--------------------------------------------------------------------------------
/sample/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
--------------------------------------------------------------------------------
/easyAndroid/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
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/exception/NetWorkException.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.exception
2 |
3 |
4 | /**
5 | * @project:FastMvvm
6 | * @author:小卷子
7 | * @date 2023/7/8
8 | * @describe:
9 | * @fix:
10 | */
11 |
12 | const val jsonParseErrorCode = -1000
13 | const val checkResponseErrorCode = -1001
14 | const val NetworkErrorCode = -1002
15 | const val unknownErrorCode = -2000
16 |
17 |
18 | class NetworkException : RuntimeException {
19 |
20 | var errorMessage: String = ""
21 | var errorCode: Int = 0
22 | var throwable: Throwable? = null
23 |
24 |
25 | @JvmOverloads
26 | constructor(errorCode: Int = 0, errorMessage: String = "", throwable: Throwable? = null) {
27 | this.errorCode = errorCode
28 | this.errorMessage = errorMessage
29 | this.throwable = throwable
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/data/LoginDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.data
2 |
3 | import com.fastmvvm.sample.view.activity.data.model.LoggedInUser
4 | import java.io.IOException
5 |
6 | /**
7 | * Class that handles authentication w/ login credentials and retrieves user information.
8 | */
9 | class LoginDataSource {
10 |
11 | fun login(username: String, password: String): Result {
12 | try {
13 | // TODO: handle loggedInUser authentication
14 | val fakeUser = LoggedInUser(java.util.UUID.randomUUID().toString(), "Jane Doe")
15 | return Result.Success(fakeUser)
16 | } catch (e: Throwable) {
17 | return Result.Error(IOException("Error logging in", e))
18 | }
19 | }
20 |
21 | fun logout() {
22 | // TODO: revoke authentication
23 | }
24 | }
--------------------------------------------------------------------------------
/sample/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/network/Api.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.network
2 |
3 | import retrofit2.http.Field
4 | import retrofit2.http.FormUrlEncoded
5 | import retrofit2.http.GET
6 | import retrofit2.http.POST
7 | import retrofit2.http.Url
8 |
9 | /**
10 | * @project:FastMvvm
11 | * @author:小卷子
12 | * @date 2023/7/8
13 | * @describe:
14 | * @fix:
15 | */
16 | interface Api {
17 |
18 |
19 | @GET
20 | suspend fun getUser(
21 | @Url url: String
22 | ): User
23 |
24 |
25 | @GET("/banner/json")
26 | suspend fun banner(): Banner
27 |
28 | @GET("/banner/json")
29 | suspend fun banner2(): ApiResponse>
30 |
31 | @FormUrlEncoded
32 | @POST("/user/login")
33 | suspend fun login(
34 | @Field("username") username: String,
35 | @Field("password") pwd: String
36 | ): ApiResponse
37 |
38 | }
--------------------------------------------------------------------------------
/sample/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/network/Banner.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.network
2 |
3 |
4 | import com.squareup.moshi.Json
5 |
6 | data class Banner(
7 | @Json(name = "data")
8 | val `data`: List?,
9 | @Json(name = "errorCode")
10 | val errorCode: Int?,
11 | @Json(name = "errorMsg")
12 | val errorMsg: String?
13 | ) {
14 | data class Data(
15 | @Json(name = "desc")
16 | val desc: String?,
17 | @Json(name = "id")
18 | val id: Int?,
19 | @Json(name = "imagePath")
20 | val imagePath: String?,
21 | @Json(name = "isVisible")
22 | val isVisible: Int?,
23 | @Json(name = "order")
24 | val order: Int?,
25 | @Json(name = "title")
26 | val title: String?,
27 | @Json(name = "type")
28 | val type: Int?,
29 | @Json(name = "url")
30 | val url: String?
31 | )
32 | }
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | fastMvvm
3 | BottomNavigationAcitvity
4 | Home
5 | Dashboard
6 | Notifications
7 | LoginActivity
8 | Email
9 | Password
10 | Sign in or register
11 | Sign in
12 | "Welcome !"
13 | Not a valid username
14 | Password must be >5 characters
15 | "Login failed"
16 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/network/NetworkClient.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.network
2 |
3 | import com.yeqiu.easyandroid.log
4 | import com.yeqiu.fastmvvm.network.BaseNetworkClient
5 | import okhttp3.OkHttpClient
6 | import retrofit2.Retrofit
7 |
8 | /**
9 | * @project:FastMvvm
10 | * @author:小卷子
11 | * @date 2023/7/10
12 | * @describe:
13 | * @fix:
14 | */
15 | object NetworkClient : BaseNetworkClient() {
16 |
17 | override fun getBaseUrl(): String {
18 | // return "https://api.github.com"
19 | return "https://www.wanandroid.com"
20 | }
21 |
22 | override fun setOkHttpClient(builder: OkHttpClient.Builder) {
23 | }
24 |
25 | override fun setRetrofit(build: Retrofit.Builder) {
26 | }
27 |
28 | //双重校验锁式-单例
29 | val api: Api by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
30 | "api by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED)".log()
31 | getService(Api::class.java)
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/view/ViewModelUtil.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.view
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import androidx.fragment.app.Fragment
5 | import com.yeqiu.fastmvvm.viewmodel.BaseViewModel
6 | import java.lang.reflect.ParameterizedType
7 |
8 |
9 | /**
10 | * 获取当前类绑定的泛型ViewModel-clazz
11 | */
12 | @Suppress("UNCHECKED_CAST")
13 | fun getViewModelClazz(obj: Any): VM {
14 | return (obj.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as VM
15 | }
16 |
17 |
18 |
19 | /**
20 | * 在Activity中得到Application上下文的ViewModel
21 | */
22 | inline fun AppCompatActivity.getAppViewModel(): VM {
23 | TODO()
24 | }
25 |
26 | /**
27 | * 在Fragment中得到Application上下文的ViewModel
28 | * 提示,在fragment中调用该方法时,请在该Fragment onCreate以后调用或者请用by lazy方式懒加载初始化调用,不然会提示requireActivity没有导致错误
29 | */
30 | inline fun Fragment.getAppViewModel(): VM {
31 | TODO()
32 | }
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/login/LoginViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.login
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 | import com.fastmvvm.sample.view.activity.data.LoginDataSource
6 | import com.fastmvvm.sample.view.activity.data.LoginRepository
7 |
8 | /**
9 | * ViewModel provider factory to instantiate LoginViewModel.
10 | * Required given LoginViewModel has a non-empty constructor
11 | */
12 | class LoginViewModelFactory : ViewModelProvider.Factory {
13 |
14 | @Suppress("UNCHECKED_CAST")
15 | override fun create(modelClass: Class): T {
16 | if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
17 | return LoginViewModel(
18 | loginRepository = LoginRepository(
19 | dataSource = LoginDataSource()
20 | )
21 | ) as T
22 | }
23 | throw IllegalArgumentException("Unknown ViewModel class")
24 | }
25 | }
--------------------------------------------------------------------------------
/sample/src/main/res/layout/fragment_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/fragment_dashboard.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/fragment_notifications.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
--------------------------------------------------------------------------------
/sample/src/main/res/navigation/mobile_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/App.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModelProvider
6 | import androidx.lifecycle.ViewModelStore
7 | import androidx.lifecycle.ViewModelStoreOwner
8 | import com.yeqiu.easyandroid.log
9 | import com.yeqiu.fastmvvm.viewmodel.BaseViewModel
10 |
11 |
12 | /**
13 | * @project:FastMvvm
14 | * @author:小卷子
15 | * @date 2023/7/10
16 | * @describe:
17 | * @fix:
18 | */
19 | class App : Application(), ViewModelStoreOwner {
20 |
21 | companion object {
22 | lateinit var instance: App
23 | lateinit var appViewModel: AppViewModel
24 | }
25 |
26 | override val viewModelStore: ViewModelStore
27 | get() = ViewModelStore()
28 |
29 |
30 |
31 | override fun onCreate() {
32 | super.onCreate()
33 | instance = this
34 | createAppViewModel()
35 | }
36 |
37 | private fun createAppViewModel() {
38 | "createAppViewModel" .log()
39 | appViewModel = ViewModelProvider(this).get(AppViewModel::class.java)
40 | }
41 |
42 |
43 |
44 | }
45 |
46 | class AppViewModel : BaseViewModel() {
47 |
48 | val data =MutableLiveData("data")
49 |
50 | }
--------------------------------------------------------------------------------
/easyAndroid/src/main/java/com/yeqiu/easyandroid/ActivityStarter.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.easyandroid
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.os.Parcelable
7 | import java.io.Serializable
8 |
9 | /**
10 | * @project:FastMvvm
11 | * @author:小卷子
12 | * @date 2023/7/12
13 | * @describe:
14 | * @fix:
15 | */
16 | inline fun Context.toActivity(vararg params: Pair) {
17 |
18 | val intent = Intent(this, T::class.java)
19 | putParams(intent, *params)
20 | if (this !is Activity){
21 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
22 | }
23 | startActivity(intent)
24 | }
25 |
26 | fun putParams(intent: Intent, vararg params: Pair) {
27 |
28 |
29 | params.forEach {
30 | when (val value = it.second) {
31 | is Int -> {intent.putExtra(it.first,value)}
32 | is Long -> {intent.putExtra(it.first,value)}
33 | is Double ->{intent.putExtra(it.first,value)}
34 | is Boolean ->{intent.putExtra(it.first,value)}
35 | is String -> {intent.putExtra(it.first,value)}
36 | is Serializable -> {intent.putExtra(it.first,value)}
37 | is Parcelable -> {intent.putExtra(it.first,value)}
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/home/HomeFragment.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.home
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.ViewModelProvider
10 | import com.fastmvvm.sample.databinding.FragmentHomeBinding
11 |
12 | class HomeFragment : Fragment() {
13 |
14 | private var _binding: FragmentHomeBinding? = null
15 |
16 | // This property is only valid between onCreateView and
17 | // onDestroyView.
18 | private val binding get() = _binding!!
19 |
20 | override fun onCreateView(
21 | inflater: LayoutInflater,
22 | container: ViewGroup?,
23 | savedInstanceState: Bundle?
24 | ): View {
25 | val homeViewModel =
26 | ViewModelProvider(this).get(HomeViewModel::class.java)
27 |
28 | _binding = FragmentHomeBinding.inflate(inflater, container, false)
29 | val root: View = binding.root
30 |
31 | val textView: TextView = binding.textHome
32 | homeViewModel.text.observe(viewLifecycleOwner) {
33 | textView.text = it
34 | }
35 | return root
36 | }
37 |
38 | override fun onDestroyView() {
39 | super.onDestroyView()
40 | _binding = null
41 | }
42 | }
--------------------------------------------------------------------------------
/sample/src/main/res/layout/dialog_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
24 |
25 |
33 |
34 |
--------------------------------------------------------------------------------
/easyAndroid/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-kapt'
5 | }
6 |
7 | def config = rootProject.ext
8 |
9 | android {
10 | namespace config.namespace.easyAndroid
11 | compileSdk config.android.compileSdk
12 |
13 | defaultConfig {
14 | minSdk config.android.minSdk
15 | targetSdk config.android.targetSdk
16 | versionCode config.android.versionCode
17 | versionName config.android.versionName
18 |
19 | testInstrumentationRunner config.android.testInstrumentationRunner
20 | }
21 |
22 | buildTypes {
23 |
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 |
30 | compileOptions {
31 | sourceCompatibility config.javaOptions.sourceCompatibility
32 | targetCompatibility config.javaOptions.targetCompatibility
33 | }
34 |
35 | kotlinOptions {
36 | jvmTarget = config.javaOptions.kotlinOptions
37 | }
38 |
39 | buildFeatures {
40 | dataBinding = true
41 | }
42 |
43 | }
44 |
45 | dependencies {
46 |
47 | implementation config.androidLibrary.androidxAppcompat
48 | implementation config.androidLibrary.androidxKtx
49 | implementation config.kotlinLibrary.coroutinesCore
50 | implementation config.kotlinLibrary.coroutinesAndroid
51 |
52 |
53 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/dashboard/DashboardFragment.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.dashboard
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.ViewModelProvider
10 | import com.fastmvvm.sample.databinding.FragmentDashboardBinding
11 |
12 | class DashboardFragment : Fragment() {
13 |
14 | private var _binding: FragmentDashboardBinding? = null
15 |
16 | // This property is only valid between onCreateView and
17 | // onDestroyView.
18 | private val binding get() = _binding!!
19 |
20 | override fun onCreateView(
21 | inflater: LayoutInflater,
22 | container: ViewGroup?,
23 | savedInstanceState: Bundle?
24 | ): View {
25 | val dashboardViewModel =
26 | ViewModelProvider(this).get(DashboardViewModel::class.java)
27 |
28 | _binding = FragmentDashboardBinding.inflate(inflater, container, false)
29 | val root: View = binding.root
30 |
31 | val textView: TextView = binding.textDashboard
32 | dashboardViewModel.text.observe(viewLifecycleOwner) {
33 | textView.text = it
34 | }
35 | return root
36 | }
37 |
38 | override fun onDestroyView() {
39 | super.onDestroyView()
40 | _binding = null
41 | }
42 | }
--------------------------------------------------------------------------------
/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=-Xmx2048m -Dfile.encoding=UTF-8
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 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
24 |
25 | android.injected.testOnly=false
26 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/notifications/NotificationsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.notifications
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.ViewModelProvider
10 | import com.fastmvvm.sample.databinding.FragmentNotificationsBinding
11 |
12 | class NotificationsFragment : Fragment() {
13 |
14 | private var _binding: FragmentNotificationsBinding? = null
15 |
16 | // This property is only valid between onCreateView and
17 | // onDestroyView.
18 | private val binding get() = _binding!!
19 |
20 | override fun onCreateView(
21 | inflater: LayoutInflater,
22 | container: ViewGroup?,
23 | savedInstanceState: Bundle?
24 | ): View {
25 | val notificationsViewModel =
26 | ViewModelProvider(this).get(NotificationsViewModel::class.java)
27 |
28 | _binding = FragmentNotificationsBinding.inflate(inflater, container, false)
29 | val root: View = binding.root
30 |
31 | val textView: TextView = binding.textNotifications
32 | notificationsViewModel.text.observe(viewLifecycleOwner) {
33 | textView.text = it
34 | }
35 | return root
36 | }
37 |
38 | override fun onDestroyView() {
39 | super.onDestroyView()
40 | _binding = null
41 | }
42 | }
--------------------------------------------------------------------------------
/easyAndroid/src/main/java/com/yeqiu/easyandroid/AppInfo.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.easyandroid
2 |
3 | import android.content.Context
4 |
5 | /**
6 | * @project:FastMvvm
7 | * @author:小卷子
8 | * @date 2023/7/12
9 | * @describe:
10 | * @fix:
11 | */
12 |
13 | fun Context.getAppName(): String {
14 |
15 | return "unKnown"
16 | }
17 |
18 | fun Context.getChannelName(): String {
19 |
20 | return "unKnown"
21 | }
22 |
23 | fun Context.getVersionName(): String {
24 |
25 | return "unKnown"
26 | }
27 |
28 | fun Context.getVersionCode(): String {
29 |
30 | return "unKnown"
31 | }
32 |
33 | fun Context.getAppIcon(): String {
34 |
35 | return "unKnown"
36 | }
37 |
38 | fun Context.getPackageName(): String {
39 |
40 | return "unKnown"
41 | }
42 |
43 | fun Context.getFirstInstallTime(): String {
44 |
45 | return "unKnown"
46 | }
47 |
48 | fun Context.getAppSize(): String {
49 |
50 | return "unKnown"
51 | }
52 |
53 | fun Context.getAppApk(): String {
54 |
55 | return "unKnown"
56 | }
57 |
58 | fun Context.isInstalled(): String {
59 |
60 | return "unKnown"
61 | }
62 |
63 | fun Context.getPackageNameLast(): String {
64 |
65 | return "unKnown"
66 | }
67 |
68 | fun Context.killProcesses(): String {
69 |
70 | return "unKnown"
71 | }
72 |
73 | fun Context.getSystemVersion(): String {
74 |
75 | return "unKnown"
76 | }
77 |
78 | fun Context.isDebug(): String {
79 |
80 | return "unKnown"
81 | }
82 |
83 |
84 | /////////AppUtil
85 | fun Context.openOtherApp(): String {
86 |
87 | return "unKnown"
88 | }
89 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/data/LoginRepository.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.data
2 |
3 | import com.fastmvvm.sample.view.activity.data.model.LoggedInUser
4 |
5 | /**
6 | * Class that requests authentication and user information from the remote data source and
7 | * maintains an in-memory cache of login status and user credentials information.
8 | */
9 |
10 | class LoginRepository(val dataSource: LoginDataSource) {
11 |
12 | // in-memory cache of the loggedInUser object
13 | var user: LoggedInUser? = null
14 | private set
15 |
16 | val isLoggedIn: Boolean
17 | get() = user != null
18 |
19 | init {
20 | // If user credentials will be cached in local storage, it is recommended it be encrypted
21 | // @see https://developer.android.com/training/articles/keystore
22 | user = null
23 | }
24 |
25 | fun logout() {
26 | user = null
27 | dataSource.logout()
28 | }
29 |
30 | fun login(username: String, password: String): Result {
31 | // handle login
32 | val result = dataSource.login(username, password)
33 |
34 | if (result is Result.Success) {
35 | setLoggedInUser(result.data)
36 | }
37 |
38 | return result
39 | }
40 |
41 | private fun setLoggedInUser(loggedInUser: LoggedInUser) {
42 | this.user = loggedInUser
43 | // If user credentials will be cached in local storage, it is recommended it be encrypted
44 | // @see https://developer.android.com/training/articles/keystore
45 | }
46 | }
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
33 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_bottom_navigation_acitvity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
32 |
33 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity
2 |
3 | import android.widget.TextView
4 | import androidx.databinding.ViewDataBinding
5 | import com.afollestad.materialdialogs.MaterialDialog
6 | import com.afollestad.materialdialogs.customview.customView
7 | import com.afollestad.materialdialogs.customview.getCustomView
8 | import com.afollestad.materialdialogs.lifecycle.lifecycleOwner
9 | import com.fastmvvm.sample.R
10 | import com.yeqiu.fastmvvm.view.ViewModelDataBindingActivity
11 | import com.yeqiu.fastmvvm.viewmodel.BaseViewModel
12 |
13 | /**
14 | * @project:FastMvvm
15 | * @author:小卷子
16 | * @date 2023/7/9
17 | * @describe:
18 | * @fix:
19 | */
20 | abstract class BaseActivity : ViewModelDataBindingActivity() {
21 |
22 |
23 | private lateinit var loadingDialog: MaterialDialog
24 |
25 |
26 | override fun showLoading(message:String) {
27 |
28 |
29 | if (!::loadingDialog.isInitialized) {
30 | loadingDialog = MaterialDialog(this)
31 | .cancelable(true)
32 | .cancelOnTouchOutside(false)
33 | .cornerRadius(12f)
34 | .customView(R.layout.dialog_loading)
35 | .lifecycleOwner(this)
36 | loadingDialog.getCustomView().run {
37 | (findViewById(R.id.loading_tips)).text =message
38 | }
39 | }
40 |
41 | loadingDialog.show()
42 | }
43 |
44 | override fun dismissLoading() {
45 |
46 | if (::loadingDialog.isInitialized){
47 | loadingDialog.dismiss()
48 | }
49 |
50 | }
51 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/BottomNavigationAcitvity.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.navigation.findNavController
6 | import androidx.navigation.ui.AppBarConfiguration
7 | import androidx.navigation.ui.setupActionBarWithNavController
8 | import androidx.navigation.ui.setupWithNavController
9 | import com.fastmvvm.sample.R
10 | import com.fastmvvm.sample.databinding.ActivityBottomNavigationAcitvityBinding
11 | import com.google.android.material.bottomnavigation.BottomNavigationView
12 |
13 | class BottomNavigationAcitvity : AppCompatActivity() {
14 |
15 | private lateinit var binding: ActivityBottomNavigationAcitvityBinding
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 |
20 | binding = ActivityBottomNavigationAcitvityBinding.inflate(layoutInflater)
21 | setContentView(binding.root)
22 |
23 | val navView: BottomNavigationView = binding.navView
24 |
25 | val navController =
26 | findNavController(R.id.nav_host_fragment_activity_bottom_navigation_acitvity)
27 | // Passing each menu ID as a set of Ids because each
28 | // menu should be considered as top level destinations.
29 | val appBarConfiguration = AppBarConfiguration(
30 | setOf(
31 | R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
32 | )
33 | )
34 | setupActionBarWithNavController(navController, appBarConfiguration)
35 | navView.setupWithNavController(navController)
36 | }
37 | }
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/fastMvvm/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-kapt'
5 | }
6 |
7 | def config = rootProject.ext
8 |
9 | android {
10 | namespace config.namespace.fastMvvm
11 | compileSdk config.android.compileSdk
12 |
13 | defaultConfig {
14 | minSdk config.android.minSdk
15 | targetSdk config.android.targetSdk
16 | versionCode config.android.versionCode
17 | versionName config.android.versionName
18 |
19 | testInstrumentationRunner config.android.testInstrumentationRunner
20 | }
21 |
22 | buildTypes {
23 |
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 |
30 | compileOptions {
31 | sourceCompatibility config.javaOptions.sourceCompatibility
32 | targetCompatibility config.javaOptions.targetCompatibility
33 | }
34 |
35 | kotlinOptions {
36 | jvmTarget = config.javaOptions.kotlinOptions
37 | }
38 |
39 | dataBinding {
40 | enable = true
41 | }
42 |
43 | }
44 |
45 | dependencies {
46 |
47 | implementation config.androidLibrary.androidxAppcompat
48 | implementation config.androidLibrary.androidxKtx
49 | implementation config.kotlinLibrary.coroutinesCore
50 | implementation config.kotlinLibrary.coroutinesAndroid
51 | implementation project(path: ':easyAndroid')
52 |
53 | api config.androidLibrary.lifecycleRuntime
54 | api config.androidLibrary.lifecycleViewmodel
55 |
56 | api config.library.retrofit
57 | api config.library.moshiConverter
58 | kapt config.library.moshiKotlinCodegen
59 | implementation config.library.okhttpLogginginterceptor
60 | implementation config.library.logginginterceptor
61 | implementation config.library.moshiKotlin
62 |
63 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/DetailActivity.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity
2 |
3 | import android.os.Bundle
4 | import android.widget.ImageView
5 | import androidx.databinding.BindingAdapter
6 | import androidx.lifecycle.MutableLiveData
7 | import com.bumptech.glide.Glide
8 | import com.fastmvvm.sample.databinding.ActivityDetailBinding
9 | import com.fastmvvm.sample.network.NetworkClient
10 | import com.fastmvvm.sample.network.User
11 | import com.yeqiu.easyandroid.showToast
12 | import com.yeqiu.fastmvvm.ext.requestOriginalData
13 | import com.yeqiu.fastmvvm.viewmodel.BaseViewModel
14 | import kotlinx.coroutines.delay
15 |
16 |
17 | class DetailActivity : BaseActivity() {
18 |
19 |
20 | override fun initData(savedInstanceState: Bundle?) {
21 | binding.mainViewModel = viewModel
22 |
23 | viewModel.getData()
24 |
25 | }
26 |
27 | override fun addObserve() {
28 |
29 | viewModel.errorMsg.observe(this) {
30 | showToast(it)
31 | }
32 |
33 | }
34 |
35 |
36 | }
37 |
38 |
39 | class ImageLoader {
40 | companion object {
41 | @JvmStatic
42 | @BindingAdapter("url")
43 | fun loadUrl(imageView: ImageView, url: String?) {
44 | url?.let {
45 | Glide.with(imageView.context)
46 | .load(it)
47 | .into(imageView)
48 | }
49 |
50 |
51 | }
52 | }
53 | }
54 |
55 |
56 | class DetailViewModel : BaseViewModel() {
57 |
58 | val user = MutableLiveData()
59 | val errorMsg = MutableLiveData()
60 |
61 | fun getData() {
62 |
63 | requestOriginalData(
64 | {
65 | delay(2000)
66 | NetworkClient.api.getUser("https://api.github.com/users/yeqiu")
67 | },
68 | { user.value = it }
69 | )
70 |
71 |
72 | }
73 |
74 | fun testError() {
75 |
76 |
77 | }
78 |
79 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/network/LoginInfo.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.network
2 |
3 |
4 | import com.squareup.moshi.Json
5 |
6 | data class LoginInfo(
7 | @Json(name = "admin")
8 | val admin: Boolean?,
9 | @Json(name = "chapterTops")
10 | val chapterTops: List?,
11 | @Json(name = "coinCount")
12 | val coinCount: Int?,
13 | @Json(name = "collectIds")
14 | val collectIds: List?,
15 | @Json(name = "email")
16 | val email: String?,
17 | @Json(name = "icon")
18 | val icon: String?,
19 | @Json(name = "id")
20 | val id: Int?,
21 | @Json(name = "nickname")
22 | val nickname: String?,
23 | @Json(name = "password")
24 | val password: String?,
25 | @Json(name = "publicName")
26 | val publicName: String?,
27 | @Json(name = "token")
28 | val token: String?,
29 | @Json(name = "type")
30 | val type: Int?,
31 | @Json(name = "username")
32 | val username: String?
33 | ) {
34 | }
35 |
36 | //data class LoginInfo(
37 | // @Json(name = "data")
38 | // val `data`: Data?,
39 | // @Json(name = "errorCode")
40 | // val errorCode: Int?,
41 | // @Json(name = "errorMsg")
42 | // val errorMsg: String?
43 | //) {
44 | // data class Data(
45 | // @Json(name = "admin")
46 | // val admin: Boolean?,
47 | // @Json(name = "chapterTops")
48 | // val chapterTops: List?,
49 | // @Json(name = "coinCount")
50 | // val coinCount: Int?,
51 | // @Json(name = "collectIds")
52 | // val collectIds: List?,
53 | // @Json(name = "email")
54 | // val email: String?,
55 | // @Json(name = "icon")
56 | // val icon: String?,
57 | // @Json(name = "id")
58 | // val id: Int?,
59 | // @Json(name = "nickname")
60 | // val nickname: String?,
61 | // @Json(name = "password")
62 | // val password: String?,
63 | // @Json(name = "publicName")
64 | // val publicName: String?,
65 | // @Json(name = "token")
66 | // val token: String?,
67 | // @Json(name = "type")
68 | // val type: Int?,
69 | // @Json(name = "username")
70 | // val username: String?
71 | // )
72 | //}
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity
2 |
3 | import android.os.Bundle
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.viewModelScope
6 | import com.fastmvvm.sample.databinding.ActivityMainBinding
7 | import com.yeqiu.easyandroid.toActivity
8 | import com.yeqiu.fastmvvm.viewmodel.BaseViewModel
9 | import kotlinx.coroutines.delay
10 | import kotlinx.coroutines.launch
11 |
12 | class MainActivity : BaseActivity() {
13 | override fun initData(savedInstanceState: Bundle?) {
14 | binding.viewModle = viewModel
15 | }
16 |
17 | override fun addObserve() {
18 |
19 | viewModel.detail.observe(this) {
20 |
21 | if (it) {
22 | toActivity()
23 | }
24 |
25 | }
26 | viewModel.login.observe(this) {
27 | if (it) {
28 | toActivity()
29 | }
30 | }
31 | viewModel.singleActivity.observe(this) {
32 | if (it) {
33 | toActivity()
34 | }
35 | }
36 | viewModel.netWork.observe(this) {
37 |
38 | if (it) {
39 | toActivity()
40 | }
41 |
42 | }
43 |
44 |
45 | }
46 |
47 | }
48 |
49 | class MainViewModel : BaseViewModel() {
50 |
51 | val detail = MutableLiveData(false)
52 | val login = MutableLiveData(false)
53 | val singleActivity = MutableLiveData(false)
54 | val netWork = MutableLiveData(false)
55 |
56 |
57 | fun clickDetail() {
58 | detail.value = true
59 | }
60 |
61 | fun clickLogin() {
62 | login.value = true
63 | }
64 |
65 | fun clickSingleActivity() {
66 | singleActivity.value = true
67 | }
68 |
69 | fun clickNetwork() {
70 | netWork.value = true
71 | }
72 | fun clickLoading() {
73 |
74 | //三秒后自动关闭
75 | viewModelScope.launch {
76 | loadingStatus.show.postValue("加载。。。")
77 | delay(3000)
78 | loadingStatus.dismiss.postValue(true)
79 | }
80 | }
81 |
82 |
83 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/ui/login/LoginViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity.ui.login
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import android.util.Patterns
7 | import com.fastmvvm.sample.R
8 | import com.fastmvvm.sample.view.activity.data.LoginRepository
9 | import com.fastmvvm.sample.view.activity.data.Result
10 |
11 |
12 | class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel() {
13 |
14 | private val _loginForm = MutableLiveData()
15 | val loginFormState: LiveData = _loginForm
16 |
17 | private val _loginResult = MutableLiveData()
18 | val loginResult: LiveData = _loginResult
19 |
20 | fun login(username: String, password: String) {
21 | // can be launched in a separate asynchronous job
22 | val result = loginRepository.login(username, password)
23 |
24 | if (result is Result.Success) {
25 | _loginResult.value =
26 | LoginResult(success = LoggedInUserView(displayName = result.data.displayName))
27 | } else {
28 | _loginResult.value = LoginResult(error = R.string.login_failed)
29 | }
30 | }
31 |
32 | fun loginDataChanged(username: String, password: String) {
33 | if (!isUserNameValid(username)) {
34 | _loginForm.value = LoginFormState(usernameError = R.string.invalid_username)
35 | } else if (!isPasswordValid(password)) {
36 | _loginForm.value = LoginFormState(passwordError = R.string.invalid_password)
37 | } else {
38 | _loginForm.value = LoginFormState(isDataValid = true)
39 | }
40 | }
41 |
42 | // A placeholder username validation check
43 | private fun isUserNameValid(username: String): Boolean {
44 | return if (username.contains('@')) {
45 | Patterns.EMAIL_ADDRESS.matcher(username).matches()
46 | } else {
47 | username.isNotBlank()
48 | }
49 | }
50 |
51 | // A placeholder password validation check
52 | private fun isPasswordValid(password: String): Boolean {
53 | return password.length > 5
54 | }
55 | }
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
20 |
21 |
22 |
28 |
29 |
35 |
36 |
37 |
44 |
45 |
46 |
52 |
53 |
54 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/network/User.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.network
2 |
3 |
4 | import com.squareup.moshi.Json
5 | import com.squareup.moshi.JsonClass
6 |
7 | @JsonClass(generateAdapter = true)
8 | data class User(
9 | @Json(name = "avatar_url")
10 | val avatarUrl: String?,
11 | @Json(name = "bio")
12 | val bio: Any?,
13 | @Json(name = "blog")
14 | val blog: String?,
15 | @Json(name = "company")
16 | val company: Any?,
17 | @Json(name = "created_at")
18 | val createdAt: String?,
19 | @Json(name = "email")
20 | val email: Any?,
21 | @Json(name = "events_url")
22 | val eventsUrl: String?,
23 | @Json(name = "followers")
24 | val followers: Int?,
25 | @Json(name = "followers_url")
26 | val followersUrl: String?,
27 | @Json(name = "following")
28 | val following: Int?,
29 | @Json(name = "following_url")
30 | val followingUrl: String?,
31 | @Json(name = "gists_url")
32 | val gistsUrl: String?,
33 | @Json(name = "gravatar_id")
34 | val gravatarId: String?,
35 | @Json(name = "hireable")
36 | val hireable: Any?,
37 | @Json(name = "html_url")
38 | val htmlUrl: String?,
39 | @Json(name = "id")
40 | val id: Int?,
41 | @Json(name = "location")
42 | val location: Any?,
43 | @Json(name = "login")
44 | val login: String?,
45 | @Json(name = "name")
46 | val name: String?,
47 | @Json(name = "node_id")
48 | val nodeId: String?,
49 | @Json(name = "organizations_url")
50 | val organizationsUrl: String?,
51 | @Json(name = "public_gists")
52 | val publicGists: Int?,
53 | @Json(name = "public_repos")
54 | val publicRepos: Int?,
55 | @Json(name = "received_events_url")
56 | val receivedEventsUrl: String?,
57 | @Json(name = "repos_url")
58 | val reposUrl: String?,
59 | @Json(name = "site_admin")
60 | val siteAdmin: Boolean?,
61 | @Json(name = "starred_url")
62 | val starredUrl: String?,
63 | @Json(name = "subscriptions_url")
64 | val subscriptionsUrl: String?,
65 | @Json(name = "twitter_username")
66 | val twitterUsername: Any?,
67 | @Json(name = "type")
68 | val type: String?,
69 | @Json(name = "updated_at")
70 | val updatedAt: String?,
71 | @Json(name = "url")
72 | val url: String?
73 | )
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/view/ViewModelDataBindingActivity.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.view
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.databinding.ViewDataBinding
7 | import androidx.lifecycle.ViewModelProvider
8 | import com.yeqiu.fastmvvm.exception.GenerateViewDataBindingException
9 | import com.yeqiu.fastmvvm.viewmodel.BaseViewModel
10 | import java.lang.reflect.ParameterizedType
11 |
12 | /**
13 | * @project:FastMvvm
14 | * @author:小卷子
15 | * @date 2023/7/8
16 | * @describe:
17 | * @fix:
18 | */
19 | abstract class ViewModelDataBindingActivity : AppCompatActivity() {
20 |
21 |
22 | protected lateinit var viewModel: VM
23 | protected lateinit var binding: VB
24 |
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | super.onCreate(savedInstanceState)
28 |
29 | binding = generateViewDataBinding()
30 | setContentView(binding.root)
31 | //绑定lifecycleOwner
32 | binding.lifecycleOwner =this
33 | init()
34 | initData(savedInstanceState)
35 | }
36 |
37 |
38 |
39 |
40 | private fun init() {
41 | viewModel = createViewModel()
42 | registerLoading()
43 | addObserve()
44 | }
45 |
46 |
47 | @Suppress("UNCHECKED_CAST")
48 | private fun generateViewDataBinding(): VB {
49 |
50 | try {
51 | val clazz =
52 | (this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[1] as Class<*>
53 | val inflate = clazz.getMethod("inflate", LayoutInflater::class.java)
54 | return inflate.invoke(null, layoutInflater) as VB
55 | } catch (e: Exception) {
56 | e.printStackTrace()
57 | throw GenerateViewDataBindingException("fail to generate ViewDataBinding cause ${e.message} ")
58 | }
59 | }
60 |
61 |
62 |
63 | private fun createViewModel(): VM {
64 |
65 | return ViewModelProvider(this)[getViewModelClazz(this)]
66 | }
67 |
68 | private fun registerLoading() {
69 |
70 | viewModel.loadingStatus.show.observe(this) {
71 | showLoading(it)
72 | }
73 | viewModel.loadingStatus.dismiss.observe(this) {
74 | dismissLoading()
75 | }
76 |
77 | }
78 |
79 |
80 |
81 |
82 | abstract fun initData(savedInstanceState: Bundle?)
83 |
84 | abstract fun addObserve()
85 |
86 | abstract fun showLoading(message:String)
87 |
88 | abstract fun dismissLoading()
89 |
90 |
91 |
92 | }
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_net_work.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
20 |
21 |
22 |
26 |
27 |
28 |
34 |
35 |
41 |
42 |
48 |
49 |
55 |
56 |
57 |
64 |
65 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/network/BaseNetworkClient.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.network
2 |
3 | import cn.netdiscovery.http.interceptor.LoggingInterceptor
4 | import com.safframework.http.interceptor.AndroidLoggingInterceptor
5 | import com.squareup.moshi.Moshi
6 | import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
7 | import okhttp3.OkHttpClient
8 | import okhttp3.logging.HttpLoggingInterceptor
9 | import retrofit2.Retrofit
10 | import retrofit2.converter.moshi.MoshiConverterFactory
11 | import java.util.concurrent.TimeUnit
12 |
13 | /**
14 | * @project:FastMvvm
15 | * @author:小卷子
16 | * @date 2023/7/8
17 | * @describe:
18 | * @fix:
19 | */
20 | abstract class BaseNetworkClient {
21 |
22 |
23 | private val okHttpClient by lazy {
24 | val builder = OkHttpClient.Builder()
25 | .connectTimeout(30,TimeUnit.SECONDS)
26 | .addInterceptor(HeadInterceptor())
27 | if (NetworkConfig.enableLog) {
28 | builder.addInterceptor(getHttpLoggingInterceptor())
29 | builder.addInterceptor(getLoggingInterceptor())
30 | }
31 | setOkHttpClient(builder)
32 | builder.build()
33 | }
34 |
35 | private val retrofit: Retrofit by lazy {
36 | val build = Retrofit.Builder()
37 | .client(okHttpClient)
38 | .addConverterFactory(MoshiConverterFactory.create(
39 | Moshi.Builder()
40 | .add(KotlinJsonAdapterFactory())
41 | .build()
42 | ))
43 | .baseUrl(getBaseUrl())
44 | setRetrofit(build)
45 | build.build()
46 |
47 | }
48 |
49 |
50 | private fun getHttpLoggingInterceptor(): HttpLoggingInterceptor {
51 | val httpLoggingInterceptor = HttpLoggingInterceptor()
52 | httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
53 | return httpLoggingInterceptor
54 | }
55 |
56 |
57 | private fun getLoggingInterceptor(): LoggingInterceptor {
58 | val tag = "NetworkClient"
59 | val requestTag = "$tag ==========> 请求开始"
60 | val responseTag = "$tag <========== 请求结束"
61 |
62 | return AndroidLoggingInterceptor.build(
63 | isDebug = true,
64 | hideVerticalLine = true,
65 | requestTag = requestTag,
66 | responseTag = responseTag
67 | )
68 | }
69 |
70 | fun getService(serviceClass: Class): T {
71 | return retrofit.create(serviceClass)
72 | }
73 |
74 |
75 | abstract fun getBaseUrl(): String
76 |
77 | abstract fun setOkHttpClient(builder: OkHttpClient.Builder)
78 |
79 | abstract fun setRetrofit(build: Retrofit.Builder)
80 | }
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-kapt'
5 | }
6 |
7 | def config = rootProject.ext
8 |
9 | android {
10 | namespace config.namespace.sample
11 | compileSdk config.android.compileSdk
12 |
13 | defaultConfig {
14 | applicationId config.namespace.sample
15 | minSdk config.android.minSdk
16 | targetSdk config.android.targetSdk
17 | versionCode config.android.versionCode
18 | versionName config.android.versionName
19 | multiDexEnabled true
20 | testInstrumentationRunner config.android.testInstrumentationRunner
21 | }
22 |
23 | buildFeatures {
24 | dataBinding = true
25 | viewBinding true
26 | }
27 |
28 | buildTypes {
29 |
30 | release {
31 | minifyEnabled false
32 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 | compileOptions {
36 | sourceCompatibility config.javaOptions.sourceCompatibility
37 | targetCompatibility config.javaOptions.targetCompatibility
38 | }
39 | kotlinOptions {
40 | jvmTarget = '1.8'
41 | }
42 |
43 |
44 | }
45 |
46 | dependencies {
47 |
48 |
49 | implementation 'androidx.appcompat:appcompat:1.6.1'
50 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
51 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
52 | implementation 'androidx.navigation:navigation-fragment-ktx:2.6.0'
53 | implementation 'androidx.navigation:navigation-ui-ktx:2.6.0'
54 | implementation 'androidx.annotation:annotation:1.6.0'
55 | testImplementation 'junit:junit:4.13.2'
56 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
57 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
58 |
59 | implementation config.androidLibrary.material
60 | implementation config.androidLibrary.constraintlayout
61 | implementation config.androidLibrary.splashscreen
62 | implementation project(path: ':fastMvvm')
63 | implementation project(path: ':easyAndroid')
64 |
65 |
66 |
67 | implementation config.library.moshiKotlin
68 | kapt config.library.moshiKotlinCodegen
69 | implementation config.library.glide
70 |
71 |
72 | //侧滑返回
73 | implementation 'me.imid.swipebacklayout.lib:library:1.1.0'
74 | //LiveEventBus https://github.com/JeremyLiao/LiveEventBus
75 | implementation 'io.github.jeremyliao:live-event-bus-x:1.8.0'
76 |
77 | implementation 'com.afollestad.material-dialogs:core:3.3.0'
78 | implementation "com.afollestad.material-dialogs:lifecycle:3.3.0"
79 |
80 | implementation 'com.google.code.gson:gson:2.9.0'
81 |
82 |
83 |
84 |
85 |
86 |
87 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/NetworkActivity.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity
2 |
3 | import android.os.Bundle
4 | import androidx.lifecycle.MutableLiveData
5 | import com.fastmvvm.sample.databinding.ActivityNetWorkBinding
6 | import com.fastmvvm.sample.network.NetworkClient
7 | import com.google.gson.Gson
8 | import com.yeqiu.easyandroid.log
9 | import com.yeqiu.easyandroid.showToast
10 | import com.yeqiu.fastmvvm.ext.requestData
11 | import com.yeqiu.fastmvvm.ext.requestOriginalData
12 | import com.yeqiu.fastmvvm.network.NetworkConfig
13 | import com.yeqiu.fastmvvm.viewmodel.BaseViewModel
14 | import kotlinx.coroutines.delay
15 |
16 | class NetworkActivity : BaseActivity() {
17 |
18 | override fun initData(savedInstanceState: Bundle?) {
19 |
20 | binding.viewModle = viewModel
21 | //默认错误处理
22 | NetworkConfig.onNetworkError = { it ->
23 | showToast("默认错误处理,错误信息 = ${it.errorMessage}")
24 | }
25 |
26 | }
27 |
28 |
29 | override fun addObserve() {
30 |
31 | }
32 |
33 | }
34 |
35 |
36 | fun Any.toJson(): String {
37 |
38 |
39 | return Gson().toJson(this)
40 |
41 | }
42 |
43 | class NetWorkViewModel : BaseViewModel() {
44 |
45 | val data = MutableLiveData()
46 |
47 |
48 | fun shuck() {
49 |
50 | requestData(
51 | {
52 | NetworkClient.api.banner2()
53 | },
54 | {
55 | data.value = it?.toJson()
56 | it?.toJson()?.log()
57 | }
58 | )
59 | }
60 |
61 | fun originalData() {
62 |
63 | requestOriginalData(
64 | block = {
65 | NetworkClient.api.banner()
66 | },
67 | success = {
68 | data.value = it?.toJson()
69 | it?.toJson()?.log()
70 | }
71 | )
72 | }
73 |
74 | fun error() {
75 |
76 | requestData(
77 | block = {
78 | NetworkClient.api.login("aa","")
79 | },
80 | success = {}
81 | )
82 |
83 | }
84 |
85 | fun handleError() {
86 | requestData(
87 | block = {
88 | delay(2000)
89 | throw IllegalArgumentException()
90 | NetworkClient.api.banner2()
91 | },
92 | success = {},
93 | error = {
94 | data.value = "这个一个自定义处理错误"
95 | }
96 | )
97 | }
98 |
99 | fun withOutLoading() {
100 | requestData(
101 | {
102 | NetworkClient.api.banner2()
103 | },
104 | {
105 | data.value = it?.toJson()
106 | it?.toJson()?.log()
107 | },
108 | isShowDialog = false
109 | )
110 | }
111 |
112 | fun withStatus() {
113 |
114 | }
115 |
116 |
117 | }
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/view/ViewModelDataBindingFragment.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.view
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.databinding.ViewDataBinding
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.ViewModelProvider
10 | import com.yeqiu.fastmvvm.exception.GenerateViewDataBindingException
11 | import com.yeqiu.fastmvvm.viewmodel.BaseViewModel
12 | import java.lang.reflect.ParameterizedType
13 |
14 | /**
15 | * @project:FastMvvm
16 | * @author:小卷子
17 | * @date 2023/7/8
18 | * @describe:
19 | * @fix:
20 | */
21 |
22 | abstract class ViewModelDataBindingFragment : Fragment() {
23 |
24 | protected lateinit var viewModel: VM
25 | protected lateinit var binding: VB
26 |
27 | override fun onCreateView(
28 | inflater: LayoutInflater,
29 | container: ViewGroup?,
30 | savedInstanceState: Bundle?
31 | ): View? {
32 |
33 |
34 | binding = generateViewDataBinding(container!!)
35 |
36 | return binding.root
37 | }
38 |
39 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
40 | super.onViewCreated(view, savedInstanceState)
41 | init()
42 | initData(savedInstanceState)
43 | }
44 |
45 | private fun init() {
46 | viewModel = createViewModel()
47 | registerLoading()
48 | addObserve()
49 |
50 |
51 |
52 | }
53 |
54 |
55 | @Suppress("UNCHECKED_CAST")
56 | private fun generateViewDataBinding(container: ViewGroup): VB {
57 |
58 | try {
59 | val clazz =
60 | (this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[1] as Class<*>
61 | val inflate = clazz.getMethod(
62 | "inflate",
63 | LayoutInflater::class.java,
64 | ViewGroup::class.java,
65 | Boolean::class.java
66 | )
67 | return inflate.invoke(null, layoutInflater, container, false) as VB
68 |
69 | } catch (e: Exception) {
70 | e.printStackTrace()
71 | throw GenerateViewDataBindingException("fail to generate ViewDataBinding cause ${e.message} ")
72 | }
73 | }
74 |
75 | private fun createViewModel(): VM {
76 |
77 | return ViewModelProvider(this)[getViewModelClazz(this)]
78 | }
79 |
80 | private fun registerLoading() {
81 |
82 |
83 | viewModel.loadingStatus.show.observe(viewLifecycleOwner){
84 | showLoading()
85 | }
86 | viewModel.loadingStatus.dismiss.observe(viewLifecycleOwner) {
87 | dismissLoading()
88 | }
89 |
90 | }
91 |
92 |
93 |
94 | abstract fun initData(savedInstanceState: Bundle?)
95 |
96 | abstract fun addObserve()
97 |
98 | abstract fun showLoading()
99 |
100 | abstract fun dismissLoading()
101 |
102 | }
103 |
104 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
25 |
26 |
39 |
40 |
54 |
55 |
68 |
69 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout-w1240dp/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
25 |
26 |
39 |
40 |
54 |
55 |
68 |
69 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout-w936dp/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
19 |
20 |
31 |
32 |
45 |
46 |
60 |
61 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/easyAndroid/src/main/java/com/yeqiu/easyandroid/Logger.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.easyandroid
2 |
3 | import android.util.Log
4 | import com.yeqiu.easyandroid.Logger.flagE
5 | import com.yeqiu.easyandroid.Logger.flagI
6 | import com.yeqiu.easyandroid.Logger.logTag
7 | import com.yeqiu.easyandroid.Logger.space
8 | import org.json.JSONArray
9 | import org.json.JSONObject
10 |
11 |
12 | /**
13 | * @project:FastMvvm
14 | * @author:小卷子
15 | * @date 2023/7/8
16 | * @describe:
17 | * @fix:
18 | */
19 | object Logger {
20 |
21 | const val space = " "
22 | const val flagI = "i"
23 | const val flagE = "e"
24 | var enabledLog = BuildConfig.DEBUG
25 | var logTag = "easyandroid_log"
26 |
27 |
28 | }
29 |
30 | fun String.log() {
31 |
32 | if (!Logger.enabledLog) {
33 | return
34 | }
35 | runCatching {
36 | val taskName = getTaskName(4)
37 | printTopLine(flagI, taskName, logTag)
38 | Log.i(logTag, space + this)
39 | printBottomLine(flagI, logTag)
40 | }.onFailure {
41 | Log.e(logTag, "$space 日志输出错误")
42 | }
43 |
44 | }
45 |
46 |
47 | fun String.logE() {
48 | if (!Logger.enabledLog) {
49 | return
50 | }
51 | runCatching {
52 | val taskName = getTaskName(4)
53 | printTopLine(flagE, taskName, logTag)
54 | Log.e(logTag, space + this)
55 | printBottomLine(flagE, logTag)
56 | }.onFailure {
57 | Log.e(logTag, "$space 日志输出错误")
58 | }
59 |
60 | }
61 |
62 |
63 | fun printException(exception: Exception) {
64 | if (!Logger.enabledLog) {
65 | return
66 | }
67 | runCatching {
68 | Log.getStackTraceString(exception).logE()
69 | }.onFailure {
70 | Log.e(logTag, "$space 日志输出错误")
71 | }
72 |
73 | }
74 |
75 |
76 | fun String.logJson() {
77 | if (!Logger.enabledLog) {
78 | return
79 | }
80 | runCatching {
81 | val logString: String = this
82 | val json = if (logString.startsWith("{")) {
83 | val jsonObject = JSONObject(logString)
84 | //最重要的方法,就一行,返回格式化的json字符串,其中的数字4是缩进字符数
85 | jsonObject.toString(4)
86 | } else if (logString.startsWith("[")) {
87 | val jsonArray = JSONArray(this)
88 | jsonArray.toString(4)
89 | } else {
90 | logString
91 | }
92 | json.log()
93 | }.onFailure {
94 | Log.e(logTag, "$space 日志输出错误")
95 | }
96 |
97 |
98 | }
99 |
100 |
101 | private fun getTaskName(index: Int): String {
102 | val stackTrace = Thread.currentThread().stackTrace
103 | //查看方法栈堆信息
104 | // for (i in stackTrace.indices) {
105 | // val stackTraceElement = stackTrace[i]
106 | // val className = stackTraceElement.className
107 | // Log.i("LogTest", "i = $i ,$className")
108 | // }
109 | var fileName: String? = "unknown"
110 | var lineNumber = 0
111 | if (stackTrace.size >= 5) {
112 | fileName = stackTrace[index].fileName
113 | lineNumber = stackTrace[index].lineNumber
114 | }
115 | val taskName = StringBuilder()
116 | taskName.append("(").append(fileName).append(":").append(lineNumber).append(")")
117 | return taskName.toString()
118 | }
119 |
120 |
121 | private fun printTopLine(flag: String, title: String, tag: String) {
122 | when (flag) {
123 | flagI -> {
124 | Log.i(tag, " ")
125 | Log.i(tag, "═════════$title═════════")
126 | }
127 |
128 | flagE -> {
129 | Log.i(tag, "═════════")
130 | Log.e(tag, "═════════$title═════════")
131 | }
132 |
133 | else -> {}
134 | }
135 | }
136 |
137 |
138 | private fun printBottomLine(flag: String, tag: String) {
139 | when (flag) {
140 | flagI -> Log.i(tag, "═════════ log end ═════════ ")
141 | flagE -> Log.e(tag, "═════════ log end ═════════ ")
142 | else -> {}
143 | }
144 | }
--------------------------------------------------------------------------------
/fastMvvm/src/main/java/com/yeqiu/fastmvvm/ext/BaseViewModelExt.kt:
--------------------------------------------------------------------------------
1 | package com.yeqiu.fastmvvm.ext
2 |
3 | import androidx.lifecycle.viewModelScope
4 | import com.yeqiu.fastmvvm.exception.NetworkErrorCode
5 | import com.yeqiu.fastmvvm.exception.NetworkException
6 | import com.yeqiu.fastmvvm.exception.checkResponseErrorCode
7 | import com.yeqiu.fastmvvm.exception.unknownErrorCode
8 | import com.yeqiu.fastmvvm.network.NetworkConfig
9 | import com.yeqiu.fastmvvm.network.NetworkResponse
10 | import com.yeqiu.fastmvvm.viewmodel.BaseViewModel
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.Job
13 | import kotlinx.coroutines.coroutineScope
14 | import kotlinx.coroutines.launch
15 | import kotlinx.coroutines.withContext
16 |
17 | /**
18 | * @project:FastMvvm
19 | * @author:小卷子
20 | * @date 2023/7/10
21 | * @describe:
22 | * @fix:
23 | */
24 |
25 | /**
26 | * 数据自动脱壳
27 | * @receiver BaseViewModel
28 | * @param block 执行网络请求
29 | * @param success 成功回调
30 | * @param error 失败回调
31 | * @param isShowDialog Boolean
32 | * @param loadingMessage String
33 | * @return Job
34 | */
35 | fun BaseViewModel.requestData(
36 | block: suspend () -> NetworkResponse,
37 | success: (T?) -> Unit,
38 | error: (NetworkException) -> Unit = NetworkConfig.onNetworkError,
39 | isShowDialog: Boolean = true,
40 | loadingMessage: String = "请求网络中..."
41 | ): Job {
42 | return viewModelScope.launch {
43 | runCatching {
44 | //校验网络是否连接
45 |
46 | if (isShowDialog) {
47 | loadingStatus.show.postValue(loadingMessage)
48 | }
49 | withContext(Dispatchers.IO) {
50 | block.invoke()
51 | }
52 | }.onSuccess {
53 | loadingStatus.dismiss.postValue(false)
54 | runCatching {
55 | checkResponse(it) {
56 | success.invoke(it)
57 | }
58 | }.onFailure {
59 | if (it is NetworkException) {
60 | //脱壳校验时错误
61 | error.invoke(
62 | NetworkException(
63 | errorCode = checkResponseErrorCode,
64 | errorMessage = it.errorMessage,
65 | throwable = it
66 | )
67 | )
68 | } else {
69 | error.invoke(
70 | NetworkException(
71 | errorCode = unknownErrorCode,
72 | errorMessage = it.message ?: "未知错误",
73 | throwable = it
74 | )
75 | )
76 | }
77 | }
78 | }.onFailure {
79 | it.printStackTrace()
80 | //网络请求错误
81 | loadingStatus.dismiss.postValue(false)
82 | error.invoke(
83 | NetworkException(
84 | errorCode = NetworkErrorCode,
85 | errorMessage = it.message?:"网络请求错误",
86 | throwable = it
87 | )
88 | )
89 | }
90 | }
91 | }
92 |
93 |
94 | fun BaseViewModel.requestOriginalData(
95 | block: suspend () -> T,
96 | success: (T?) -> Unit,
97 | error: (NetworkException) -> Unit = NetworkConfig.onNetworkError,
98 | isShowDialog: Boolean = true,
99 | loadingMessage: String = "请求网络中..."
100 | ): Job {
101 |
102 | return viewModelScope.launch {
103 | runCatching {
104 | if (isShowDialog) {
105 | loadingStatus.show.postValue(loadingMessage)
106 | }
107 | block.invoke()
108 | }.onSuccess {
109 | loadingStatus.dismiss.postValue(false)
110 | success.invoke(it)
111 | }.onFailure {
112 | it.printStackTrace()
113 | //网络请求错误
114 | loadingStatus.dismiss.postValue(false)
115 | // 网络请求错误
116 | // TODO: 是否需要定义错误的code和msg
117 | error.invoke(NetworkException(throwable = it))
118 | }
119 | }
120 | }
121 |
122 |
123 | suspend fun checkResponse(
124 | response: NetworkResponse,
125 | success: (T?) -> Unit
126 | ) {
127 |
128 | coroutineScope {
129 | if (response.isSuccess()) {
130 | success.invoke(response.getResponse())
131 | } else {
132 | throw NetworkException(
133 | response.getCode(),
134 | response.getErrorMessage()
135 | )
136 | }
137 |
138 | }
139 |
140 | }
141 |
142 |
143 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/fastmvvm/sample/view/activity/LoginActivity.kt:
--------------------------------------------------------------------------------
1 | package com.fastmvvm.sample.view.activity
2 |
3 | import android.app.Activity
4 | import android.os.Bundle
5 | import android.text.Editable
6 | import android.text.TextWatcher
7 | import android.view.View
8 | import android.view.inputmethod.EditorInfo
9 | import android.widget.EditText
10 | import android.widget.Toast
11 | import androidx.annotation.StringRes
12 | import androidx.appcompat.app.AppCompatActivity
13 | import androidx.lifecycle.Observer
14 | import androidx.lifecycle.ViewModelProvider
15 | import com.fastmvvm.sample.R
16 | import com.fastmvvm.sample.databinding.ActivityLoginBinding
17 | import com.fastmvvm.sample.view.activity.ui.login.LoggedInUserView
18 | import com.fastmvvm.sample.view.activity.ui.login.LoginViewModel
19 | import com.fastmvvm.sample.view.activity.ui.login.LoginViewModelFactory
20 |
21 |
22 | class LoginActivity : AppCompatActivity() {
23 |
24 | private lateinit var loginViewModel: LoginViewModel
25 | private lateinit var binding: ActivityLoginBinding
26 |
27 | override fun onCreate(savedInstanceState: Bundle?) {
28 | super.onCreate(savedInstanceState)
29 |
30 | binding = ActivityLoginBinding.inflate(layoutInflater)
31 | setContentView(binding.root)
32 |
33 | val username = binding.username
34 | val password = binding.password
35 | val login = binding.login
36 | val loading = binding.loading
37 |
38 | loginViewModel = ViewModelProvider(this, LoginViewModelFactory())
39 | .get(LoginViewModel::class.java)
40 |
41 | loginViewModel.loginFormState.observe(this@LoginActivity, Observer {
42 | val loginState = it ?: return@Observer
43 |
44 | // disable login button unless both username / password is valid
45 | login.isEnabled = loginState.isDataValid
46 |
47 | if (loginState.usernameError != null) {
48 | username.error = getString(loginState.usernameError)
49 | }
50 | if (loginState.passwordError != null) {
51 | password.error = getString(loginState.passwordError)
52 | }
53 | })
54 |
55 | loginViewModel.loginResult.observe(this@LoginActivity, Observer {
56 | val loginResult = it ?: return@Observer
57 |
58 | loading.visibility = View.GONE
59 | if (loginResult.error != null) {
60 | showLoginFailed(loginResult.error)
61 | }
62 | if (loginResult.success != null) {
63 | updateUiWithUser(loginResult.success)
64 | }
65 | setResult(Activity.RESULT_OK)
66 |
67 | //Complete and destroy login activity once successful
68 | finish()
69 | })
70 |
71 | username.afterTextChanged {
72 | loginViewModel.loginDataChanged(
73 | username.text.toString(),
74 | password.text.toString()
75 | )
76 | }
77 |
78 | password.apply {
79 | afterTextChanged {
80 | loginViewModel.loginDataChanged(
81 | username.text.toString(),
82 | password.text.toString()
83 | )
84 | }
85 |
86 | setOnEditorActionListener { _, actionId, _ ->
87 | when (actionId) {
88 | EditorInfo.IME_ACTION_DONE ->
89 | loginViewModel.login(
90 | username.text.toString(),
91 | password.text.toString()
92 | )
93 | }
94 | false
95 | }
96 |
97 | login.setOnClickListener {
98 | loading.visibility = View.VISIBLE
99 | loginViewModel.login(username.text.toString(), password.text.toString())
100 | }
101 | }
102 | }
103 |
104 | private fun updateUiWithUser(model: LoggedInUserView) {
105 | val welcome = getString(R.string.welcome)
106 | val displayName = model.displayName
107 | // TODO : initiate successful logged in experience
108 | Toast.makeText(
109 | applicationContext,
110 | "$welcome $displayName",
111 | Toast.LENGTH_LONG
112 | ).show()
113 | }
114 |
115 | private fun showLoginFailed(@StringRes errorString: Int) {
116 | Toast.makeText(applicationContext, errorString, Toast.LENGTH_SHORT).show()
117 | }
118 | }
119 |
120 | /**
121 | * Extension function to simplify setting an afterTextChanged action to EditText components.
122 | */
123 | fun EditText.afterTextChanged(afterTextChanged: (String) -> Unit) {
124 | this.addTextChangedListener(object : TextWatcher {
125 | override fun afterTextChanged(editable: Editable?) {
126 | afterTextChanged.invoke(editable.toString())
127 | }
128 |
129 | override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
130 |
131 | override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
132 | })
133 | }
--------------------------------------------------------------------------------
/config.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 |
3 | android = [
4 | compileSdk : 33,
5 | minSdk : 24,
6 | targetSdk : 33,
7 | versionCode : 1,
8 | versionName : "1.0.0",
9 | testInstrumentationRunner: "androidx.test.runner.AndroidJUnitRunner",
10 | ]
11 |
12 |
13 | javaOptions = [
14 | sourceCompatibility: JavaVersion.VERSION_1_8,
15 | targetCompatibility: JavaVersion.VERSION_1_8,
16 | jvmTarget : "1.8",
17 | ]
18 |
19 |
20 | namespace = [
21 | sample : "com.fastmvvm.sample",
22 | fastMvvm : "com.yeqiu.fastmvvm",
23 | fastHttp : "com.yeqiu.fasthttp",
24 | easyAndroid: "com.yeqiu.easyandroid",
25 | ]
26 |
27 |
28 | androidLibrary = [
29 | "androidxAppcompat" : 'androidx.appcompat:appcompat:1.4.2',
30 | "androidxKtx" : 'androidx.core:core-ktx:1.7.0',
31 | "activityKtx" : 'androidx.activity:activity-ktx:1.6.0',
32 | "fragmentKtx" : 'androidx.fragment:fragment-ktx:1.6.0',
33 | "material" : 'com.google.android.material:material:1.4.0',
34 | "constraintlayout" : 'androidx.constraintlayout:constraintlayout:2.0.4',
35 | "multidex" : 'androidx.multidex:multidex:2.0.1',
36 | "splashscreen" : 'androidx.core:core-splashscreen:1.0.0-alpha02',
37 |
38 | //lifecycle
39 | "lifecycleService" : "androidx.lifecycle:lifecycle-service:2.5.1",
40 | "lifecycleProcess" : "androidx.lifecycle:lifecycle-process:2.5.1",
41 | "lifecycleViewmodel" : "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1",
42 | "lifecycleLivedata" : "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1",
43 | "lifecycleRuntime" : "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1",
44 |
45 | //room
46 | "roomRuntime" : "androidx.room:room-runtime:2.5.0",
47 | "roomcompiler" : "androidx.room:room-compiler:2.5.0",
48 | //navigation
49 | "navigationFragment" : "androidx.navigation:navigation-fragment-ktx:2.5.3",
50 | "navigationUi" : "androidx.navigation:navigation-ui-ktx:2.5.3",
51 | "navigationSafeArgsGradlePlugin": "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.3",
52 | //workManager
53 | "workRuntimeKtx" : "androidx.work:work-runtime-ktx:2.8.0",
54 | ]
55 |
56 | kotlinLibrary = [
57 | "kotlinReflect" : "org.jetbrains.kotlin:kotlin-reflect:1.6.21",
58 | "coroutinesCore" : "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2",
59 | "coroutinesAndroid": "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2",
60 | ]
61 |
62 | library = [
63 | //moshi
64 | "moshiKotlin" : "com.squareup.moshi:moshi-kotlin:1.13.0",
65 | // 使用 kapt
66 | "moshiKotlinCodegen" : "com.squareup.moshi:moshi-kotlin-codegen:1.15.0",
67 | //retrofit
68 | "retrofit" : "com.squareup.retrofit2:retrofit:2.9.0",
69 | "moshiConverter" : "com.squareup.retrofit2:converter-moshi:2.9.0",
70 | "okhttpLogginginterceptor": "com.squareup.okhttp3:logging-interceptor:4.11.0",
71 | "logginginterceptor" : "com.github.fengzhizi715:saf-logginginterceptor:v1.6.13",
72 | //glide
73 | "glide" : "com.github.bumptech.glide:glide:4.15.1",
74 | "gson" : "com.google.code.gson:gson:2.9.0",
75 |
76 | ]
77 |
78 |
79 | todo = [
80 | //设置 https://blog.csdn.net/hhbstudy/article/details/128304762
81 | "preference" : "androidx.preference:preference-ktx:1.2.0",
82 |
83 |
84 | "mmkv" : "com.tencent:mmkv:1.0.22",
85 | "BannerViewPager" : "com.github.zhpanvip:BannerViewPager:3.1.5",
86 | "BaseRecyclerViewAdapterHelper": "com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4",
87 | //管理界面状态库
88 | "loadsir" : "com.kingja.loadsir:loadsir:1.3.8",
89 | //指示器库
90 | "MagicIndicator" : "com.github.hackware1993:MagicIndicator:1.7.0",
91 | //流式布局
92 | "flexbox" : "com.google.android:flexbox:2.0.1",
93 | //webview
94 | "agentweb" : "com.just.agentweb:agentweb:4.1.3",
95 | "agentwebFilechooser" : "com.just.agentweb:filechooser:4.1.3",
96 | //下载
97 | "downloader" : "com.download.library:Downloader:4.1.3",
98 |
99 | //防崩溃
100 | "customactivityoncrash" : "cat.ereza:customactivityoncrash:2.3.0",
101 |
102 | ]
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
29 |
30 |
31 |
36 |
37 |
43 |
44 |
52 |
53 |
57 |
58 |
64 |
65 |
72 |
73 |
80 |
81 |
88 |
89 |
90 |
91 |
95 |
96 |
102 |
103 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------