Skip to content

Commit b309f30

Browse files
committed
feat: Display ticket price range and revalidate tickets (#1990)
1 parent 7802a0f commit b309f30

File tree

10 files changed

+122
-7
lines changed

10 files changed

+122
-7
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"formatVersion": 1,
33
"database": {
44
"version": 7,
5-
"identityHash": "bf12d8e7557281fa0414606f818fac5e",
5+
"identityHash": "a641e7fa047321119d684609308e713a",
66
"entities": [
77
{
88
"tableName": "Event",
@@ -576,7 +576,7 @@
576576
},
577577
{
578578
"tableName": "Ticket",
579-
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `description` TEXT, `type` TEXT, `name` TEXT NOT NULL, `maxOrder` INTEGER NOT NULL, `isFeeAbsorbed` INTEGER, `isDescriptionVisible` INTEGER, `price` REAL, `position` TEXT, `quantity` TEXT, `isHidden` INTEGER, `salesStartsAt` TEXT, `salesEndsAt` TEXT, `minOrder` INTEGER NOT NULL, `event` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`event`) REFERENCES `Event`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
579+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `description` TEXT, `type` TEXT, `name` TEXT NOT NULL, `maxOrder` INTEGER NOT NULL, `isFeeAbsorbed` INTEGER, `isDescriptionVisible` INTEGER, `price` REAL NOT NULL, `position` TEXT, `quantity` TEXT, `isHidden` INTEGER, `salesStartsAt` TEXT, `salesEndsAt` TEXT, `minOrder` INTEGER NOT NULL, `event` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`event`) REFERENCES `Event`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
580580
"fields": [
581581
{
582582
"fieldPath": "id",
@@ -624,7 +624,7 @@
624624
"fieldPath": "price",
625625
"columnName": "price",
626626
"affinity": "REAL",
627-
"notNull": false
627+
"notNull": true
628628
},
629629
{
630630
"fieldPath": "position",
@@ -1899,7 +1899,7 @@
18991899
"views": [],
19001900
"setupQueries": [
19011901
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
1902-
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bf12d8e7557281fa0414606f818fac5e')"
1902+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a641e7fa047321119d684609308e713a')"
19031903
]
19041904
}
19051905
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ val viewModelModule = module {
215215
viewModel { EventsViewModel(get(), get(), get(), get(), get(), get(), get()) }
216216
viewModel { ProfileViewModel(get(), get()) }
217217
viewModel { SignUpViewModel(get(), get(), get()) }
218-
viewModel { EventDetailsViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) }
218+
viewModel { EventDetailsViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) }
219219
viewModel { SessionViewModel(get(), get(), get()) }
220220
viewModel { SearchViewModel(get(), get()) }
221221
viewModel { SearchResultsViewModel(get(), get(), get(), get(), get()) }

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ import kotlinx.android.synthetic.main.content_event.view.socialLinkContainer
5454
import kotlinx.android.synthetic.main.content_event.view.similarEventsRecycler
5555
import kotlinx.android.synthetic.main.content_event.view.similarEventsContainer
5656
import kotlinx.android.synthetic.main.content_event.view.alreadyRegisteredLayout
57+
import kotlinx.android.synthetic.main.content_event.view.ticketPriceLinearLayout
58+
import kotlinx.android.synthetic.main.content_event.view.priceRangeTextView
5759
import kotlinx.android.synthetic.main.fragment_event.view.buttonTickets
5860
import kotlinx.android.synthetic.main.fragment_event.view.eventErrorCard
5961
import kotlinx.android.synthetic.main.fragment_event.view.container
@@ -203,6 +205,8 @@ class EventDetailsFragment : Fragment() {
203205
eventViewModel.fetchEventSponsors(it.id)
204206
if (eventViewModel.socialLinks.value == null)
205207
eventViewModel.fetchSocialLink(it.id)
208+
if (eventViewModel.priceRange.value == null)
209+
eventViewModel.syncTickets(it)
206210

207211
// Update favorite icon and external event url menu option
208212
activity?.invalidateOptionsMenu()
@@ -212,6 +216,13 @@ class EventDetailsFragment : Fragment() {
212216
setHasOptionsMenu(true)
213217
})
214218

219+
eventViewModel.priceRange
220+
.nonNull()
221+
.observe(viewLifecycleOwner, Observer {
222+
rootView.ticketPriceLinearLayout.isVisible = true
223+
rootView.priceRangeTextView.text = it
224+
})
225+
215226
val eventIdentifier = arguments?.getString(EVENT_IDENTIFIER)
216227
val event = eventViewModel.event.value
217228
when {

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ import org.fossasia.openevent.general.speakers.Speaker
2727
import org.fossasia.openevent.general.speakers.SpeakerService
2828
import org.fossasia.openevent.general.sponsor.Sponsor
2929
import org.fossasia.openevent.general.sponsor.SponsorService
30+
import org.fossasia.openevent.general.ticket.TicketPriceRange
31+
import org.fossasia.openevent.general.ticket.TicketService
3032
import org.fossasia.openevent.general.utils.extensions.withDefaultSchedulers
3133
import timber.log.Timber
34+
import java.lang.StringBuilder
3235

3336
class EventDetailsViewModel(
3437
private val eventService: EventService,
38+
private val ticketService: TicketService,
3539
private val authHolder: AuthHolder,
3640
private val speakerService: SpeakerService,
3741
private val sponsorService: SponsorService,
@@ -74,6 +78,8 @@ class EventDetailsViewModel(
7478
val similarEventsProgress: LiveData<Boolean> = mutableSimilarEventsProgress
7579
private val mutableOrders = MutableLiveData<List<Order>>()
7680
val orders: LiveData<List<Order>> = mutableOrders
81+
private val mutablePriceRange = MutableLiveData<String>()
82+
val priceRange: LiveData<String> = mutablePriceRange
7783

7884
fun isLoggedIn() = authHolder.isLoggedIn()
7985

@@ -255,6 +261,55 @@ class EventDetailsViewModel(
255261
})
256262
}
257263

264+
fun syncTickets(event: Event) {
265+
compositeDisposable += ticketService.syncTickets(event.id)
266+
.withDefaultSchedulers()
267+
.subscribe({
268+
if (!it.isNullOrEmpty())
269+
loadPriceRange(event)
270+
}, {
271+
Timber.e(it, "Error fetching tickets")
272+
})
273+
}
274+
275+
private fun loadPriceRange(event: Event) {
276+
compositeDisposable += ticketService.getTicketPriceRange(event.id)
277+
.withDefaultSchedulers()
278+
.subscribe({
279+
setRange(it, event.paymentCurrency.toString())
280+
}, {
281+
Timber.e(it, "Error fetching ticket price range")
282+
})
283+
}
284+
285+
private fun setRange(priceRange: TicketPriceRange, paymentCurrency: String) {
286+
val maxPrice = priceRange.maxValue
287+
val minPrice = priceRange.minValue
288+
val range = StringBuilder()
289+
if (maxPrice == minPrice) {
290+
if (maxPrice == 0f)
291+
range.append("Free")
292+
else {
293+
range.append(paymentCurrency)
294+
range.append(" ")
295+
range.append(minPrice)
296+
}
297+
} else {
298+
if (minPrice == 0f)
299+
range.append("Free")
300+
else {
301+
range.append(paymentCurrency)
302+
range.append(" ")
303+
range.append(minPrice)
304+
}
305+
range.append(" - ")
306+
range.append(paymentCurrency)
307+
range.append(" ")
308+
range.append(maxPrice)
309+
}
310+
mutablePriceRange.value = range.toString()
311+
}
312+
258313
fun loadMap(event: Event): String {
259314
// location handling
260315
val BASE_URL = "https://api.mapbox.com/v4/mapbox.emerald/pin-l-marker+673ab7"

app/src/main/java/org/fossasia/openevent/general/ticket/Ticket.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ data class Ticket(
2828
val maxOrder: Int = 0,
2929
val isFeeAbsorbed: Boolean? = false,
3030
val isDescriptionVisible: Boolean? = false,
31-
val price: Float?,
31+
val price: Float,
3232
val position: String?,
3333
val quantity: String?,
3434

app/src/main/java/org/fossasia/openevent/general/ticket/TicketDao.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ interface TicketDao {
2323

2424
@Query("SELECT * from Ticket WHERE id in (:ids)")
2525
fun getTicketsWithIds(ids: List<Int>): Single<List<Ticket>>
26+
27+
@Query("SELECT MAX(price) as maxValue, MIN(price) as minValue from Ticket WHERE event = :eventId")
28+
fun getTicketPriceRange(eventId: Long): Single<TicketPriceRange>
2629
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.fossasia.openevent.general.ticket
2+
3+
data class TicketPriceRange(
4+
val maxValue: Float,
5+
val minValue: Float
6+
)

app/src/main/java/org/fossasia/openevent/general/ticket/TicketService.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ class TicketService(
2929
}
3030
}
3131

32+
fun syncTickets(id: Long): Flowable<List<Ticket>> {
33+
return ticketApi.getTickets(id).map {
34+
ticketDao.insertTickets(it)
35+
it
36+
}
37+
}
38+
39+
fun getTicketPriceRange(id: Long): Single<TicketPriceRange> {
40+
return ticketDao.getTicketPriceRange(id)
41+
}
42+
3243
fun getTicketDetails(id: Long): Single<Ticket> {
3344
return ticketDao.getTicketDetails(id)
3445
}

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,34 @@
184184
tools:text="Location" />
185185
</LinearLayout>
186186

187+
<LinearLayout
188+
android:id="@+id/ticketPriceLinearLayout"
189+
android:layout_width="0dp"
190+
android:layout_height="wrap_content"
191+
android:layout_marginTop="@dimen/layout_margin_large"
192+
android:layout_marginEnd="@dimen/layout_margin_medium"
193+
android:visibility="gone"
194+
android:background="?selectableItemBackground"
195+
android:orientation="horizontal"
196+
app:layout_constraintEnd_toEndOf="parent"
197+
app:layout_constraintStart_toStartOf="@+id/refundPolicyLinearLayout"
198+
app:layout_constraintTop_toBottomOf="@+id/refundPolicyLinearLayout">
199+
200+
<ImageView
201+
android:layout_width="wrap_content"
202+
android:layout_height="wrap_content"
203+
android:layout_margin="@dimen/layout_margin_medium"
204+
app:srcCompat="@drawable/ic_outline_ticket"
205+
app:tint="@color/eventDetailsFragmentIcon"/>
206+
207+
<TextView
208+
android:id="@+id/priceRangeTextView"
209+
android:layout_width="wrap_content"
210+
android:layout_height="wrap_content"
211+
android:layout_margin="@dimen/layout_margin_medium"
212+
android:textColor="@color/dark_grey"/>
213+
</LinearLayout>
214+
187215
<LinearLayout
188216
android:id="@+id/refundPolicyLinearLayout"
189217
android:layout_width="0dp"
@@ -237,7 +265,7 @@
237265
app:layout_constraintEnd_toEndOf="parent"
238266
app:layout_constraintHorizontal_bias="0.5"
239267
app:layout_constraintStart_toStartOf="parent"
240-
app:layout_constraintTop_toBottomOf="@+id/refundPolicyLinearLayout"
268+
app:layout_constraintTop_toBottomOf="@+id/ticketPriceLinearLayout"
241269
tools:visibility="visible">
242270

243271
<View

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@
2424
<color name="orderStatusBlue">#2889D2</color>
2525
<color name="orderStatusGreen">#21BA45</color>
2626
<color name="orderStatusOrange">#F2711C</color>
27+
<color name="eventDetailsFragmentIcon">#b2b2b2</color>
2728
</resources>

0 commit comments

Comments
 (0)