Implementing Registration API in Open Event Front-end

In this post I will discuss how I implemented the registration feature in Open Event Front-end using the Open-Event-Orga API. The project uses Ember Data for consumption of the API in the ember application. The front end sends POST request to Open Event Orga Server which verifies and creates the user.

We use a custom serialize method for trimming the request payload of the user model by creating a custom user serializer. Lets see how we did it.

Implementing register API

The register API takes username & password in the payload for a POST request which are validated in the register-form component using the semantic-ui form validation. After validating the inputs from the user we bubble the save action to the controller form the component.

submit() {
  this.onValid(() => {
    this.set('errorMessage', null);
    this.set('isLoading', true);
    this.sendAction('submit');
  });
}

In controller we have `createUser()` action where we send a POST request to the server using the save() method, which returns a promise.

createUser() {
  var user = this.get('model');
  user.save()
    .then(() => {
      this.set('session.newUser', user.get('email'));
      this.set('isLoading', false);
      this.transitionToRoute('login');
    })
    .catch(reason => {
      this.set('isLoading', false);
      if (reason.hasOwnProperty('errors') && reason.errors[0].status === 409) {
        this.set('errorMessage', this.l10n.t('User already exists.'));
      } else {
        this.set('errorMessage', this.l10n.t('An unexpected error occurred.'));
      }
    });
}

The `user.save()` returns a promise, therefore we handle it using a then-catch clause. If the request is successful, it executes the `then` clause where we redirect to the login route. If the request fails we check if the status is 409 which translates to a duplicate entry i.e the user already exists in the server.

Serializing the user model using custom serializer

Ember lets us customise the payload using serializers for models. The serializers have serialize function where we can trim the payload of the model. In the user serializer we check if the request is for record creation using `options.includeId`. If the request is for record creation we trim the payload using the lodash `pick` method and pick only email & password for payload for POST request.

serialize(snapshot, options) {
  const json = this._super(...arguments);
  if (options && options.includeId) {
    json.data.attributes = pick(json.data.attributes, ['email', 'password']);
  }
  return json;
}

Thank you for reading the blog, you can check the source code for the example here.

Resources

Continue ReadingImplementing Registration API in Open Event Front-end

Adding Unit Test For Local JSON Parsing in Open Event Android App

The Open Event project uses JSON format for transferring event information like tracks, sessions, microlocations and other. The event exported in the zip format from the Open Event server also contains the data in JSON format. The Open Event Android application uses this JSON data. Before we use this data in the app, we have to parse the data to get Java objects that can be used for populating views. There is a chance that the model and the JSON format changes in future. It is necessary that the models are able to parse the JSON data and the change in the model or JSON format don’t break JSON parsing.  In this post I explain how to unit test local JSON parsing so that we can ensure that the models are able to parse the local JSON sample data successfully.

Firstly we need to access assets from the main source set into the unit test. There is no way to directly access assets from main source set. We need to first add assets in test/resources directory. If assets are present in test/resources directory then we can use it using ClassLoader in the unit test. But we can’t just copy assets from the main source set to resources directory. If there is any change in sample JSON then we need to maintain both resources and it may make the sample inconsistent. We need to make assets shared.

Add the following code in the app level build.gradle file.

android {
    ...
    sourceSets.test.resources.srcDirs += ["src/main/assets"]
}

It will add src/main/assets as a source directory for test/resources directory.So after building the project the test will have access to the assets.

Create readFile() method

Now create a method readFile(String name) which takes a filename as a parameter and returns data of the file as a string.

