Setting up environment to build PSLab Android app using Fdroid Build

Fdroid is a place for open source enthusiasts and developers to host their Free and Open Source Software (FOSS) for free and get more people onboard into their community. In order to host an app in their repository, one has to go through a several steps of builds and tests. This is to ensure that the software provided by them are as quality and safe as they can ever be. They are not allowing proprietary libraries or tools to integrate into any app or they will  be published outside the Fdroid main repository (fdroid-data) so that the users will know what they are downloading. In a normal Linux computer where we are developing Android apps and have setup Android Studio will not be able to run the build command using: $ fdroid build -v -l org.fossasia.pslab The reason behind this is that we have not installed gradle and build tools required by the “fdroid build” because they are not useful in our day today activities for standalone activities. First thing we need to do is, install gradle separately. This will include adding gradle to $PATH as well. Download the latest gradle version zip file or the version your project is using with the following command. In PSLab Android app, we are using 4.5.1 version and the snippet below include that version. $ wget https://services.gradle.org/distributions/gradle-4.5.1-bin.zip Next step is to install this in a local folder. We can select any path we want, but /opt/ folder is generally used in such scenarios. sudo mkdir /opt/gradle sudo unzip -d /opt/gradle gradle-4.5.1-bin.zip Then we can add gradle to our $PATH variable using the following command: $ export PATH=$PATH:/opt/gradle/gradle-4.5.1/bin Now we are all set with gradle settings. Next step is to verify that the fdroid server is properly configured and up to date. When you run the build command after setting up the gradle in PC, it will throw an error similar to “failed to find any output apks”. This causes if the installed fdroid server version is old. Fdroid server is running on python 3 and it will require some additional libraries pre-installed to properly function. $ sudo apt-get install vagrant virtualbox git python3-certifi python3-libvirt python3-requestbuilder python3-yaml python3-clint python3-vagrant python3-paramiko python3-pyasn1 python3-pyasn1-modules Once these libraries are installed, remove the previous instance of fdroidserver by using the following command: $ sudo apt-get remove fdroidserver Then we can reinstall the latest version of fdroid server from git using the following command: $ git clone https://gitlab.com/fdroid/fdroidserver.git export PATH="$PATH:$PWD/fdroidserver" Now we are all set to do a brand new lint build on our PC to make our app ready to be published in Fdroid repository! Reference: Install gradle : https://www.vultr.com/docs/how-to-install-gradle-on-ubuntu-16-10 Gradle versions : https://gradle.org/releases Setting up Fdroid-server : https://f-droid.org/en/docs/Build_Server_Setup/ Installing fdroidserver : https://gitlab.com/fdroid/fdroiddata/blob/master/README.md#quickstart

Continue ReadingSetting up environment to build PSLab Android app using Fdroid Build

Using external UART modules to debug PSLab operations

