Selecting Multiple Tickets in Open Event Android

Open Event Android allows the user to select multiple tickets for an event this blog post will guide you on how its done. Ticket Id and quantity of ticket selected is stored in the form of List of pair. The first element of the List is the Id of the ticket and the second element is its quantity. private var tickeIdAndQty = ArrayList<Pair<Int, Int>>() Whenever the user selects any ticket using the dropdown the following snippet of code is executed. handleTicketSelect takes id and quantity of the selected ticket and search if any pair with passed id as the first element exists in the ticketIdAndQty list, if exists it updates that record else it inserts a new pair with given id and quantity into the list. private fun handleTicketSelect(id: Int, quantity: Int) {        val pos = ticketIdAndQty.map { it.first }.indexOf(id)        if (pos == -1) {            ticketIdAndQty.add(Pair(id, quantity))        } else {            ticketIdAndQty[pos] = Pair(id, quantity)        } When the user selects register the ticketIdAndQty list which contains details of selected tickets is added to the bundle along with the event id and are passed to attendee fragment. Attendee fragment allows the user to fill in other details such as country, payment option, first name etc. Later attendee fragment with the help of attendee view model creates individual attendee on the server rootView.register.setOnClickListener {            if (!ticketsViewModel.totalTicketsEmpty(ticketIdAndQty)) {                val fragment = AttendeeFragment()                val bundle = Bundle()                bundle.putLong(EVENT_ID, id)                bundle.putSerializable(TICKET_ID_AND_QTY, ticketIdAndQty)                fragment.arguments = bundle                activity?.supportFragmentManager                        ?.beginTransaction()                        ?.replace(R.id.rootLayout, fragment)                        ?.addToBackStack(null)                        ?.commit()            } else {                handleNoTicketsSelected()            }        } When the register is selected an attendee is created for every ticket id inside ticketIdandQty list wherever the second element of the pair that is quantity is greater than zero. FFirst name last name, email and other information is taken from the text views populated on the screen and attendee object is created using these data. Lastly, createAttendee view model function is called passing the generated attendee, country, and selected payment option. The former calls service layer function and created an attendee by making a post request to the server.  ticketIdAndQty?.forEach {                    if (it.second > 0) {                        val attendee = Attendee(id = attendeeFragmentViewModel.getId(),                                firstname = firstName.text.toString(),                                lastname = lastName.text.toString(),                                email = email.text.toString(),                                ticket = TicketId(it.first.toLong()),                                event = eventId)                        val country = if (country.text.isEmpty()) country.text.toString() else null                        attendeeFragmentViewModel.createAttendee(attendee, id, country, selectedPaymentOption)                    }                } The above-discussed procedure creates one attendee for every ticket quantity which means if a user select ticket id 1 with 3 quantity and ticket id 2 with 5 as quantity total 8 attendees will be generated. Later after successfully generating the attendee's order is created. Every order has an array of attendees along with other other related information. Resources Open Event Server Attendee Documentation - http://open-event-api-dev.herokuapp.com/#attendees Stack Overflow (List of Pair) - https://stackoverflow.com/questions/4777622/creating-a-list-of-pairs-in-java Room - https://developer.android.com/topic/libraries/architecture/room Kotlin Language Control Flow in Kotlin - https://kotlinlang.org/docs/reference/control-flow.html

Continue ReadingSelecting Multiple Tickets in Open Event Android

Updating User information in Open Event Android

A user can update its information such as first name, last name from the Edit Profile Fragment in Open Event Android. Edit Profile Fragment can be accessed from the menu inside the Profile page. On opening Edit Profile Fragment user can interact with the simple UI to update his/her information. This blog post will guide you on how its implemented in Open Event Android. To update a User we send a patch request to Open Event Server. The patch request contains the Updated User as body and auth token as header and it returns the updated user in response. Following it what the interface method looks like @PATCH("users/{id}") fun updateUser(@Body user: User, @Path("id") id: Long): Single<User> This method is exposed to the View Model using a service layer function which calls the above function and also inserts the returned user in the database. fun updateUser(user: User, id: Long): Single<User> {        return authApi.updateUser(user, id).map {            userDao.insertUser(it)            it        }    } On using map on Single<User> returned by updateUser we can access the user inside the scope which is then inserted into the database using the DAO method insert user and the same user object is returned by the function. This service layer method is then used in updateUser method of EditProfileViewModel class which specifies how it is subscribed and on which thread observer should be set etc. The Edit Profile Fragment fragment calls this method whenever the user clicks on the Update button. fun updateUser(firstName: String, lastName: String) {        val id = authHolder.getId()        if (firstName.isEmpty() || lastName.isEmpty()) {            message.value = "Please provide first name and last name!"            return        }        compositeDisposable.add(authService.updateUser(User(id = id,          firstName = firstName, lastName = lastName), id)                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .doOnSubscribe {                    progress.value = true                }                .doFinally {                    progress.value = false                }                .subscribe({                    message.value = "User updated successfully!"                    Timber.d("User updated")                }) {                    message.value = "Error updating user!"                    Timber.e(it, "Error updating user!")                })    } UpdateUser takes two parameters first name and last name if any of these parameters is empty the function returns with an error message which is displayed on the UI else service layer update user function is called with argument a User object with first name and last name as provided to view model function and an id which is accessed using authHolder’s getId method. Whenever this is subscribed we set progress.value true which displays spinner on the UI this is set false after the operation is complete. If the patch request results in success then toast message is shown on screen and a success message is logged similar to this in case of error, an error toast is displayed and an error is logged. This goes for the logic to update user we also need UI and menu item which launches this fragment. Inside Menu.xml add the following snippet of code <item   android:id="@+id/edit_profile"   android:title="@string/edit_profile" /> This will create a menu item inside the ProfileFragment. The next step is to wire this logic which tells what happens when the user selects this menu item. The following code wires it…

Continue ReadingUpdating User information in Open Event Android

Bottom Navigation Bar in Open Event Android

Bottom navigation bar provides an easy access and convenient way for users to navigate in between different sections of an App where the sections are of equal importance. We use bottom navigation move between different fragments such as events screen, favorites, tickets profile and so on. This blog post will guide you on how its implemented in Open Event Android. To create a bottom navigation bar first create items for your menu. Menu items will be rendered as elements of the bottom navigation bar. Add icon and title to your navigation item here.    <item        android:id="@+id/navigation_profile"        android:icon="@drawable/ic_baseline_account_circle_24px"        android:title="@string/profile" /> After we have written menu xml for our navigation view, we will have to create a view for it. The following snippet of code creates a BottomNavigationView type view element on the screen with different attributes as specified and menu file as specified by app:menu. Make sure you have android support design dependency set up before this. <android.support.design.widget.BottomNavigationView            android:id="@+id/navigation"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_gravity="bottom"            android:background="?android:attr/windowBackground"            app:itemBackground="@android:color/white"            android:foreground="?attr/selectableItemBackground"            app:itemTextColor="@color/colorPrimaryDark"            app:menu="@menu/navigation" /> No that our view will be created we need to wire menu items with different fragment and set up listener for item selected events. Inside onCreate of MainActivity we attach a ItemSelectListener with the bottom navigation bar, navigation.setOnNavigationItemSelectedListener(listener) . private val listener = BottomNavigationView.OnNavigationItemSelectedListener { item ->        val fragment: Fragment        when (item.itemId) {            R.id.navigation_profile -> {                supportActionBar?.title = "Profile"                fragment = ProfileFragment()                loadFragment(fragment)                return@OnNavigationItemSelectedListener true            }            R.id.navigation_favorite -> {                supportActionBar?.title = "Likes"                fragment = FavoriteFragment()                loadFragment(fragment)                return@OnNavigationItemSelectedListener true            }            R.id.navigation_tickets -> {                supportActionBar?.title = "Tickets"                fragment = OrdersUnderUserFragment()                loadFragment(fragment)                return@OnNavigationItemSelectedListener true            }        }        false    } The above listener object listens for item selection in the bottom navigation bar. Whenever any item is selected lambda function is executed and item.itemId is matched with different menu item ids. On any successful match, an instance of the fragment corresponding to the selected item is loaded. References Simplified Coding Bottom Navigation Bar- https://www.simplifiedcoding.net/bottom-navigation-android-example/ Google Developers Bottom Naviagtion Bar - https://developer.android.com/reference/com/google/android/material/bottomnavigation/BottomNavigationView

Continue ReadingBottom Navigation Bar in Open Event Android

Changing Profile Image in Open Event Android

A user can create a custom Avatar in Open Event Android. We use Picasso Library for easy image loading and caching in Open Event Android. This blog post will help you understand how its implemented in Open Event Android. These are the steps we follow : Create UI element which allows the user to pick an avatar Checking and requesting Read External Storage permission Compress and Encode Image Use Picasso to display image on UI Upload it on the server on user’s command We will discuss the above steps in detail in the following section. Create UI element which allows the user to pick an avatar To display the selected avatar image as well as to fire image pick action when clicked we need a UI element. We display a placeholder in case no avatar image is provide, in this case, its ic_account_circle_grey_24dp which lies in drawable folder. Rest of the code is self explanatory. <ImageView        android:id="@+id/profilePhoto"        android:layout_width="@dimen/item_image_view_large"        android:layout_height="@dimen/item_image_view_large"        android:layout_gravity="center_horizontal"        android:contentDescription="Profile Photo"        android:padding="@dimen/padding_large"        app:srcCompat="@drawable/ic_account_circle_grey_24dp" /> Once we have created the UI we need to wire it with the action to pick an image, the following code snippet does that. When this ImageView is clicked permissionGranted variable is checked which keeps a track of read external storage permission if this is true file chooser is displayed to allows user to select an image else an dialog for requesting permissions is shown. rootView.profilePhoto.setOnClickListener { v ->            if (permissionGranted) {                showFileChooser()            } else {                requestPermissions(READ_STORAGE, REQUEST_CODE)            }        } Checking and requesting Read External Storage permission As discussed in the above section permission check is performed when ImageView is clicked and if not granted a dialog request for read external storage is displayed. Initially, the boolean permissionGranted is set to false which means clicking on ImageView fires requestPermission method with permissions array and request code and by overriding the onRequestPermissionResult method we can look at request status. override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {        if (requestCode == REQUEST_CODE) {            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                permissionGranted = true                Toast.makeText(context, "Permission to Access External Storage Granted !", Toast.LENGTH_SHORT).show()                showFileChooser()            } else {                Toast.makeText(context, "Permission to Access External Storage Denied :(", Toast.LENGTH_SHORT).show()            }        }    } onRequestPermissionsResult is called everytime requestPermission finishes, to check for which request it’s called we can check the Request code if it matches with the one we passed in our requestPermissions method that means the grant result carries information about our request. We can check the grantResult and if permission is granted we set our permissionGranted variable to true and display the file chooser menu. Compress and Encode Image Once the user picks the image from the file chooser we need to convert it into an input stream and we encode it into our JPEG format and specify the image quality. The following code snippet will help you understand how this happens. val imageUri = intentData.data            var imageStream: InputStream? = null            try {                imageStream = activity?.contentResolver?.openInputStream(imageUri)            } catch (e: FileNotFoundException) {                Timber.d(e, "File Not Found Exception")            } w            val…