private String readFile(String name) throws IOException {
        String json = "";
        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(name);
            int size = inputStream.available();
            byte[] buffer = new byte[size];
            inputStream.read(buffer);
            inputStream.close();
            json = new String(buffer, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return json;
}

Here the getResourceAsStream() function is used to open file as a InputStream. Then we are creating byte array object of size same as inputStream data. Using read function we are storing data of file into byte array. After this we are creating a String object using a byte array.

Create ObjectMapper object

Create and initialize an ObjectMapper object in the Test class.

private ObjectMapper objectMapper;

    @Before
    public void setUp() {
        objectMapper = OpenEventApp.getObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
}

Here setting DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES to true is very important. It will fail the test for any unrecognized fields in the sample.

Create doModelDeserialization() method

In the Open Event Android App we are using Jackson for JSON serialization and deserialization. Converting JSON data to java is called deserialization or parsing.

Now create doModelDeserialization() method which takes three parameters,

  • Class<T> type: Model Class type of the data
  • String name: Name of the JSON data file
  • boolean isList: true if JSON string contains the list of object else false

This method returns true if parsing is successful and false if there is any error in parsing.

private <T> boolean doModelDeserialization(Class<T> type, String name, boolean isList) throws IOException {
        if (isList) {
            List<T> items = objectMapper.readValue(readFile(name), objectMapper.getTypeFactory().constructCollectionType(List.class, type));
            if (items == null)
                return false;
        } else {
            T item = objectMapper.readValue(readFile(name), type);
            if (item == null)
                return false;
        }
        return true;
}

Here ObjectMapper is doing the main work of parsing data and returns parsed object using readValue() method.

Add Test

Now all the setup is done we just need to assert value returned by doModelDeserialization() method by passing appropriate parameters.

@Test
public void testLocalJsonDeserialization() throws IOException {
        assertTrue(doModelDeserialization(Event.class, "event", false));
        assertTrue(doModelDeserialization(Microlocation.class, "microlocations", true));
        assertTrue(doModelDeserialization(Sponsor.class, "sponsors", true));
        assertTrue(doModelDeserialization(Track.class, "tracks", true));
        assertTrue(doModelDeserialization(SessionType.class, "session_types", true));
        assertTrue(doModelDeserialization(Session.class, "sessions", true));
        assertTrue(doModelDeserialization(Speaker.class, "speakers", true));
}

Here only event JSON file doesn’t have a list of the objects so passing false as isList parameter for others we are passing true because its data contains a list of objects.

Conclusion:

Running unit tests after every build helps you to quickly catch and fix software regressions introduced by code changes to your app

Continue ReadingAdding Unit Test For Local JSON Parsing in Open Event Android App

Generic Social Links Implementation in Open Event Android App

The Open Event Android App has an About Fragment which displays all the info about the event like name, time, location etc. It also shows social media buttons for the event. The problem was that the implementation of showing the social media buttons was not generic. The implementation was working fine for current FOSSASIA sample. If we generate the app for other events it creates a problem. It shows static buttons without proper mapping from social media button to social media link which creates a problem like on clicking GitHub button it opens Facebook link (issue #1792).

One solution to this problem is to implement recyclerview with social media buttons. In this post I explain how I have made social links implementation generic using RecyclerView.

Add RecyclerView in layout

The first step to do is to add recyclerview in the layout xml file and to create a list item for recyclerview which holds the image for the social link button. Then in the About Fragment find recyclerview element added in the xml file using findFragmentById() method.

1. Add recyclerview in xml file

In the layout xml file of About Fragment add recyclerview element. Define id, width, height, and gravity of recyclerview. Then specify list item for recyclerview using listitem attribute.

<android.support.v7.widget.RecyclerView
            android:id="@+id/list_social_links"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:overScrollMode="never"
            android:clipToPadding="false"
            tools:listitem="@layout/item_social_link" />

2. Create item_social_link.xml

Now create a item_social_link.xml file and add a FrameLayout element. Inside the FrameLayout add an ImageView with appropriate id, width, height and padding.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_social_link_parent"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/img_social_link"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="?attr/selectableItemBackgroundBorderless"
        android:contentDescription="@string/social_link"
        android:padding="@dimen/padding_large"
        android:tint="@color/white" />
</FrameLayout>

Add and initialize RecyclerView

After adding recyclerview in xml file we need to add RecyclerView field in the About Fragment java file. Now add and initialize SocialLinksListAdapter which extends RecyclerView.Adapter and will be used for populating the recyclerview with the social links.

@BindView(R.id.list_social_links)
protected RecyclerView socialLinksRecyclerView;

private SocialLinksListAdapter socialLinksListAdapter;
private List<SocialLink> mSocialLinks = new ArrayList<>();

Here mSocialLinks is the list of social links which is fetched from the Event object.

Create ViewHolder for social link button

Now create SocialLinkViewHolder which extends RecyclerView.ViewHolder and holds one social link item defined in item_social_link.xml file. This file is where the magic happens. Add ImageView, FrameLayout, SocialLink and context fields in it.

public class SocialLinkViewHolder extends RecyclerView.ViewHolder {

    @BindView(R.id.img_social_link)
    protected ImageView imageView;

    @BindView(R.id.layout_social_link_parent)
    protected FrameLayout layout;

    private SocialLink socialLink;
    private Context context;

    public SocialLinkViewHolder(View itemView, Context context) {
        super(itemView);
        ButterKnife.bind(this, itemView);
        this.context = context;
    }

    public void bindSocialLink(@NonNull SocialLink socialLink) {...}

    private void setImageDrawable(@NonNull String name,@NonNull String link) {...}

    private Drawable getDrawable(@DrawableRes int id) {...}

    private void showView(boolean show) {...}
}

The bindSocialLink(SocialLink socialLink) method is called in the onBindViewHolder() method of the SocialLinksListAdapter. In this method initialize socialLink field and set drawable for ImageView according to SocialLink name using setImageDrawable() method.

public void bindSocialLink(@NonNull SocialLink socialLink) {
        this.socialLink = socialLink;
        setImageDrawable(socialLink.getName(), socialLink.getLink());
}

The setImageDrawable() method finds and sets appropriate image for social link button using the name of the social link. If the image for the social link is not found then it sets the visibility of the image view to GONE using showView(boolean show).

private void setImageDrawable(@NonNull String name,@NonNull String link) {

        if (Utils.isEmpty(name) || Utils.isEmpty(link) || Utils.getSocialLinkDrawableId(name) == 1) {
            showView(false);
            return;
        }
        imageView.setImageDrawable(getDrawable(Utils.getSocialLinkDrawableId(name)));
}

The showView(boolean show) method handles visibility of ImageView and ImageView’s parent FrameLayout using setVisibility() method.

private void showView(boolean show) {
        if (show) {
            imageView.setVisibility(View.VISIBLE);
            layout.setVisibility(View.VISIBLE);
        } else {
            imageView.setVisibility(View.GONE);
            layout.setVisibility(View.GONE);
        }
}

Set onClickListener to ImageView

Now it’s time to set the onClickListener in the constructor of the SocialLinkViewHolder to define what to do when user clicks on the ImageView.

imageView.setOnClickListener(view -> {
            if (socialLink != null && !Utils.isEmpty(socialLink.getLink())) {
                Utils.setUpCustomTab(context, socialLink.getLink());
            }
        });

Here we are setting custom tab for the social link using the setUpCustomTab() util method which will open the link.

Now run the app on the device or emulator. Here’s how it looks like,

Conclusion

The SocialLink impementation using the RecyclerView gives the great user experience in the application.

Additional resources

Continue ReadingGeneric Social Links Implementation in Open Event Android App

Presenters via Loaders in Open Event Organizer Android App

Open Event Organizer‘s App design follows Model View Presenter (MVP) architecture which facilitates heavy unit testing of the app. In this design pattern, each fragment/activity implements a view interface which uses a presenter interface to interact with a model interface. The presenter contains most of the data of the view. So it is very important to restore presenters after configuration changes like rotation. As on rotation, the complete activity is re-created hence all the fields are destroyed and as a result, everything is re-generated resulting in state loss on configuration change which is unexpected. Open Event Organizer App uses the loader to store/provide presenters to the activity/fragment. Loader survives configuration changes. The idea of using the loader to provide presenter is taken from Antonio Gutierrez’s blog on “Presenters surviving orientation changes with loaders“.

The first thing to do is make a PresenterLoader<T> class extending Loader<T> where T is your presenter’s base interface. The PresenterLoader class in the app looks like:

public class PresenterLoader<T extends IBasePresenter> extends Loader<T> {

   private T presenter;

   ...

   @Override
   protected void onStartLoading() {
       super.onStartLoading();
       deliverResult(presenter);
   }

   @Override
   protected void onReset() {
       super.onReset();
       presenter.detach();
       presenter = null;
   }

   public T getPresenter() {
       return presenter;
   }
}

 

The methods are pretty clear from the names itself. Once this is done, now you are ready to use this loader in for your fragment/activity. Creating a BaseFragment or BaseActivity will be clever as then you don’t have to add same logic everywhere. We will take a use case of an activity. A loader has a unique id by which it is saved in the app. Use unique id for each fragment/activity. Using the id, the loader is obtained in the app.

Loader<P> loader = getSupportLoaderManager().getLoader(getLoaderId());

 

When creating for the first time, the loader is set up with the loader callbacks where we actually set a presenter logic. In the Organizer App, we are using dagger dependency injection for injecting presenter in the app for the first time. If you are not using the dagger, you should create PresenterFactory class containing create method for the presenter. And pass the PresenterFactory object to the PresenterLoader in onCreateLoader. In this case, we are using dagger so it simplifies to this:

getSupportLoaderManager().initLoader(getLoaderId(), null, new LoaderManager.LoaderCallbacks<P>() {
   @Override
   public Loader<P> onCreateLoader(int id, Bundle args) {
       return new PresenterLoader<>(BaseActivity.this, getPresenterProvider().get());
   }

   @Override
   public void onLoadFinished(Loader<P> loader, P presenter) {
       BaseActivity.this.presenter = presenter;
   }

   @Override
   public void onLoaderReset(Loader<P> loader) {
       BaseActivity.this.presenter = null;
   }
});

 

getPresenterProvider method returns Lazy<Presenter> provider to ensure single presenter creation in the activity/fragment. The lifecycle to setup PresenterLoader in activity is onCreate and in the fragment is onActivityCreated. Use presenter field from next lifecycle that is start. If the presenter is used before the start, it creates null pointer exception. For example, if implementing with the BaseFragment, setup loader in onActivityCreated method.

@Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       Loader<P> loader = getSupportLoaderManager().getLoader(getLoaderId());
       if (loader == null) {
           initLoader();
       } else {
           presenter = ((PresenterLoader<P>) loader).getPresenter();
       }
   }

 

Make sure that your base interface implements some of the basic methods. For example, onDetach, onAttach etc. getLoaderId method must be implemented in each fragment/activity using loaders. The method returns unique id for each fragment/activity. In Organizer App, the method returns layout id of the fragment/activity as a unique id.

Using the loader approach to store/restore presenters helps in surviving their instances in configuration changes in the app. Hence improves the performance.

Links:
Antonio Gutierrez’s blog post about Presenter surviving orientation changes with Loaders in Android
Android Documentation for Loaders

Continue ReadingPresenters via Loaders in Open Event Organizer Android App

Working With Inter-related Resource Endpoints In Open Event API Server

In this blogpost I will discuss how the resource inter-related endpoints work. These are the endpoints which involve two resource objects which are also related to another same resource object.


The discussion in this post is of the endpoints related to Sessions Model. In the API server, there exists a relationship between event and sessions. Apart from these, session also has relationships with microlocations, tracks, speakers and session-types. Let’s take a look at the endpoints related with the above.

`/v1/tracks/<int:track_id>/sessions` is a list endpoint which can be used to list and create the sessions related to a particular track of an event. To get the list we define the query() method in ResourceList class as such:

The query method is executed for GET requests, so this if clause looks for track_id in view_kwargs dict. When the request is made to `/v1/tracks/<int:track_id>/sessions`, track id will be present as ‘track_id in the view_kwargs. The tracks are filtered based on the id passed here and then joined on the query with all sessions object from database.

For the POST method, we need to add the track_id from view_kwargs to pass into the track_id field of database model. This is achieved by using flask-rest-jsonapi’s before_create_object() method. The implementation for track_id is the following:

When a POST request is made to `/v1/tracks/<int:track_id>/sessions`, the view_kwargs dict will have ‘track_id’ in it. So if track_id is present in the url params, we first ensure that a track with the passed id exists, then only proceed to create a sessions object under the given track. Now the safe_query() method is a generic custom method written to check for such things. The model is passed along with the filter attribute, and a field to include in the error message. This method throws an ObjectNotFound exception if no such object exists for a given id.

We also need to take care of the permissions for these endpoints. As the decorators are called even before schema validation, it was difficult to get the event_id for permissions unless adding highly endpoint-specific code in the permission manager core, leading to loss of generality.  So the leave_if parameter of permission check was used to overcome this issue. Since the permissions manager isn’t fully developed yet, this is to be changed in the improved implementation of the permissions manager.

Similar implementations for micro locations and session types was done. All the same is not explained in this blogpost. For extended code, take a look at the source code of this schema.

For speaker relation, a few things were different. This is because speakers-sessions is a many-to-many relationship. Let’s take a look at this:

As it is a many-to-many relationship, a association_table was used with flask-sqlalchemy. So for the query() method, the same association table is queried after extracting the speaker_id from view_kwargs dict.

For the POST request on `/v1/speakers/<int:speaker_id>/sessions` , flask-rest-jsonapi’s after_create_object() method is used to insert the request in association_table. In this method the parameters are the following: self, obj, data, view_kwargs

Now view_kwargs contains the url parameters, so we make a check for speaker_id in view_wargs. If it is present, then before proceeding to insert data, we ensure that a speaker exists with that id using the safe_query() method as described above. After that, the obj argument of the method is used. This contains the object that was created in  previous method. So now once the sessions object has been created and we are sure that a speaker exists with given speaker_id, this is just to be appended to obj.speakers  so that this relationship tuple is inserted into the association table.

This updates the association table ‘speakers_session’ in this case. The other such endpoints are being worked upon in a similar fashion and will be consolidated as part of a set of robust APIs, along with the improved permissions manager for the Open Event API Server.

Additional Resources

Code, Issues and Pull Request involved

Continue ReadingWorking With Inter-related Resource Endpoints In Open Event API Server

Using Map View to Display Location of Clicked Image in Phimpme

Previously in Phimpme Android app we used to display all the images on the map, based on their location they have taken. In the upcoming version, we are introducing mapview to specify the location when user checks out the details of the image. In this post, I am explaining that how I have implemented Google’s mapView in Phimpme. Note: The prerequisite to display image location in the map view, an image should have geolocation in its meta data.

Let’s get started

Step -1 : First, enable the setting to ‘Show mapview in Image description’ and save it somewhere.

Although, it’s your choice you want to give users choice to view map or not.

First, we need to turn on the movie visibility from map provider in settings. Right now we are adding two maps in our list Google maps and openstreetmap.

Choose Map Provider from the list in Phimpme

Once you choose your preference, it will get stored in sharedPref. As we are displaying the map in the image details so we need to add Image view of map.

Step -2 : Add a ImageView in your XML, in which we will display map.

<ImageView
   android:id="@+id/photo_map"
   android:layout_width="match_parent"
   android:layout_height="150dp"
   android:visibility="gone"
/>

Keep default visibility of mapview is GONE, If a user will enable map view in setting then we will make this image visible.

Step -3 : Load image with map in ImageView:

Good things are that StaticMapProvier gives you the URL of the image in corresponding to particular GeoLocation, which actually is a view of the map.

Now we need to display mapview when the user taps on details of an image.

ImageView imgMap = (ImageView) dialogLayout.findViewById(R.id.photo_map);
final GeoLocation location;
if ((location = f.getGeoLocation()) != null) {
   PreferenceUtil SP = PreferenceUtil.getInstance(activity.getApplicationContext());

   StaticMapProvider staticMapProvider = StaticMapProvider.fromValue(
           SP.getInt(activity.getString(R.string.preference_map_provider), StaticMapProvider.GOOGLE_MAPS.getValue()));

   Glide.with(activity.getApplicationContext())
           .load(staticMapProvider.getUrl(location))
           .asBitmap()
           .centerCrop()
           .animate(R.anim.fade_in)
           .into(imgMap);

To load an image, we used Glide Image library, you can use any library of your choice.

MapView on the top of dialog box in Phimpme

Step 4: Open navigation on the tap of mapView or Image.

Attach a click listener on the imageView and on click of that create a Uri correspond to geolocation and through an Intent to Android to view that link, it will open Google maps with navigation.

 String uri = String.format(Locale.ENGLISH, "geo:%f,%f?z=%d", location.getLatitude(), location.getLongitude(), 17);
            activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(uri)));

