Skip to content

Commit db28c72

Browse files
feat: add event types for search
1 parent 5e286dd commit db28c72

File tree

14 files changed

+315
-5
lines changed

14 files changed

+315
-5
lines changed

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ import org.fossasia.openevent.general.event.EventsListAdapter
4242
import org.fossasia.openevent.general.event.EventsViewModel
4343
import org.fossasia.openevent.general.event.topic.EventTopic
4444
import org.fossasia.openevent.general.event.topic.EventTopicApi
45+
import org.fossasia.openevent.general.event.types.EventType
46+
import org.fossasia.openevent.general.event.types.EventTypesApi
4547
import org.fossasia.openevent.general.event.topic.SimilarEventsViewModel
4648
import org.fossasia.openevent.general.favorite.FavoriteEventsRecyclerAdapter
4749
import org.fossasia.openevent.general.favorite.FavoriteEventsViewModel
@@ -59,6 +61,7 @@ import org.fossasia.openevent.general.search.GeoLocationViewModel
5961
import org.fossasia.openevent.general.search.SearchLocationViewModel
6062
import org.fossasia.openevent.general.search.SearchViewModel
6163
import org.fossasia.openevent.general.search.LocationService
64+
import org.fossasia.openevent.general.search.SearchTypeViewModel
6265
import org.fossasia.openevent.general.search.LocationServiceImpl
6366
import org.fossasia.openevent.general.settings.SettingsViewModel
6467
import org.fossasia.openevent.general.social.SocialLink
@@ -118,11 +121,15 @@ val apiModule = module {
118121
val retrofit: Retrofit = get()
119122
retrofit.create(PaypalApi::class.java)
120123
}
124+
single {
125+
val retrofit: Retrofit = get()
126+
retrofit.create(EventTypesApi::class.java)
127+
}
121128

122129
factory { AuthHolder(get()) }
123130
factory { AuthService(get(), get(), get()) }
124131

125-
factory { EventService(get(), get(), get(), get()) }
132+
factory { EventService(get(), get(), get(), get(), get()) }
126133
factory { TicketService(get(), get()) }
127134
factory { SocialLinksService(get(), get()) }
128135
factory { AttendeeService(get(), get(), get()) }
@@ -139,6 +146,7 @@ val viewModelModule = module {
139146
viewModel { SearchViewModel(get(), get(), get(), get()) }
140147
viewModel { AttendeeViewModel(get(), get(), get(), get(), get(), get(), get()) }
141148
viewModel { SearchLocationViewModel(get()) }
149+
viewModel { SearchTypeViewModel(get()) }
142150
viewModel { TicketsViewModel(get(), get(), get(), get()) }
143151
viewModel { AboutEventViewModel(get(), get()) }
144152
viewModel { SocialLinksViewModel(get(), get()) }
@@ -188,7 +196,7 @@ val networkModule = module {
188196
SignUp::class.java, Ticket::class.java, SocialLink::class.java, EventId::class.java,
189197
EventTopic::class.java, Attendee::class.java, TicketId::class.java, Order::class.java,
190198
AttendeeId::class.java, Charge::class.java, Paypal::class.java, ConfirmOrder::class.java,
191-
CustomForm::class.java))
199+
CustomForm::class.java, EventType::class.java))
192200
.addConverterFactory(JacksonConverterFactory.create(objectMapper))
193201
.baseUrl(baseUrl)
194202
.build()

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ import io.reactivex.Single
66
import org.fossasia.openevent.general.event.topic.EventTopic
77
import org.fossasia.openevent.general.event.topic.EventTopicApi
88
import org.fossasia.openevent.general.event.topic.EventTopicsDao
9+
import org.fossasia.openevent.general.event.types.EventType
10+
import org.fossasia.openevent.general.event.types.EventTypesApi
11+
912
import java.util.Locale.filter
1013

