Skip to content

Commit c77fc5a

Browse files
anhanh11001iamareebjamal
authored andcommitted
feat: Add log in to save favorite event (#2118)
Fixes: #1652
1 parent 7ee0873 commit c77fc5a

28 files changed

+570
-153
lines changed

app/schemas/org.fossasia.openevent.general.OpenEventDatabase/8.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
"formatVersion": 1,
33
"database": {
44
"version": 8,
5-
"identityHash": "bf7cbd2b19683a13c4f43725b790ccd4",
5+
"identityHash": "220a5a8960fa7289b6b6f4a9fe11c92d",
66
"entities": [
77
{
88
"tableName": "Event",
9-
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `identifier` TEXT NOT NULL, `startsAt` TEXT NOT NULL, `endsAt` TEXT NOT NULL, `timezone` TEXT NOT NULL, `privacy` TEXT NOT NULL, `paymentCountry` TEXT, `paypalEmail` TEXT, `thumbnailImageUrl` TEXT, `schedulePublishedOn` TEXT, `paymentCurrency` TEXT, `ownerDescription` TEXT, `originalImageUrl` TEXT, `onsiteDetails` TEXT, `ownerName` TEXT, `largeImageUrl` TEXT, `deletedAt` TEXT, `ticketUrl` TEXT, `locationName` TEXT, `codeOfConduct` TEXT, `state` TEXT, `searchableLocationName` TEXT, `description` TEXT, `pentabarfUrl` TEXT, `xcalUrl` TEXT, `logoUrl` TEXT, `externalEventUrl` TEXT, `iconImageUrl` TEXT, `icalUrl` TEXT, `createdAt` TEXT, `bankDetails` TEXT, `chequeDetails` TEXT, `isComplete` INTEGER NOT NULL, `latitude` REAL, `longitude` REAL, `refundPolicy` TEXT, `canPayByStripe` INTEGER NOT NULL, `canPayByCheque` INTEGER NOT NULL, `canPayByBank` INTEGER NOT NULL, `canPayByPaypal` INTEGER NOT NULL, `canPayOnsite` INTEGER NOT NULL, `isSponsorsEnabled` INTEGER NOT NULL, `hasOwnerInfo` INTEGER NOT NULL, `isSessionsSpeakersEnabled` INTEGER NOT NULL, `isTicketingEnabled` INTEGER NOT NULL, `isTaxEnabled` INTEGER NOT NULL, `isMapShown` INTEGER NOT NULL, `favorite` INTEGER NOT NULL, `eventTopic` TEXT, `eventType` TEXT, `eventSubTopic` TEXT, `speakersCall` TEXT, PRIMARY KEY(`id`))",
9+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `identifier` TEXT NOT NULL, `startsAt` TEXT NOT NULL, `endsAt` TEXT NOT NULL, `timezone` TEXT NOT NULL, `privacy` TEXT NOT NULL, `paymentCountry` TEXT, `paypalEmail` TEXT, `thumbnailImageUrl` TEXT, `schedulePublishedOn` TEXT, `paymentCurrency` TEXT, `ownerDescription` TEXT, `originalImageUrl` TEXT, `onsiteDetails` TEXT, `ownerName` TEXT, `largeImageUrl` TEXT, `deletedAt` TEXT, `ticketUrl` TEXT, `locationName` TEXT, `codeOfConduct` TEXT, `state` TEXT, `searchableLocationName` TEXT, `description` TEXT, `pentabarfUrl` TEXT, `xcalUrl` TEXT, `logoUrl` TEXT, `externalEventUrl` TEXT, `iconImageUrl` TEXT, `icalUrl` TEXT, `createdAt` TEXT, `bankDetails` TEXT, `chequeDetails` TEXT, `isComplete` INTEGER NOT NULL, `latitude` REAL, `longitude` REAL, `refundPolicy` TEXT, `canPayByStripe` INTEGER NOT NULL, `canPayByCheque` INTEGER NOT NULL, `canPayByBank` INTEGER NOT NULL, `canPayByPaypal` INTEGER NOT NULL, `canPayOnsite` INTEGER NOT NULL, `isSponsorsEnabled` INTEGER NOT NULL, `hasOwnerInfo` INTEGER NOT NULL, `isSessionsSpeakersEnabled` INTEGER NOT NULL, `isTicketingEnabled` INTEGER NOT NULL, `isTaxEnabled` INTEGER NOT NULL, `isMapShown` INTEGER NOT NULL, `favorite` INTEGER NOT NULL, `favoriteEventId` INTEGER, `eventTopic` TEXT, `eventType` TEXT, `eventSubTopic` TEXT, `speakersCall` TEXT, PRIMARY KEY(`id`))",
1010
"fields": [
1111
{
1212
"fieldPath": "id",
@@ -302,6 +302,12 @@
302302
"affinity": "INTEGER",
303303
"notNull": true
304304
},
305+
{
306+
"fieldPath": "favoriteEventId",
307+
"columnName": "favoriteEventId",
308+
"affinity": "INTEGER",
309+
"notNull": false
310+
},
305311
{
306312
"fieldPath": "eventTopic",
307313
"columnName": "eventTopic",
@@ -1967,7 +1973,7 @@
19671973
"views": [],
19681974
"setupQueries": [
19691975
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
1970-
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bf7cbd2b19683a13c4f43725b790ccd4')"
1976+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '220a5a8960fa7289b6b6f4a9fe11c92d')"
19711977
]
19721978
}
19731979
}

app/src/main/java/org/fossasia/openevent/general/auth/AuthFragment.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import org.fossasia.openevent.general.ComplexBackPressFragment
2525
import org.fossasia.openevent.general.PLAY_STORE_BUILD_FLAVOR
2626
import org.fossasia.openevent.general.R
2727
import org.fossasia.openevent.general.event.EVENT_DETAIL_FRAGMENT
28+
import org.fossasia.openevent.general.search.ORDER_COMPLETED_FRAGMENT
29+
import org.fossasia.openevent.general.search.SEARCH_RESULTS_FRAGMENT
2830
import org.fossasia.openevent.general.search.location.SEARCH_LOCATION_FRAGMENT
2931
import org.fossasia.openevent.general.ticket.TICKETS_FRAGMENT
3032
import org.fossasia.openevent.general.utils.Utils.hideSoftKeyboard
@@ -161,6 +163,8 @@ class AuthFragment : Fragment(), ComplexBackPressFragment {
161163
WELCOME_FRAGMENT -> findNavController(rootView).popBackStack(R.id.welcomeFragment, false)
162164
SEARCH_LOCATION_FRAGMENT -> findNavController(rootView).popBackStack(R.id.searchLocationFragment, false)
163165
PROFILE_FRAGMENT -> findNavController(rootView).popBackStack(R.id.profileFragment, false)
166+
SEARCH_RESULTS_FRAGMENT -> findNavController(rootView).popBackStack(R.id.searchResultsFragment, false)
167+
ORDER_COMPLETED_FRAGMENT -> findNavController(rootView).popBackStack(R.id.orderCompletedFragment, false)
164168
else -> findNavController(rootView).navigate(AuthFragmentDirections.actionAuthToEventsPop())
165169
}
166170
}

