Last active
February 21, 2018 14:06
-
-
Save PrashamTrivedi/9e7d4d89eedd39ffe8f06b44f4e817a6 to your computer and use it in GitHub Desktop.
Code for blogpost. Koroutines, MVP+VM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed class ApiResponse<T> { | |
class Loading<Unit> : ApiResponse<Unit>() | |
class Nothing<Unit> : ApiResponse<Unit>() | |
class NoInternet<Unit> : ApiResponse<Unit>() | |
class ConnectionError<Unit>(val throwable: Throwable, val error: String) : ApiResponse<Unit>() | |
data class Success<T>(val response: Response<T>, | |
val data: T? = response.body(), | |
val headers: Headers? = response.headers()) : ApiResponse<T>() | |
data class SuccessData<T>(val data: T?) : ApiResponse<T>() | |
open class WebserviceError<Unit>(open val errorMessage: String, | |
val throwable: Throwable = RuntimeException(errorMessage), | |
val errorCode: Int = 0) : ApiResponse<Unit>() | |
class ServerBusyError<Unit>(override val errorMessage: String) : WebserviceError<Unit>( | |
errorMessage = errorMessage, | |
errorCode = 503) | |
class UnauthorizedError<Unit>(override val errorMessage: String) : WebserviceError<Unit>( | |
errorMessage = errorMessage, | |
errorCode = 401) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun <T> Throwable.parseWsError(): ApiResponse<T> { | |
val defaultMessage = "Something has gone wrong" | |
val offlineMessage = "You are currently offline." | |
return when { | |
this is HttpException -> this.parseWsError(defaultMessage) | |
this is UnknownHostException -> NoInternet() | |
this is HttpException -> ConnectionError(this, offlineMessage) | |
this is SocketTimeoutException -> ConnectionError(this, offlineMessage) | |
this is SocketException -> ConnectionError(this, offlineMessage) | |
else -> WebserviceError(errorMessage = defaultMessage) | |
} | |
} | |
private fun <T> HttpException.parseWsError(defaultMessage: String): WebserviceError<T> { | |
val message = response().errorBody()?.string() ?: defaultMessage | |
var errorMessage = defaultMessage | |
try { | |
if (!message.isEmptyString()) { | |
val mJsonObject = JSONObject(message) | |
errorMessage = mJsonObject.optString("Message") | |
} | |
} catch (e: Exception) { | |
e.printStackTrace() | |
} | |
val code = response().code() | |
return when (code) { | |
401 -> UnauthorizedError(errorMessage = errorMessage) | |
503 -> ServerBusyError(errorMessage = errorMessage) | |
else -> WebserviceError(errorMessage = errorMessage, errorCode = code) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class LoginActivity : AppCompatActivity() { | |
@Inject lateinit var loginPresenter: LoginPresenter | |
lateinit var binding: ActivityLoginBinding | |
val loginViewModel: LoginViewmodel by lazy { | |
LoginViewmodel() | |
} | |
override fun onCreate(savedInstanceState: Bundle?) { | |
AndroidInjection.inject(this) | |
super.onCreate(savedInstanceState) | |
binding = DataBindingUtil.setContentView(this, R.layout.activity_login) | |
binding.login = loginViewModel | |
btnSignIn.setOnClickListener { | |
if (loginViewModel.isValid) { | |
loginPresenter.doLogin(loginViewModel.loginModel) | |
} | |
} | |
observe(loginPresenter.loginResponse) { | |
when (it) { | |
is Loading -> showLoading() | |
is SuccessData<LoginResponse> -> handleData(it.data) | |
is WebserviceError -> handleError(it.throwable) | |
} | |
} | |
} | |
private fun handleError(throwable: Throwable) { | |
hideLoading() | |
} | |
private fun handleData(data: LoginResponse?) { | |
hideLoading() | |
d("Login resp: $data") | |
} | |
private fun showLoading() { | |
btnSignIn.setVisible(false) | |
progressBar.setVisible(true) | |
} | |
private fun hideLoading() { | |
btnSignIn.setVisible(true) | |
progressBar.setVisible(false) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface LoginApi { | |
//Here all classes LoginRequest, LoginResponse etc are just placeholder for your actual classes | |
@POST("{Your own url}") | |
fun loginUser(@Body loginRequest: LoginRequest): Call<LoginResponse> | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typealias LiveDataApi<T> = LiveData<ApiResponse<T>> | |
typealias MutableLiveDataApi<T> = MutableLiveData<ApiResponse<T>> | |
typealias Presenter = ViewModel | |
class LoginPresenter(val loginApi: LoginApi) : Presenter() { | |
private val loginData = MutableLiveDataApi<LoginResponse>().apply { value = Nothing() } | |
val loginResponse: LiveDataApi<LoginResponse> = loginData | |
private val loginActor = actor<LoginRequest>(context = UI, capacity = Channel.CONFLATED) { | |
for (loginRequest in this) { | |
loginData.value = Loading() | |
try { | |
val loginResponse = loginApi.loginUser(loginRequest).await() | |
loginData.value = SuccessData(data = loginResponse) | |
} catch (e: Exception) { | |
loginData.value = e.parseWsError() | |
} | |
} | |
} | |
fun doLogin(loginRequest: LoginRequest) = loginActor.offer(loginRequest) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class LoginViewmodel : BaseObservable() { | |
var userName: String = "" | |
@Bindable get | |
var password: String = "" | |
@Bindable get | |
var userNameError: String = "" | |
@Bindable get | |
var passwordError: String = "" | |
@Bindable get | |
val isValid: Boolean | |
get() { | |
userNameError = "" | |
notifyPropertyChanged(BR.userNameError) | |
passwordError = "" | |
notifyPropertyChanged(BR.passwordError) | |
return when { | |
userName.isEmptyString() -> { | |
userNameError = "Please enter username" | |
notifyPropertyChanged(BR.userNameError) | |
false | |
} | |
password.isEmptyString() -> { | |
passwordError = "Please enter password" | |
notifyPropertyChanged(BR.passwordError) | |
false | |
} | |
else -> true | |
} | |
} | |
val loginModel: LoginRequest | |
get() = LoginRequest(userName = userName, password = password) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment