Skip to content

Commit 0284897

Browse files
feat: Add submit feedbacks
1 parent 25a1838 commit 0284897

File tree

10 files changed

+184
-9
lines changed

10 files changed

+184
-9
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.fossasia.openevent.general.auth
2+
3+
import com.github.jasminb.jsonapi.IntegerIdHandler
4+
import com.github.jasminb.jsonapi.annotations.Id
5+
import com.github.jasminb.jsonapi.annotations.Type
6+
7+
@Type("user")
8+
data class UserId(
9+
@Id(IntegerIdHandler::class)
10+
var id: Long
11+
)

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ val viewModelModule = module {
169169
viewModel { EventsViewModel(get(), get(), get(), get()) }
170170
viewModel { ProfileViewModel(get(), get()) }
171171
viewModel { SignUpViewModel(get(), get(), get()) }
172-
viewModel { EventDetailsViewModel(get(), get(), get()) }
172+
viewModel { EventDetailsViewModel(get(), get(), get(), get()) }
173173
viewModel { SearchViewModel(get(), get(), get(), get()) }
174174
viewModel { AttendeeViewModel(get(), get(), get(), get(), get(), get(), get()) }
175175
viewModel { SearchLocationViewModel(get(), get()) }
@@ -225,8 +225,6 @@ val networkModule = module {
225225
CustomForm::class.java, EventLocation::class.java, EventType::class.java,
226226
EventSubTopic::class.java, Feedback::class.java, Speaker::class.java)
227227

228-
onlineApiResourceConverter.enableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES)
229-
230228
Retrofit.Builder()
231229
.client(get())
232230
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

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

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import android.net.Uri
55
import android.os.Build
66
import android.os.Bundle
77
import android.provider.CalendarContract
8+
import android.text.Editable
9+
import android.text.TextWatcher
810
import android.view.LayoutInflater
911
import android.view.Menu
1012
import android.view.MenuInflater
1113
import android.view.MenuItem
1214
import android.view.View
1315
import android.view.ViewGroup
1416
import android.widget.TextView
17+
import androidx.appcompat.app.AlertDialog
1518
import androidx.core.content.ContextCompat
1619
import androidx.core.view.isVisible
1720
import androidx.fragment.app.Fragment
@@ -37,10 +40,11 @@ import kotlinx.android.synthetic.main.content_event.view.eventTimingLinearLayout
3740
import kotlinx.android.synthetic.main.content_event.view.imageMap
3841
import kotlinx.android.synthetic.main.content_event.view.locationUnderMap
3942
import kotlinx.android.synthetic.main.content_event.view.eventImage
40-
import kotlinx.android.synthetic.main.content_event.view.feedbackContainer
43+
import kotlinx.android.synthetic.main.content_event.view.feedbackBtn
4144
import kotlinx.android.synthetic.main.content_event.view.feedbackRv
4245
import kotlinx.android.synthetic.main.content_event.view.organizerLogoIcon
4346
import kotlinx.android.synthetic.main.content_event.view.nestedContentEventScroll
47+
import kotlinx.android.synthetic.main.content_event.view.noFeedBackTv
4448
import kotlinx.android.synthetic.main.content_event.view.organizerName
4549
import kotlinx.android.synthetic.main.content_event.view.refundPolicy
4650
import kotlinx.android.synthetic.main.content_event.view.seeMore
@@ -52,9 +56,13 @@ import kotlinx.android.synthetic.main.fragment_event.view.buttonTickets
5256
import kotlinx.android.synthetic.main.fragment_event.view.eventErrorCard
5357
import kotlinx.android.synthetic.main.fragment_event.view.container
5458
import kotlinx.android.synthetic.main.content_fetching_event_error.view.retry
59+
import kotlinx.android.synthetic.main.dialog_feedback.view.feedback
60+
import kotlinx.android.synthetic.main.dialog_feedback.view.feedbackTextInputLayout
61+
import kotlinx.android.synthetic.main.dialog_feedback.view.feedbackrating
5562
import org.fossasia.openevent.general.CircleTransform
5663
import org.fossasia.openevent.general.R
5764
import org.fossasia.openevent.general.about.AboutEventFragmentArgs
65+
import org.fossasia.openevent.general.auth.LoginFragmentArgs
5866
import org.fossasia.openevent.general.event.EventUtils.loadMapUrl
5967
import org.fossasia.openevent.general.event.feedback.FeedbackRecyclerAdapter
6068
import org.fossasia.openevent.general.event.topic.SimilarEventsFragment
@@ -71,6 +79,8 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
7179
import timber.log.Timber
7280
import java.util.Currency
7381
import org.fossasia.openevent.general.utils.Utils.setToolbar
82+
import org.jetbrains.anko.design.longSnackbar
83+
import org.jetbrains.anko.design.snackbar
7484
import java.lang.Exception
7585

