The Open Event Organizer Android App has the ability to scan and check-in attendees holding different ticket types for an event. But often there are cases when the attendees holding a particular ticket type need to be check-in restricted. It can be because of reasons such as facilitating entry of premium ticket holders before general ticket holders, or not allowing general ticket holders in a VIP queue.
To facilitate this, we have a field called ‘is-checkin-restricted’ for the entity Ticket. So when it is set to true, any check ins for the holder of that particular ticket type will be restricted. Let’s look at how this was implemented in the Orga App.
This is what we want to achieve:
Even though we needed it to be present in the settings screen, we needed it to be dynamic in nature as the types of tickets are themselves dynamic. This meant that we couldn’t achieve this using the plain old preference themes. We must create a whole new fragment for it and try to make it as similar to a preference theme as possible.
We need the following to create a dynamic tickets fragment:
- The fragment itself, which should implement the interfaces: Progressive, Erroneous to show progress and error.
- An Adapter and a ViewHolder
- A ViewModel
The fragment CheckinRestriction is similar to the TicketsFragment for the most part except for the part where we need to restrict check in. In the fragment we are providing a checkbox at the top to restrict check-in for all ticket types. So we need to setup click listeners not just for the checkbox, but for the whole view as well, like this:
binding.restrictAll.setOnClickListener(v -> { restrictAll(!binding.restrictAllCheckbox.isChecked()); }); binding.restrictAllCheckbox.setOnClickListener(v -> { //checkbox already checked restrictAll(binding.restrictAllCheckbox.isChecked()); }); |
The restrictAll() method restricts check-in for all ticket types by updating the view and updating the tickets using the ViewModel:
private void restrictAll(boolean toRestrict) { binding.restrictAllCheckbox.setChecked(toRestrict); ticketSettingsViewModel.updateAllTickets(toRestrict); ticketsAdapter.notifyDataSetChanged(); } |
It’s also important to note here how we are handling the clicks in the ViewHolder for each ticket item:
public void bind(Ticket ticket) { binding.setTicket(ticket); View.OnClickListener listener = v -> { ticket.isCheckinRestricted = ticket.isCheckinRestricted == null || !ticket.isCheckinRestricted; binding.ticketCheckbox.setChecked(ticket.isCheckinRestricted); updateTicketAction.push(ticket); binding.executePendingBindings(); }; itemView.setOnClickListener(listener); binding.ticketCheckbox.setOnClickListener(listener); } |
A method that is run each time in order to check if all the tickets are restricted and then accordingly tick the ‘restrict-all’ box.
private void checkRestrictAll() { if (ticketSettingsViewModel.getTickets() == null) { return; } boolean restrictAll = true; for (Ticket ticket : ticketSettingsViewModel.getTickets().getValue()) { if (ticket.isCheckinRestricted == null || !ticket.isCheckinRestricted) { restrictAll = false; break; } } binding.restrictAllCheckbox.setChecked(restrictAll); } |
This is all of the code we need apart from the boilerplate code in order to successfully build a check-in-restrictions fragment.
Read more of the code here
Resources:
- Android Developer Guide on View Models
https://developer.android.com/topic/libraries/architecture/viewmodel#sharing
- Android Architecture Components: ViewModel – AndroidPub
https://android.jlelse.eu/android-architecture-components-viewmodel-e74faddf5b94