app/src/main/java/org/fossasia/openevent/general/auth/AuthService.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import org.fossasia.openevent.general.auth.change.Password
99
import org.fossasia.openevent.general.auth.forgot.Email
1010
import org.fossasia.openevent.general.auth.forgot.RequestToken
1111
import org.fossasia.openevent.general.auth.forgot.RequestTokenResponse
12+
import org.fossasia.openevent.general.event.EventApi
13+
import org.fossasia.openevent.general.event.EventDao
1214
import org.fossasia.openevent.general.order.OrderDao
1315
import timber.log.Timber
1416

@@ -17,7 +19,9 @@ class AuthService(
1719
private val authHolder: AuthHolder,
1820
private val userDao: UserDao,
1921
private val orderDao: OrderDao,
20-
private val attendeeDao: AttendeeDao
22+
private val attendeeDao: AttendeeDao,
23+
private val eventDao: EventDao,
24+
private val eventApi: EventApi
2125
) {
2226
fun login(username: String, password: String): Single<LoginResponse> {
2327
if (username.isEmpty() || password.isEmpty())
@@ -61,6 +65,7 @@ class AuthService(
6165
userDao.deleteUser(authHolder.getId())
6266
orderDao.deleteAllOrders()
6367
attendeeDao.deleteAllAttendees()
68+
eventDao.clearFavoriteEvents()
6469
}
6570
}
6671

app/src/main/java/org/fossasia/openevent/general/auth/LoginFragment.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ import org.fossasia.openevent.general.BuildConfig
2828
import org.fossasia.openevent.general.PLAY_STORE_BUILD_FLAVOR
2929
import org.fossasia.openevent.general.R
3030
import org.fossasia.openevent.general.event.EVENT_DETAIL_FRAGMENT
31+
import org.fossasia.openevent.general.favorite.FAVORITE_FRAGMENT
3132
import org.fossasia.openevent.general.notification.NOTIFICATION_FRAGMENT
3233
import org.fossasia.openevent.general.order.ORDERS_FRAGMENT
34+
import org.fossasia.openevent.general.search.ORDER_COMPLETED_FRAGMENT
35+
import org.fossasia.openevent.general.search.SEARCH_RESULTS_FRAGMENT
3336
import org.fossasia.openevent.general.speakercall.SPEAKERS_CALL_FRAGMENT
3437
import org.fossasia.openevent.general.ticket.TICKETS_FRAGMENT
3538
import org.fossasia.openevent.general.utils.Utils.setToolbar
@@ -194,6 +197,9 @@ class LoginFragment : Fragment() {
194197
TICKETS_FRAGMENT -> R.id.ticketsFragment
195198
NOTIFICATION_FRAGMENT -> R.id.notificationFragment
196199
SPEAKERS_CALL_FRAGMENT -> R.id.speakersCallFragment
200+
FAVORITE_FRAGMENT -> R.id.favoriteFragment
201+
SEARCH_RESULTS_FRAGMENT -> R.id.searchResultsFragment
202+
ORDER_COMPLETED_FRAGMENT -> R.id.orderCompletedFragment
197203
else -> R.id.eventsFragment
198204
}
199205
if (destinationId == R.id.eventsFragment) {

app/src/main/java/org/fossasia/openevent/general/auth/LoginViewModel.kt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,22 @@ package org.fossasia.openevent.general.auth
33
import androidx.lifecycle.LiveData
44
import androidx.lifecycle.MutableLiveData
55
import androidx.lifecycle.ViewModel
6+
import io.reactivex.Single
67
import io.reactivex.disposables.CompositeDisposable
78
import org.fossasia.openevent.general.R
89
import io.reactivex.rxkotlin.plusAssign
910
import org.fossasia.openevent.general.utils.extensions.withDefaultSchedulers
1011
import org.fossasia.openevent.general.common.SingleLiveEvent
1112
import org.fossasia.openevent.general.data.Network
1213
import org.fossasia.openevent.general.data.Resource
14+
import org.fossasia.openevent.general.event.EventService
1315
import timber.log.Timber
1416

1517
class LoginViewModel(
1618
private val authService: AuthService,
1719
private val network: Network,
18-
private val resource: Resource
20+
private val resource: Resource,
21+
private val eventService: EventService
1922
) : ViewModel() {
2023

2124
private val compositeDisposable = CompositeDisposable()
@@ -37,7 +40,17 @@ class LoginViewModel(
3740

3841
fun login(email: String, password: String) {
3942
if (!isConnected()) return
40-
compositeDisposable += authService.login(email, password)
43+
44+
val loginObservable: Single<LoginResponse> = authService.login(email, password).flatMap { loginResponse ->
45+
eventService.loadFavoriteEvent().flatMap { favsList ->
46+
val favIds = favsList.filter { favEvent -> favEvent.event != null }
47+
eventService.saveFavoritesEventFromApi(favIds).flatMap {
48+
Single.just(loginResponse)
49+
}
50+
}
51+
}
52+
53+
compositeDisposable += loginObservable
4154
.withDefaultSchedulers()
4255
.doOnSubscribe {
4356
mutableProgress.value = true

app/src/main/java/org/fossasia/openevent/general/auth/SignUpFragment.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ import android.text.method.LinkMovementMethod
3535
import androidx.navigation.fragment.navArgs
3636
import org.fossasia.openevent.general.utils.StringUtils.getTermsAndPolicyText
3737
import org.fossasia.openevent.general.event.EVENT_DETAIL_FRAGMENT
38+
import org.fossasia.openevent.general.favorite.FAVORITE_FRAGMENT
3839
import org.fossasia.openevent.general.notification.NOTIFICATION_FRAGMENT
3940
import org.fossasia.openevent.general.order.ORDERS_FRAGMENT
41+
import org.fossasia.openevent.general.search.ORDER_COMPLETED_FRAGMENT
42+
import org.fossasia.openevent.general.search.SEARCH_RESULTS_FRAGMENT
4043
import org.fossasia.openevent.general.speakercall.SPEAKERS_CALL_FRAGMENT
4144
import org.fossasia.openevent.general.ticket.TICKETS_FRAGMENT
4245
import org.fossasia.openevent.general.utils.extensions.setSharedElementEnterTransition
@@ -200,6 +203,9 @@ class SignUpFragment : Fragment() {
200203
TICKETS_FRAGMENT -> R.id.ticketsFragment
201204
NOTIFICATION_FRAGMENT -> R.id.notificationFragment
202205
SPEAKERS_CALL_FRAGMENT -> R.id.speakersCallFragment
206+
FAVORITE_FRAGMENT -> R.id.favoriteFragment
207+
SEARCH_RESULTS_FRAGMENT -> R.id.searchResultsFragment
208+
ORDER_COMPLETED_FRAGMENT -> R.id.orderCompletedFragment
203209
else -> R.id.eventsFragment
204210
}
205211
if (destinationId == R.id.eventsFragment) {

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

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ import org.fossasia.openevent.general.sessions.Session
8181
import org.fossasia.openevent.general.sessions.SessionApi
8282
import org.fossasia.openevent.general.sessions.SessionService
8383
import org.fossasia.openevent.general.event.faq.EventFAQViewModel
84+
import org.fossasia.openevent.general.favorite.FavoriteEvent
85+
import org.fossasia.openevent.general.favorite.FavoriteEventApi
8486
import org.fossasia.openevent.general.feedback.FeedbackViewModel
8587
import org.fossasia.openevent.general.feedback.Feedback
8688
import org.fossasia.openevent.general.feedback.FeedbackService
@@ -142,6 +144,10 @@ val apiModule = module {
142144
val retrofit: Retrofit = get()
143145
retrofit.create(TicketApi::class.java)
144146
}
147+
single {
148+
val retrofit: Retrofit = get()
149+
retrofit.create(FavoriteEventApi::class.java)
150+
}
145151
single {
146152
val retrofit: Retrofit = get()
147153
retrofit.create(SocialLinkApi::class.java)
@@ -204,9 +210,9 @@ val apiModule = module {
204210
}
205211

206212
factory { AuthHolder(get()) }
207-
factory { AuthService(get(), get(), get(), get(), get()) }
213+
factory { AuthService(get(), get(), get(), get(), get(), get(), get()) }
208214

209-
factory { EventService(get(), get(), get(), get(), get(), get(), get(), get()) }
215+
factory { EventService(get(), get(), get(), get(), get(), get(), get(), get(), get()) }
210216
factory { SpeakerService(get(), get(), get()) }
211217
factory { SponsorService(get(), get(), get()) }
212218
factory { TicketService(get(), get(), get()) }
@@ -220,26 +226,26 @@ val apiModule = module {
220226
}
221227

222228
val viewModelModule = module {
223-
viewModel { LoginViewModel(get(), get(), get()) }
224-
viewModel { EventsViewModel(get(), get(), get(), get(), get()) }
229+
viewModel { LoginViewModel(get(), get(), get(), get()) }
230+
viewModel { EventsViewModel(get(), get(), get(), get(), get(), get()) }
225231
viewModel { StartupViewModel(get(), get(), get(), get(), get(), get()) }
226232
viewModel { ProfileViewModel(get(), get()) }
227233
viewModel { SignUpViewModel(get(), get(), get()) }
228234
viewModel {
229235
EventDetailsViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) }
230236
viewModel { SessionViewModel(get(), get(), get()) }
231237
viewModel { SearchViewModel(get(), get()) }
232-
viewModel { SearchResultsViewModel(get(), get(), get(), get(), get()) }
238+
viewModel { SearchResultsViewModel(get(), get(), get(), get(), get(), get()) }
233239
viewModel { AttendeeViewModel(get(), get(), get(), get(), get(), get(), get(), get()) }
234240
viewModel { SearchLocationViewModel(get(), get()) }
235241
viewModel { SearchTimeViewModel(get()) }
236242
viewModel { SearchTypeViewModel(get(), get(), get()) }
237243
viewModel { TicketsViewModel(get(), get(), get(), get(), get()) }
238244
viewModel { AboutEventViewModel(get(), get()) }
239245
viewModel { EventFAQViewModel(get(), get()) }
240-
viewModel { FavoriteEventsViewModel(get(), get()) }
246+
viewModel { FavoriteEventsViewModel(get(), get(), get()) }
241247
viewModel { SettingsViewModel(get()) }
242-
viewModel { OrderCompletedViewModel(get(), get(), get()) }
248+
viewModel { OrderCompletedViewModel(get(), get(), get(), get()) }
243249
viewModel { OrdersUnderUserViewModel(get(), get(), get(), get(), get()) }
244250
viewModel { OrderDetailsViewModel(get(), get(), get(), get()) }
245251
viewModel { EditProfileViewModel(get(), get(), get()) }
@@ -299,7 +305,7 @@ val networkModule = module {
299305
EventTopic::class.java, Attendee::class.java, TicketId::class.java, Order::class.java,
300306
AttendeeId::class.java, Charge::class.java, Paypal::class.java, ConfirmOrder::class.java,
301307
CustomForm::class.java, EventLocation::class.java, EventType::class.java,
302-
EventSubTopic::class.java, Feedback::class.java, Speaker::class.java,
308+
EventSubTopic::class.java, Feedback::class.java, Speaker::class.java, FavoriteEvent::class.java,
303309
Session::class.java, SessionType::class.java, MicroLocation::class.java, SpeakersCall::class.java,
304310
Sponsor::class.java, EventFAQ::class.java, Notification::class.java, Track::class.java,
305311
DiscountCode::class.java, Settings::class.java)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ data class Event(
7070
val isTaxEnabled: Boolean = false,
7171
val isMapShown: Boolean = false,
7272
var favorite: Boolean = false,
73+
var favoriteEventId: Long? = null,
7374
@ColumnInfo(index = true)
7475
@Relationship("event-topic", resolve = true)
7576
val eventTopic: EventTopic? = null,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ interface EventApi {
1515
fun getEventFromApi(@Path("eventIdentifier") eventIdentifier: String): Single<Event>
1616

1717
@GET("events")
18-
fun eventsUnderUser(@Query("filter") eventId: String): Single<List<Event>>
18+
fun eventsWithQuery(@Query("filter") filter: String): Single<List<Event>>
1919

2020
@GET("events/{eventId}/speakers-call")
2121
fun getSpeakerCallForEvent(@Path("eventId") id: Long): Single<SpeakersCall>

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,15 @@ interface EventDao {
3737
@Query("SELECT * from Event WHERE favorite = 1")
3838
fun getFavoriteEvents(): Flowable<List<Event>>
3939

40-
@Query("SELECT id from Event WHERE favorite = 1 AND id in (:ids)")
41-
fun getFavoriteEventWithinIds(ids: List<Long>): Single<List<Long>>
40+
@Query("SELECT * from Event WHERE favorite = 1 AND id in (:ids)")
41+
fun getFavoriteEventWithinIds(ids: List<Long>): Single<List<Event>>
4242

4343
@Query("SELECT * from Event WHERE eventTopic = :eventTopic")
4444
fun getAllSimilarEvents(eventTopic: EventTopic): Flowable<List<Event>>
4545

4646
@Query("SELECT * FROM EventTopic WHERE id=:topicId")
4747
fun getEventTopic(topicId: Long): Single<EventTopic>
48+
49+
@Query("UPDATE Event SET favorite = :favorite AND favoriteEventId = NULL")
50+
fun clearFavoriteEvents(favorite: Boolean = false)
4851
}

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,11 +533,22 @@ class EventDetailsFragment : Fragment() {
533533
}
534534
}
535535

536+
val redirectToLogin = object : RedirectToLogin {
537+
override fun goBackToLogin() {
538+
redirectToLogin()
539+
}
540+
}
541+
536542
val favFabClickListener: FavoriteFabClickListener = object : FavoriteFabClickListener {
537543
override fun onClick(event: Event, itemPosition: Int) {
538-
eventViewModel.setFavorite(event.id, !event.favorite)
539-
event.favorite = !event.favorite
540-
similarEventsAdapter.notifyItemChanged(itemPosition)
544+
if (eventViewModel.isLoggedIn()) {
545+
event.favorite = !event.favorite
546+
eventViewModel.setFavorite(event, event.favorite)
547+
similarEventsAdapter.notifyItemChanged(itemPosition)
548+
} else {
549+
EventUtils.showLoginToLikeDialog(requireContext(),
550+
layoutInflater, redirectToLogin, event.originalImageUrl, event.name)
551+
}
541552
}
542553
}
543554

@@ -572,7 +583,16 @@ class EventDetailsFragment : Fragment() {
572583
true
573584
}
574585
R.id.favorite_event -> {
575-
currentEvent?.let { eventViewModel.setFavorite(it.id, !it.favorite) }
586+
currentEvent?.let {
587+
if (eventViewModel.isLoggedIn()) {
588+
it.favorite = !it.favorite
589+
eventViewModel.setFavorite(it, it.favorite)
590+
currentEvent = it
591+
} else {
592+
EventUtils.showLoginToLikeDialog(requireContext(), layoutInflater, object : RedirectToLogin {
593+
override fun goBackToLogin() { redirectToLogin() } }, it.originalImageUrl, it.name)
594+
}
595+
}
576596
true
577597
}
578598
R.id.call_for_speakers -> {

0 commit comments

Comments
 (0)