7686
const val EVENT_ID = "eventId"
@@ -144,9 +154,20 @@ class EventDetailsFragment : Fragment() {
144154

145155
eventViewModel.eventFeedback.observe(viewLifecycleOwner, Observer {
146156
feedbackAdapter.addAll(it)
147-
rootView.feedbackContainer.isVisible = !it.isEmpty()
157+
if(it.isEmpty()){
158+
rootView.feedbackRv.isVisible = false
159+
rootView.noFeedBackTv.isVisible = true
160+
}
161+
else{
162+
rootView.feedbackRv.isVisible = true
163+
rootView.noFeedBackTv.isVisible = false
164+
}
148165
})
149166

167+
rootView.feedbackBtn.setOnClickListener {
168+
checkForAuthentication()
169+
}
170+
150171
eventViewModel.loadEvent(safeArgs.eventId)
151172
rootView.retry.setOnClickListener {
152173
eventViewModel.loadEvent(safeArgs.eventId)
@@ -454,6 +475,60 @@ class EventDetailsFragment : Fragment() {
454475
menuActionBar?.getItem(i)?.isVisible = !show
455476
}
456477
}
478+
private fun checkForAuthentication() {
479+
if (eventViewModel.isLoggedIn())
480+
writefeedback()
481+
else {
482+
rootView.nestedContentEventScroll.longSnackbar(getString(R.string.log_in_first))
483+
redirectToLogin()
484+
}
485+
}
486+
487+
private fun redirectToLogin() {
488+
LoginFragmentArgs.Builder()
489+
.setSnackbarMessage(getString(R.string.log_in_first))
490+
.build()
491+
.toBundle()
492+
.also { bundle ->
493+
findNavController(rootView).navigate(R.id.loginFragment, bundle, Utils.getAnimFade())
494+
}
495+
}
496+
497+
private fun writefeedback() {
498+
val layout = layoutInflater.inflate(R.layout.dialog_feedback, null)
499+
500+
val alertDialog = AlertDialog.Builder(requireContext())
501+
.setTitle(getString(R.string.submit_feedback))
502+
.setView(layout)
503+
.setPositiveButton(getString(R.string.submit)) { _, _ ->
504+
eventViewModel.submitFeedback(layout.feedback.text.toString(),
505+
layout.feedbackrating.rating,
506+
safeArgs.eventId)
507+
rootView.snackbar(R.string.feedback_submitted)
508+
}
509+
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
510+
dialog.cancel()
511+
}
512+
513+
.show()
514+
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
515+
layout.feedback.addTextChangedListener(object : TextWatcher {
516+
override fun afterTextChanged(p0: Editable?) {
517+
518+
if (layout.feedback.text.toString().isNotEmpty()) {
519+
layout.feedbackTextInputLayout.error = null
520+
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = true
521+
layout.feedbackTextInputLayout.isErrorEnabled = false
522+
} else {
523+
layout.feedbackTextInputLayout.error = "Can't be Empty"
524+
}
525+
}
526+
527+
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { /*Implement here*/ }
528+
529+
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { /*Implement here*/ }
530+
})
531+
}
457532

