Skip to content

Commit 8b970b7

Browse files
anhanh11001iamareebjamal
authored andcommitted
feat: Add custom form for speakers and sessions (#2170)
Fixes: #2166
1 parent 629b01f commit 8b970b7

File tree

16 files changed

+555
-34
lines changed

16 files changed

+555
-34
lines changed

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"formatVersion": 1,
33
"database": {
44
"version": 8,
5-
"identityHash": "c65ffea75fee1faf6cd199cbbc5c25ee",
5+
"identityHash": "35acee6b8147d48c581bb8f884508c79",
66
"entities": [
77
{
88
"tableName": "Event",
@@ -1223,7 +1223,7 @@
12231223
},
12241224
{
12251225
"tableName": "Speaker",
1226-
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `email` TEXT, `photoUrl` TEXT, `shortBiography` TEXT, `longBiography` TEXT, `speakingExperience` TEXT, `position` TEXT, `mobile` TEXT, `location` TEXT, `country` TEXT, `city` TEXT, `organisation` TEXT, `gender` TEXT, `website` TEXT, `twitter` TEXT, `facebook` TEXT, `linkedin` TEXT, `github` TEXT, `isFeatured` INTEGER NOT NULL, `event` INTEGER, `user` INTEGER, PRIMARY KEY(`id`))",
1226+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `email` TEXT, `photoUrl` TEXT, `shortBiography` TEXT, `longBiography` TEXT, `speakingExperience` TEXT, `position` TEXT, `mobile` TEXT, `location` TEXT, `country` TEXT, `city` TEXT, `organisation` TEXT, `gender` TEXT, `website` TEXT, `twitter` TEXT, `facebook` TEXT, `linkedin` TEXT, `github` TEXT, `heardFrom` TEXT, `isFeatured` INTEGER NOT NULL, `event` INTEGER, `user` INTEGER, PRIMARY KEY(`id`))",
12271227
"fields": [
12281228
{
12291229
"fieldPath": "id",
@@ -1339,6 +1339,12 @@
13391339
"affinity": "TEXT",
13401340
"notNull": false
13411341
},
1342+
{
1343+
"fieldPath": "heardFrom",
1344+
"columnName": "heardFrom",
1345+
"affinity": "TEXT",
1346+
"notNull": false
1347+
},
13421348
{
13431349
"fieldPath": "isFeatured",
13441350
"columnName": "isFeatured",
@@ -1985,7 +1991,7 @@
19851991
},
19861992
{
19871993
"tableName": "Proposal",
1988-
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `title` TEXT, `language` TEXT, `shortAbstract` TEXT, `comments` TEXT, `startsAt` TEXT, `endsAt` TEXT, `track` TEXT, `event` INTEGER, `speakers` TEXT NOT NULL, PRIMARY KEY(`id`))",
1994+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `title` TEXT, `language` TEXT, `shortAbstract` TEXT, `comments` TEXT, `startsAt` TEXT, `endsAt` TEXT, `subTitle` TEXT, `longAbstract` TEXT, `track` TEXT, `event` INTEGER, `speakers` TEXT NOT NULL, PRIMARY KEY(`id`))",
19891995
"fields": [
19901996
{
19911997
"fieldPath": "id",
@@ -2029,6 +2035,18 @@
20292035
"affinity": "TEXT",
20302036
"notNull": false
20312037
},
2038+
{
2039+
"fieldPath": "subTitle",
2040+
"columnName": "subTitle",
2041+
"affinity": "TEXT",
2042+
"notNull": false
2043+
},
2044+
{
2045+
"fieldPath": "longAbstract",
2046+
"columnName": "longAbstract",
2047+
"affinity": "TEXT",
2048+
"notNull": false
2049+
},
20322050
{
20332051
"fieldPath": "track",
20342052
"columnName": "track",
@@ -2086,7 +2104,7 @@
20862104
"views": [],
20872105
"setupQueries": [
20882106
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
2089-
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c65ffea75fee1faf6cd199cbbc5c25ee')"
2107+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '35acee6b8147d48c581bb8f884508c79')"
20902108
]
20912109
}
20922110
}

app/src/main/java/org/fossasia/openevent/general/sessions/SessionApi.kt

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

33
import io.reactivex.Single
4+
import org.fossasia.openevent.general.attendees.forms.CustomForm
45
import org.fossasia.openevent.general.speakercall.Proposal
56
import retrofit2.http.GET
67
import retrofit2.http.Path
@@ -32,4 +33,10 @@ interface SessionApi {
3233

3334
@GET("sessions/{sessionId}?include=track,session-type,event,creator,speakers")
3435
fun getSessionById(@Path("sessionId") sessionId: Long): Single<Session>
36+
37+
@GET("events/{id}/custom-forms")
38+
fun getCustomForms(
39+
@Path("id") eventId: Long,
40+
@Query("filter") filter: String
41+
): Single<List<CustomForm>>
3542
}

app/src/main/java/org/fossasia/openevent/general/sessions/SessionService.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.fossasia.openevent.general.sessions
22

33
import io.reactivex.Single
4+
import org.fossasia.openevent.general.attendees.forms.CustomForm
45
import org.fossasia.openevent.general.speakercall.Proposal
56

67
class SessionService(
@@ -30,4 +31,19 @@ class SessionService(
3031

3132
fun getSessionsUnderSpeakerAndEvent(speakerId: Long, query: String): Single<List<Session>> =
3233
sessionApi.getSessionsUnderSpeaker(speakerId, filter = query)
34+
35+
fun getCustomFormsForSessions(id: Long): Single<List<CustomForm>> {
36+
val filter = """[{
37+
| 'and':[{
38+
| 'name':'form',
39+
| 'op':'eq',
40+
| 'val':'session'
41+
| },{
42+
| 'name':'is-included',
43+
| 'op':'eq',
44+
| 'val':true
45+
| }]
46+
|}]""".trimMargin().replace("'", "\"")
47+
return sessionApi.getCustomForms(id, filter)
48+
}
3349
}

app/src/main/java/org/fossasia/openevent/general/speakercall/EditSpeakerFragment.kt

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import androidx.fragment.app.Fragment
2020
import androidx.lifecycle.Observer
2121
import androidx.navigation.Navigation.findNavController
2222
import androidx.navigation.fragment.navArgs
23+
import com.google.android.material.textfield.TextInputLayout
2324
import com.squareup.picasso.MemoryPolicy
2425
import com.squareup.picasso.Picasso
2526
import kotlinx.android.synthetic.main.dialog_edit_profile_image.view.editImage
@@ -37,13 +38,35 @@ import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerTwit
3738
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.submitButton
3839
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerEmailLayout
3940
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerNameLayout
41+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerOrgLayout
42+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerPositionLayout
43+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerShortBioLayout
44+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerWebsiteLayout
45+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerTwitterLayout
46+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerLongBio
47+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerLongBioLayout
48+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerFacebook
49+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerGithub
50+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerGithubLayout
51+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerLinkedIn
52+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerLinkedInLayout
53+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerMobile
54+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerMobileLayout
55+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerCountry
56+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerCountryLayout
57+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerHeardFrom
58+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerHeardFromLayout
59+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerSpeakingExp
60+
import kotlinx.android.synthetic.main.fragment_proposal_speaker.view.speakerSpeakingExpLayout
4061
import org.fossasia.openevent.general.CircleTransform
4162
import org.fossasia.openevent.general.ComplexBackPressFragment
4263
import org.fossasia.openevent.general.R
4364
import org.fossasia.openevent.general.RotateBitmap
65+
import org.fossasia.openevent.general.attendees.forms.CustomForm
4466
import org.fossasia.openevent.general.auth.User
4567
import org.fossasia.openevent.general.auth.UserId
4668
import org.fossasia.openevent.general.event.EventId
69+
import org.fossasia.openevent.general.speakercall.form.SpeakerIdentifier
4770
import org.fossasia.openevent.general.speakers.Speaker
4871
import org.fossasia.openevent.general.utils.Utils.progressDialog
4972
import org.fossasia.openevent.general.utils.Utils.show
@@ -140,6 +163,8 @@ class EditSpeakerFragment : Fragment(), ComplexBackPressFragment {
140163
findNavController(rootView).popBackStack()
141164
})
142165

166+
setupCustomForms()
167+
143168
rootView.speakerNameLayout.setRequired()
144169
rootView.speakerEmailLayout.setRequired()
145170
rootView.submitButton.text = getString(if (isCreatingNewSpeaker)
@@ -175,6 +200,14 @@ class EditSpeakerFragment : Fragment(), ComplexBackPressFragment {
175200
organisation = rootView.speakerOrganization.text.toString(),
176201
position = rootView.speakerPosition.text.toString(),
177202
shortBiography = rootView.speakerShortBio.text.toString(),
203+
longBiography = rootView.speakerLongBio.text.toString(),
204+
country = rootView.speakerCountry.text.toString(),
205+
mobile = rootView.speakerMobile.text.toString(),
206+
speakingExperience = rootView.speakerSpeakingExp.text.toString(),
207+
heardFrom = rootView.speakerHeardFrom.text.toString(),
208+
facebook = rootView.speakerFacebook.text.toString().emptyToNull(),
209+
github = rootView.speakerGithub.text.toString().emptyToNull(),
210+
linkedin = rootView.speakerLinkedIn.text.toString().emptyToNull(),
178211
website = rootView.speakerWebsite.text.toString().emptyToNull(),
179212
twitter = rootView.speakerTwitter.text.toString().emptyToNull(),
180213
event = EventId(safeArgs.eventId),
@@ -368,5 +401,54 @@ class EditSpeakerFragment : Fragment(), ComplexBackPressFragment {
368401
rootView.speakerShortBio.setText(speaker.shortBiography)
369402
rootView.speakerWebsite.setText(speaker.website)
370403
rootView.speakerTwitter.setText(speaker.twitter)
404+
rootView.speakerHeardFrom.setText(speaker.heardFrom)
405+
rootView.speakerSpeakingExp.setText(speaker.speakingExperience)
406+
}
407+
408+
private fun setupCustomForms() {
409+
editSpeakerViewModel.forms
410+
.nonNull()
411+
.observe(viewLifecycleOwner, Observer {
412+
it.forEach { form ->
413+
setupFormWithSpeakerFields(form)
414+
}
415+
})
416+
417+
val currentForms = editSpeakerViewModel.forms.value
418+
if (currentForms != null)
419+
currentForms.forEach {
420+
setupFormWithSpeakerFields(it)
421+
}
422+
else
423+
editSpeakerViewModel.getFormsForSpeaker(safeArgs.eventId)
424+
}
425+
426+
private fun setupFormWithSpeakerFields(form: CustomForm) {
427+
when (form.fieldIdentifier) {
428+
SpeakerIdentifier.NAME -> setupField(rootView.speakerNameLayout, form.isRequired)
429+
SpeakerIdentifier.EMAIL -> setupField(rootView.speakerEmailLayout, form.isRequired)
430+
SpeakerIdentifier.PHOTO -> rootView.speakerImage.isVisible = true
431+
SpeakerIdentifier.ORGANIZATION -> setupField(rootView.speakerOrgLayout, form.isRequired)
432+
SpeakerIdentifier.POSITION -> setupField(rootView.speakerPositionLayout, form.isRequired)
433+
SpeakerIdentifier.SHORT_BIO -> setupField(rootView.speakerShortBioLayout, form.isRequired)
434+
SpeakerIdentifier.LONG_BIO -> setupField(rootView.speakerLongBioLayout, form.isRequired)
435+
SpeakerIdentifier.COUNTRY -> setupField(rootView.speakerCountryLayout, form.isRequired)
436+
SpeakerIdentifier.MOBILE -> setupField(rootView.speakerMobileLayout, form.isRequired)
437+
SpeakerIdentifier.WEBSITE -> setupField(rootView.speakerWebsiteLayout, form.isRequired)
438+
SpeakerIdentifier.FACEBOOK -> setupField(rootView.speakerWebsiteLayout, form.isRequired)
439+
SpeakerIdentifier.GITHUB -> setupField(rootView.speakerGithubLayout, form.isRequired)
440+
SpeakerIdentifier.TWITTER -> setupField(rootView.speakerTwitterLayout, form.isRequired)
441+
SpeakerIdentifier.LINKEDIN -> setupField(rootView.speakerLinkedInLayout, form.isRequired)
442+
SpeakerIdentifier.HEARD_FROM -> setupField(rootView.speakerHeardFromLayout, form.isRequired)
443+
SpeakerIdentifier.SPEAKING_EXPERIENCE -> setupField(rootView.speakerSpeakingExpLayout, form.isRequired)
444+
else -> return
445+
}
446+
}
447+
448+
private fun setupField(layout: TextInputLayout, isRequired: Boolean) {
449+
layout.isVisible = true
450+
if (isRequired) {
451+
layout.setRequired()
452+
}
371453
}
372454
}

app/src/main/java/org/fossasia/openevent/general/speakercall/EditSpeakerViewModel.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel
66
import io.reactivex.disposables.CompositeDisposable
77
import io.reactivex.rxkotlin.plusAssign
88
import org.fossasia.openevent.general.R
9+
import org.fossasia.openevent.general.attendees.forms.CustomForm
910
import org.fossasia.openevent.general.auth.AuthHolder
1011
import org.fossasia.openevent.general.auth.AuthService
1112
import org.fossasia.openevent.general.auth.UploadImage
@@ -38,6 +39,8 @@ class EditSpeakerViewModel(
3839
private val mutableSubmitSuccess = MutableLiveData<Boolean>()
3940
val submitSuccess: LiveData<Boolean> = mutableSubmitSuccess
4041
private var updatedImageTemp = MutableLiveData<File>()
42+
private val mutableForms = MutableLiveData<List<CustomForm>>()
43+
val forms: LiveData<List<CustomForm>> = mutableForms
4144

4245
var encodedImage: String? = null
4346

@@ -57,6 +60,20 @@ class EditSpeakerViewModel(
5760
})
5861
}
5962

63+
fun getFormsForSpeaker(eventId: Long) {
64+
compositeDisposable += speakerService.getCustomFormsForSpeakers(eventId)
65+
.withDefaultSchedulers()
66+
.doOnSubscribe {
67+
mutableProgress.value = true
68+
}.doFinally {
69+
mutableProgress.value = false
70+
}.subscribe({
71+
mutableForms.value = it
72+
}, {
73+
Timber.e(it, "Fail on fetching custom forms for event $eventId")
74+
})
75+
}
76+
6077
fun loadSpeaker(speakerId: Long) {
6178
if (speakerId == -1L) {
6279
mutableMessage.value = resource.getString(R.string.no_speaker_info)

app/src/main/java/org/fossasia/openevent/general/speakercall/Proposal.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ data class Proposal(
2525
val comments: String? = null,
2626
val startsAt: String? = null,
2727
val endsAt: String? = null,
28+
val subTitle: String? = null,
29+
val longAbstract: String? = null,
2830
@ColumnInfo(index = true)
2931
@Relationship("track", resolve = true)
3032
val track: Track? = null,

0 commit comments

Comments
 (0)