Continue ReadingChanging Profile Image in Open Event Android

Hiding Multiple Attendee Recycler for Single Tickets in Open Event Android

Multiple attendee recycler allows the user to easily write in attendee details for all tickets he/she is buying. The UI for attendee details fragment can be divided into two segments, one contains the details of the person creating the whole order and followed by multiple details section for the attendee of every ticket. This is a good way to take details when multiple ticket or tickets with greater than 1 quantity is involved. However, if there is only one attendee detail to be taken instead of asking the user for order creator’s details and then first attendee details it is better to add some views in the creator segment and not ask for the same details again from the user. This blog post will help you in understanding how it's done in Open Event Android. Keeping a track of orders with single attendee We keep a boolean to track whether or not the sum of quantities of tickets selected by a user is one since one attendee is to be generated per ticket quantity. And incase it is boolean variable singleTicket is set to True which is false by default initially. Following is how it can be done singleTicket = ticketIdAndQty?.map { it.second }?.sum() == 1 The above statements basically iterate over the list of pairs of tickets and their quantity and then sums over the second element of all pairs that is the quantities, if the summation leads to 1 single ticket is set to True else false. Adding elements to recycler adapter The next step is to update the logic as to when blank attendees are added to recycler adapter. The idea is to check the boolean singleTicket and if it is false dont insert any attendee. attendeeFragmentViewModel.tickets.observe(this, Observer {                it?.let {                    if (!singleTicket)                        it.forEach {                            val pos = ticketIdAndQty?.map { it.first }?.indexOf(it.id)                            val iterations = pos?.let { it1 -> ticketIdAndQty?.get(it1)?.second } ?: 0                            for (i in 0 until iterations)                                attendeeRecyclerAdapter.add(Attendee(attendeeFragmentViewModel.getId()), it)                            attendeeRecyclerAdapter.notifyDataSetChanged()                        }                }            }) If a single ticket is false regular procedure to add blank attendee is carried out. The quantity of ticket is found and the same quantity of attendees are added to recycler adapter’s attendee's list similary ticket information is also added to the recycler adapter. The id for blank attendees is taken from the attendeeViewModel’s getId function which in turn simply returns id using the authHolder’s getId function. Modify the register method to check for the single attendee So far what we have discussed helps us display the right no of details section on the UI. We will also have to modify the register method to take into account the above changes. Following is the implementation of what happens when the user selects register. rootView.register.setOnClickListener {                if (selectedPaymentOption == "Stripe")                    sendToken()                val attendees = ArrayList<Attendee>()                if (singleTicket) {                    val pos = ticketIdAndQty?.map { it.second }?.indexOf(1)                    val ticket = pos?.let { it1 -> ticketIdAndQty?.get(it1)?.first?.toLong() } ?: -1                    val attendee = Attendee(id = attendeeFragmentViewModel.getId(),                            firstname = firstName.text.toString(),                            lastname = lastName.text.toString(),                            city = getAttendeeField("city"),                            address =…

Continue ReadingHiding Multiple Attendee Recycler for Single Tickets in Open Event Android

Displaying Events In Open Event Android

The user can browse through different events happening nearby or all over the world quickly from the events fragment, the latter is accessible from the bottom navigation bar and provides the user with some details about the event. The user if interested can select the event by clicking on it and will be taken to event details fragment where all the necessary information about the event is given. This blog post will help in understanding how events are fetched and shown in Open Event Android. The implementation of displaying events can be divided into two parts Fetching and storing events Displaying events on UI using recycler view Fetching and Storing Events To fetch an event we need to make get the request to the Open Event Server’s list events endpoint.    @GET("events?include=event-topic")    fun getEvents(): Single<List<Event>> We are using retrofit to make the network calls @GET specifies that it a get request and the URL inside the parentheses is the endpoint we are hitting. This method returns a Single<List<Event>>. Given below is the service layer method which uses DAO method and the API call and returns a Flowable<List<Event>>. fun getEvents(): Flowable<List<Event>> {        val eventsFlowable = eventDao.getAllEvents()        return eventsFlowable.switchMap {            if (it.isNotEmpty())                eventsFlowable            else                eventApi.getEvents()                        .map {                            eventDao.insertEvents(it)                            }                        .toFlowable()                        .flatMap {                            eventsFlowable                        }        }    } Firstly all the events from the database are fetched using the DAO method getAllEvents. If the list returned from the DAO method is not empty this function simply returns the events otherwise it will make the get request to server endpoint using Event API’s getEvents method and the response of this is mapped and stored into the database using the DAO method insertEvents this enables local caching of events and the same list of events are converted into flowable and returned by the function. The events fragment calls the view model function which specifies where to observe (we are observing on main thread because it is involved with UI related changes) and what to subscribe on also handles the displaying of progress bar. Given following is the implementation of the same. fun loadEvents() {        compositeDisposable.add(eventService.getEvents()                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .doOnSubscribe({                    progress.value = true                }).doFinally({                    progress.value = false                }).subscribe({                    events.value = it                }, {                    Timber.e(it, "Error fetching events")                    error.value = "Error fetching events"                }))    } You would notice the following parts in the above snippet doOnSubscribe - This part of code is executed whenever the source is subscribed Subscribe - This part of the code will have the end result when subscribed and success doFinally - This part of the code will be executed at the end   Creating Recycler View Recycler view is similar to ListView with some enhancements. When we are dealing with larger datasets our typical choice for displaying lists type UI is Recycler view because its views can be recycled and scrolled very efficiently. Every custom RecyclerView consists of three parts Layout for individual list items Recycler View adapter View Holder that holds views for individual list items The item UI for events in Open Event Android…

Continue ReadingDisplaying Events In Open Event Android

Saving Current State when Redirected to Login Fragment in Open Event Android

Some features in Open Event Android requires the user to be logged in, for example, buying tickets or viewing bought tickets. If the user selects to buy tickets for an event and he/she is not logged in, the user will be redirected to login fragment and on successful login, the user will return to the last state. This blog post will help you understand how its done in Open Event Android we will be taking the example of buying tickets without logged in. To give you an overview once a user selects to buy tickets he is taken to a Tickets Fragment which contains different tickets and allows the user to pick their respective quantity. After selecting the right quantities the user can select on the register and he/she will be taken to Attendee Fragment which requires the user to be logged in, if not he will be redirected to login fragment and on successful login he can continue from attendee fragment without losing the selected tickets and their quantity information To do this when redirecting from Attendee Fragment to the AuthActivity we modify the redirect method and send additional information with the intent such as even id and list of ticket id and quantity selected by the user. Following is how it can be done. val intent = Intent(activity, AuthActivity::class.java)        val bundle = Bundle()        bundle.putLong(EVENT_ID, id.toLong())        if (ticketIdAndQty != null)            bundle.putSerializable(TICKET_ID_AND_QTY, ticketIdAndQty as ArrayList) intent.putExtras(bundle)  startActivity(intent) Now that we have sent additional information with intent we will also have to modify the login fragment to use this information. The above-discussed method will redirect the user to AuthActivity which handles all the authentication part. The user can either select to log in with an existing account or he may sign up with a new account. For existing accounts login fragment is shown and similarly for new sign up sign up fragment is shown. The AuthActivity simply takes the bundle it received using intent.getExtras and passes the same to the fragment it is rendering. The load fragment function in Auth Activity looks like below. Whatever fragment is opened (signup/login) it passes the bundle that AuthActivity received as arguments to the fragments. This is done by setting fragment.arguments = bundle private fun loadFragment(fragment: Fragment) {        if (bundle != null)            fragment.arguments = bundle        supportFragmentManager.beginTransaction()                .replace(R.id.frameContainerAuth, fragment)                .commit() Now we have all the bundle information in our login fragment next what we want is whenever login completes successfully send the user back to Attendee Fragment along with the event and ticket id and selected quantity information. The following snippet of code takes the user to MainActivity whenever user information is received which means the user has successfully logged in  loginActivityViewModel.user.observe(this, Observer {            redirectToMain(bundle)        }) redirectToMain accepts bundle as a parameter this bundle contains the ticket id and quantity list and the event id this is what we received from AuthActivity.  private fun redirectToMain(bundle: Bundle?) {        val intent = Intent(activity, MainActivity::class.java)        if (((bundle != null) && !id.equals(-1)) && (ticketIdAndQty != null)) {            intent.putExtra(LAUNCH_ATTENDEE, true)            intent.putExtras(bundle)…

Continue ReadingSaving Current State when Redirected to Login Fragment in Open Event Android

Generating Order QR codes in Open Event Android

QR codes provide a very fast and convenient way to share information to other device, one device generates a bitmap image with information encoded in it, this bitmap can be easily scanned from the other device. QR codes are used in Open Event Android to share order identifier information, the latter can be used to check in attendee in Open Event Orga App. This blog post will guide you on how its implemented in Open Event Android. Add the dependency We use Zixing’s Barcode scanning library in Open Event Android for generating QR bitmaps. Add the following dependency in your app level gradle file. Please visit zxing GitHub page for latest version information. implementation 'com.journeyapps:zxing-android-embedded:3.4.0' Create View for QR code To display QR code we need to create and bitmap and then populate it on an Image View. The following code snippet generated an Image View on the screen, we have set the scale type to center crop so that image is scaled uniformly and the dimension of the image is equal to the corresponding dimension of the view.     <ImageView                android:layout_width="200dp"                android:layout_gravity="center"                android:layout_height="200dp"                android:id="@+id/qrCodeView"                android:layout_margin="@dimen/layout_margin_medium"                android:scaleType="centerCrop" /> Generating the QR Bitmap The following code snippet generates QR bitmap for order identifier. try {            val bitMatrix = MultiFormatWriter().encode(orderIdentifier, BarcodeFormat.QR_CODE, 200, 200)            itemView.qrCodeView.setImageBitmap(BarcodeEncoder().createBitmap(bitMatrix))        } catch (e: WriterException) {            e.printStackTrace()        } MultiformatWriter encodes the provided string in the format specified in the second parameter of encode function and generates a bitMatrix of specified dimensions in our case orderIdentifier is the string to be encoded and the format is QR_CODE. The last two parameters in the encode method are the width and height respectively for the Image Matrix to be generated. This bitMatrix can be then used to create QR bitmaps, BarcodeEncode() function creates a bitmap from this bitMatrix which is then set on the image View using setImageBitmap method. As a writer exception may occur while encoding string to specified format this whole block of code is put inside a try catch block which catches and logs the WriterException. References Zxing Library:  https://github.com/zxing/zxing Google Developers Documentation: https://developer.android.com/reference/android/graphics/Bitmap

Continue ReadingGenerating Order QR codes in Open Event Android

Creating Orders in Open Event Android

An Order is generated whenever a user buys a ticket in Open Event Android. It contains all the details regarding the tickets and their quantity, also information regarding payment method and relation to list of attendees, through this blog post we will see how Orders are generated in Open Event Android. Implementing Order system can be divided into following parts Writing model class to serialize/deserialize API responses Creating TypeConverter for Object used in Model class Creating the API interface method Wiring everything together Model Class Model class server two purpose - Entity class for storing orders in room Serialize / Deserialize API response The architecture of the Order Model Class depends upon the response returned by the API, different fields inside the Entity Class defines what different attributes an Order consists of and their data types. Since every Order has a relationship with Event and Attendee we also have to define foreign key relations with them. Given below is the implementation of the Order Class in Open Event Android. @Type("order") @JsonNaming(PropertyNamingStrategy.KebabCaseStrategy::class) @Entity(foreignKeys = [(ForeignKey(entity = Event::class, parentColumns = ["id"], childColumns = ["event"], onDelete = ForeignKey.CASCADE)), (ForeignKey(entity = Attendee::class, parentColumns = ["id"], childColumns = ["attendees"], onDelete = ForeignKey.CASCADE))]) data class Order(        @Id(IntegerIdHandler::class)        @PrimaryKey        @NonNull        val id: Long,        val paymentMode: String? = null,        val country: String? = null,        val status: String? = null,        val amount: Float? = null,        val orderNotes: String? = null,        @ColumnInfo(index = true)        @Relationship("event")        var event: EventId? = null,        @Relationship("attendees")        var attendees: List<AttendeeId>? = null )   We are using Jackson for serializing/deserializing JSON response, @Type(“order”) annotation tells jackson that the following object is for key order in json response. Since we are using this as our room entity class we will also have to add a @Entity annotation to this class. Order contains attendee and event id fields which are foreign keys to other entity classes, this also has to be explicitly mentioned while writing the @Entitty annotation as shown in the snippet above . All relationship must be annotated with @Relationship annotation. All the variables serves as attributes in the order table and key name for json conversions. The fields of this class are the attributes for the Order Table. Payment mode, country, status are all made up of primitive data type and hence require no type convertors whereas we will have to specify type converter for objects like eventId and List<Attendees> Type Converter Type Converter allows us to store any custom object type inside room database. Essentially we break down the Object into smaller primitive data types that Object is composed of and which can be stored by room database. To create a TypeConverter we have to add a @TypeConverter annotation to it, this tells room that this is a special function. For every custom Object, you have to create two different TypeConverter functions. One takes the Object and converts it into primitive data type and the other takes the primitive data type and constructs your custom Object from it. For the Order data class we discussed…

Continue ReadingCreating Orders in Open Event Android

Adding Multiple Attendees inside an Order in Open Event Android

Orders endpoint allows multiple attendees to be passed in the body of post request which essentially means that and an order may contain tickets for different attendees. This blog post will guide you on how multiple attendees under an Order is handled and implemented in Open Event Android. An attendee as the name implies gives us information about how many people are attending any particular event. Let’s say if a User selects two tickets with 3 and 7 quantity total 10 attendees will be generated and can be put inside one Order request. Whenever multiple tickets are selected by the user following function is called to create Attendee fun createAttendees(attendees: List<Attendee>, country: String?, paymentOption: String) {        this.country = country        this.paymentOption = paymentOption        this.attendees?.clear()        attendees.forEach {            createAttendee(it, attendees.size)        }    }   Create attendees accepts a list of attendees and calls the createAttendees for every attendee in the list. Actual attendee creation is handled in createAttendee. The above function also set up the country and payment option as provided by the user. fun createAttendee(attendee: Attendee, totalAttendee: Int) {        compositeDisposable.add(attendeeService.postAttendee(attendee)                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .doOnSubscribe {                    progress.value = true                }.doFinally {                    progress.value = false                }.subscribe({                    attendees?.add(it)                    if (attendees != null && attendees?.size == totalAttendee) {                        loadTicketsAndCreateOrder()                    }                    message.value = "Attendee created successfully!"                    Timber.d("Success! %s", attendees?.toList().toString())                }, {                    message.value = "Unable to create Attendee!"                    Timber.d(it, "Failed")                }))    } Create an Attendee on the other hand deals with creating individual attendees on the server. It calls the service function attendeeService.postAttendee with attendee as the parameter if the post request made is succeeds the attendee returned from the API is added to the list of attendees, when the size of list of attendees become equal to the list of attendees that had to be generated loadTicketsAndCreateOrder is called which takes care of getting charges for user and creating an order. If the post request for the attendee is failed a message is displayed and a log is added to console with error details. fun loadTicketsAndCreateOrder() {        if (this.tickets.value == null) {            this.tickets.value = ArrayList()        }        this.tickets.value?.clear()        attendees?.forEach {            loadTicket(it.ticket?.id)        }    } Load tickets and create order also works in a similar way as of creating attendees as there are two functions in here also one of which takes a list of attendees and calls the other function which gets data for individual ticket items passes as the parameter. Here ticket details for every attendee are fetched using the loadTicket function which takes ticket id corresponding to an attendee (using it.tickets?.id) and returns the Ticket object. Given below is the implementation for loadTicket method. fun loadTicket(ticketId: Long?) {        compositeDisposable.add(ticketService.getTicketDetails(ticketId)                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe({                    tickets.value?.add(it)                    Timber.d("Loaded tickets! %s", tickets.value?.toList().toString())                    if (tickets.value?.size == attendees?.size) {                        createOrder()                    }                }, {                    Timber.d(it, "Error loading Ticket!")                }))    } Load ticket uses the service method to fetch the ticket details using the passed ticket id and the returned ticket object is added to the list of ticket. When the size of the ticket becomes equal to the size of total no of attendees which means that…

Continue ReadingAdding Multiple Attendees inside an Order in Open Event Android