458533
override fun onDestroy() {
459534
Picasso.get().cancelRequest(rootView.eventImage)

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import io.reactivex.disposables.CompositeDisposable
99
import io.reactivex.schedulers.Schedulers
1010
import org.fossasia.openevent.general.BuildConfig.MAPBOX_KEY
1111
import org.fossasia.openevent.general.R
12+
import org.fossasia.openevent.general.auth.AuthHolder
1213
import org.fossasia.openevent.general.auth.User
14+
import org.fossasia.openevent.general.auth.UserId
1315
import org.fossasia.openevent.general.common.SingleLiveEvent
1416
import org.fossasia.openevent.general.data.Resource
1517
import org.fossasia.openevent.general.event.feedback.Feedback
@@ -19,6 +21,7 @@ import timber.log.Timber
1921

2022
class EventDetailsViewModel(
2123
private val eventService: EventService,
24+
private val authHolder: AuthHolder,
2225
private val speakerService: SpeakerService,
2326
private val resource: Resource
2427
) : ViewModel() {
@@ -35,6 +38,11 @@ class EventDetailsViewModel(
3538
val event: LiveData<Event> = mutableEvent
3639
private val mutableEventFeedback = MutableLiveData<List<Feedback>>()
3740
val eventFeedback: LiveData<List<Feedback>> = mutableEventFeedback
41+
var eventSpeakers: LiveData<List<Speaker>> = MutableLiveData()
42+
43+
fun isLoggedIn() = authHolder.isLoggedIn()
44+
45+
fun getId() = authHolder.getId()
3846

3947
fun loadEventFeedback(id: Long) {
4048
compositeDisposable.add(eventService.getEventFeedback(id)
@@ -47,7 +55,20 @@ class EventDetailsViewModel(
4755
})
4856
)
4957
}
50-
var eventSpeakers: LiveData<List<Speaker>> = MutableLiveData()
58+
59+
fun submitFeedback(comment: String, rating: Float?, eventId: Long) {
60+
val feedback = Feedback(rating = rating.toString(), comment = comment,
61+
event = EventId(eventId), user = UserId(getId()))
62+
compositeDisposable.add(eventService.submitFeedback(feedback)
63+
.subscribeOn(Schedulers.io())
64+
.observeOn(AndroidSchedulers.mainThread())
65+
.subscribe({
66+
//Do Nothing
67+
}, {
68+
it.message.toString() == "HTTP 400 BAD REQUEST"
69+
})
70+
)
71+
}
5172

5273
fun fetchEventSpeakers(id: Long) {
5374
speakerService.fetchSpeakersForEvent(id)

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ class EventService(
6565
fun getEventFeedback(id: Long): Single<List<Feedback>> {
6666
return eventFeedbackApi.getEventFeedback(id)
6767
}
68+
fun submitFeedback(feedback: Feedback): Single<Feedback> {
69+
return eventFeedbackApi.postfeedback(feedback)
70+
}
6871

6972
fun getSearchEvents(eventName: String): Single<List<Event>> {
7073
return eventApi.searchEvents("name", eventName).flatMap { apiList ->

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategy
44
import com.fasterxml.jackson.databind.annotation.JsonNaming
55
import com.github.jasminb.jsonapi.LongIdHandler
66
import com.github.jasminb.jsonapi.annotations.Id
7+
import com.github.jasminb.jsonapi.annotations.Relationship
78
import com.github.jasminb.jsonapi.annotations.Type
9+
import org.fossasia.openevent.general.auth.UserId
10+
import org.fossasia.openevent.general.event.EventId
811

912
@Type("feedback")
1013
@JsonNaming(PropertyNamingStrategy.KebabCaseStrategy::class)
1114
data class Feedback(
1215
@Id(LongIdHandler::class)
13-
val id: Long,
16+
val id: Long? = null,
1417
val rating: String?,
1518
val comment: String?,
16-
val deletedAt: String?
17-
19+
@Relationship("event")
20+
var event: EventId? = null,
21+
@Relationship("user")
22+
var user: UserId? = null
1823
)

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.fossasia.openevent.general.event.feedback
22

33
import io.reactivex.Single
4+
import retrofit2.http.Body
45
import retrofit2.http.GET
6+
import retrofit2.http.POST
57
import retrofit2.http.Path
68
import retrofit2.http.Query
79

@@ -13,4 +15,7 @@ interface FeedbackApi {
1315
@Query("sort") sort: String = "rating",
1416
@Query("filter") eventName: String = "[]"
1517
): Single<List<Feedback>>
18+
19+
@POST("feedbacks")
20+
fun postfeedback(@Body feedback: Feedback): Single<Feedback>
1621
}

app/src/main/res/layout/content_event.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,24 @@
403403

404404
<androidx.recyclerview.widget.RecyclerView
405405
android:id="@+id/feedbackRv"
406+
tools:itemCount="3"
407+
android:layout_width="match_parent"
408+
tools:listitem="@layout/item_feedback"
409+
android:layout_height="wrap_content" />
410+
411+
<TextView
412+
android:id="@+id/noFeedBackTv"
413+
android:visibility="gone"
414+
android:textSize="@dimen/heading_text_size"
415+
android:text="@string/be_the_first_to_write_a_review"
416+
android:layout_width="match_parent"
417+
android:textAlignment="center"
418+
android:layout_height="wrap_content" />
419+
420+
<Button
421+
android:id="@+id/feedbackBtn"
422+
android:text="@string/write_feedback"
423+
android:layout_margin="@dimen/layout_margin_large"
406424
android:layout_width="match_parent"
407425
android:layout_height="wrap_content" />
408426
</LinearLayout>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
android:orientation="vertical"
5+
android:layout_width="match_parent"
6+
android:layout_height="match_parent"
7+
android:padding="@dimen/padding_large">
8+
9+
<RatingBar
10+
android:id="@+id/feedbackrating"
11+
android:layout_width="wrap_content"
12+
android:layout_gravity="center_horizontal"
13+
android:layout_height="wrap_content"
14+
android:numStars="5" />
15+
16+
<com.google.android.material.textfield.TextInputLayout
17+
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
18+
android:id="@+id/feedbackTextInputLayout"
19+
android:layout_width="match_parent"
20+
android:layout_height="wrap_content"
21+
app:errorEnabled="true"
22+
android:layout_marginBottom="@dimen/padding_medium"
23+
android:layout_marginTop="@dimen/padding_medium"
24+
app:passwordToggleEnabled="true">
25+
26+
<com.google.android.material.textfield.TextInputEditText
27+
android:id="@+id/feedback"
28+
android:layout_width="match_parent"
29+
android:layout_height="wrap_content"
30+
android:hint="@string/write_feedback"
31+
android:inputType="textCapSentences" />
32+
</com.google.android.material.textfield.TextInputLayout>
33+
34+
</LinearLayout>

app/src/main/res/values/strings.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,5 +309,10 @@
309309
<string name="savedType">savedType</string>
310310
<string name="what_type">What Sounds good?</string>
311311
<string name="feedback">Feedback</string>
312+
<string name="write_feedback">Write Feedback</string>
313+
<string name="submit">Submit</string>
314+
<string name="submit_feedback">Submit Feedback</string>
315+
<string name="feedback_submitted">Feedback submitted Successfully</string>
316+
<string name="be_the_first_to_write_a_review">Be the first to write a review</string>
312317

313318
</resources>

0 commit comments

Comments
 (0)