Skip to content

Commit

Permalink
Ref. #18: adjust /offers and /match requests to meet new requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
dkazakov committed Jun 6, 2023
1 parent 2b454d2 commit f522aad
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import androidx.paging.PagingSource
import androidx.paging.PagingState
import retrofit2.HttpException
import ru.home.swap.App
import ru.home.swap.core.model.MatchSubject
import ru.home.swap.core.model.Service
import ru.home.swap.core.model.SwapMatch
import ru.home.swap.core.network.IApi
import ru.home.swap.utils.AppCredentials
import java.io.IOException
Expand All @@ -14,7 +16,7 @@ import kotlin.IllegalStateException
import kotlin.collections.ArrayList

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

companion object {
const val DEFAULT_START_PAGE = 1
Expand All @@ -23,14 +25,14 @@ class MatchesPagingSource(private val api: IApi, private val pageSize: Int)
private var contact: String? = null
private var secret: String? = null

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import ru.home.swap.R
import ru.home.swap.core.model.Service
import ru.home.swap.databinding.DemandsFragmentBinding
import ru.home.swap.core.di.ViewModelFactory
import ru.home.swap.core.model.SwapMatch
import ru.home.swap.ui.common.BaseFragment
import ru.home.swap.ui.contacts.ContactsFragment
import ru.home.swap.ui.offers.OffersAdapter
Expand Down Expand Up @@ -70,10 +71,10 @@ class DemandsFragment: BaseFragment(), OffersAdapter.IListener {
viewModel.removeShownError()
}

override fun onItemClick(item: Service) {
Log.e(App.TAG, "On item click ${item.title}")
val bundle = bundleOf(ContactsFragment.Params.EXTRA_SERVICE_ID to item.uid)
findNavController().navigate(R.id.action_demandsFragment_to_contactsFragment, bundle)
override fun onItemClick(item: SwapMatch) {
Log.e(App.TAG, "On item click ${item.userSecondServiceTitle}")
val bundle = bundleOf(ContactsFragment.Params.EXTRA_SERVICE_ID to item.id) // FIXME just a stub due refactoring, reimplemenet it
findNavController().navigate(R.id.action_offersFragment_to_contactsFragment, bundle)
}

private fun setupList() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import kotlinx.coroutines.flow.*
import ru.home.swap.R
import ru.home.swap.core.model.PersonProfile
import ru.home.swap.core.model.Service
import ru.home.swap.core.model.SwapMatch
import ru.home.swap.repository.IPersonRepository
import ru.home.swap.repository.PersonRepository
import ru.home.swap.repository.pagination.DemandsPagingSource
import javax.inject.Inject

data class Model(
val pagingData: PagingData<Service>? = null,
val pagingData: PagingData<SwapMatch>? = null,
val profile: PersonProfile? = null,
val isLoading: Boolean = false,
val errors: List<String> = emptyList()
Expand All @@ -36,7 +37,7 @@ class DemandsViewModel
.stateIn(viewModelScope, SharingStarted.Eagerly, state.value)

suspend fun fetchDemands() {
if (uiState.value.profile == null) {
/* if (uiState.value.profile == null) {
repository.getCachedAccount()
.onStart {state.update { state -> state.copy(isLoading = true) } }
.flatMapConcat { it ->
Expand Down Expand Up @@ -69,7 +70,7 @@ class DemandsViewModel
)
}
}
}
}*/
}

private fun getPagingData(profile: PersonProfile): Flow<PagingData<Service>> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,23 @@ import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import ru.home.swap.core.model.Service
import ru.home.swap.core.model.SwapMatch
import ru.home.swap.databinding.OffersViewItemBinding
import ru.home.swap.providers.PersonProvider

class OffersAdapter(val listener: IListener, diffCallback: DiffUtil.ItemCallback<Service> = OffersComparator())
: PagingDataAdapter<Service, OffersAdapter.ViewHolder>(diffCallback) {
class OffersAdapter(val listener: IListener, diffCallback: DiffUtil.ItemCallback<SwapMatch> = OffersComparator())
: PagingDataAdapter<SwapMatch, OffersAdapter.ViewHolder>(diffCallback) {

interface IListener {
fun onItemClick(item: Service)
fun onItemClick(item: SwapMatch)
}

class ViewHolder(internal val binding: OffersViewItemBinding)
: RecyclerView.ViewHolder(binding.root)

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
holder.binding.service = item!!
holder.binding.swapMatch = item!!
holder.binding.root.setOnClickListener {
listener.onItemClick(item)
}
Expand All @@ -36,11 +37,14 @@ class OffersAdapter(val listener: IListener, diffCallback: DiffUtil.ItemCallback
return holder
}

class OffersComparator: DiffUtil.ItemCallback<Service>() {
override fun areItemsTheSame(oldItem: Service, newItem: Service): Boolean =
oldItem.uid == newItem.uid
class OffersComparator: DiffUtil.ItemCallback<SwapMatch>() {
override fun areItemsTheSame(oldItem: SwapMatch, newItem: SwapMatch): Boolean {
return (oldItem.id == newItem.id)
&& (oldItem.userFirstService.id == newItem.userFirstService.id)
&& (oldItem.userSecondService.id == newItem.userSecondService.id)
}

override fun areContentsTheSame(oldItem: Service, newItem: Service): Boolean =
override fun areContentsTheSame(oldItem: SwapMatch, newItem: SwapMatch): Boolean =
oldItem == newItem

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import ru.home.swap.R
import ru.home.swap.core.model.Service
import ru.home.swap.databinding.OffersFragmentBinding
import ru.home.swap.core.di.ViewModelFactory
import ru.home.swap.core.model.SwapMatch
import ru.home.swap.ui.common.BaseFragment
import ru.home.swap.ui.contacts.ContactsFragment
import javax.inject.Inject
Expand Down Expand Up @@ -73,9 +74,9 @@ class OffersFragment: BaseFragment(), OffersAdapter.IListener {
viewModel.removeShownError()
}

override fun onItemClick(item: Service) {
Log.e(App.TAG, "On item click ${item.title}")
val bundle = bundleOf(ContactsFragment.Params.EXTRA_SERVICE_ID to item.uid)
override fun onItemClick(item: SwapMatch) {
Log.e(App.TAG, "On item click ${item.userSecondServiceTitle}")
val bundle = bundleOf(ContactsFragment.Params.EXTRA_SERVICE_ID to item.id) // FIXME just a stub due refactoring, reimplemenet it
findNavController().navigate(R.id.action_offersFragment_to_contactsFragment, bundle)
}

Expand All @@ -102,8 +103,8 @@ class OffersFragment: BaseFragment(), OffersAdapter.IListener {
showErrorDialog(it.errors.get(0))
}
if (it.pagingData != null) {
throw UnsupportedOperationException("Not supported yet for new type ${it.pagingData.toString()}")
// (binding.offersList.adapter as OffersAdapter).submitData(it.pagingData)
// throw UnsupportedOperationException("Not supported yet for new type ${it.pagingData}")
(binding.offersList.adapter as OffersAdapter).submitData(it.pagingData)
}
binding.noContent.visibility = if (binding.offersList.adapter!!.itemCount == 0) View.VISIBLE else View.GONE
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import kotlinx.coroutines.flow.*
import ru.home.swap.R
import ru.home.swap.core.model.PersonProfile
import ru.home.swap.core.model.Service
import ru.home.swap.core.model.SwapMatch
import ru.home.swap.repository.IPersonRepository
import ru.home.swap.repository.pagination.MatchesPagingSource
import javax.inject.Inject

data class Model(
val pagingData: PagingData<Any>? = null,
val pagingData: PagingData<SwapMatch>? = null,
val profile: PersonProfile? = null,
val isLoading: Boolean = false,
val errors: List<String> = emptyList(),
Expand Down Expand Up @@ -72,7 +73,7 @@ class OffersViewModel
}
}

private fun getPagingData(profile: PersonProfile): Flow<PagingData<Any>> {
private fun getPagingData(profile: PersonProfile): Flow<PagingData<SwapMatch>> {
matchesPagingSource.setCredentials(profile.contact, profile.secret)
val pageSize = application.getString(R.string.page_size).toInt()
return Pager(
Expand Down
20 changes: 10 additions & 10 deletions mobile client/app/src/main/res/layout/offers_view_item.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

<data>
<variable
name="service"
type="ru.home.swap.core.model.Service" />
name="swapMatch"
type="ru.home.swap.core.model.SwapMatch" />
<variable
name="provider"
type="ru.home.swap.providers.PersonProvider" />
Expand All @@ -31,16 +31,16 @@
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/blue_light"
android:text="@{service.title}"
android:text="@{swapMatch.userSecondServiceTitle}"
tools:text="I offer more this French nice soft rolls and the tea." />

<TextView
android:id="@+id/offer_available_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/offer_title"
android:text="@{provider.getDateInHumanReadableFormat(service.date)}"
tools:text="till May 2024"/>
<!-- <TextView-->
<!-- android:id="@+id/offer_available_date"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_below="@+id/offer_title"-->
<!-- android:text="@{provider.getDateInHumanReadableFormat(swapMatch.date)}"-->
<!-- tools:text="till May 2024"/>-->

</RelativeLayout>

Expand Down
10 changes: 9 additions & 1 deletion server/controllers/profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ let converter = require('../utils/converter')

const config = require('config');

const MAX_PAGE_SIZE = config.dbConfig.maxPageSize;

// const chain = require('../models/chain/chain');
const { SwapToken, SwapChainV2, DebugUtil, chain } = require('../models/chain/chain');

Expand Down Expand Up @@ -296,6 +298,12 @@ exports.getMatchesByProfile = async function(req, res) {
result = network.getErrorMsg(401, global.noAuthHeaderMsg)
} else if (network.getAuthHeaderAsTokens(req).error) {
result = network.getErrorMsg(400, network.getAuthHeaderAsTokens(req).result);
} else if (!network.isTherePageParamInQuery(req.query)) {
result = network.getErrorMsg(400, "Did you forget to pass page in query, e.g. ?page=1 ?");
} else if (!network.isTherePageSizeParamInQuery(req.query)) {
result = network.getErrorMsg(400, `Did you pass page size? Maximum values per page is ${MAX_PAGE_SIZE}`)
} else if (req.query.size > MAX_PAGE_SIZE) {
result = network.getErrorMsg(400, `Did you pass page size within allowed range? Maximum items per page is ${MAX_PAGE_SIZE}, but you passed ${req.query.size}`)
} else {
let credentials = network.getAuthNameSecretPair(
network.getAuthHeaderAsTokens(req)
Expand Down Expand Up @@ -381,7 +389,7 @@ exports.getMatchesByProfile = async function(req, res) {
]
*
*/
let model = await match.getByProfileId(profileResult.id);
let model = await match.getByProfileId(profileResult.id, req.query.page, req.query.size);
logger.log(`[model] model ${JSON.stringify(model)}`);
/**
* Aggregated chain & db query is not necessary here,
Expand Down
18 changes: 16 additions & 2 deletions server/models/match.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ exports.getByProfileIdAndServiceIds = function(profileId, firstServiceId, second
})
}

exports.getByProfileId = function(profileId, req, res) {
exports.getByProfileId = function(profileId, page, size) {
return new Promise((resolve) => {
pool.getConnection(function(err, connection) {
if (err) throw err;
Expand All @@ -130,9 +130,12 @@ exports.getByProfileId = function(profileId, req, res) {
INNER JOIN ${ServiceTable.TABLE_NAME} as secondService
ON secondService.id = ${MatchTable.TABLE_NAME}.${MatchTable.USER_SECOND_SERVICE_ID}
WHERE
(
${MatchTable.USER_FIRST_PROFILE_ID} = ${profileId}
OR
${MatchTable.USER_SECOND_PROFILE_ID} = ${profileId}
${MatchTable.USER_SECOND_PROFILE_ID} = ${profileId}
)
${prepareLimitClause(page, size)}
;`;
logger.log("sql query: " + sql)
connection.query(
Expand Down Expand Up @@ -417,3 +420,14 @@ function prepareMatchBulkInsertQuery(matches) {
return baseSqlQuery.substring(0, baseSqlQuery.length - 1) + ";";
}


function prepareLimitClause(page, size) {
const MIN_VALUE = 1;
let result = '';
if (page < MIN_VALUE || page == MIN_VALUE) {
page = MIN_VALUE;
}
result = `LIMIT ${size} OFFSET ${page * size - size}`;
return result;
}

Loading

0 comments on commit f522aad

Please sign in to comment.