Skip to content

Commit a6521e9

Browse files
authored
Merge branch 'development' into development
2 parents 22b9511 + 88609f9 commit a6521e9

17 files changed

+224
-161
lines changed

app/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ dependencies {
103103
def ktx2_version = "2.0.0"
104104
def nav_version = "2.1.0-alpha05"
105105
def anko_version = "0.10.8"
106+
def paging_version = "2.1.0"
106107

107108
implementation fileTree(dir: 'libs', include: ['*.jar'])
108109
implementation 'androidx.multidex:multidex:2.0.1'
@@ -191,6 +192,11 @@ dependencies {
191192
//LeakCanary
192193
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-2'
193194

195+
// Paging
196+
implementation "androidx.paging:paging-runtime:$paging_version"
197+
implementation "androidx.paging:paging-rxjava2:$paging_version"
198+
199+
194200
testImplementation 'junit:junit:4.12'
195201
testImplementation "io.mockk:mockk:1.9.3"
196202
testImplementation 'org.threeten:threetenbp:1.4.0'

app/src/main/java/org/fossasia/openevent/general/di/Modules.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.fossasia.openevent.general.di
22

3+
import androidx.paging.PagedList
34
import androidx.room.Room
45
import com.facebook.stetho.okhttp3.StethoInterceptor
56
import com.fasterxml.jackson.databind.DeserializationFeature
@@ -210,7 +211,7 @@ val apiModule = module {
210211

211212
val viewModelModule = module {
212213
viewModel { LoginViewModel(get(), get(), get()) }
213-
viewModel { EventsViewModel(get(), get(), get(), get(), get(), get()) }
214+
viewModel { EventsViewModel(get(), get(), get(), get(), get(), get(), get()) }
214215
viewModel { ProfileViewModel(get(), get()) }
215216
viewModel { SignUpViewModel(get(), get(), get()) }
216217
viewModel { EventDetailsViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) }
@@ -249,6 +250,16 @@ val networkModule = module {
249250
objectMapper
250251
}
251252

253+
single {
254+
PagedList
255+
.Config
256+
.Builder()
257+
.setPageSize(5)
258+
.setInitialLoadSizeHint(5)
259+
.setEnablePlaceholders(false)
260+
.build()
261+
}
262+
252263
single {
253264
val connectTimeout = 15 // 15s
254265
val readTimeout = 15 // 15s

app/src/main/java/org/fossasia/openevent/general/event/EventApi.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,12 @@ interface EventApi {
2525

2626
@GET("events/{eventId}/speakers-call")
2727
fun getSpeakerCallForEvent(@Path("eventId") id: Long): Single<SpeakersCall>
28+
29+
@GET("events?include=event-sub-topic,event-topic,event-type")
30+
fun searchEventsPaged(
31+
@Query("sort") sort: String,
32+
@Query("filter") eventName: String,
33+
@Query("page[number]") page: Int,
34+
@Query("page[size]") pageSize: Int = 5
35+
): Single<List<Event>>
2836
}

app/src/main/java/org/fossasia/openevent/general/event/EventDetailsViewModel.kt

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ class EventDetailsViewModel(
6666
val eventSponsors: LiveData<List<Sponsor>> = mutableEventSponsors
6767
private val mutableSocialLinks = MutableLiveData<List<SocialLink>>()
6868
val socialLinks: LiveData<List<SocialLink>> = mutableSocialLinks
69-
private val mutableSimilarEvents = MutableLiveData<Set<Event>>()
70-
val similarEvents: LiveData<Set<Event>> = mutableSimilarEvents
69+
private val mutableSimilarEvents = MutableLiveData<List<Event>>()
70+
val similarEvents: LiveData<List<Event>> = mutableSimilarEvents
7171
private val mutableOrders = MutableLiveData<List<Order>>()
7272
val orders: LiveData<List<Order>> = mutableOrders
7373

@@ -144,24 +144,17 @@ class EventDetailsViewModel(
144144
if (topicId != -1L) {
145145
similarEventsFlowable = similarEventsFlowable.zipWith(eventService.getSimilarEvents(topicId),
146146
BiFunction { firstList: List<Event>, secondList: List<Event> ->
147-
val similarList = mutableListOf<Event>()
148-
similarList.addAll(firstList)
149-
similarList.addAll(secondList)
150-
similarList
147+
val similarList = mutableSetOf<Event>()
148+
similarList.addAll(firstList + secondList)
149+
similarList.toList()
151150
})
152151
}
153152
compositeDisposable += similarEventsFlowable
154153
.withDefaultSchedulers()
155154
.distinctUntilChanged()
156155
.subscribe({ events ->
157156
val list = events.filter { it.id != eventId }
158-
val oldList = mutableSimilarEvents.value
159-
val similarEventList = mutableSetOf<Event>()
160-
similarEventList.addAll(list)
161-
oldList?.let {
162-
similarEventList.addAll(it)
163-
}
164-
mutableSimilarEvents.value = similarEventList
157+
mutableSimilarEvents.value = list
165158
}, {
166159
Timber.e(it, "Error fetching similar events")
167160
mutablePopMessage.value = resource.getString(R.string.error_fetching_event_section_message,

app/src/main/java/org/fossasia/openevent/general/event/EventService.kt

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,6 @@ class EventService(
2727
private val speakersCallDao: SpeakersCallDao
2828
) {
2929

30-
fun getEvents(): Flowable<List<Event>> {
31-
val eventsFlowable = eventDao.getAllEvents()
32-
return eventsFlowable.switchMap {
33-
if (it.isNotEmpty())
34-
eventsFlowable
35-
else
36-
eventApi.getEvents()
37-
.map {
38-
eventDao.insertEvents(it)
39-
eventTopicsDao.insertEventTopics(getEventTopicList(it))
40-
}
41-
.toFlowable()
42-
.flatMap {
43-
eventsFlowable
44-
}
45-
}
46-
}
47-
4830
fun getEventLocations(): Single<List<EventLocation>> {
4931
return eventLocationApi.getEventLocation()
5032
}
@@ -88,6 +70,14 @@ class EventService(
8870
}
8971
}
9072

73+
fun getEventsByLocationPaged(locationName: String?, page: Int): Flowable<List<Event>> {
74+
val query = "[{\"name\":\"location-name\",\"op\":\"ilike\",\"val\":\"%$locationName%\"}," +
75+
"{\"name\":\"ends-at\",\"op\":\"ge\",\"val\":\"%${EventUtils.getTimeInISO8601(Date())}%\"}]"
76+
return eventApi.searchEventsPaged("name", query, page).flatMapPublisher { apiList ->
77+
updateFavorites(apiList)
78+
}
79+
}
80+
9181
private fun updateFavorites(apiList: List<Event>): Flowable<List<Event>> {
9282

9383
val ids = apiList.map { it.id }.toList()

app/src/main/java/org/fossasia/openevent/general/event/EventsFragment.kt

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import kotlinx.android.synthetic.main.content_no_internet.view.noInternetCard
1717
import kotlinx.android.synthetic.main.content_no_internet.view.retry
1818
import kotlinx.android.synthetic.main.fragment_events.view.eventsRecycler
1919
import kotlinx.android.synthetic.main.fragment_events.view.locationTextView
20-
import kotlinx.android.synthetic.main.fragment_events.view.progressBar
2120
import kotlinx.android.synthetic.main.fragment_events.view.shimmerEvents
2221
import kotlinx.android.synthetic.main.fragment_events.view.eventsEmptyView
2322
import kotlinx.android.synthetic.main.fragment_events.view.emptyEventsText
@@ -37,7 +36,6 @@ import org.fossasia.openevent.general.data.Preference
3736
import org.fossasia.openevent.general.search.location.SAVED_LOCATION
3837
import org.fossasia.openevent.general.utils.extensions.nonNull
3938
import org.koin.androidx.viewmodel.ext.android.viewModel
40-
import timber.log.Timber
4139
import org.fossasia.openevent.general.utils.Utils.setToolbar
4240
import org.fossasia.openevent.general.utils.extensions.setPostponeSharedElementTransition
4341
import org.fossasia.openevent.general.utils.extensions.setStartPostponedEnterTransition
@@ -67,8 +65,6 @@ class EventsFragment : Fragment(), BottomIconDoubleClick {
6765
}
6866
setToolbar(activity, show = false)
6967

70-
rootView.progressBar.isIndeterminate = true
71-
7268
rootView.eventsRecycler.layoutManager =
7369
GridLayoutManager(activity, resources.getInteger(R.integer.events_column_count))
7470

@@ -84,30 +80,24 @@ class EventsFragment : Fragment(), BottomIconDoubleClick {
8480
handleNotificationDotVisibility(it)
8581
})
8682

87-
eventsViewModel.showShimmerEvents
88-
.nonNull()
89-
.observe(viewLifecycleOwner, Observer { shouldShowShimmer ->
90-
if (shouldShowShimmer) {
91-
rootView.shimmerEvents.startShimmer()
92-
eventsListAdapter.clear()
93-
} else {
94-
rootView.shimmerEvents.stopShimmer()
95-
}
96-
rootView.shimmerEvents.isVisible = shouldShowShimmer
97-
})
98-
99-
eventsViewModel.events
83+
eventsViewModel.pagedEvents
10084
.nonNull()
10185
.observe(this, Observer { list ->
10286
eventsListAdapter.submitList(list)
103-
showEmptyMessage(list.size)
104-
Timber.d("Fetched events of size %s", eventsListAdapter.itemCount)
10587
})
10688

10789
eventsViewModel.progress
10890
.nonNull()
10991
.observe(viewLifecycleOwner, Observer {
110-
rootView.swiperefresh.isRefreshing = it
92+
if (it) {
93+
rootView.shimmerEvents.startShimmer()
94+
showEmptyMessage(false)
95+
} else {
96+
rootView.shimmerEvents.stopShimmer()
97+
rootView.swiperefresh.isRefreshing = false
98+
showEmptyMessage(eventsListAdapter.currentList?.isEmpty() ?: true)
99+
}
100+
rootView.shimmerEvents.isVisible = it
111101
})
112102

113103
eventsViewModel.error
@@ -117,6 +107,11 @@ class EventsFragment : Fragment(), BottomIconDoubleClick {
117107
})
118108

119109
eventsViewModel.loadLocation()
110+
if (rootView.locationTextView.text == getString(R.string.enter_location)) {
111+
rootView.emptyEventsText.text = getString(R.string.choose_preferred_location_message)
112+
} else {
113+
rootView.emptyEventsText.text = getString(R.string.no_events_message)
114+
}
120115
rootView.locationTextView.text = eventsViewModel.savedLocation.value
121116
rootView.toolbar.title = rootView.locationTextView.text
122117

@@ -131,10 +126,10 @@ class EventsFragment : Fragment(), BottomIconDoubleClick {
131126
eventsViewModel.connection
132127
.nonNull()
133128
.observe(viewLifecycleOwner, Observer { isConnected ->
134-
if (isConnected && eventsViewModel.events.value == null) {
129+
if (isConnected && eventsViewModel.pagedEvents.value == null) {
135130
eventsViewModel.loadLocationEvents()
136131
}
137-
showNoInternetScreen(!isConnected && eventsViewModel.events.value == null)
132+
showNoInternetScreen(!isConnected && eventsViewModel.pagedEvents.value == null)
138133
})
139134

140135
rootView.locationTextView.setOnClickListener {
@@ -247,17 +242,8 @@ class EventsFragment : Fragment(), BottomIconDoubleClick {
247242
rootView.noInternetCard.isVisible = show
248243
}
249244

250-
private fun showEmptyMessage(itemCount: Int) {
251-
if (itemCount == 0) {
252-
rootView.eventsEmptyView.visibility = View.VISIBLE
253-
if (rootView.locationTextView.text == getString(R.string.enter_location)) {
254-
rootView.emptyEventsText.text = getString(R.string.choose_preferred_location_message)
255-
} else {
256-
rootView.emptyEventsText.text = getString(R.string.no_events_message)
257-
}
258-
} else {
259-
rootView.eventsEmptyView.visibility = View.GONE
260-
}
245+
private fun showEmptyMessage(show: Boolean) {
246+
rootView.eventsEmptyView.isVisible = show
261247
}
262248

263249
override fun doubleClick() = rootView.scrollView.smoothScrollTo(0, 0)

app/src/main/java/org/fossasia/openevent/general/event/EventsListAdapter.kt

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package org.fossasia.openevent.general.event
22

33
import android.view.LayoutInflater
44
import android.view.ViewGroup
5-
import androidx.recyclerview.widget.ListAdapter
5+
import androidx.paging.PagedListAdapter
66
import org.fossasia.openevent.general.common.EventClickListener
77
import org.fossasia.openevent.general.common.EventsDiffCallback
88
import org.fossasia.openevent.general.common.FavoriteFabClickListener
@@ -15,7 +15,7 @@ import org.fossasia.openevent.general.databinding.ItemCardEventsBinding
1515
* @property onEventClick The callback to be invoked when an event is clicked
1616
* @property onFavFabClick The callback to be invoked when the favorite FAB is clicked
1717
*/
18-
class EventsListAdapter : ListAdapter<Event, EventViewHolder>(EventsDiffCallback()) {
18+
class EventsListAdapter : PagedListAdapter<Event, EventViewHolder>(EventsDiffCallback()) {
1919

2020
var onEventClick: EventClickListener? = null
2121
var onFavFabClick: FavoriteFabClickListener? = null
@@ -28,19 +28,20 @@ class EventsListAdapter : ListAdapter<Event, EventViewHolder>(EventsDiffCallback
2828

2929
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
3030
val event = getItem(position)
31-
holder.apply {
32-
bind(event, position)
33-
eventClickListener = onEventClick
34-
favFabClickListener = onFavFabClick
35-
hashTagClickListAdapter = onHashtagClick
36-
}
31+
if (event != null)
32+
holder.apply {
33+
bind(event, position)
34+
eventClickListener = onEventClick
35+
favFabClickListener = onFavFabClick
36+
hashTagClickListAdapter = onHashtagClick
37+
}
3738
}
3839

3940
/**
4041
* The function to call when the adapter has to be cleared of items
4142
*/
4243
fun clear() {
43-
this.submitList(emptyList())
44+
this.submitList(null)
4445
}
4546
}
4647

0 commit comments

Comments
 (0)