Skip to content

Commit

Permalink
Ref #18: add paging source for matches
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitry Kazakov committed Mar 20, 2023
1 parent 438727b commit f7d8ab8
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ interface IPersonRepository {
fun removeDemand(contact: String, secret: String, id: Long): Flow<PersonRepository.Response<PersonProfile>>
fun getContacts(contact: String, secret: String, serviceId: Long): Flow<PersonRepository.Response<PersonProfile>>
fun cleanCachedAccount(): Flow<Any>

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ru.home.swap.App
import ru.home.swap.R
import ru.home.swap.core.converters.ApiResponseConverter
import ru.home.swap.core.extensions.attachIdlingResource
import ru.home.swap.core.logger.Logger
import ru.home.swap.core.model.PersonProfile
import ru.home.swap.core.model.Service
import ru.home.swap.core.network.IApi
Expand All @@ -17,50 +18,52 @@ import java.net.HttpURLConnection

class PersonRepository(val api: IApi, val cache: Cache, val context: Context): IPersonRepository {

private var logger: Logger = Logger.getInstance()

override fun createAccountAsFlow(person: PersonProfile): Flow<Response<PersonProfile>> {
return flow {
Log.d(App.TAG, "[a] createProfile() call")
logger.d( "[a] createProfile() call")
val response = api.createProfile(
credentials = AppCredentials.basic(person.contact, person.secret),
person = person
)
Log.d(App.TAG, "[b] get profile response")
logger.d( "[b] get profile response")
if (response.isSuccessful) {
Log.d(App.TAG, "[c] response is ok")
logger.d( "[c] response is ok")
var payload = response.body()!!
emit(Response.Data(payload.payload))
} else {
Log.d(App.TAG, "[d] response is not ok")
logger.d( "[d] response is not ok")
val errorPayload = ApiResponseConverter().toDomain(response.errorBody()?.string()!!);
emit(Response.Error.Message("${response.message()}:\n\n${errorPayload.payload}"))
}
}
.catch { ex ->
Log.e(App.TAG, "Failed to create account and process result on network layer", ex)
logger.e( "Failed to create account and process result on network layer", ex)
emit(Response.Error.Exception(ex))
}
}

override suspend fun createAccount(person: PersonProfile): Response<PersonProfile> {
lateinit var result: Response<PersonProfile>
try {
Log.d(App.TAG, "[a] createProfile() call")
logger.d( "[a] createProfile() call")
val response = api.createProfile(
credentials = AppCredentials.basic(person.contact, person.secret),
person = person
)
Log.d(App.TAG, "[b] get profile response")
logger.d( "[b] get profile response")
if (response.isSuccessful) {
Log.d(App.TAG, "[c] response is ok")
logger.d( "[c] response is ok")
var payload = response.body()!!
result = Response.Data(payload.payload)
} else {
Log.d(App.TAG, "[d] response is not ok")
logger.d( "[d] response is not ok")
val errorPayload = ApiResponseConverter().toDomain(response.errorBody()?.string()!!);
result = Response.Error.Message("${response.message()}:\n\n${errorPayload.payload}")
}
} catch (ex: Exception) {
Log.e(App.TAG, "Failed to create account and process result on network layer", ex)
logger.e("Failed to create account and process result on network layer", ex)
result = Response.Error.Exception(ex)
}
return result
Expand All @@ -84,33 +87,33 @@ class PersonRepository(val api: IApi, val cache: Cache, val context: Context): I

override fun getAccount(person: PersonProfile): Flow<Response<PersonProfile>> {
return flow {
Log.d(App.TAG, "[a] getProfile() call")
logger.d( "[a] getProfile() call")
val response = api.getProfile(
credentials = AppCredentials.basic(person.contact, person.secret)
)
if (response.isSuccessful) {
Log.d(App.TAG, "[b1] get body and emit")
logger.d( "[b1] get body and emit")
if (response.code() == HttpURLConnection.HTTP_NO_CONTENT) {
emit(Response.Error.Message(context.getString(R.string.error_no_data_for_your_params)))
} else {
val payload = response.body()!!
emit(Response.Data(payload.payload))
}
} else {
Log.d(App.TAG, "[b2] get error and emit")
logger.d( "[b2] get error and emit")
emit(Response.Error.Message(response.message()))
}
}
.catch { ex ->
Log.d(App.TAG, "[c] get an exception")
Log.e(App.TAG, "Exception on getAccount() call", ex)
logger.d("[c] get an exception")
logger.e( "Exception on getAccount() call", ex)
emit(Response.Error.Exception(ex))
}
}

override fun addOffer(contact: String, secret: String, newService: Service): Flow<Response<PersonProfile>> {
return flow {
Log.d(App.TAG, "[add offer] start")
logger.d( "[add offer] start")
val response = api.addOffer(
credentials = AppCredentials.basic(contact, secret),
service = newService
Expand All @@ -120,22 +123,22 @@ class PersonRepository(val api: IApi, val cache: Cache, val context: Context): I
* with server resources atomic at the same time
* */
if (response.isSuccessful) {
Log.d(App.TAG, "[add offer] success case")
logger.d( "[add offer] success case")
val profileResponse = api.getProfile(
credentials = AppCredentials.basic(contact, secret)
)
val payload = profileResponse.body()!!
emit(Response.Data(payload.payload))
} else {
Log.d(App.TAG, "[add offer] error case")
logger.d( "[add offer] error case")
val errorPayload = ApiResponseConverter().toDomain(response.errorBody()?.string()!!);
emit(Response.Error.Message("${response.message()}:\n\n${errorPayload.payload}"))
}
Log.d(App.TAG, "[add offer] end")
logger.d( "[add offer] end")
}
.attachIdlingResource()
.catch { ex ->
Log.e(App.TAG, "Exception on addOffer() call", ex)
logger.e( "Exception on addOffer() call", ex)
emit(Response.Error.Exception(ex))
}
}
Expand All @@ -147,7 +150,7 @@ class PersonRepository(val api: IApi, val cache: Cache, val context: Context): I
service = newService
)
if (response.isSuccessful) {
Log.d(App.TAG, "[add demand] success case")
logger.d( "[add demand] success case")
val profileResponse = api.getProfile(
credentials = AppCredentials.basic(contact, secret)
)
Expand All @@ -159,7 +162,7 @@ class PersonRepository(val api: IApi, val cache: Cache, val context: Context): I
}
}
.catch { ex ->
Log.e(App.TAG, "Exception on addDemand() call", ex)
logger.e( "Exception on addDemand() call", ex)
emit(Response.Error.Exception(ex))
}
}
Expand All @@ -171,7 +174,7 @@ class PersonRepository(val api: IApi, val cache: Cache, val context: Context): I
serviceId = id
)
if (response.isSuccessful) {
Log.d(App.TAG, "[delete offer] success case")
logger.d( "[delete offer] success case")
val profileResponse = api.getProfile(
credentials = AppCredentials.basic(contact, secret)
)
Expand All @@ -182,7 +185,7 @@ class PersonRepository(val api: IApi, val cache: Cache, val context: Context): I
}
}
.catch { ex ->
Log.e(App.TAG, "Exception on removeOffer() call", ex)
logger.e( "Exception on removeOffer() call", ex)
emit(Response.Error.Exception(ex))
}
}
Expand All @@ -204,7 +207,7 @@ class PersonRepository(val api: IApi, val cache: Cache, val context: Context): I
}
}
.catch { ex ->
Log.e(App.TAG, "Exception on removeOffer() call", ex)
logger.e( "Exception on removeOffer() call", ex)
emit(Response.Error.Exception(ex))
}
}
Expand All @@ -223,7 +226,7 @@ class PersonRepository(val api: IApi, val cache: Cache, val context: Context): I
}
}
.catch { ex ->
Log.e(App.TAG, "Exception on removeOffer() call", ex)
logger.e( "Exception on removeOffer() call", ex)
emit(Response.Error.Exception(ex))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import kotlin.collections.ArrayList
class DemandsPagingSource(private val api: IApi, private val pageSize: Int)
: PagingSource<Int, Service>() {

companion object {
const val DEFAULT_START_PAGE = 1
}

private var contact: String? = null
private var secret: String? = null

Expand All @@ -40,7 +44,7 @@ class DemandsPagingSource(private val api: IApi, private val pageSize: Int)
)
if (response.isSuccessful) {
val body = response.body()
val data = body?.payload?.asList() ?: Collections.emptyList()
val data = body?.payload?.toList() ?: Collections.emptyList()
Log.d(App.PAGING, "Paging call")
return LoadResult.Page(
data = data,
Expand All @@ -62,8 +66,4 @@ class DemandsPagingSource(private val api: IApi, private val pageSize: Int)
this.secret = secret
}

private fun Collection<Service>.asList(): List<Service> {
return ArrayList<Service>(this)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ru.home.swap.repository.pagination

import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import retrofit2.HttpException
import ru.home.swap.App
import ru.home.swap.core.model.Service
import ru.home.swap.core.network.IApi
import ru.home.swap.utils.AppCredentials
import java.io.IOException
import java.util.*
import kotlin.IllegalStateException
import kotlin.collections.ArrayList

class MatchesPagingSource(private val api: IApi, private val pageSize: Int)
: PagingSource<Int, Any>() {

companion object {
const val DEFAULT_START_PAGE = 1
}

private var contact: String? = null
private var secret: String? = null

override fun getRefreshKey(state: PagingState<Int, Any>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Any> {
if (contact == null || secret == null)
throw IllegalStateException("Credentials are empty. Did you pass credentials for API request?")

try {
val page = params.key ?: DEFAULT_START_PAGE

val response = api.getMatchesForUserDemands(
credentials = AppCredentials.basic(contact, secret),
page = page,
size = pageSize
)
if (response.isSuccessful) {
val body = response.body()
val data = body?.payload?.toList() ?: Collections.emptyList()
Log.d(App.PAGING, "Paging call")
return LoadResult.Page(
data = data,
prevKey = if (page == DEFAULT_START_PAGE) null else page.minus(1),
nextKey = if (data.isEmpty()) null else page.plus(params.loadSize / pageSize)
)
} else {
return LoadResult.Error(IllegalStateException("Server returned response, but it wasn't successful."))
}
} catch (ex: IOException) {
return LoadResult.Error(ex)
} catch (ex: HttpException) {
return LoadResult.Error(ex)
}
}

fun setCredentials(contact: String, secret: String) {
this.contact = contact
this.secret = secret
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import ru.home.swap.utils.AppCredentials
import java.io.IOException
import java.util.*
import kotlin.IllegalStateException
import kotlin.collections.ArrayList

const val DEFAULT_START_PAGE = 1

class OffersPagingSource(private val api: IApi, private val pageSize: Int)
: PagingSource<Int, Service>() {

companion object {
const val DEFAULT_START_PAGE = 1
}

private var contact: String? = null
private var secret: String? = null

Expand All @@ -42,7 +43,7 @@ class OffersPagingSource(private val api: IApi, private val pageSize: Int)
)
if (response.isSuccessful) {
val body = response.body()
val data = body?.payload?.asList() ?: Collections.emptyList()
val data = body?.payload?.toList() ?: Collections.emptyList()
Log.d(App.PAGING, "Paging call")
return LoadResult.Page(
data = data,
Expand All @@ -64,8 +65,4 @@ class OffersPagingSource(private val api: IApi, private val pageSize: Int)
this.secret = secret
}

private fun Collection<Service>.asList(): List<Service> {
return ArrayList<Service>(this)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,12 @@ interface IApi {
suspend fun getContacts(
@Header("Authorization") credentials: String,
@Query("serviceId") serviceId: Long): Response<ApiResponse<PersonProfile>>

@Headers("Content-Type: application/json; charset=utf-8")
@GET("/api/v1/account/matches")
suspend fun getMatchesForUserDemands(
@Header("Authorization") credentials: String,
@Query("page") page: Int,
@Query("size") size: Int
): Response<ApiResponse<Collection<Any>>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class WalletRepository(
web3 = Web3j.build(httpService)
runBlocking {
launch(Dispatchers.IO) {
loadContract(R.string.test_account_3_private_key)
loadContract(R.string.test_account_private_key)
}
}
}
Expand Down

0 comments on commit f7d8ab8

Please sign in to comment.