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

Hiding Payment Options for Free Tickets in Open Event Android

Hiding Payment Options for Free Tickets in Open Event Android Payment Options spinner allows the user to pick any convenient payment method for an order however, Payment Options should not be shown if the total worth of order is zero or the event is free. This blog post will guide you on how its implemented in Open Event Android. Following are the sequence of steps that are followed for this Allow the user to select tickets and their quantity Use DAO method to get the prices of the tickets selected by the user Iterate through the List and keep storing the prices Display Payment Selector for order with the total amount greater than zero Given below is DAO method to get the list of prices for different tickets. The method makes a simple select statement and returns price attribute of tickets with id in passed ids. A single list of float is returned by the function.  @Query("SELECT price from Ticket WHERE id in (:ids)")    fun getTicketPriceWithIds(ids : List<Int>): Single<List<Float>> This DAO method is then exposed to other parts (ViewModels, Fragments) using service layer class method getTicketPriceWithIds which just makes calls to DAO method and return the result provided by it. Service classes are used for separation of concerns. fun getTicketPriceWithIds(ids: List<Int>): Single<List<Float>> {        return ticketsDao.getTicketPriceWithIds(ids)    } When a list of tickets and their quantity is specified by the user the prices of the ticket are fetched using the above-explained methods. These are then stored it in a List of pair with the first element being ticket id and second its quantity. fun updatePaymentSelectorVisibility(ticketIdAndQty: List<Pair<Int, Int>>?) {        val ticketIds = ArrayList<Int>()        ticketIdAndQty?.forEach { if (it.second > 0) ticketIds.add(it.first) }        compositeDisposable.add(ticketService.getTicketPriceWithIds(ticketIds)                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe({                    var total = 0.toFloat()                    it?.forEach {                        if (it.toFloat() > 0) total += it.toFloat()                    }                    paymentSelectorVisibility.value = total != 0.toFloat()                }, {                    Timber.e(it, "Error Loading tickets!")                }))    } The above method controls the visibility boolean for payment selector, it essentially iterates over the List<Pair<Int, Int>> and add all the ticket id to a temporary list if quantity for that ticket is greater than zero after this prices for the tickets in temporary list is fetched and sum total is calculated. If this total is greater than zero the visibility boolean is set else reset. Finally an observable is set on this boolean which automatically updates the UI whenever boolean changes accordingly. attendeeFragmentViewModel.paymentSelectorVisibility.observe(this, Observer {            if (it !=null && it) {                rootView.paymentSelector.visibility = View.VISIBLE            } else {                rootView.paymentSelector.visibility = View.GONE            }         }) Resources Room and RxJava :  https://medium.com/google-developers/room-rxjava-acb0cd4f3757 Room :  https://developer.android.com/topic/libraries/architecture/room

Continue ReadingHiding Payment Options for Free Tickets in Open Event Android

Speaker details in the Open Event Orga App