Resources

Continue ReadingUsing Map View to Display Location of Clicked Image in Phimpme

Acceptance Testing of a Feature in Open Event Frontend

In Open Event Frontend, we have integration tests for ember components which are used throughout the project. But even after those tests, user interaction could pose some errors. We perform acceptance tests to alleviate such scenarios.

Acceptance tests interact with application as the user does and ensures proper functionality of a feature or to determine whether or not the software system has met the requirement specifications. They are quite helpful for ensuring that our core features work properly.

Let us write an acceptance test for register feature in Open Event Frontend.

import { test } from 'qunit';
import moduleForAcceptance from 'open-event-frontend/tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | register');

In the first line we import test from ‘ember-qunit’ (default unit testing helper suite for Ember) which contains all the required test functions. For example, here we are using test function to check the rendering of our component. We can use test function multiple times to check multiple components.

Next, we import moduleForAcceptance from ‘open-event-frontend/tests/helpers/module-for-acceptance’ which deals with application setup and teardown.

test('visiting /register', function(assert) {
  visit('/register');

  andThen(function() {
    assert.equal(currentURL(), '/register');
  });
});

Inside our test function, we simulate visiting  /register route and then check for the current route to be /register.

test('visiting /register and registering with existing user', function(assert) {
  visit('/register');
  andThen(function() {
    assert.equal(currentURL(), '/register');
    fillIn('input[name=email]', 'opev_test_user@nada.email');
    fillIn('input[name=password]', 'opev_test_user');
    fillIn('input[name=password_repeat]', 'opev_test_user');
    click('button[type=submit]');
    andThen(function() {
      assert.equal(currentURL(), '/register');
      // const errorMessageDiv = findWithAssert('.ui.negative.message');
      // assert.equal(errorMessageDiv[0].textContent.trim(), 'An unexpected error occurred.');
    });
  });
});