1114
class EventService(
1215
private val eventApi: EventApi,
1316
private val eventDao: EventDao,
1417
private val eventTopicApi: EventTopicApi,
15-
private val eventTopicsDao: EventTopicsDao
18+
private val eventTopicsDao: EventTopicsDao,
19+
private val eventTypesApi: EventTypesApi
1620
) {
1721

1822
fun getEvents(): Flowable<List<Event>> {
@@ -44,6 +48,10 @@ class EventService(
4448
return eventTopicsDao.getAllEventTopics()
4549
}
4650

51+
fun getEventTypes(): Single<List<EventType>> {
52+
return eventTypesApi.getEventTypes()
53+
}
54+
4755
fun getSearchEvents(eventName: String): Single<List<Event>> {
4856
return eventApi.searchEvents("name", eventName).flatMap { apiList ->
4957
var eventIds = apiList.map { it.id }.toList()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.fossasia.openevent.general.event.types
2+
3+
import androidx.room.Entity
4+
import androidx.room.PrimaryKey
5+
import com.github.jasminb.jsonapi.LongIdHandler
6+
import com.github.jasminb.jsonapi.annotations.Id
7+
import com.github.jasminb.jsonapi.annotations.Type
8+
9+
@Type("event-type")
10+
@Entity
11+
data class EventType(
12+
@Id(LongIdHandler::class)
13+
@PrimaryKey
14+
val id: Long?,
15+
val name: String?,
16+
val slug: String?
17+
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.fossasia.openevent.general.event.types
2+
3+
import io.reactivex.Single
4+
import retrofit2.http.GET
5+
6+
interface EventTypesApi {
7+
8+
@GET("event-types?sort=name")
9+
fun getEventTypes(): Single<List<EventType>>
10+
}

app/src/main/java/org/fossasia/openevent/general/search/SearchFragment.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import androidx.navigation.Navigation.findNavController
1313
import kotlinx.android.synthetic.main.fragment_search.view.fabSearch
1414
import kotlinx.android.synthetic.main.fragment_search.view.locationTextView
1515
import kotlinx.android.synthetic.main.fragment_search.view.timeTextView
16+
import kotlinx.android.synthetic.main.fragment_search.view.eventTypeTextView
1617
import org.fossasia.openevent.general.R
1718
import org.fossasia.openevent.general.utils.nullToEmpty
1819
import org.koin.androidx.viewmodel.ext.android.viewModel
@@ -73,6 +74,8 @@ class SearchFragment : Fragment() {
7374
rootView.timeTextView.text = time
7475
}
7576
}
77+
val type = safeArgs?.stringSavedType
78+
rootView.eventTypeTextView.text = if (type.isNullOrBlank()) getString(R.string.anything) else type
7679

7780
searchViewModel.loadSavedLocation()
7881
rootView.locationTextView.text = searchViewModel.savedLocation
@@ -87,6 +90,16 @@ class SearchFragment : Fragment() {
8790
}
8891
}
8992

93+
rootView.eventTypeTextView.setOnClickListener {
94+
SearchLocationFragmentArgs.Builder()
95+
.setFromSearchFragment(true)
96+
.build()
97+
.toBundle()
98+
.also { bundle ->
99+
Navigation.findNavController(rootView).navigate(R.id.searchTypeFragment, bundle, getAnimSlide())
100+
}
101+
}
102+
90103
return rootView
91104
}
92105

@@ -117,6 +130,7 @@ class SearchFragment : Fragment() {
117130
.setQuery(query)
118131
.setLocation(rootView.locationTextView.text.toString().nullToEmpty())
119132
.setDate((safeArgs?.stringSavedDate ?: getString(R.string.anytime)).nullToEmpty())
133+
.setType((safeArgs?.stringSavedType ?: getString(R.string.anything)).nullToEmpty())
120134
.build()
121135
.toBundle()
122136
.also { bundle ->

app/src/main/java/org/fossasia/openevent/general/search/SearchResultsFragment.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,10 @@ class SearchResultsFragment : Fragment() {
195195
private fun performSearch(args: SearchResultsFragmentArgs, eventDate: String = "") {
196196
val query = args.query
197197
val location = args.location
198+
val type = args.type
198199
val date = if (eventDate.isNotEmpty()) eventDate else args.date
199200
searchViewModel.searchEvent = query
200-
searchViewModel.loadEvents(location, date)
201+
searchViewModel.loadEvents(location, date, type)
201202
}
202203

203204
private fun showNoSearchResults(events: List<Event>) {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.fossasia.openevent.general.search
2+
3+
import android.os.Bundle
4+
import android.view.LayoutInflater
5+
import android.view.View
6+
import android.view.ViewGroup
7+
import android.widget.ArrayAdapter
8+
import androidx.fragment.app.Fragment
9+
import androidx.lifecycle.Observer
10+
import androidx.navigation.NavOptions
11+
import androidx.navigation.Navigation
12+
import androidx.navigation.fragment.navArgs
13+
import kotlinx.android.synthetic.main.fragment_search_type.view.eventTypesLv
14+
import org.fossasia.openevent.general.R
15+
import org.fossasia.openevent.general.utils.Utils.setToolbar
16+
import org.fossasia.openevent.general.utils.extensions.nonNull
17+
import org.koin.androidx.viewmodel.ext.android.viewModel
18+
19+
class SearchTypeFragment : Fragment() {
20+
private val searchTypeViewModel by viewModel<SearchTypeViewModel>()
21+
private val safeArgs: SearchTypeFragmentArgs by navArgs()
22+
private lateinit var rootView: View
23+
private val eventTypesList: MutableList<String> = ArrayList()
24+
25+
override fun onCreateView(
26+
inflater: LayoutInflater,
27+
container: ViewGroup?,
28+
savedInstanceState: Bundle?
29+
): View? {
30+
// Inflate the layout for this fragment
31+
rootView = inflater.inflate(R.layout.fragment_search_type, container, false)
32+
setToolbar(activity,"",hasUpEnabled = true)
33+
setHasOptionsMenu(true)
34+
searchTypeViewModel.loadEventTypes()
35+
val adapter = ArrayAdapter(context, R.layout.event_type_list, eventTypesList)
36+
rootView.eventTypesLv.adapter = adapter
37+
38+
searchTypeViewModel.eventLocations
39+
.nonNull()
40+
.observe(this, Observer { list ->
41+
list.forEach {
42+
eventTypesList.add(it.name ?: "")
43+
}
44+
adapter.notifyDataSetChanged()
45+
})
46+
rootView.eventTypesLv.setOnItemClickListener { parent, view, position, id ->
47+
redirectToSearch(eventTypesList[position])
48+
}
49+
return rootView
50+
}
51+
52+
private fun redirectToSearch(type: String) {
53+
val args = SearchFragmentArgs.Builder().setStringSavedType(type).build().toBundle()
54+
val navOptions = NavOptions.Builder().setPopUpTo(R.id.eventsFragment, false).build()
55+
Navigation.findNavController(rootView).navigate(R.id.searchFragment, args, navOptions)
56+
}
57+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.fossasia.openevent.general.search
2+
3+
import androidx.lifecycle.LiveData
4+
import androidx.lifecycle.MutableLiveData
5+
import androidx.lifecycle.ViewModel
6+
import io.reactivex.android.schedulers.AndroidSchedulers
7+
import io.reactivex.disposables.CompositeDisposable
8+
import io.reactivex.schedulers.Schedulers
9+
import org.fossasia.openevent.general.event.EventService
10+
import org.fossasia.openevent.general.event.types.EventType
11+
import timber.log.Timber
12+
13+
class SearchTypeViewModel(
14+
private val eventService: EventService
15+
) : ViewModel() {
16+
17+
private val compositeDisposable = CompositeDisposable()
18+
private val mutableEventLocations = MutableLiveData<List<EventType>>()
19+
val eventLocations: LiveData<List<EventType>> = mutableEventLocations
20+
21+
fun loadEventTypes() {
22+
compositeDisposable.add(eventService.getEventTypes()
23+
.subscribeOn(Schedulers.io())
24+
.observeOn(AndroidSchedulers.mainThread())
25+
.subscribe({
26+
mutableEventLocations.value = it
27+
}, {
28+
Timber.e(it, "Error fetching events types")
29+
})
30+
)
31+
}
32+
}

app/src/main/java/org/fossasia/openevent/general/search/SearchViewModel.kt

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class SearchViewModel(
5454
savedLocation = preference.getString(SAVED_LOCATION)
5555
}
5656

57-
fun loadEvents(location: String, time: String) {
57+
fun loadEvents(location: String, time: String, type: String) {
5858
if (mutableEvents.value != null) {
5959
mutableShowShimmerResults.value = false
6060
mutableShowNoInternetError.value = false
@@ -68,6 +68,17 @@ class SearchViewModel(
6868
| 'op':'ilike',
6969
| 'val':'%$searchEvent%'
7070
|}]""".trimMargin().replace("'", "'")
71+
time == "Anytime" && type == "Anything" -> """[{
72+
| 'and':[{
73+
| 'name':'location-name',
74+
| 'op':'ilike',
75+
| 'val':'%$location%'
76+
| }, {
77+
| 'name':'name',
78+
| 'op':'ilike',
79+
| 'val':'%$searchEvent%'
80+
| }]
81+
|}]""".trimMargin().replace("'", "\"")
7182
time == "Anytime" -> """[{
7283
| 'and':[{
7384
| 'name':'location-name',
@@ -77,6 +88,14 @@ class SearchViewModel(
7788
| 'name':'name',
7889
| 'op':'ilike',
7990
| 'val':'%$searchEvent%'
91+
| }, {
92+
| 'name':'event-type',
93+
| 'op':'has',
94+
| 'val': {
95+
| 'name':'name',
96+
| 'op':'eq',
97+
| 'val':'$type'
98+
| }
8099
| }]
81100
|}]""".trimMargin().replace("'", "\"")
82101
time == "Today" -> """[{
@@ -96,6 +115,14 @@ class SearchViewModel(
96115
| 'name':'starts-at',
97116
| 'op':'lt',
98117
| 'val':'$savedNextDate%'
118+
| }, {
119+
| 'name':'event-type',
120+
| 'op':'has',
121+
| 'val': {
122+
| 'name':'name',
123+
| 'op':'eq',
124+
| 'val':'$type'
125+
| }
99126
| }]
100127
|}]""".trimMargin().replace("'", "\"")
101128
time == "Tomorrow" -> """[{
@@ -115,6 +142,14 @@ class SearchViewModel(
115142
| 'name':'starts-at',
116143
| 'op':'lt',
117144
| 'val':'$savedNextToNextDate%'
145+
| }, {
146+
| 'name':'event-type',
147+
| 'op':'has',
148+
| 'val': {
149+
| 'name':'name',
150+
| 'op':'eq',
151+
| 'val':'$type'
152+
| }
118153
| }]
119154
|}]""".trimMargin().replace("'", "\"")
120155
time == "This weekend" -> """[{
@@ -134,6 +169,14 @@ class SearchViewModel(
134169
| 'name':'starts-at',
135170
| 'op':'lt',
136171
| 'val':'$savedWeekendNextDate%'
172+
| }, {
173+
| 'name':'event-type',
174+
| 'op':'has',
175+
| 'val': {
176+
| 'name':'name',
177+
| 'op':'eq',
178+
| 'val':'$type'
179+
| }
137180
| }]
138181
|}]""".trimMargin().replace("'", "\"")
139182
time == "In the next month" -> """[{
@@ -153,6 +196,14 @@ class SearchViewModel(
153196
| 'name':'starts-at',
154197
| 'op':'lt',
155198
| 'val':'$savedNextToNextMonth%'
199+
| }, {
200+
| 'name':'event-type',
201+
| 'op':'has',
202+
| 'val': {
203+
| 'name':'name',
204+
| 'op':'eq',
205+
| 'val':'$type'
206+
| }
156207
| }]
157208
|}]""".trimMargin().replace("'", "\"")
158209
else -> """[{
@@ -172,6 +223,14 @@ class SearchViewModel(
172223
| 'name':'starts-at',
173224
| 'op':'lt',
174225
| 'val':'$savedNextDate%'
226+
| }, {
227+
| 'name':'event-type',
228+
| 'op':'has',
229+
| 'val': {
230+
| 'name':'name',
231+
| 'op':'eq',
232+
| 'val':'$type'
233+
| }
175234
| }]
176235
|}]""".trimMargin().replace("'", "\"")
177236
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<CheckedTextView
3+
android:id="@+id/text1"
4+
android:layout_width="match_parent"
5+
android:layout_height="wrap_content"
6+
android:paddingStart="@dimen/layout_margin_large"
7+
android:paddingTop="@dimen/layout_margin_large"
8+
android:paddingBottom="@dimen/layout_margin_large"
9+
android:gravity="center_vertical"
10+
android:text="@string/anytime"
11+
android:background="?attr/selectableItemBackground"
12+
android:textColor="@color/black"
13+
android:textSize="@dimen/text_size_expanded_title"
14+
android:paddingLeft="@dimen/layout_margin_large"
15+
xmlns:android="http://schemas.android.com/apk/res/android" />

0 commit comments

Comments
 (0)