The Open Event Organiser Android App is currently released in the Alpha phase on the Google Play Store here. This blog post explains how the speaker details feature has been implemented in the app. Model The model for Speaker is pretty straightforward. It includes the personal details of the speaker such as name, biography, country, social media profiles, designation etc. Apart from these details, every instance of speaker is associated with a single event. A speaker will also have multiple instances of sessions. Full implementation of the speaker’s model can be found here. Network Call We use Retrofit in order to make the network call and Jackson Factory to deserialize the data received from the call into an instance of the speaker model. The following endpoint provides us with the required information: https://open-event-api-dev.herokuapp.com/speakers/{speaker_id} Repository In any typical android application using both network calls and data persistence, there is a need of a repository class to handle them. Speaker Repository handles the network call to the API in order to fetch the speaker details. It then saves the data returned by the api into the database asynchronously. It also ensures that we send the latest data that we have stored in the database to the view model. Given below is the full implementation for reference: @Override public Observable<Speaker> getSpeaker(long speakerId, boolean reload) { Observable<Speaker> diskObservable = Observable.defer(() -> repository .getItems(Speaker.class, Speaker_Table.id.eq(speakerId)).take(1) ); Observable<Speaker> networkObservable = Observable.defer(() -> speakerApi.getSpeaker(speakerId) .doOnNext(speaker -> repository .save(Speaker.class, speaker) .subscribe())); return repository .observableOf(Speaker.class) .reload(reload) .withDiskObservable(diskObservable) .withNetworkObservable(networkObservable) .build(); } ViewModel The View Model is responsible for fetching the necessary details from the repository and displaying it in the view. It handles all the view binding logic. The most important method in the SpeakerDetailsViewModel is the getSpeakers method. It accepts a speaker id from the fragment, queries the repository for the details of the speaker and returns it back to the fragment in the form of a LiveData. Below is the full implementation of the getSpeakers method: protected LiveData<Speaker> getSpeaker(long speakerId, boolean reload) { if (speakerLiveData.getValue() != null && !reload) return speakerLiveData; compositeDisposable.add(speakerRepository.getSpeaker(speakerId, reload) .compose(dispose(compositeDisposable)) .doOnSubscribe(disposable -> progress.setValue(true)) .doFinally(() -> progress.setValue(false)) .doOnNext(speaker -> speakerLiveData.setValue(speaker)) .flatMap(speaker -> sessionRepository.getSessionsUnderSpeaker(speakerId, reload)) .toList() .subscribe(sessionList -> sessionLiveData.setValue(sessionList), throwable -> error.setValue(ErrorUtils.getMessage(throwable)))); return speakerLiveData; } We add the disposable to a composite disposable and dispose it in the onCleared method of the View Model. The full implementation of the View Model can be found here. Fragment The SpeakerDetailsFragment acts as the view and is responsible for everything the user sees on the screen. It accepts the id of the speaker whose details are to be displayed in the constructor. When an instance of the fragment is created it sets up it’s view model and inflates it’s layout using the Data binding framework. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { context = getContext(); binding = DataBindingUtil.inflate(inflater, R.layout.speaker_details_fragment, container, false); speakerDetailsViewModel = ViewModelProviders.of(this, viewModelFactory).get(SpeakerDetailsViewModel.class); speakerId = getArguments().getLong(SPEAKER_ID); AppCompatActivity activity = ((AppCompatActivity) getActivity()); activity.setSupportActionBar(binding.toolbar); ActionBar actionBar = activity.getSupportActionBar(); if (actionBar != null) { actionBar.setHomeButtonEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true); }…

Continue ReadingSpeaker details in the Open Event Orga App

Ticket Quantity Spinner in Open Event Android

Spinners are basically drop down menu which provides an easy way to select an item from a set of items. Spinner is used in Open Event Android to allow user select quantity of tickets as shown in the image above. This blog post will guide you on how its implemented in Open Event Android. Add Spinner to the XML file <Spinner            android:id="@+id/orderRange"            android:layout_width="30dp"            android:layout_height="30dp"            android:spinnerMode="dialog"            android:textSize="@dimen/text_size_small" /> The above code spinnet will create a spinner type view with 30dp height and width, spinnerMode can be dialog or dropDown following are example spinner for both of the modes left being dialog type and right dropDown type.                  (Image Source: Stack Overflow) Set Up Adapter and Populate Data on Spinner To show the list of acceptable Quantities for a Ticket, create an ArrayList of String and add all values from ticket.minOrder to ticket.maxOrder along with a zero option. Since ArrayList is of String and the values are integer they need to be converted to String using Integer.toString(i) method. Following code snippet will give you more understanding about it. val spinnerList = ArrayList<String>()            spinnerList.add("0")            for (i in ticket.minOrder..ticket.maxOrder) {                spinnerList.add(Integer.toString(i))            } We will also need to set up an onItemSelectedListener to listen for Item Selections and override onItemSelected and onNothingSelected functions in it. Whenever an item is selected onItemSelected is called with arguments such as view, position of the selected item, id etc, these can be used to find the selected Quantity from the ArrayList of acceptable Quantities.           itemView.orderRange.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {                override fun onItemSelected(parent: AdapterView<*>, view: View, pos: Int, id: Long) {                    itemView.order.text = spinnerList[pos]                    selectedListener?.onSelected(ticket.id, spinnerList[pos].toInt())                }                override fun onNothingSelected(parent: AdapterView<*>) {                }            } Since Spinner is an Adapter Based view we need to create a SpinnerAdapter and attach it with the Spinner. If you want to create custom Spinners you would have to create a custom adapter for it along with a layout for its row elements or else one can use library-provided layout. Given below is the implementation for library-provided spinner row type. There are different options available for row type we are using R.layout.select_dialog_singlechoice because we need single selectable Quantity spinner along with Radio button for every ticket.      itemView.orderRange.adapter = ArrayAdapter(itemView.context, R.layout.select_dialog_singlechoice, spinnerList) Resources Android Developers Documentation : https://developer.android.com/guide/topics/ui/controls/spinner Stack OverFlow: https://www.javatpoint.com/android-spinner-example