Then we simulate visiting /register route and register a dummy user. For this, we first go to /register route and then check for the current route to be register route. We fill the register form with appropriate data and hit submit.

test('visiting /register after login', function(assert) {
  login(assert);
  andThen(function() {
    visit('/register');
    andThen(function() {
      assert.equal(currentURL(), '/');
    });
  });
});

The third test is to simulate visiting /register route with user logged in and this is very simple. We just visit /register route and then check if we are are at / route or not because a user redirects to / route when he tries to visit /register after login.

And since we checked for all the possible combinations, to run the test we simply use the following command-

ember test --server

But there is a little demerit to acceptance tests. They boot up the whole EmberJS application and start us at the application.index route. We then have to navigate to the page that contains the feature being tested. Writing acceptance tests for each and every feature would be a big waste of time and CPU cycles. For this reason, only core features are tested for acceptance.

Resources

Continue ReadingAcceptance Testing of a Feature in Open Event Frontend

Implementing QR Code Detector in Open Event Organizer App

One of the main features of Open Event Organizer App is to scan a QR code from an attendee’s ticket to validate his/her entry to an event. The app uses Google’s Vision API library, com.google.android.gms.vision.barcode for QR code detection. In this blog, I talk about how to use this library to implement QR code detection with dynamic frame support in an Android App. The library uses a term barcode for all the supported formats including QR code. Hence in the blog, I use the term barcode for QR code format.