Pocket Science Lab by FOSSASIA is a compact tool that can be used for circuit analytics and debugging. To make things more interesting, this device can be accessed via the user interface using an Android app or also a desktop app. Both these apps use the UART protocol (Universal Asynchronous Receiver-Transmitter) to transmit commands to the PSLab device from mobile phone or PC and receive commands vice versa. The peculiar thing about hardware is that the developer cannot simply log data just like developing and debugging a software program. He needs some kind of an external mechanism or a tool to visualize those data packets travelling through the wires. Figure 1: UART Interface in PSLab PSLab has a UART interface extracted out simply for this reason and also to connect external sensors that use the UART protocol. With this, a developer who is debugging any of the Android app or the desktop app can view the command and data packets transmitted between the device and the user end application. This  requires some additional components. UART interface has two communication related pins: Rx(Receiver) and Tx(Transmitter). We will need to monitor both these pin signals for input and output data packets. It should be kept in mind that PSLab is using 3.3V signals. This voltage level is important to mention here because if someone uses 5V signals on these pins, it will damage the main IC. There are FTDI modules available in market. FTDI stands for Future Technology Devices International which is a company name and their main product is this USB transceiver chip. These chips play a major role in electronic industry due to product reliability and multiple voltage support. PSLab uses 3.3V USB Tx Rx pins and modules other than FTDI wouldn’t support it. Figure 2: FTDI Module from SparkFun The module shown in Fig.2 is a FTDI module which you can simply plug in to computer and have a serial monitor interface. There are cheaper versions in shopping websites like eBay or Alibaba and they will also work fine. Both Tx and Rx pins will require two of these modules and connectivity is as follows; PSLab [Rx Pin] → FTDI Module 1 [Rx Pin] PSLab [Tx Pin] → FTDI Module 2 [Rx Pin] This might look strange because everywhere we see a UART module is connected Rx → Tx and Tx → Rx. Notice that our idea is to monitor data packets. Not communicate with PSLab device directly. We want to see if our mobile phone Android app is sending correct commands to PSLab device or not and if PSLab device is transmitting back the expected result or not. This method helped a lot when debugging resistance measurement application in PSLab Android app. Monitoring these UART data packets can be done simply using a serial monitor. You can either download and install some already built serial monitors or you can simply write a python script as follows which does the trick. import serial ser = serial.Serial( port='/dev/ttyUSB1', baudrate=1000000000 )…

Continue ReadingUsing external UART modules to debug PSLab operations

Offline support for Open Event Android with ROOM

So until now we were fetching data from the server and directly displaying it to the user in the Open Event Android app. There are several problems in this approach if the user changes the fragment and then returns to the same fragment he will have to fetch the data again, valuable network gets wasted. There is also no offline support. So we decided to introduce a local database in the app. ROOM was without a doubt our first choice What is ROOM? According to the official documentation, The Room persistence library provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite. The library helps you create a cache of your app's data on a device that's running your app. This cache, which serves as your app's single source of truth, allows users to view a consistent copy of key information within your app, regardless of whether users have an internet connection. Let’s get started Integration of the ROOM database majorly consists of 3 steps 1 Create an entity 2 Create a DAO 3 Create a Database That’s it, you are done ! Create the entity There are just 2 requirements in order to make a model an entity First use @Entity annotation on the model class to make it an entity. Secondly you need at least one field with @PrimaryKey annotation. This entity class represents a table in database and all its fields are the columns of the table. @Type("event") @JsonNaming(PropertyNamingStrategy.KebabCaseStrategy::class) @Entity data class Event( @Id(LongIdHandler::class) @PrimaryKey val id: Long, val name: String, val identifier: String, val startsAt: String) Create DAO Data Access Object or DAO for short are used to tell the database how to to put the data. We can use the following annotations to perform simple SQL queries in ROOM @Insert, @Update, @Delete for proper actions: inserting, updating and deleting records @Query for creating queries — we can make select from the database @Dao interface EventDao { @Insert(onConflict = REPLACE) fun insertEvents(events: List<Event>) @Insert(onConflict = REPLACE) fun insertEvent(event: Event) @Query("DELETE FROM Event") fun deleteAll() @Query("SELECT * from Event ORDER BY startsAt DESC") fun getAllEvents(): Flowable<List<Event>> @Query("SELECT * from Event WHERE id = :id") fun getEvent(id: Long): Flowable<Event> } Create the Database We need to create a public abstract class that extends RoomDatabase After that annotate the class to be a Room database, declare the entities that belong in the database and set the version number. Listing the entities will create tables in the database. Define the DAOs that work with the database. Make the database a singleton to prevent having multiple instances of the database opened at the same time. A lot has been said let’s have a look at the code now. @Database(entities = [Event::class, User::class], version = 1) abstract class OpenEventDatabase : RoomDatabase() { abstract fun eventDao(): EventDao abstract fun userDao(): UserDao } Room.databaseBuilder(androidApplication(), OpenEventDatabase::class.java, "open_event_database") .fallbackToDestructiveMigration() .build() The important thing here is that all operations must be done in the background thread. You can do it by…

Continue ReadingOffline support for Open Event Android with ROOM

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