Continue ReadingTicket Quantity Spinner in Open Event Android

Mapping Events to Load from Database

Mapping Events to Load from Database In Open Event Android whenever App is started events are fetched for the location given by the user, since we have locally added isFavorite extra field for every event it is necessary to be updated for all the events returned in the API response before inserting it into our database otherwise all the favorite related information would be lost. This blog post will guide you on how its done in Open Event Android. The sequence of steps followed Take the IDs of events being saved into the database Use DAO method which does “SELECT id from Event where favorite = 1 AND id in :eventIds and pass API returned eventIds to this function Set the old favorited on new event objects Save them in database Let's see how all of these steps are performed in greater details. Whenever user gives in a location following function is called fun getEventsByLocation(locationName: String): Single<List<Event>> {        return eventApi.searchEvents("name", locationName).flatMap { apiList ->            val eventIds = apiList.map { it.id }.toList()            eventDao.getFavoriteEventWithinIds(eventIds).flatMap { favIds ->                updateFavorites(apiList, favIds)            }        }    } Here we are extracting all the Ids of events returned in the API response and then calling getFavoriteEventWithinIds on it. The latter takes the list of eventIds and return the Ids of events which are favorite out of them. This is then passed to the function updateFavorite along with the API returned Events. Following is the implementation of updateFavorite method. fun updateFavorites(apiEvents: List<Event>, favEventIds: List<Long>): Single<List<Event>> {        apiEvents.map { if (favEventIds.contains(it.id)) it.favorite = true }        eventDao.insertEvents(apiEvents)        val eventIds = apiEvents.map { it.id }.toList()        return eventDao.getEventWithIds(eventIds)    } updateFavorite checks for all events in the list of events whether if its Id is present in the favorite event ids it sets favorite field of that event true. After the favorites for the list of events are updated they are inserted into the database using DAO method insertEvents. The last task is to take the fetch these events again from the database, to do this first we extract the Ids of the events we just inserted into the database and call the DAO method getEventsWithIds passing the extracted eventIds, getEventsWithids simply returns the Events with given Ids. Given below are the implementations of the functions getEventWithIds and getFavoriteEventWithinIds @Query("SELECT * from Event WHERE id in (:ids)")    fun getEventWithIds(ids: List<Long>): Single<List<Event>> @Query("SELECT id from Event WHERE favorite = 1 AND id in (:ids)")    fun getFavoriteEventWithinIds(ids : List<Long>): Single<List<Long>> getEventWithIds simply makes a select query and checks for events whose ids lies in the ids passed to the method getFavoriteEventWithinids returns the Ids of the favorite event out of the list of event id passed to the method. Resources Android Developers Documetation for Room : https://developer.android.com/topic/libraries/architecture/room RxJava Documentation : https://github.com/ReactiveX/RxJava

Continue ReadingMapping Events to Load from Database

Setting an Event Favorite in Open Event Android