We use Google’s dagger for dependency injections in the app. So all the barcode related dependencies are injected in the activity using the dagger. Basically, there are these two classes – BarcodeDetector and CameraSource. The basic workflow is to create BarcodeDetector object which handles QR code detection. Add a SurfaceView in the layout which is used by the CameraSource to show preview to the user. Pass both of these to CameraSource. Enough talk, let’s look into the code while moving forward from here on. If you are not familiar with dagger dependency injection, I strictly suggest you have a look at some tutorial introducing dagger dependency injection.

So we have a barcode module class which takes care of creating  BarcodeDetector and CameraSource.

@Provides
BarcodeDetector providesBarCodeDetector(Context context) {
   BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context)
       .setBarcodeFormats(Barcode.QR_CODE)
       .build();
   return barcodeDetector;
}

@Provides
CameraSource providesCameraSource(Context context, BarcodeDetector barcodeDetector) {
   return new CameraSource
       .Builder(context, barcodeDetector)
       ...
       .build();
}

 

You can see in the code that BarcodeDetector is passed to the CameraSource builder. Now comes preview part. The user of the app should be able to see what is actually detected. Google has provided samples showing how to do that. It provides some classes that you can just add to your projects. The classes with the links are – BarcodeGraphic, CameraSourcePreview, GraphicOverlay and BarcodeGraphicTracker.

