Upstream changes (#23)
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ApiResponse<T>(
|
||||
@Json(name = "error") val error: RestApiError?,
|
||||
@Json(name = "response") val response: T?
|
||||
) {
|
||||
val isSuccessful get() = error == null && response != null
|
||||
|
||||
fun requireResponse(): T = requireNotNull(response)
|
||||
fun requireError(): RestApiError = requireNotNull(error)
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
import com.slack.eithernet.ApiResult
|
||||
|
||||
fun <Success : Any, Error : Any, SuccessDomain : Any, ErrorDomain : Any>
|
||||
ApiResult<Success, Error>.mapResult(
|
||||
successMapper: (Success) -> SuccessDomain,
|
||||
errorMapper: (Error?) -> ErrorDomain?
|
||||
): ApiResult<SuccessDomain, ErrorDomain> {
|
||||
if (BuildConfig.DEBUG) printStackTraceIfAny()
|
||||
|
||||
return when (this) {
|
||||
is ApiResult.Success -> {
|
||||
ApiResult.success(successMapper(value))
|
||||
}
|
||||
|
||||
is ApiResult.Failure.NetworkFailure -> {
|
||||
ApiResult.networkFailure(error)
|
||||
}
|
||||
|
||||
is ApiResult.Failure.UnknownFailure -> {
|
||||
ApiResult.unknownFailure(error)
|
||||
}
|
||||
|
||||
is ApiResult.Failure.HttpFailure -> {
|
||||
ApiResult.httpFailure(code, errorMapper(error))
|
||||
}
|
||||
|
||||
is ApiResult.Failure.ApiFailure -> {
|
||||
ApiResult.apiFailure(errorMapper(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <Success : Any, Error : Any, SuccessDomain : Any, ErrorDomain : Any>
|
||||
ApiResult<Success, Error>.mapOAuthResult(
|
||||
successMapper: (Success) -> SuccessDomain,
|
||||
errorMapper: (Error?) -> ErrorDomain?
|
||||
): ApiResult<SuccessDomain, ErrorDomain> {
|
||||
if (BuildConfig.DEBUG) printStackTraceIfAny()
|
||||
|
||||
return when (this) {
|
||||
is ApiResult.Success -> {
|
||||
ApiResult.success(successMapper(value))
|
||||
}
|
||||
|
||||
is ApiResult.Failure.NetworkFailure -> {
|
||||
ApiResult.networkFailure(error)
|
||||
}
|
||||
|
||||
is ApiResult.Failure.UnknownFailure -> {
|
||||
ApiResult.unknownFailure(error)
|
||||
}
|
||||
|
||||
is ApiResult.Failure.HttpFailure -> {
|
||||
|
||||
ApiResult.httpFailure(code, errorMapper(error))
|
||||
}
|
||||
|
||||
is ApiResult.Failure.ApiFailure -> {
|
||||
ApiResult.apiFailure(errorMapper(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <Success : ApiResponse<*>, SuccessDomain : Any, ErrorDomain : Any>
|
||||
ApiResult<Success, RestApiError>.mapApiResult(
|
||||
successMapper: (Success) -> SuccessDomain,
|
||||
errorMapper: (RestApiError?) -> ErrorDomain?
|
||||
): ApiResult<SuccessDomain, ErrorDomain> {
|
||||
if (BuildConfig.DEBUG) printStackTraceIfAny()
|
||||
|
||||
return when (this) {
|
||||
is ApiResult.Success -> {
|
||||
if (value.isSuccessful) {
|
||||
ApiResult.success(successMapper(value))
|
||||
} else {
|
||||
ApiResult.apiFailure(errorMapper(value.error))
|
||||
}
|
||||
}
|
||||
|
||||
is ApiResult.Failure.NetworkFailure -> ApiResult.networkFailure(error)
|
||||
is ApiResult.Failure.UnknownFailure -> ApiResult.unknownFailure(error)
|
||||
is ApiResult.Failure.HttpFailure -> ApiResult.httpFailure(code, errorMapper(error))
|
||||
is ApiResult.Failure.ApiFailure -> ApiResult.apiFailure(errorMapper(error))
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any, R : ApiResponse<T>> ApiResult<R, RestApiError>.mapApiDefault(): ApiResult<T, RestApiErrorDomain> =
|
||||
mapResult(
|
||||
successMapper = { response -> response.requireResponse() },
|
||||
errorMapper = { error -> error?.toDomain() }
|
||||
)
|
||||
|
||||
//@OptIn(ExperimentalContracts::class)
|
||||
//inline fun <R : Any, E : Any, C> OAuthResponse<R, E>.fold(
|
||||
// onSuccess: (value: R) -> C,
|
||||
// onFailure: (failure: E) -> C,
|
||||
//): C {
|
||||
// contract {
|
||||
// callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
|
||||
// callsInPlace(onFailure, InvocationKind.AT_MOST_ONCE)
|
||||
// }
|
||||
// return when (this) {
|
||||
// is OAuthResponse.Success -> onSuccess(response)
|
||||
// is OAuthResponse.Error -> onFailure(error)
|
||||
// }
|
||||
//}
|
||||
|
||||
fun <Success : Any, Error : Any> ApiResult<Success, Error>.isSuccess(): Boolean =
|
||||
this is ApiResult.Success
|
||||
|
||||
fun <Success : Any, Error : Any> ApiResult<Success, Error>.printStackTraceIfAny() {
|
||||
val throwable = when (this) {
|
||||
is ApiResult.Failure.NetworkFailure -> error
|
||||
is ApiResult.Failure.UnknownFailure -> error
|
||||
else -> null
|
||||
}
|
||||
throwable?.printStackTrace()
|
||||
}
|
||||
|
||||
fun ApiResult.Failure.HttpFailure<*>?.tryCastToRestErrorDomain() =
|
||||
this?.error as? RestApiErrorDomain
|
||||
|
||||
fun ApiResult.Failure.ApiFailure<*>?.tryCastToRestErrorDomain() =
|
||||
this?.error as? RestApiErrorDomain
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
import java.lang.reflect.Type
|
||||
|
||||
interface JsonConverter {
|
||||
|
||||
fun fromJson(clazz: Class<*>, jsonString: String): Any?
|
||||
|
||||
fun fromJson(type: Type, jsonString: String): Any?
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import java.lang.reflect.Type
|
||||
|
||||
internal class MoshiConverter(private val moshi: Moshi) : JsonConverter {
|
||||
|
||||
@kotlin.jvm.Throws(RuntimeException::class)
|
||||
override fun fromJson(clazz: Class<*>, jsonString: String): Any? {
|
||||
return moshi.adapter(clazz).fromJson(jsonString)
|
||||
}
|
||||
|
||||
@kotlin.jvm.Throws(RuntimeException::class)
|
||||
override fun fromJson(type: Type, jsonString: String): Any? {
|
||||
return moshi.adapter<Any>(type).fromJson(jsonString)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
// TODO: 09/05/2024, Danil Nikolaev: reimplement as sealed class
|
||||
@JsonClass(generateAdapter = true)
|
||||
open class OAuthError(
|
||||
@Json(name = "error") open val error: String,
|
||||
@Json(name = "error_description") open val errorDescription: String?,
|
||||
@Json(name = "error_type") open val errorType: String?
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ValidationRequiredError(
|
||||
@Json(name = "error") override val error: String, // "need_validation"
|
||||
@Json(name = "error_description") override val errorDescription: String, // "sms sent, use code param" if sms method; "use app code" if 2fa app
|
||||
@Json(name = "validation_type") val validationType: String, // 2fa_app, 2sa_sms
|
||||
@Json(name = "validation_sid") val validationSid: String,
|
||||
@Json(name = "phone_mask") val phoneMask: String, // "+7 *** *** ** 50"
|
||||
@Json(name = "redirect_uri") val redirectUri: String,
|
||||
@Json(name = "validation_resend") val validationResend: String?, // Приходит, если для отправки кода нужно вызвать метод auth.validatePhone
|
||||
@Json(name = "cant_get_code_open_restore") val restoreIfCannotGetCode: Boolean?
|
||||
) : OAuthError(
|
||||
error = error,
|
||||
errorDescription = errorDescription,
|
||||
errorType = null
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CaptchaRequiredError(
|
||||
@Json(name = "error") override val error: String, // "need_captcha"
|
||||
@Json(name = "captcha_sid") val captchaSid: String,
|
||||
@Json(name = "captcha_img") val captchaImage: String,
|
||||
@Json(name = "captcha_ts") val captchaTs: Double?,
|
||||
@Json(name = "captcha_ratio") val captchaRatio: Double?,
|
||||
@Json(name = "captcha_track") val captchaTrack: String?,
|
||||
@Json(name = "is_refresh_enabled") val isRefreshEnabled: Boolean?,
|
||||
@Json(name = "is_sound_captcha_available") val isSoundCaptchaAvailable: Boolean?
|
||||
) : OAuthError(
|
||||
error = error,
|
||||
errorDescription = null,
|
||||
errorType = null
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class UserBannedError(
|
||||
@Json(name = "error") override val error: String, // need_validation
|
||||
@Json(name = "error_description") override val errorDescription: String, // user has been banned
|
||||
@Json(name = "ban_info") val banInfo: BanInfo
|
||||
) : OAuthError(
|
||||
error = error,
|
||||
errorDescription = errorDescription,
|
||||
errorType = null
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class BanInfo(
|
||||
@Json(name = "member_name") val memberName: String,
|
||||
@Json(name = "message") val message: String,
|
||||
@Json(name = "access_token") val accessToken: String,
|
||||
@Json(name = "restore_url") val restoreUrl: String
|
||||
)
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class InvalidCredentialsError(
|
||||
@Json(name = "error") override val error: String, // "invalid_client"
|
||||
@Json(name = "error_description") override val errorDescription: String,
|
||||
@Json(name = "error_type") override val errorType: String // "username_or_password_is_incorrect"
|
||||
) : OAuthError(
|
||||
error = error,
|
||||
errorDescription = errorDescription,
|
||||
errorType = errorType
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WrongTwoFaCode(
|
||||
@Json(name = "error") override val error: String, // "invalid_request"
|
||||
@Json(name = "error_description") override val errorDescription: String,
|
||||
@Json(name = "error_type") override val errorType: String // "wrong_otp"
|
||||
) : OAuthError(
|
||||
error = error,
|
||||
errorDescription = errorDescription,
|
||||
errorType = errorType
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WrongTwoFaCodeFormat(
|
||||
@Json(name = "error") override val error: String, // "invalid_request"
|
||||
@Json(name = "error_description") override val errorDescription: String,
|
||||
@Json(name = "error_type") override val errorType: String // "otp_format_is_incorrect"
|
||||
) : OAuthError(
|
||||
error = error,
|
||||
errorDescription = errorDescription,
|
||||
errorType = errorType
|
||||
)
|
||||
|
||||
fun OAuthError.toDomain(): OAuthErrorDomain? = when (this) {
|
||||
is ValidationRequiredError -> {
|
||||
OAuthErrorDomain.ValidationRequiredError(
|
||||
description = errorDescription,
|
||||
validationType = ValidationType.parse(validationType),
|
||||
validationSid = validationSid,
|
||||
phoneMask = phoneMask,
|
||||
redirectUri = redirectUri,
|
||||
validationResend = validationResend,
|
||||
restoreIfCannotGetCode = restoreIfCannotGetCode
|
||||
)
|
||||
}
|
||||
|
||||
is CaptchaRequiredError -> {
|
||||
OAuthErrorDomain.CaptchaRequiredError(
|
||||
captchaSid = captchaSid,
|
||||
captchaImageUrl = captchaImage
|
||||
)
|
||||
}
|
||||
|
||||
is UserBannedError -> {
|
||||
OAuthErrorDomain.UserBannedError(
|
||||
memberName = banInfo.memberName,
|
||||
message = banInfo.message,
|
||||
accessToken = banInfo.accessToken,
|
||||
restoreUrl = banInfo.restoreUrl
|
||||
)
|
||||
}
|
||||
|
||||
is InvalidCredentialsError -> {
|
||||
OAuthErrorDomain.InvalidCredentialsError
|
||||
}
|
||||
|
||||
is WrongTwoFaCode -> {
|
||||
OAuthErrorDomain.WrongTwoFaCode
|
||||
}
|
||||
|
||||
is WrongTwoFaCodeFormat -> {
|
||||
OAuthErrorDomain.WrongTwoFaCodeFormat
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
sealed class OAuthErrorDomain {
|
||||
|
||||
data class ValidationRequiredError(
|
||||
val description: String,
|
||||
val validationType: ValidationType,
|
||||
val validationSid: String,
|
||||
val phoneMask: String,
|
||||
val redirectUri: String,
|
||||
val validationResend: String?,
|
||||
val restoreIfCannotGetCode: Boolean?
|
||||
) : OAuthErrorDomain()
|
||||
|
||||
data class CaptchaRequiredError(
|
||||
val captchaSid: String,
|
||||
val captchaImageUrl: String
|
||||
) : OAuthErrorDomain()
|
||||
|
||||
data class UserBannedError(
|
||||
val memberName: String,
|
||||
val message: String,
|
||||
val accessToken: String,
|
||||
val restoreUrl: String
|
||||
) : OAuthErrorDomain()
|
||||
|
||||
data object InvalidCredentialsError : OAuthErrorDomain()
|
||||
data object WrongTwoFaCode : OAuthErrorDomain()
|
||||
data object WrongTwoFaCodeFormat : OAuthErrorDomain()
|
||||
data object UnknownError : OAuthErrorDomain()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
sealed interface OAuthResponse<out R : Any, out E : Any> {
|
||||
|
||||
data class Success<out R : Any>(val response: R) : OAuthResponse<R, Nothing>
|
||||
|
||||
data class Error<out E : Any>(val error: E?) : OAuthResponse<Nothing, E>
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
import android.util.Log
|
||||
import com.squareup.moshi.Moshi
|
||||
import okhttp3.Request
|
||||
import okio.Timeout
|
||||
import retrofit2.Call
|
||||
import retrofit2.CallAdapter
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import retrofit2.Retrofit
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
|
||||
class OAuthResultCallFactory(private val moshi: Moshi) : CallAdapter.Factory() {
|
||||
|
||||
override fun get(
|
||||
returnType: Type,
|
||||
annotations: Array<out Annotation>,
|
||||
retrofit: Retrofit,
|
||||
): CallAdapter<*, *>? {
|
||||
val rawReturnType: Class<*> = getRawType(returnType)
|
||||
|
||||
if (rawReturnType == Call::class.java) {
|
||||
if (returnType is ParameterizedType) {
|
||||
val callInnerType: Type = getParameterUpperBound(0, returnType)
|
||||
|
||||
if (getRawType(callInnerType) == OAuthResponse::class.java) {
|
||||
if (callInnerType is ParameterizedType) {
|
||||
val resultInnerType = getParameterUpperBound(0, callInnerType)
|
||||
return ResultCallAdapter<Any, OAuthError>(resultInnerType, moshi)
|
||||
}
|
||||
|
||||
return ResultCallAdapter<Nothing, Nothing>(Nothing::class.java, moshi)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class CallDelegate<In, Out>(protected val proxy: Call<In>) : Call<Out> {
|
||||
|
||||
override fun execute(): Response<Out> = throw NotImplementedError()
|
||||
|
||||
final override fun enqueue(callback: Callback<Out>) = enqueueImpl(callback)
|
||||
|
||||
final override fun clone(): Call<Out> = cloneImpl()
|
||||
|
||||
override fun cancel() = proxy.cancel()
|
||||
|
||||
override fun request(): Request = proxy.request()
|
||||
|
||||
override fun isExecuted() = proxy.isExecuted
|
||||
|
||||
override fun isCanceled() = proxy.isCanceled
|
||||
|
||||
abstract fun enqueueImpl(callback: Callback<Out>)
|
||||
|
||||
abstract fun cloneImpl(): Call<Out>
|
||||
}
|
||||
|
||||
private class ResultCallAdapter<R : Any, E : OAuthError>(
|
||||
private val type: Type,
|
||||
private val moshi: Moshi
|
||||
) : CallAdapter<R, Call<OAuthResponse<R, E>>> {
|
||||
|
||||
override fun responseType() = type
|
||||
|
||||
override fun adapt(call: Call<R>): Call<OAuthResponse<R, E>> = ResultCall(call, moshi)
|
||||
}
|
||||
|
||||
internal class ResultCall<R : Any, E : OAuthError>(
|
||||
proxy: Call<R>,
|
||||
private val moshi: Moshi
|
||||
) : CallDelegate<R, OAuthResponse<R, E>>(proxy) {
|
||||
|
||||
override fun enqueueImpl(callback: Callback<OAuthResponse<R, E>>) {
|
||||
proxy.enqueue(ResultCallback(this, callback, moshi))
|
||||
}
|
||||
|
||||
override fun cloneImpl(): ResultCall<R, E> {
|
||||
return ResultCall(proxy.clone(), moshi)
|
||||
}
|
||||
|
||||
private class ResultCallback<R : Any, E : OAuthError>(
|
||||
private val proxy: ResultCall<R, E>,
|
||||
private val callback: Callback<OAuthResponse<R, E>>,
|
||||
private val moshi: Moshi
|
||||
) : Callback<R> {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun onResponse(call: Call<R>, response: Response<R>) {
|
||||
when {
|
||||
response.isSuccessful -> {
|
||||
val baseBody = response.body()
|
||||
|
||||
baseBody?.let {
|
||||
callback.onResponse(
|
||||
proxy,
|
||||
Response.success(OAuthResponse.Success(baseBody))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
val errorBodyString = response.errorBody()?.string()
|
||||
|
||||
val baseError: OAuthError = moshi.adapter(OAuthError::class.java)
|
||||
.fromJson(errorBodyString.orEmpty()) ?: return
|
||||
|
||||
val error: OAuthError? = when (baseError.error) {
|
||||
"invalid_client" -> {
|
||||
moshi.adapter(InvalidCredentialsError::class.java)
|
||||
.fromJson(errorBodyString.orEmpty())
|
||||
}
|
||||
|
||||
"need_captcha" -> {
|
||||
moshi.adapter(CaptchaRequiredError::class.java)
|
||||
.fromJson(errorBodyString.orEmpty())
|
||||
}
|
||||
|
||||
"invalid_request" -> {
|
||||
when (val type = baseError.errorType) {
|
||||
"wrong_otp" -> {
|
||||
moshi.adapter(WrongTwoFaCode::class.java)
|
||||
.fromJson(errorBodyString.orEmpty())
|
||||
}
|
||||
|
||||
"otp_format_is_incorrect" -> {
|
||||
moshi.adapter(WrongTwoFaCodeFormat::class.java)
|
||||
.fromJson(errorBodyString.orEmpty())
|
||||
}
|
||||
|
||||
else -> {
|
||||
Log.d(
|
||||
"ResultCallback",
|
||||
"onResponse: invalid_request; error_type: $type"
|
||||
)
|
||||
|
||||
error("Unknown type: $type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"need_validation" -> {
|
||||
when (val description = baseError.errorDescription) {
|
||||
"user has been banned" -> {
|
||||
moshi.adapter(UserBannedError::class.java)
|
||||
.fromJson(errorBodyString.orEmpty())
|
||||
}
|
||||
|
||||
"sms sent, use code param",
|
||||
"use app code" -> {
|
||||
moshi.adapter(ValidationRequiredError::class.java)
|
||||
.fromJson(errorBodyString.orEmpty())
|
||||
}
|
||||
|
||||
else -> {
|
||||
Log.d(
|
||||
"ResultCallback",
|
||||
"onResponse: need_validation; description: $description"
|
||||
)
|
||||
|
||||
error("Unknown description: $description")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
error?.let {
|
||||
callback.onResponse(
|
||||
proxy,
|
||||
Response.success(OAuthResponse.Error(error) as OAuthResponse<R, E>)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<R>, error: Throwable) {
|
||||
val b = error
|
||||
// TODO: 12/04/2024, Danil Nikolaev: handle
|
||||
// callback.onResponse(
|
||||
// proxy,
|
||||
// Response.success(OAuthAnswer.Error((throwable = error)))
|
||||
// )
|
||||
}
|
||||
}
|
||||
|
||||
override fun timeout(): Timeout {
|
||||
return proxy.timeout()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
import android.util.Log
|
||||
import com.slack.eithernet.ApiException
|
||||
import com.slack.eithernet.errorType
|
||||
import com.slack.eithernet.toType
|
||||
import com.squareup.moshi.JsonDataException
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* конвертер пытается перевести string с сервера в SuccessType
|
||||
* если не получается, то в ErrorType и выбрасывает [ApiException]
|
||||
*
|
||||
* допускает Unit как SuccessType в случае невозможности каста ответа в ErrorType
|
||||
*/
|
||||
class ResponseConverterFactory(private val converter: JsonConverter) : Converter.Factory() {
|
||||
|
||||
override fun responseBodyConverter(
|
||||
type: Type,
|
||||
annotations: Array<out Annotation>,
|
||||
retrofit: Retrofit
|
||||
): Converter<ResponseBody, *>? {
|
||||
val (errorType, b) = annotations.errorType() ?: return null
|
||||
val errorRaw = getRawType(errorType.toType())
|
||||
return ResponseBodyConverter(
|
||||
successType = type,
|
||||
errorRaw = errorRaw,
|
||||
converter = converter,
|
||||
)
|
||||
}
|
||||
|
||||
class ResponseBodyConverter(
|
||||
private val successType: Type,
|
||||
private val errorRaw: Class<*>,
|
||||
private val converter: JsonConverter,
|
||||
) : Converter<ResponseBody, Any?> {
|
||||
override fun convert(value: ResponseBody): Any? {
|
||||
val string = value.string()
|
||||
kotlin.runCatching {
|
||||
converter.fromJson(successType, string)
|
||||
}.fold(
|
||||
onSuccess = { successModel ->
|
||||
return successModel
|
||||
},
|
||||
onFailure = { failure ->
|
||||
if(failure is JsonDataException) {
|
||||
throw failure
|
||||
}
|
||||
|
||||
val isUnit = successType == Unit::class.java
|
||||
|
||||
kotlin.runCatching {
|
||||
converter.fromJson(errorRaw, string)
|
||||
}.fold(
|
||||
onSuccess = { errorModel ->
|
||||
Log.d("ResponseBodyConverter", "convert: $errorModel")
|
||||
throw ApiException(errorModel)
|
||||
},
|
||||
onFailure = { exception ->
|
||||
if (!isUnit) {
|
||||
throw exception
|
||||
} else {
|
||||
return Unit
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RestApiError(
|
||||
// @Json(name = "code") val code: Int?,
|
||||
// @Json(name = "message") val message: String?,
|
||||
@Json(name = "error_code") val errorCode: Int,
|
||||
@Json(name = "error_msg") val errorMsg: String
|
||||
) {
|
||||
fun toDomain(): RestApiErrorDomain = RestApiErrorDomain(
|
||||
code = errorCode,
|
||||
message = errorMsg
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
data class RestApiErrorDomain(
|
||||
val code: Int,
|
||||
val message: String
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.meloda.app.fast.network;
|
||||
|
||||
enum class ValidationType(val value: String) {
|
||||
APP("2fa_app"), SMS("2fa_sms");
|
||||
|
||||
companion object {
|
||||
fun parse(value: String): ValidationType = entries.first { it.value == value }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.meloda.app.fast.network
|
||||
|
||||
@Suppress("unused")
|
||||
object VkErrorCodes {
|
||||
const val UnknownError = 1
|
||||
const val AppDisabled = 2
|
||||
const val UnknownMethod = 3
|
||||
const val InvalidSignature = 4
|
||||
const val UserAuthorizationFailed = 5
|
||||
const val TooManyRequests = 6
|
||||
const val NoRights = 7
|
||||
const val BadRequest = 8
|
||||
const val TooManySimilarActions = 9
|
||||
const val InternalServerError = 10
|
||||
const val InTestMode = 11
|
||||
const val ExecuteCodeCompileError = 12
|
||||
const val ExecuteCodeRuntimeError = 13
|
||||
const val CaptchaNeeded = 14
|
||||
const val AccessDenied = 15
|
||||
const val RequiresRequestsOverHttps = 16
|
||||
const val ValidationRequired = 17
|
||||
const val UserBannedOrDeleted = 18
|
||||
const val ActionProhibited = 20
|
||||
const val ActionAllowedOnlyForStandalone = 21
|
||||
const val MethodOff = 23
|
||||
const val ConfirmationRequired = 24
|
||||
const val ParameterIsNotSpecified = 100
|
||||
const val IncorrectAppId = 101
|
||||
const val OutOfLimits = 103
|
||||
const val IncorrectUserId = 113
|
||||
const val IncorrectTimestamp = 150
|
||||
const val AccessToAlbumDenied = 200
|
||||
const val AccessToAudioDenied = 201
|
||||
const val AccessToGroupDenied = 203
|
||||
const val AlbumIsFull = 300
|
||||
const val ActionDenied = 500
|
||||
const val PermissionDenied = 600
|
||||
const val CannotSendMessageBlackList = 900
|
||||
const val CannotSendMessageGroup = 901
|
||||
const val InvalidDocId = 1150
|
||||
const val InvalidDocTitle = 1152
|
||||
const val AccessToDocDenied = 1153
|
||||
|
||||
const val AccessTokenExpired = 1117
|
||||
}
|
||||
|
||||
object VkOAuthErrors {
|
||||
const val UNKNOWN = "unknown_error"
|
||||
|
||||
const val NEED_VALIDATION = "need_validation"
|
||||
const val NEED_CAPTCHA = "need_captcha"
|
||||
const val INVALID_CLIENT = "invalid_client"
|
||||
const val INVALID_REQUEST = "invalid_request"
|
||||
|
||||
}
|
||||
|
||||
object VkErrorTypes {
|
||||
const val WRONG_OTP_FORMAT = "otp_format_is_incorrect"
|
||||
const val WRONG_OTP = "wrong_otp"
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.meloda.app.fast.network.di
|
||||
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
import com.meloda.app.fast.common.AuthInterceptor
|
||||
import com.meloda.app.fast.network.JsonConverter
|
||||
import com.meloda.app.fast.network.MoshiConverter
|
||||
import com.meloda.app.fast.network.OAuthResultCallFactory
|
||||
import com.meloda.app.fast.network.ResponseConverterFactory
|
||||
import com.meloda.app.fast.network.service.account.AccountService
|
||||
import com.meloda.app.fast.network.service.audios.AudiosService
|
||||
import com.meloda.app.fast.network.service.auth.AuthService
|
||||
import com.meloda.app.fast.network.service.conversations.ConversationsService
|
||||
import com.meloda.app.fast.network.service.files.FilesService
|
||||
import com.meloda.app.fast.network.service.friends.FriendsService
|
||||
import com.meloda.app.fast.network.service.longpoll.LongPollService
|
||||
import com.meloda.app.fast.network.service.messages.MessagesService
|
||||
import com.meloda.app.fast.network.service.oauth.OAuthService
|
||||
import com.meloda.app.fast.network.service.photos.PhotosService
|
||||
import com.meloda.app.fast.network.service.users.UsersService
|
||||
import com.meloda.app.fast.network.service.videos.VideosService
|
||||
import com.slack.eithernet.ApiResultCallAdapterFactory
|
||||
import com.slack.eithernet.ApiResultConverterFactory
|
||||
import com.squareup.moshi.Moshi
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.qualifier.named
|
||||
import org.koin.core.scope.Scope
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
val networkModule = module {
|
||||
single { Moshi.Builder().build() }
|
||||
singleOf(::MoshiConverter) bind JsonConverter::class
|
||||
single { ChuckerCollector(get()) }
|
||||
single { ChuckerInterceptor.Builder(get()).collector(get()).build() }
|
||||
singleOf(::AuthInterceptor)
|
||||
single {
|
||||
OkHttpClient.Builder()
|
||||
.connectTimeout(20, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.addInterceptor(get<AuthInterceptor>())
|
||||
.addInterceptor(get<ChuckerInterceptor>())
|
||||
.followRedirects(true)
|
||||
.followSslRedirects(true)
|
||||
.addInterceptor(
|
||||
HttpLoggingInterceptor().apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
}
|
||||
)
|
||||
.build()
|
||||
}
|
||||
single {
|
||||
Retrofit.Builder()
|
||||
.baseUrl("${AppConstants.URL_API}/")
|
||||
.addConverterFactory(ApiResultConverterFactory)
|
||||
.addCallAdapterFactory(ApiResultCallAdapterFactory)
|
||||
.addConverterFactory(ResponseConverterFactory(get<JsonConverter>()))
|
||||
.addConverterFactory(MoshiConverterFactory.create(get()))
|
||||
.client(get())
|
||||
.build()
|
||||
}
|
||||
|
||||
singleOf(::OAuthResultCallFactory)
|
||||
single<Retrofit>(named("oauth")) {
|
||||
Retrofit.Builder()
|
||||
.baseUrl("${AppConstants.URL_OAUTH}/")
|
||||
.addCallAdapterFactory(get<OAuthResultCallFactory>())
|
||||
.addConverterFactory(MoshiConverterFactory.create(get()))
|
||||
.client(get())
|
||||
.build()
|
||||
}
|
||||
|
||||
single { service(AccountService::class.java) }
|
||||
single { service(AudiosService::class.java) }
|
||||
single { service(AuthService::class.java) }
|
||||
single { service(ConversationsService::class.java) }
|
||||
single { service(FilesService::class.java) }
|
||||
single { service(LongPollService::class.java) }
|
||||
single { service(MessagesService::class.java) }
|
||||
single { service(OAuthService::class.java) }
|
||||
// single { get<Retrofit>(named("oauth")).create(OAuthService::class.java) }
|
||||
single { service(PhotosService::class.java) }
|
||||
single { service(UsersService::class.java) }
|
||||
single { service(VideosService::class.java) }
|
||||
single { service(FriendsService::class.java) }
|
||||
}
|
||||
|
||||
private fun <T> Scope.service(className: Class<T>): T = get<Retrofit>().create(className)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.meloda.app.fast.network.service.account
|
||||
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.QueryMap
|
||||
|
||||
interface AccountService {
|
||||
|
||||
@GET(AccountUrls.SET_ONLINE)
|
||||
suspend fun setOnline(
|
||||
@QueryMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<Any>, RestApiError>
|
||||
|
||||
@POST(AccountUrls.SET_OFFLINE)
|
||||
suspend fun setOffline(
|
||||
@QueryMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<Any>, RestApiError>
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.meloda.app.fast.network.service.account
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object AccountUrls {
|
||||
const val SET_ONLINE = "${AppConstants.URL_API}/account.setOnline"
|
||||
const val SET_OFFLINE = "${AppConstants.URL_API}/account.setOffline"
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.meloda.app.fast.network.service.audios
|
||||
|
||||
import com.meloda.app.fast.model.api.data.VkAudioData
|
||||
import com.meloda.app.fast.model.api.responses.AudiosGetUploadServerResponse
|
||||
import com.meloda.app.fast.model.api.responses.AudiosUploadResponse
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import okhttp3.MultipartBody
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Part
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface AudiosService {
|
||||
|
||||
@POST(AudiosUrls.GET_UPLOAD_SERVER)
|
||||
suspend fun getUploadServer(): ApiResult<ApiResponse<AudiosGetUploadServerResponse>, RestApiError>
|
||||
|
||||
@Multipart
|
||||
@POST
|
||||
suspend fun upload(
|
||||
@Url url: String,
|
||||
@Part file: MultipartBody.Part
|
||||
): ApiResult<AudiosUploadResponse, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(AudiosUrls.SAVE)
|
||||
suspend fun save(@FieldMap map: Map<String, String>): ApiResult<ApiResponse<VkAudioData>, RestApiError>
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.meloda.app.fast.network.service.audios
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object AudiosUrls {
|
||||
|
||||
const val GET_UPLOAD_SERVER = "${AppConstants.URL_API}/audio.getUploadServer"
|
||||
|
||||
const val SAVE = "${AppConstants.URL_API}/audio.save"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.meloda.app.fast.network.service.auth
|
||||
|
||||
import com.meloda.app.fast.model.api.responses.SendSmsResponse
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface AuthService {
|
||||
|
||||
@GET(AuthUrls.SEND_SMS)
|
||||
suspend fun sendSms(@Query("sid") validationSid: String): ApiResult<ApiResponse<SendSmsResponse>, RestApiError>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.meloda.app.fast.network.service.auth
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object AuthUrls {
|
||||
|
||||
const val SEND_SMS = "${AppConstants.URL_API}/auth.validatePhone"
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.meloda.app.fast.network.service.conversations
|
||||
|
||||
import com.meloda.app.fast.model.api.responses.ConversationsDeleteResponse
|
||||
import com.meloda.app.fast.model.api.responses.ConversationsGetResponse
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface ConversationsService {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(ConversationsUrls.GET)
|
||||
suspend fun getConversations(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<ConversationsGetResponse>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(ConversationsUrls.DELETE)
|
||||
suspend fun delete(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<ConversationsDeleteResponse>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(ConversationsUrls.PIN)
|
||||
suspend fun pin(@FieldMap params: Map<String, String>): ApiResult<ApiResponse<Int>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(ConversationsUrls.UNPIN)
|
||||
suspend fun unpin(@FieldMap params: Map<String, String>): ApiResult<ApiResponse<Int>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(ConversationsUrls.REORDER_PINNED)
|
||||
suspend fun reorderPinned(@FieldMap params: Map<String, String>): ApiResult<Unit, RestApiError>
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.meloda.app.fast.network.service.conversations
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object ConversationsUrls {
|
||||
|
||||
const val GET = "${AppConstants.URL_API}/messages.getConversations"
|
||||
const val DELETE = "${AppConstants.URL_API}/messages.deleteConversation"
|
||||
const val PIN = "${AppConstants.URL_API}/messages.pinConversation"
|
||||
const val UNPIN = "${AppConstants.URL_API}/messages.unpinConversation"
|
||||
const val REORDER_PINNED = "${AppConstants.URL_API}/messages.reorderPinnedConversations"
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.meloda.app.fast.network.service.files
|
||||
|
||||
import com.meloda.app.fast.model.api.responses.FilesGetMessagesUploadServerResponse
|
||||
import com.meloda.app.fast.model.api.responses.FilesSaveFileResponse
|
||||
import com.meloda.app.fast.model.api.responses.FilesUploadFileResponse
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import okhttp3.MultipartBody
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Part
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface FilesService {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(FilesUrls.GET_MESSAGES_UPLOAD_SERVER)
|
||||
suspend fun getUploadServer(
|
||||
@FieldMap map: Map<String, String>
|
||||
): ApiResult<ApiResponse<FilesGetMessagesUploadServerResponse>, RestApiError>
|
||||
|
||||
@Multipart
|
||||
@POST
|
||||
suspend fun upload(
|
||||
@Url url: String,
|
||||
@Part file: MultipartBody.Part
|
||||
): ApiResult<FilesUploadFileResponse, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(FilesUrls.SAVE)
|
||||
suspend fun save(
|
||||
@FieldMap map: Map<String, String>
|
||||
): ApiResult<ApiResponse<FilesSaveFileResponse>, RestApiError>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.meloda.app.fast.network.service.files
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object FilesUrls {
|
||||
|
||||
const val GET_MESSAGES_UPLOAD_SERVER = "${AppConstants.URL_API}/docs.getMessagesUploadServer"
|
||||
|
||||
const val SAVE = "${AppConstants.URL_API}/docs.save"
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.meloda.app.fast.network.service.friends
|
||||
|
||||
import com.meloda.app.fast.model.api.responses.GetFriendsResponse
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface FriendsService {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(FriendsUrls.GET)
|
||||
suspend fun getFriends(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<GetFriendsResponse>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(FriendsUrls.GET_ONLINE)
|
||||
suspend fun getOnlineFriends(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<List<Int>>, RestApiError>
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.meloda.app.fast.network.service.friends
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object FriendsUrls {
|
||||
|
||||
const val GET = "${AppConstants.URL_API}/friends.get"
|
||||
const val GET_ONLINE = "${AppConstants.URL_API}/friends.getOnline"
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.meloda.app.fast.network.service.longpoll
|
||||
|
||||
import com.meloda.app.fast.model.api.data.LongPollUpdates
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.QueryMap
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface LongPollService {
|
||||
|
||||
@GET
|
||||
suspend fun getResponse(
|
||||
@Url serverUrl: String,
|
||||
@QueryMap params: Map<String, String>
|
||||
): ApiResult<LongPollUpdates, RestApiError>
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package com.meloda.app.fast.network.service.messages
|
||||
|
||||
import com.meloda.app.fast.model.api.data.VkLongPollData
|
||||
import com.meloda.app.fast.model.api.responses.MessagesGetByIdResponse
|
||||
import com.meloda.app.fast.model.api.responses.MessagesGetHistoryResponse
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface MessagesService {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(MessagesUrls.GET_HISTORY)
|
||||
suspend fun getHistory(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<MessagesGetHistoryResponse>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(MessagesUrls.GET_BY_ID)
|
||||
suspend fun getById(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<MessagesGetByIdResponse>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(MessagesUrls.SEND)
|
||||
suspend fun send(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<Int>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(MessagesUrls.GET_LONG_POLL_SERVER)
|
||||
suspend fun getLongPollServer(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<VkLongPollData>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(MessagesUrls.MARK_AS_READ)
|
||||
suspend fun markAsRead(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<Int>, RestApiError>
|
||||
|
||||
// @FormUrlEncoded
|
||||
// @POST(MessagesUrls.MarkAsImportant)
|
||||
// suspend fun markAsImportant(
|
||||
// @FieldMap params: Map<String, String>
|
||||
// ): ApiResult<ApiResponse<List<Int>>, RestApiError>
|
||||
//
|
||||
// @FormUrlEncoded
|
||||
// @POST(MessagesUrls.Pin)
|
||||
// suspend fun pin(
|
||||
// @FieldMap params: Map<String, String>
|
||||
// ): ApiResult<ApiResponse<VkMessageData>, RestApiError>
|
||||
//
|
||||
// @FormUrlEncoded
|
||||
// @POST(MessagesUrls.Unpin)
|
||||
// suspend fun unpin(
|
||||
// @FieldMap params: Map<String, String>
|
||||
// ): ApiResult<ApiResponse<Unit>, RestApiError>
|
||||
//
|
||||
// @FormUrlEncoded
|
||||
// @POST(MessagesUrls.Delete)
|
||||
// suspend fun delete(
|
||||
// @FieldMap params: Map<String, String>
|
||||
// ): ApiResult<ApiResponse<Unit>, RestApiError>
|
||||
//
|
||||
// @FormUrlEncoded
|
||||
// @POST(MessagesUrls.Edit)
|
||||
// suspend fun edit(
|
||||
// @FieldMap params: Map<String, String>
|
||||
// ): ApiResult<ApiResponse<Int>, RestApiError>
|
||||
//
|
||||
//
|
||||
// @FormUrlEncoded
|
||||
// @POST(MessagesUrls.GetChat)
|
||||
// suspend fun getChat(
|
||||
// @FieldMap params: Map<String, String>
|
||||
// ): ApiResult<ApiResponse<VkChatData>, RestApiError>
|
||||
//
|
||||
// @FormUrlEncoded
|
||||
// @POST(MessagesUrls.GetConversationMembers)
|
||||
// suspend fun getConversationMembers(
|
||||
// @FieldMap params: Map<String, String>
|
||||
// ): ApiResult<ApiResponse<MessagesGetConversationMembersResponse>, RestApiError>
|
||||
//
|
||||
// @FormUrlEncoded
|
||||
// @POST(MessagesUrls.RemoveChatUser)
|
||||
// suspend fun removeChatUser(
|
||||
// @FieldMap params: Map<String, String>
|
||||
// ): ApiResult<ApiResponse<Int>, RestApiError>
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.meloda.app.fast.network.service.messages
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object MessagesUrls {
|
||||
|
||||
const val GET_HISTORY = "${AppConstants.URL_API}/messages.getHistory"
|
||||
const val SEND = "${AppConstants.URL_API}/messages.send"
|
||||
const val MARK_AS_IMPORTANT = "${AppConstants.URL_API}/messages.markAsImportant"
|
||||
const val GET_LONG_POLL_SERVER = "${AppConstants.URL_API}/messages.getLongPollServer"
|
||||
const val GET_LONG_POLL_HISTORY = "${AppConstants.URL_API}/messages.getLongPollHistory"
|
||||
const val PIN = "${AppConstants.URL_API}/messages.pin"
|
||||
const val UNPIN = "${AppConstants.URL_API}/messages.unpin"
|
||||
const val DELETE = "${AppConstants.URL_API}/messages.delete"
|
||||
const val EDIT = "${AppConstants.URL_API}/messages.edit"
|
||||
const val GET_BY_ID = "${AppConstants.URL_API}/messages.getById"
|
||||
const val MARK_AS_READ = "${AppConstants.URL_API}/messages.markAsRead"
|
||||
const val GET_CHAT = "${AppConstants.URL_API}/messages.getChat"
|
||||
const val GET_CONVERSATIONS_MEMBERS = "${AppConstants.URL_API}/messages.getConversationMembers"
|
||||
const val REMOVE_CHAT_USER = "${AppConstants.URL_API}/messages.removeChatUser"
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.meloda.app.fast.network.service.oauth
|
||||
|
||||
import com.meloda.app.fast.model.api.responses.AuthDirectResponse
|
||||
import com.slack.eithernet.ApiResult
|
||||
import com.slack.eithernet.DecodeErrorBody
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.QueryMap
|
||||
|
||||
interface OAuthService {
|
||||
|
||||
@DecodeErrorBody
|
||||
@GET(OAuthUrls.DIRECT_AUTH)
|
||||
suspend fun auth(
|
||||
@QueryMap param: Map<String, String?>
|
||||
): ApiResult<AuthDirectResponse, AuthDirectResponse>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.meloda.app.fast.network.service.oauth
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object OAuthUrls {
|
||||
|
||||
const val DIRECT_AUTH = "${AppConstants.URL_OAUTH}/token"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.meloda.app.fast.network.service.photos
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object PhotoUrls {
|
||||
|
||||
const val GET_MESSAGES_UPLOAD_SERVER = "${AppConstants.URL_API}/photos.getMessagesUploadServer"
|
||||
|
||||
const val SAVE_MESSAGE_PHOTO = "${AppConstants.URL_API}/photos.saveMessagesPhoto"
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.meloda.app.fast.network.service.photos
|
||||
|
||||
import com.meloda.app.fast.model.api.data.VkPhotoData
|
||||
import com.meloda.app.fast.model.api.responses.PhotosGetMessagesUploadServerResponse
|
||||
import com.meloda.app.fast.model.api.responses.PhotosUploadPhotoResponse
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import okhttp3.MultipartBody
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Part
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface PhotosService {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(PhotoUrls.GET_MESSAGES_UPLOAD_SERVER)
|
||||
suspend fun getUploadServer(
|
||||
@FieldMap map: Map<String, String>
|
||||
): ApiResult<ApiResponse<PhotosGetMessagesUploadServerResponse>, RestApiError>
|
||||
|
||||
@Multipart
|
||||
@POST
|
||||
suspend fun upload(
|
||||
@Url url: String,
|
||||
@Part photo: MultipartBody.Part
|
||||
): ApiResult<PhotosUploadPhotoResponse, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(PhotoUrls.SAVE_MESSAGE_PHOTO)
|
||||
suspend fun save(
|
||||
@FieldMap map: Map<String, String>
|
||||
): ApiResult<ApiResponse<List<VkPhotoData>>, RestApiError>
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.meloda.app.fast.network.service.users
|
||||
|
||||
import com.meloda.app.fast.model.api.data.VkUserData
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface UsersService {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(UsersUrls.GET_BY_ID)
|
||||
suspend fun getById(
|
||||
@FieldMap params: Map<String, String>?
|
||||
): ApiResult<ApiResponse<List<VkUserData>>, RestApiError>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.meloda.app.fast.network.service.users
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object UsersUrls {
|
||||
|
||||
const val GET_BY_ID = "${AppConstants.URL_API}/users.get"
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.meloda.app.fast.network.service.videos
|
||||
|
||||
import com.meloda.app.fast.model.api.responses.VideosSaveResponse
|
||||
import com.meloda.app.fast.model.api.responses.VideosUploadResponse
|
||||
import com.meloda.app.fast.network.ApiResponse
|
||||
import com.meloda.app.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import okhttp3.MultipartBody
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Part
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface VideosService {
|
||||
|
||||
@POST(VideosUrls.SAVE)
|
||||
suspend fun save(): ApiResult<ApiResponse<VideosSaveResponse>, RestApiError>
|
||||
|
||||
@Multipart
|
||||
@POST
|
||||
suspend fun upload(
|
||||
@Url url: String,
|
||||
@Part file: MultipartBody.Part
|
||||
): ApiResult<VideosUploadResponse, RestApiError>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.meloda.app.fast.network.service.videos
|
||||
|
||||
import com.meloda.app.fast.common.AppConstants
|
||||
|
||||
object VideosUrls {
|
||||
|
||||
const val SAVE = "${AppConstants.URL_API}/video.save"
|
||||
}
|
||||
Reference in New Issue
Block a user