The favorite events feature in Open Event Android allows any user to favorite an event and those events can are available in the favorite events fragment which is easily accessible from the bottom navigation bar. This blog article will walk you through on how favorite works in Open Event Android. There are a couple of different ways to do it, in Open Event Android we are keeping track of favorite events using a favorite Boolean stored along with the information of the event ie we have added a favorite boolean field inside the event entity class. However, this method has its own pros and cons. The big plus point of this method is the fact that we can simply check the favorite field of the event object to check if that particular event is favorite or not. But since we have set onConflict strategy as replace in the event insert DAO method (shown below)  @Insert(onConflict = REPLACE)    fun insertEvents(events: List<Event>) This leads to a big problem when the same event is fetched or is present in the response while inserting the favorite field will be set to default value (false) and the favorite information would be lost. Hence extra care needs to be taken while updating events. Given following is the event model class for serializing / deserializing JSON responses. Note the extra field favorite added here which helps us to provide user favorite feature locally. @Type("event") @JsonNaming(PropertyNamingStrategy.KebabCaseStrategy::class) @Entity data class Event(       @Id(LongIdHandler::class)       @PrimaryKey       val id: Long,       val name: String,       val identifier: String,       val isMapShown: Boolean = false,       val favorite: Boolean = false ) Since we added a new field to the Event model class, to access the favorite events we will have to create DAO methods. To fetch all the favorite events we will have to create a Query method which returns all the events wherever favorite property is set. This can be done using a simple select statement which looks for events with favorite boolean set ie. 1, the method implementation is shown below. @Query("SELECT * from Event WHERE favorite = 1")    fun getFavoriteEvents(): Flowable<List<Event>> To set an event favorite we will have to add one more method to the EventDao. We can create a generalized method which sets according to the boolean passed as a parameter. The function implementation is shown below, setFavorite takes in EventId, Id of the event which has to be updated and the boolean favorite which is what the new value for the favorite field is. setFavorite makes an SQL update query and matches for EventId and sets favorite for that event. @Query("UPDATE Event SET favorite = :favorite WHERE id = :eventId")    fun setFavorite(eventId: Long, favorite: Boolean) In Open Event Android we use the service class which can be used to expose the DAO methods to the rest of the project. The idea behind creating service layer is the separation of concerns this service method is then called from the view model function (following the MVVM approach). Given following is the implementation of…

Continue ReadingSetting an Event Favorite in Open Event Android

Use Timber for Logging in SUSI.AI Android App

As per the official GitHub repository of Timber : “Timber is a logger with a small, extensible API which provides utility on top of Android's normal Log class”. It is a flexible logging library for Android which makes logging a lot more convenient. In this blog you will learn how to use Timber in SUSI.AI Android app. To begin, add Timber to your build.gradle and refresh your gradle dependencies. implementation 'com.jakewharton.timber:timber:4.7.0’ Two easy steps to use Timber: Install any Tree instances that you want in the onCreate() of your application class. Call Timber's static methods everywhere throughout the app. You can add the following code to your application class : @Override public void onCreate() { super.onCreate(); ….. if (BuildConfig.DEBUG) { Timber.plant(new Timber.DebugTree() { //Add the line number to the tag @Override protected String createStackElementTag(StackTraceElement element) { return super.createStackElementTag(element) + ": " + element.getLineNumber(); } }); } else { //Release mode Timber.plant(new ReleaseLogTree()); } } private static class ReleaseLogTree extends Timber.Tree { @Override protected void log(int priority, String tag, @NonNull String message, Throwable throwable) { if (priority == Log.DEBUG || priority == Log.VERBOSE || priority == Log.INFO) { return; } if (priority == Log.ERROR) { if (throwable == null) { Timber.e(message); } else { Timber.e(throwable, message); } } } } Timber ships with a ‘Debug Tree’ that provides all the basic facilities that you are very used to in the common Android.log framework. Timber has all the logging levels that are used in the normal Android logging framework which are as follows: Log.e: Use this tag in places like inside a catch statement where you are aware that an error has occurred and therefore you're logging an error. Log.w: Use this to log stuff you didn't expect to happen but isn't necessarily an error. Log.i: Use this to post useful information to the log. For instance, a message that you have successfully connected to a server. Log.d: Use this for debugging purposes. For instance, if you want to print out a bunch of messages so that you can log the exact flow of your program or if you want to keep a log of variable values. Log.v: Use this if, for some reason, you need to log every little thing in a particular part of your app. Log.wtf: Use this when you encounter a terrible failure.   You can use Timber.e, Timber.w, Timber.i, Timber.d and Timber.v respectively for the logging levels mentioned above. However, there is a small difference. In Android logging framework the exception is passed as the last parameter. But, when using Timber, you need to provide the exception as the first parameter. Interestingly, while using Timber you don’t have to provide a TAG in logging calls because it automatically does that for you. It uses the file name, where you are logging from, as the TAG. To log an exception you can simply write: Timber.e(exception, "Message"); Or a null message if you want: Timber.e(exception, null); A simple message can be logged sent via Crashlytics too: Timber.e("An error message"); Did you…