CameraSourcePreview is the custom view which is used in the QR detecting layout for preview. It handles all the SurfaceView related stuff with the additional BarcodeGraphic view which extends GraphicOveraly which is used to draw dynamic info based on the QR code detected. We use this class to draw a frame around the QR code detected. BarcodeGraphicTracker is used to receive newly detected items, add a graphical representation to an overlay, update the graphics as the item changes, and remove the graphics when the item goes away.

Override draw method of BarcodeGraphic according to your need of how you want to show results on the screen once barcode is detected. The method in the Organizer app looks like:

@Override
public void draw(Canvas canvas) {
   if (barcode == null) {
       return;
   }
   // Draws the bounding box around the barcode.
   RectF rect = new RectF(barcode.getBoundingBox());
   ...
   int width = (int) ((rect.right - rect.left)/3);
   int height = (int) ((rect.top - rect.bottom)/3);

   canvas.drawBitmap(Bitmap.createScaledBitmap(frameBottomLeft, width, height, false), rect.left, rect.top, null);
   ...
   canvas.drawRect(rect, rectPaint);
}

 

The class has a Barcode field which gets updated on barcode detection. In the above method, the field rect gets dimensions of the bounding box of the QR code detector. And accordingly, frames are drawn at the vertices of the rect . Include CameraSourcePreview inclosing GraphicOverlay in the activity’s layout.

<...CameraSourcePreview
   android:id="@+id/preview"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

   <...GraphicOverlay />

</...CameraSourcePreview>

 

CameraSourcePreview and GraphicOverlay are saved in the activity from the layout. Pass CameraSource and GraphicOverlay to the CameraSourcePreview using the method start. Now the last part left is setting the processor to the BarcodeDetector to add a connection to the GraphicOverlay. Use BarcodeGraphicTracker which connects GraphicOverlay to BarcodeDetector. This is done by passing BarcodeTrackerFactory which has create method for BarcodeGraphicTracker to Multiprocessor. The code looks like:

barcodeDetector.setProcessor(
   new MultiProcessor.Builder<>(
       new BarcodeTrackerFactory(graphicOverlay)).build());

 

Now BarcodeDetector is connected to the layout. This will update the preview on the layout as overridden in the draw method of BarcodeGraphic on each barcode detection.

Links:
Google’s Vision API – link
Google Dagger github repo link – https://github.com/google/dagger

Continue ReadingImplementing QR Code Detector in Open Event Organizer App

Add Autocomplete SearchView in Open Event Android App

The Open Event Android App has a map for showing all locations of sessions. All the locations have a marker in the map. It is difficult to find a particular location on the map because to know the name of location user has to click on the marker. Adding autocomplete SearchView will improve user experience by providing an ability to search the location by name and by suggesting name according to the search query. In this post I explain how to add autocomplete SearchView in the fragment or activity.

Add search icon in actionbar

The first step to do is to create a menu xml file and add a search menu item in it. Then inflate this menu xml file in Fragment in onCreateOptionsMenu() method.

1. Create menu.xml file

In this file add search menu element. Inside menu element add search menu item. Define id, title, and icon of search menu item. Add android.support.v7.widget.SearchView” as actionViewClass which will be used as action view when the user clicks on the icon.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    
   <item
        android:id="@+id/action_search"
        android:icon="@drawable/ic_search_white_24dp"
        android:title="@string/search"
        app:actionViewClass="android.support.v7.widget.SearchView"
        app:showAsAction="ifRoom | collapseActionView"/>
</menu>

2. Inflate menu.xml file in Fragment

In the fragment’s onCreateOptionsMenu() method inflate menu.xml file using MenuInflater’s inflate() method. Then find search menu item using menu’s findItem() method by passing id of search menu item as parameter.

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.menu_map, menu);
        MenuItem item = menu.findItem(R.id.action_search);
}

Add and initialize SearchView  

Now after adding search icon we need to add SearchView and SearchAutoComplete fields in the fragment.

private SearchView searchView;
private SearchView.SearchAutoComplete   mSearchAutoComplete;

Initialize SearchView in onCreateOptionMenu() method by passing search menu item in the getActionView() method of MenuItemCompat.

Here SearchAutoComplete is a child object of SearchView so initialize it using findViewById method of SearchView by passing the id as parameter.

searchView = (SearchView) MenuItemCompat.getActionView(item);
mSearchAutoComplete = (SearchView.SearchAutoComplete) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);

Define properties of SearchAutoCompleteView

By default background of drop down menu in SearchAutoComplete is black. You can change background using setDropDownBackgroundResource() method. Here i’m making it white by providing white drawable resource.

mSearchAutoComplete.setDropDownBackgroundResource(R.drawable.background_white);
mSearchAutoComplete.setDropDownAnchor(R.id.action_search);
mSearchAutoComplete.setThreshold(0)