Continue ReadingUse Timber for Logging in SUSI.AI Android App

Implementing Settings for Lux Meter Instrument in PSLab Android App

In PSLab android app, we have included sensor instruments which use either inbuilt sensor of smartphone or external sensor to record sensor data. For example, Lux Meter uses the light sensor to record lux data but the problem is that these instruments doesn’t contain settings option to configure the sensor record-setting like which sensor to use, change the update period etc. Therefore, we need to create a settings page for the Lux Meter instrument which allows the user to modify the properties of the sensor instrument. For that I will use Android Preference APIs to build a settings interface that is similar to setting activity in any other android app. The main building block of the settings activity is the Preference object. Each preference appears as a single setting item in an activity and it corresponds to key-value pair which stores the settings in default Shared Preferences file. Every time any setting is changed by the user the Android will store the updated value of the setting in the default shared preferences which we can read in any other activity across the app. In the following steps I will describe instruction on how to create the setting interface in Android app:  Step1 Include the dependency First, we need to include the dependency for v7 Preference Support Library by including the following code: dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:design:23.1.1' compile 'com.android.support:preference-v7:23.1.1' }  Step 2 Creating the preferences screen in XML For this step, I have created a preference screen which will be inflated when the settings fragment is being created. I created a file named  “lux_meter_settings.xml” and place it in the res/xml/ directory. The root node for the XML file must be a <PreferenceScreen> element. We have to add each Preference within this element. Each child I added within the <PreferenceScreen> element appears as a single item in the list of settings. The preference which I have used are: <EdittextPreference> This preference opens up a dialog box with edit text and stores whatever value is written by the user in the edit text. I have used this preference for inputting update period and high limit of data during recording. <CheckboxPreference> shows an item with a checkbox for a setting that is either enabled or disabled. The saved value is a boolean (true if it's checked). I have used this preference for enabling or disabling location data with the recorded data. <ListPreference> opens a dialog with a list of radio buttons. The saved value can be any one of the supported value types. I have used this preference to allow the user to choose between multiple sensor types. <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <EditTextPreference android:key="setting_lux_update_period" android:title="@string/update_period" android:dialogTitle="@string/update_period" android:defaultValue="1000" android:dialogMessage="Please provide time interval(in ms) at which data will be updated" android:summary="Update period is 900ms"/> <EditTextPreference android:key="setting_lux_high_limit" android:title="High Limit" android:dialogTitle="High Limit" android:defaultValue="2000" android:dialogMessage="Please provide maximum limit of LUX value to be recorded" android:summary="High Limit is 2000 Lux"/> <CheckBoxPreference android:defaultValue="false" android:key="include_location_sensor_data" android:summary="Include the location data in the logged file" android:title="Include Location…

Continue ReadingImplementing Settings for Lux Meter Instrument in PSLab Android App

Retrofit2 Rxjava2 Error Response Handling in Open Event Organizer App