The setDropDownAnchor() method sets the view to which the auto-complete drop down list should anchor. The setThreshold() method specifies the minimum number of characters the user has to type in the edit box before the drop down list is shown.

Create array adapter

Now it’s time to make the ArrayAdapter object which will provide the data set (strings) which will be used to run search queries.

ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, searchItems);

Here searchItems is List of strings. Now set this adapter to the mSearchAutoComplete object using setAdapter() method.

mSearchAutoComplete.setAdapter(adapter);

Now we are all set to run the app on device or emulator. Here’s demo how it will look

Conclusion

The SearchView with an ability to give suggestions serves the great user experience in the application.

Additional resources:

Continue ReadingAdd Autocomplete SearchView in Open Event Android App

Communicate between Child and Parent Components in React JS of SUSI Web Chat

When we were developing SUSI AI web chat  some components became huge. So the team wanted to break some components into parts. Since the Login dialog-box is used in several  places we decided to make a separate component for Login Dialog-box. In this post I am discussing how we implemented the feature as a separate component and how we have changed the state of the parent component of the child component.

Login Dialog-box contains all the things of the login dialog-box component.

Child-component (Login Dialog-box component) is here:

This method executes the ‘switchDialog’ function of the parent component.

export default class LoginDialog extends React.Component {

   handleClose = () => {
      this.props.switchDialog(false);
   };

   render() {
       this.state = { open: this.props.open }
       const actions = <RaisedButton
           label="Cancel"
           backgroundColor={
               UserPreferencesStore.getTheme() === 'light' ? '#607D8B' : '#19314B'}
           labelColor="#fff"
           width='200px'
           keyboardFocused={true}
           onTouchTap={this.handleClose}
       />;

       return (
           <Dialog
               actions={actions}
               modal={false}
               open={this.props.open}
               autoScrollBodyContent={true}
               bodyStyle={bodyStyle}
               contentStyle={{ width: '35%', minWidth: '300px' }}
               onRequestClose={this.handleClose}>
               <Login {...this.props} />
           </Dialog>
       );
   }

};

In this part we validate property types that has passed from the parent component.

LoginDialog.propTypes = {
   open: PropTypes.bool,
   switchDialog: PropTypes.func
};

In render() method I have returned the element.
To open and close dialog we have to communicate with parent component. We can send an instruction as an attribute of the element and we can refer it inside the element as “props”. This is how I have sent an instruction to the child element.
Parent-component:
‘handleOpen’ function opens the dialog when user hit on the login button.

   handleOpen = () => {
       this.setState({ open: true });
   };

‘switchDialog’ function is using for change the state of parent component from child Component (Login Dialog-box component).

   switchDialog=(dialogState)=>{
       this.setState({open:dialogState});
   };

   render() {

       const styles = {
           'margin': '60px auto',
           'width': '100%',
           'padding': '20px',
           'textAlign': 'center'
       }

       return (
           <div className="signUpForm">
               <Paper zDepth={1} style={styles}>
                   <h1>Sign Up with SUSI</h1>
                   <form onSubmit={this.handleSubmit}>
                       <div>
                           <h4>If you have an Account Please Login</h4>
                           <RaisedButton
                               onTouchTap={this.handleOpen}
                               label='Login'
                               backgroundColor={
                                   UserPreferencesStore.getTheme()==='light'
                                   ? '#607D8B' : '#19314B'}
                               labelColor="#fff" />
                       </div>
                   </form>
               </Paper>

               <LoginDialog {...this.props} open={this.state.open} switchDialog={this.switchDialog} />
           </div>
       );
   };

To open and close the dialog-box we have to send the state of the parent component to child component. To close the dialog-box we have to update the parent component’s state from child component.

To change the parent component’s state we have used this in element.

switchDialog={this.switchDialog}

To send the state to the child component we used this.

open={this.state.open}

To send other properties to the element we used this.

{...this.props}

After closing the dialog-box it calls this method and it updates the state of the parent component.

handleClose = () => {
      this.props.switchDialog(false);
};

This is how we can communicate between child and parent components using react.

Resources:

Component Communication: http://andrewhfarmer.com/component-communication/
Material UI Dialogs: http://www.material-ui.com/#/components/dialog

Continue ReadingCommunicate between Child and Parent Components in React JS of SUSI Web Chat