In the Open Event Organizer Android app the challenge is to provide user, a readable error description for the input requests. The Organizer App was showing a coded message which was understandable only to a programmer making it unfriendly to the common user. The blog describes how we tackled this problem and implemented a mechanism to provide user friendly error messages for user requests (if any). Let’s consider the scenario when an organizer want to create an Event or maybe a Ticket so what he has to do is fill out a form containing some user input fields and click on submit button to send the data to the server which in turn sends a response for the request. If the information is valid the server sends a HTTP 201 Response and user gets feedback that the Event/Ticket is created. But if the information is not valid the user gets feedback that there is HTTP 422 error in your request. There is no readable description of error provided to the user. To handle this problem we will be using Retrofit 2.3.0 to make Network Requests, which is a REST client for Android and Java by Square Inc. It makes it relatively easy to retrieve and upload JSON (or other structured data) via a REST based Web Service. Further, we will be using other awesome libraries like RxJava 2.1.10 (by ReactiveX) to handle tasks asynchronously, Jackson, Jasminb-Json-Api in an MVP architecture. Let’s move on to the code. Retrofit to the rescue Now we will see how we can extract the details about the error response and provide user a better feedback rather than just throwing the error code. Firstly let’s make the Request to our REST API Server using Retrofit2. @POST("faqs") Observable<Faq> postFaq(@Body Faq faq); Here we are making a POST request and expecting a Observable<Faq> Response from the server.The  @Body annotation indicates the Request Body is an Faq object. Please note that Observable used here is ReactiveX Observable so don’t confuse it with java.util Observable. public class Faq { @Id(LongIdHandler.class) public Long id;  @Relationship("event") @ForeignKey(stubbedRelationship = true, onDelete = ForeignKeyAction.CASCADE) public Event event; public String question; public String answer; } Let’s say the API declares both question and answer as mandatory fields  for creation of an Faq. We supply the following input to the app. question = "Do I need to buy a Ticket to get In ?"; answer = null We used RxJava to make an asynchronous request to server. In case of error we will get a Retrofit throwable and we will pass that on to ErrorUtils.java which will do all the processing and return a readable error message. faqRepository .createFaq(faq) .compose(dispose(getDisposable())) .compose(progressive(getView()))  .doOnError(throwable -> getView().showError(ErrorUtils.getMessage(throwable))) .subscribe(createdFaq -> { getView().onSuccess("Faq Created"); getView().dismiss(); }, Logger::logError); Now we will extract the ResponseBody from the Retrofit throwable. ResponseBody responseBody = ((HttpException) throwable) .response().errorBody(); return getErrorDetails(responseBody); The ResponseBody is a JSON containing all the information about the error. { "errors": [ { "status": "422", "source": { "pointer": "/data/attributes/answer" }, "detail": "Missing data…

Continue ReadingRetrofit2 Rxjava2 Error Response Handling in Open Event Organizer App

Producing Waveforms using Wave Generator module in the PSLab Android App

This blog will demonstrate how to produce different waveforms using the Wave Generator module in the PSLab android app and view them on the Oscilloscope. The Wave Generator in PSLab android app is simple to use and has a UI which is similar to physical commodity wave generators. It is capable of producing different waveforms like sine, sawtooth and square wave. Apparatus Required Before getting started with the wave generator we require the following items: PSLab device An android phone with PSLab app installed in it. USB cable (Mini B) OTG(On the Go) wire Some connecting wires having pins at both ends Understanding the Wave Generator Pins Let me briefly explain the use of the pins that are going to be used in the Wave generator module: S1 and S2 pins The PSLab device contains two pins (S1, S2) which are capable of producing two independent analog waveforms (sine,  sawtooth) having different frequencies and phase offset. The frequency range is from 10Hz to 5Khz. SQR1, SQR2, SQR3 and SQR4 pin The SQR1 pin is used for producing the square waveform and all the SQ pins can be used together to produce four different PWM signal having the same frequency. These PWM signal can have a different duty cycle and phase. CH1, CH2 and CH3 pin The CH pins are used by the oscilloscope in the  PSLab android app to monitor waveform signals produced by the wave generator pins. They can be used together to simultaneously monitor multiple waveforms. Setting up the Device We need to connect the PSLab device with the mobile phone as shown in Figure 2 which can be done by following steps: Connect a micro USB(Mini B) to the PSLab device. Connect the other end of the micro USB cable to the OTG. Connect the OTG to the phone. Producing Waveforms Now, once the device has been properly connected to the device (which is shown at the top right corner of the app), then in the instruments page scroll down to the Wave Generator card and click on it to open the WaveGenerator activity. Here you will see a screen like shown in Figure 4 containing two monitors and a controlling panel with lots of buttons. Here the Waveform panel is used to control the S1 and S2 pins whose properties are shown on the left monitor screen and the Digital panel is used to control the SQR pins whose properties are shown on the right monitor screen. For sine/sawtooth wave: Connect the S1 pin to the CH1 pin using a connecting wire, then in the Waveform panel select the Wave1 button, choose the type of waveform(either sine or sawtooth), then click on the Freq button to change the frequency of the wave, then use the Seek bar or the up/down arrow buttons to change the value of frequency and then press the set button to set the frequency for the S1 pin as shown below: Now, click the view button at bottom right corner, this will directly…

Continue ReadingProducing Waveforms using Wave Generator module in the PSLab Android App