Enhance the Map Fragment in the Open Event Android app

The usual map fragment in the Open Event Android App didn’t match to the other UI enhancements in the app. Therefore it was needed to enhance it in order for the users to take full advantages of the map based services that the app offered. The enhancements primarily included the following features –

  • Better marker drawables – The usual markers were dull and didn’t match the app theme of the rest of the app.
  • Location searching with autocomplete dropdown – Initially, there was no way the user could search for the location of the sessions happening in the event. Also, it was decided that it was best if the search auto suggested locations for easy navigation.
  • Navigation to the location marker – The google map class comes bundled with in built UI features such as floor recognition, location pointer etc. Navigation to the location is one of those features which appears on a marker click. The user gets directed to the Google Maps android application for navigation from the current location.

Implementation

Add the following dependencies to your app’s Gradle build file. Do update the libraries if a newer version is available.

dependencies {
  compile ‘com.google.maps.android:android-maps-utils:0.4+’
  compile ‘com.google.android.gms:play-services-location:8.1.0’
  compile ‘com.google.android.gms:play-services-maps:8.1.0’
}

Use vector drawables instead of raster icons for the marker

<!– drawable/map_marker.xml –>
<vector xmlns:android=“http://schemas.android.com/apk/res/android”
  android:height=“40dp”
  android:width=“40dp”
  android:viewportWidth=“40”
  android:viewportHeight=“40”>
  <path android:fillColor=“#000” android:pathData=“M12,11.5A2.5,2.5 0 0,1 9.5,9A2.5,2.5 0 0,1 12,6.5A2.5,2.5 0 0,1 14.5,9A2.5,2.5 0 0,1 12,11.5M12,2A7,7 0 0,0 5,9C5,14.25 12,22 12,22C12,22 19,14.25 19,9A7,7 0 0,0 12,2Z” />
</vector>

Customize the marker events including color selections onclick and title display.

private Marker handleMarkerEvents(LatLng location, String locationTitle) {
  if (mMap != null) {
      locationMarker = mMap.addMarker(new MarkerOptions().position(location).title(locationTitle)
              .icon(vectorToBitmap(getContext(), R.drawable.map_marker, R.color.dark_grey)));
      mMap.setOnMarkerClickListener(marker -> {
          locationMarker.setIcon(vectorToBitmap(getContext(), R.drawable.map_marker, R.color.dark_grey));
          locationMarker = marker;
          marker.setIcon(vectorToBitmap(getContext(), R.drawable.map_marker, R.color.color_primary));
          return false;
      });
      mMap.setOnMapClickListener(latLng -> locationMarker.setIcon(
              vectorToBitmap(getContext(), R.drawable.map_marker, R.color.dark_grey)));
  }
  return locationMarker;
}

//Vector currently cannot be directly used with the markers hence it is necessary to convert it into bitmap first

private BitmapDescriptor vectorToBitmap(Context context, @DrawableRes int id, int color) {
  Drawable vectorDrawable = ResourcesCompat.getDrawable(context.getResources(), id, null);
  assert vectorDrawable != null;
  Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
          vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
  Canvas canvas = new Canvas(bitmap);
  vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
  DrawableCompat.setTint(vectorDrawable, ContextCompat.getColor(context, color));
  vectorDrawable.draw(canvas);
  return BitmapDescriptorFactory.fromBitmap(bitmap);
}

Enable the google maps UI enhancements by getting the UI settings and subsequently setting true to google map toolbar

mMap.getUiSettings().setMapToolbarEnabled(true);

Conclusion

The google maps is an important service for the open event android project since events are all about happenings and happenings are best served with accurate locations of their whereabouts.

For more information on the code, please visit the link here.

Continue ReadingEnhance the Map Fragment in the Open Event Android app

Remove redundancy of images while uploading it from the Phimpme photo app

Uploading images is an important feature for the Phimpme Photo App. While uploading images in the Phimpme application, there was a high probability that the user uploaded redundant images since there was no check on the upload. Therefore to tackle this problem, images should be hashed so that no two same images gets uploaded. To generate a hash of the file, the md5 algorithm and the sha1 algorithm is used.

What is MD5 algorithm?

The MD5 hashing algorithm is a one-way cryptographic function that accepts a message of any length as input and returns as output a fixed-length digest value to be used for authenticating the original message. It produces a 128 bit hash value. 

WhatIs.com

What is SHA1 algorithm?

SHA-1 (Secure Hash Algorithm 1) is a cryptographic hash function designed by the United States National Security Agency and is a U.S. Federal Information Processing Standard published by the United States NIST. SHA-1 produces a 160-bit (20-byte) hash value known as a message digest. A SHA-1 hash value is typically rendered as a hexadecimal number, 40 digits long.  

 – Wikipedia

Reason for using MD5 + SHA1 instead of SHA256

  1. The file becomes highly secured while maintaining its integrity.
  2. The algorithm MD5 + SHA1 is faster in hashing than SHA256.

Implementation

Create a separate Utils class named FileUtils.java. The class contains the static function to get the hash of any file in general. The message digest class is being used in both the algorithms.

The hash is the combination of the md5 hash string along with the SHA1 hash string. The message digest takes up algorithm as its argument to specify which hashing function would be used. The fileinputstream takes up the input file for initialization and the message digest is updated with the data bytes of the file. The StringBuffer class is then used to generate the fixed length hexadecimal value from the message digest since the string is going to be mutable in nature. The string value of the generated string buffer object is returned.

public class FileUtils {

//The utility method to get the hash of the file
 public static String getHash(final File file) throws NoSuchAlgorithmException, IOException {

  return md5(file) + "_" + sha1(file);
 }

//The md5 alogorithm
 public static String md5(final File file) throws NoSuchAlgorithmException, IOException {

  MessageDigest md = MessageDigest.getInstance("MD5");
  FileInputStream fis = new FileInputStream(file);
  byte[] dataBytes = new byte[1024];
  int nread = 0;
  while ((nread = fis.read(dataBytes)) != -1) {
   md.update(dataBytes, 0, nread);
  }

  //convert the byte to hex format
  StringBuffer sb = new StringBuffer("");
  for (byte mdbyte: md.digest()) {
   sb.append(Integer.toString((mdbyte & 0xff) + 0x100, 16).substring(1));
  }

  fis.close();
  md.reset();
  return sb.toString();
 }

//The SHA1 algorithm
 public static String sha1(final File file) throws NoSuchAlgorithmException, IOException {

  MessageDigest md = MessageDigest.getInstance("SHA1");
  FileInputStream fis = new FileInputStream(file);
  byte[] dataBytes = new byte[1024];
  int nread = 0;
  while ((nread = fis.read(dataBytes)) != -1) {
   md.update(dataBytes, 0, nread);
  }

  //convert the byte to hex format
  StringBuffer sb = new StringBuffer("");
  for (byte mdbyte: md.digest()) {
   sb.append(Integer.toString((mdbyte & 0xff) + 0x100, 16).substring(1));
  }

  fis.close();
  md.reset();
  return sb.toString();
 }
}

Conclusion

Physical memory is limited. Hence it is of utmost importance that a particular file is identified using a unique identifier in terms of a fixed hash value. Not only will it be beneficial for optimum space utilization, it will also be useful to track it if necessary.

To learn more about the hash alogorithms, visit – https://www.tutorialspoint.com/cryptography/cryptography_hash_functions.htm  

 

Continue ReadingRemove redundancy of images while uploading it from the Phimpme photo app

Managing Edge Glow Color in Nested ScrollView in Open Event Android App

After the introduction of material design by Google many new UI elements have been introduced. Material design is based on the interaction and movement of colours and objects in real world rather than synthetic unnatural phenomenon. Sometimes it gets messy when we try to keep up with our material aesthetic. The most popular example of it is edge glow colour. The edge glow colour of ListView, RecyclerView, ScrollView and NestedScrollView is managed by the accent colour declared in the styles. We cannot change the accent colour of a particular activity as it is a constant, so it is same across entire app but in popular apps like Contacts by Google it appears different for every individual contacts. Fixing an issue in Open Event Android app, I came across the same problem. In this tutorial I solve this problem particularly for NestedScrollView. See the bottom of screenshots for comparison.

   
  • You need to pre check if the Android version is above or equal to LOLLIPOP before doing this as the setColor() function for edge glow is introduced in LOLLIPOP
  • The fields are declared as “mEdgeGlowTop” and “mEdgeGlowBottom” that we have to modify.
  • We get the glow property of NestedScrollView through EdgeEffectCompat class instead of EdgeEffect class directly, unlike for ListView due its new introduction.

Let’s have a look at the function which accepts arguments color as an integer and nested scroll view of which the color has to be set.

First you have to get the fields “mEdgeGlowTop” and “mEdgeGlowBottom” that signifies the bubbles that are generated when you scroll up and down from Nested Scroll View Class. Similarly “mEdgeGlowLeft”  and “mEdgeGlowRight” for the horizontal scrolling.

public static void changeGlowColor(int color, NestedScrollView scrollView) {
   try {

       Field edgeGlowTop = NestedScrollView.class.getDeclaredField("mEdgeGlowTop");

       edgeGlowTop.setAccessible(true);

       Field edgeGlowBottom = NestedScrollView.class.getDeclaredField("mEdgeGlowBottom");

       edgeGlowBottom.setAccessible(true);

Get the reference to edge effect which is the different part unlike recycler view or list view of setting the edge glow color in nested scrollview.

EdgeEffectCompat edgeEffect = (EdgeEffectCompat) edgeGlowTop.get(scrollView);

       if (edgeEffect == null) {
           edgeEffect = new EdgeEffectCompat(scrollView.getContext());
           edgeGlowTop.set(scrollView, edgeEffect);
       }

       Views.setEdgeGlowColor(edgeEffect, color);

       edgeEffect = (EdgeEffectCompat) edgeGlowBottom.get(scrollView);
       if (edgeEffect == null) {
           edgeEffect = new EdgeEffectCompat(scrollView.getContext());
           edgeGlowBottom.set(scrollView, edgeEffect);
       }

       Views.setEdgeGlowColor(edgeEffect, color);

   } catch (Exception ex) {

       ex.printStackTrace();
   }

}

Finally set the edge glow color. This only works for the versions that are above or equal to LOLLIPOP as edge effect was introduced in the android beginning from those versions.

@TargetApi(Build.VERSION_CODES.LOLLIPOP)

public static void setEdgeGlowColor(@NonNull EdgeEffectCompat edgeEffect, @ColorInt int color) throws Exception {
        Field field = EdgeEffectCompat.class.getDeclaredField("mEdgeEffect");

        field.setAccessible(true);
        EdgeEffect effect = (EdgeEffect) field.get(edgeEffect);
        
        if (effect != null)
            effect.setColor(color);
    }

 

(Don’t forget to catch any exception. You can monitor them by using Log.e(“Error”, ”Message”, e ); for debugging and testing).

Resources

  • https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html
Continue ReadingManaging Edge Glow Color in Nested ScrollView in Open Event Android App

Use of SwipeRefreshLayout in Phimpme

In an image application, the first thing we want is to get a list of all images from the users device at the start of the application in the splash screen. But what if the number of images in the device is altered by deleting or copying any other images to the device when the application is running. This is where the swipe refresh layout helps us to obtain the real-time list of images from our device by just swiping vertically downwards.

In the Phimpme application, we have made use of the swipe refresh layout to update the image according to the latest data. In this post, I will be discussing how we achieved this in the Phimpme application with the help of some code examples.

Steps to implement the SwipeRefreshLayout:

  1. The first thing we need to do is add the support library to our project build.gradle file.
dependencies {
 compile 'com.android.support:recyclerview-v7:25.3.1'
 compile 'com.android.support:support-v4:25.3.1'
}

2. Now add the SwipeRefreshLayout in Activity.xml file where you want to implement the SwipeRefreshLayout with the recyclerView and the child view should match the parent layout. This can be done using the line of code below:

<android.support.v4.widget.SwipeRefreshLayout
   android:id="@+id/swipeRefreshLayout"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingBottom="@dimen/height_bottombar" > <android.support.v7.widget.RecyclerView
   android:id="@+id/grid_albums"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_gravity="center_horizontal"
   android:scrollbarThumbVertical="@drawable/ic_scrollbar"
   android:scrollbars="vertical" />
</android.support.v4.widget.SwipeRefreshLayout>

3. Now we have to implement the onRefreshListener which handles the refresh operation when a vertical swipe is performed.

Activity.java

SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.sr);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
   @Override
   public void onRefresh() {
   }

});

 

Now we can do anything in onRefresh method which we want to do when user swipes vertically.

For example, we want to refresh the recyclerView with latest images and display the content so this should be done in a background thread.

So we will use AsyncTask to update the data.

  @Override
 public void onRefresh() {
new AsyncTask().execute(); //  This will execute the AsyncTask
   }
});

AsyncTask.java

private class AsyncTask extends AsyncTask<Void, Integer, Void> {


   @Override

   protected void onPreExecute() {

       swipeRefreshLayout.setRefreshing(true);

       super.onPreExecute();

   }


   @Override

   protected Void doInBackground(Void... arg0) {

       // refresh the content of recyclerView here

       return null;

   }


   @Override

   protected void onPostExecute(Void result) {

    swipeRefreshLayout.setRefreshing(false);

   }

}

 

When the user swipes up vertically the progress bar is shown to screen and which can be done by swipeRefreshLayout.setRefreshing(true) in onPreExecute() method.

In doInBackground() method we have to load the content of RecyclerView through an adapter.

Once the data is loaded and set to recyclerView onPostExecute() method is called and now we have to dismiss the loading progress bar by  

  swipeRefreshLayout.setRefreshing(false);

This is how SwipeRefreshLayout works.

The above code helps us to reload the album content in the gallery.

For more details refer here in the Phimpme project for SwipeRefreshLayout.

https://github.com/fossasia/phimpme-android/blob/development/app/src/main/java/vn/mbm/phimp/me/leafpic/activities/LFMainActivity.java

Resources :

https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html

https://developer.android.com/training/swipe/add-swipe-interface.html

Continue ReadingUse of SwipeRefreshLayout in Phimpme

Efficient use of event card component on Open Event Frontend

Ember JS is a powerful framework when it comes to code reusability. Components are at it’s core and enable the developers to reuse the same code at different places. The event-card component on Open event-front-end is one such component. It is used on various routes across the app thereby illustrating the usefulness. However, in this article we are going to see how components can be made even more efficient by rendering them differently for different situations.Originally the component was used to display events in the card format on the public page.

And this was the code :

<.div class="ui fluid event card">
 <.a class="image" href="{{href-to 'public' event.identifier}}">
   {{widgets/safe-image src=(if event.large event.large event.placeholderUrl)}}
 <./a>
 <.div class="content">
   <.a class="header" href="{{href-to 'public' event.identifier}}">
     <.span>{{event.name}}<./span>
   <./a>
   <.div class="meta">
     <.span class="date">
       {{moment-format event.startTime 'ddd, MMM DD HH:mm A'}}
     <./span>
   <./div>
   <.div class="description">
     {{event.shortLocationName}}
   <./div>
 <./div>
 <.div class="extra content small text">
   <.span class="right floated">
     <.i role="button" class="share alternate link icon" {{action shareEvent event}}><./i>
   <./span>
   <.span>
     {{#each tags as |tag|}}
       <.a>{{tag}}<./a>
     {{/each}}
   <./span>
 <./div>
<./div>

Next we modify it in such a way that it is suitable to be displayed on the explore route as well, and that requires it to be such that is instead of being box-like it should be possible to render it such that it is wide and takes the width of the container it is in. So How do we determine which version should be rendered when. In ember it is really easy to pass on parameters to components while calling them, and they can make use of these paraemeters as they are being rendered. It is best if the name of the parameters is chosen logically, here we want to make it wide for selected routes so we name it : isWide

And the code after modification, would be something like this with isWide taken into account. We will just wrap it an extra div which will conditionally add an extra class ‘wide’ if isWide is true.

<.div class="{{if isWide 'event wide ui grid row'}}">
<.!-- Previous code -->
<./div>

//And the corresponding styling for wide class


.event.wide {
  border-radius: 0 !important;
  margin: 0 !important;

  .column {
    margin: 0;
    padding: 0 !important;
  }

  img {
    height: 170px !important;
    object-fit: cover;
  }

.main.content {

  height: 130px;

  display: block;

}

}

Next What we are going to do is, modify the component to become yieldable. So that they can also be used to display the tickets of a user! `{{yield}}` allows code outside the component to be rendered inside it.

Let’s make a change so that, if the event card component is rendered on the my tickets page, then instead of hashtags it should display the ticket details. Which we will conveniently provide to the component externally (via {{yield}} ) Next we need to determine which version of the component should be rendered when? The hasBlock helper enables us to do just that. So the final code should look something just like this 😉 The hasBlock helper allows us to differentiate between the yieldable and non yieldable forms of the component.

<.div class="{{if isWide 'event wide ui grid row'}}"
 {{#if isWide}}
   {{#unless device.isMobile}}
     <.div class="ui card three wide computer six wide tablet column">
       <.a class="image" href="{{href-to 'public' event.identifier}}">
         {{widgets/safe-image src=(if event.large event.large event.placeholderUrl)}}
       <./a>
     <./div>
   {{/unless}}
 {{/if}}
 <.div class="ui card {{unless isWide 'event fluid' 'thirteen wide computer ten wide tablet sixteen wide mobile column'}}">
   {{#unless isWide}}
     <.a class="image" href="{{href-to 'public' event.identifier}}">
       {{widgets/safe-image src=(if event.large event.large event.placeholderUrl)}}
     <./a>
   {{/unless}}
   <.div class="main content">
     <.a class="header" href="{{href-to 'public' event.identifier}}">
       <.span>{{event.name}}<./span>
     <./a>
     <.div class="meta">
       <.span class="date">
         {{moment-format event.startTime 'ddd, MMM DD HH:mm A'}}
       <./span>
     <./div>
     <.div class="description">
       {{event.shortLocationName}}
     <./div>
   <./div>
   <.div class="extra content small text">
     <.span class="right floated">
       <.i role="button" class="share alternate link icon" {{action shareEvent event}}><./i>
     <./span>
     <.span>
       {{#if hasBlock}}
         {{yield}}
       {{else}}
         {{#each tags as |tag|}}
           <.a>{{tag}}<./a>
         {{/each}}
       {{/if}}
     <./span>
   <./div>
 <./div>
<./div> 

And now the component can be used for displaying the tickets, with the area displaying hashtags now being replaced by the order details.

 

 

Continue ReadingEfficient use of event card component on Open Event Frontend

Test SUSI Web App with Facebook Jest

Jest is used by Facebook to test all Javascript codes specially React code snippets. If you need to setup jest on your react application you can follow up these simple steps. But if your React application is made with “create-react-app”, you do not need to setup jest manually. Because it comes with Jest. You can run test using “react-scripts” node module.

Since SUSI chat is made with “create-react-app” we do not need to install and run Jest directly. We executed our test cases using “npm test” it executes “react-scripts test” command. It executes all “.js” files under “__tests__” folders. And all other files with “.spec.js” and “.test.js” suffixes.

React apps that are made from “create-react-app” come with sample test case (smoke test) and that checks whether whole application is built correctly or not. If it passes the smoke test then it starts to run further test cases.

import React from 'react';
import ReactDOM from 'react-dom';
import ChatApp from '../../components/ChatApp.react';
it('renders without crashing', () => {
 const div = document.createElement('div');
 ReactDOM.render( < ChatApp / > , div);
});

This checks all components which are inside of the “<ChatApp />” component and it check whether all these components integrate correctly or not.

If we need to check only one component in isolated environment. We can use shallow rendering API. we have used shallow rendering API to check each and every component in isolated environment.

We have to install enzyme and test renderer before use it.

npm install --save-dev enzyme react-test-renderer

import React from 'react';
import MessageSection from '../../components/MessageSection.react';
import { shallow } from 'enzyme';
it('render MessageListItem without crashing',()=>{
  shallow(<MessageSection />);
})

This test case tests only the “MessageListItem”, not its child components.

After executing “npm test” you will get the passed and failed number of test cases.

If you need to see the coverage you can see it without installing additional dependencies.

You just need to run this.

npm test -- --coverage

It will show the output like this.

This view shows how many lines, functions, statements, branches your program has and this shows how much of those covered from the test cases you have.

If we are going to write new test cases for susi chat, we have to make separate file in “__tests__” folder and name it with corresponding file name that we are going to test.

it('your test case description',()=>{
 //test what you need 
})

Normally test cases looks like this.in test cases you can use “test” instead of “it” .after test case description, there is a fat arrow function. In side this fat arrow function you can add what you need to test

In below example I have compared returned value of the function with static value.

function funcName(){
 return 1;
}

it('your test case description',()=>{
 expect(funcName()).toBe(1);
})

You have to add your function/variable that need to be tested into “expect()” and value you expect from that function or variable into “toBe()”.  Instead of “toBe()” you can use different functions according to your need.

If you have a long list of test cases you can group them ( using describe()).

describe('my beverage', () => {
  test('is delicious', () => {
    expect(myBeverage.delicious).toBeTruthy();
  });

  test('is not sour', () => {
    expect(myBeverage.sour).toBeFalsy();
  });
});

This post covers only few things of testing . You can learn more about jest testing from official documentation here.

Continue ReadingTest SUSI Web App with Facebook Jest

Step by step guide for Beginners in Web Development for Open Event Frontend

Originally the frontend and backend of the Open Event Server project were handled by FLASK with jinja2 being used for rendering templates. As the size of the project grew, it became difficult to keep track of all the modifications made on the frontend side. It also increased the complexity of the code. As a result of this, a new project Open Event Frontend was developed by decoupling the backend and frontend of the Open Event Orga Server. Now the server is being converted fully into functional API and database and the open event frontend project is primarily the frontend for the Open event server API where organisers, speakers and attendees can sign-up and perform various functions.     

The Open Event Frontend project is built on JavaScript web application framework, “Ember.js”. To communicate with the server API Ember.js user Ember data which is a data persistence module via the exposed endpoints. Suppose if you’re coming from the Android background, soon after diving into the web development you can relate that the web ecosystem is much larger than the mobile one and for the first timers it can be difficult to adopt with it because of the reason that in web there are multiple ways to perform a task which can be restricted to very few in the case of Android. For web applications, one can find that much more components are involved in setting up the project while in android one can easily start contributing to project soon after compiling it in Android Studio. One thing which is relatable for both the android and web development is that in the case of android one has to deal with the varying screen sizes and compatibility issue while in the web one has to deal with adding support for different browsers and versions which can be really annoying.

Now let’s see how one can start contributing to the Open event frontend project while having no or a little knowledge of web development. In case if you’ve previous knowledge of JavaScript then you can skip the step 1 and move directly to another step which is learning the framework.

(Here all the steps have been explained in reference if you’re switching from Android  to Web development.)

Step 1. Learning the Language – JavaScript

Now that when you’ve already put your feet into the web development it’s high time to get acquainted with the JavaScript. Essentially in the case of Ember which is easy to comprehend, you can though start with learning the framework itself but the executables file are written in JavaScript so to write them you must have basic knowledge of the concepts in the language. Understanding of JavaScript will help in letting know where the language ends and where the framework starts. It will also help in better understanding of the framework. In my opinion, the basic knowledge of JavaScript like the scope of variables, functions, looping, conditional statements, modifying array and dictionaries, ‘this’ keyword etc. helps in writing and understanding the .js files easily. Also, sometimes in JavaScript, an error might not be thrown as an exception while compiling but it may evaluate the program to undefined, knowledge of the language will help in debugging the code.

Step 2. Learning the Framework – Ember

Ember is a JavaScript Framework which works on Model-View-Controller(MVC) approach. The Ember is a battery included framework which generates all the boilerplate code including components, routes. Templates etc.  required for building an application’s frontend. It is very easy to understand and comprehend. In Ember, we can easily define the data models and relationships and ember will automatically guess the correct API endpoints. Apart from this, the documentation of the ember on its website is very much sufficient to start with. One can easily start developing applications after going through the tutorial mentioned on the ember’s website.  

Step 3. Testing

In the case of Android application development to write test we use android libraries like Mockito and Robolectric. Also, testing is a bit more difficult in Android app development because we have to explicitly write the test but it is a lot easier in the case of web development. In the case of Ember, it provides an ease of testing which no other framework and libraries provide. While generating a component or template ember itself generates the test files for them and all we have to do is to change them according to our requirement. Ember generates unit, acceptance and integration tests by making testing easier. So we don’t have to write the test explicitly we only have to modify the test files generated by ember.    

Step 4. Styling

In Android we have colors.xml, styles.xml, drawables, gradients, shapes etc. for styling our application but in the case of Web, we have Cascading Style Sheets (CSS) for styling our application. Simply using pure CSS make design complicated and difficult to understand, so to make it easier we combine a bunch of design elements with a style file and use Syntactically Awesome Style Sheets (Saas) with mixins to do that which makes creating styles a lot easier and more straightforward. So for styling, our web application one should have the knowledge of HTML as well as CSS.

In conclusion, I can say that learning web development requires learning a few things in parallel which includes learning a language, learning a framework, how to perform testing and different styling skills to make an application beautiful. Due to dynamic nature of the JavaScript and the sheer number of packages and components involved, as opposed to the safe environment that Android Studio provides, it can be sometimes really frustrating.  However, once learned the basics, the knowledge and skills can be easily transferred and applied over and over again.    

Continue ReadingStep by step guide for Beginners in Web Development for Open Event Frontend

Using Root Directory as the Documentation Directory with Yaydoc

In our test builds for Yaydoc, we found that If we set the root as the documentation directory, the build would fail with a very long build log. In the build process, we create some temporary directories such as a virtual environment and the build directory in the root. After some inspection of the build logs, we found out that when the root is itself used as the documentation directory, we were accidently recursively copying the build directory into itself which led to build failure. Together with this, since the virtual environment directory was also being accidently copied to the build directory, we were actually building the documentation of the entire Python standard library on each build.

Once the problem and It’s cause was known, the course of action to be taken was clear. We needed to ensure that any temporary directories which we create as part of the build process was not being copied to the build directory. The following changes were made to achieve that.

  • The virtual environment directory was now being created in the HOME directory instead of the root.
  • Any other temporary directories which except the main build directory was now deleted before copying.
  • To prevent the recursive copying, we used the –exclude parameter of rsync.
rsync --exclude=BUILD_DIR DOCS_DIR/ BUILD_DIR/

After this patch, root can also be used as the documentation directory with Yaydoc. To do so, just set the environment variable DOCPATH as “.”

Continue ReadingUsing Root Directory as the Documentation Directory with Yaydoc

Adding dynamic segments to a route in Open Event Frontend Project

When we talk about a web application the first thing comes up is how to decide what to display at a given time which in most of the application is decided with the help of the URL. The URL of the application can be set either by loading the application or by writing the URL manually or may be by clicking some link. In our Open Event Frontend project which is written in Ember.js, an incredibly powerful JavaScript framework for creating web applications, the URL is mapped to the router handlers with the helper of router to render the template for the page, to load the data model to display, to navigate within the application or to handle any actions within the page like button clicking etc.

Suppose the user opens the open event application for the very first time what s/he will see a page containing the list of all the events which are going to happen in the near future along with their details like event name, timings, place, tags etc. If the user clicks one of the events from the list, the current page will be redirected to the detailed specific page for that particular event. The behaviour of changing the content of the page which we observed during this process can be explained with the help of the dynamic segments concept. The dynamic segment is a section of the path for a route which changes based on the content of a page.
This post will focus on how we have added dynamic segments to the route in the open event frontend project.

Let’s demonstrate the process of adding the dynamic segments to the route by taking an example of sessions routes where we can see the list of all the accepted, pending, confirmed and rejected sessions along with their details.

To add a dynamic segment, we need to have a route with path which we add to the route definition in app/router.js file

this.route('sessions',  function() {
   this.route('list', { path: '/:sessions_state' });
});

Dynamic segments are made up of a : followed by an identifier. Ember follows the convention of :model-name_id for two reasons. The first reason is that routes know how to fetch the right model by default if we follow the convention. The second is that params is an object, and can only have one value associated with a key.

After defining the path in app/router.js file we need to add template file,  app/templates/events/sessions/list.hbs which contain the markup to display the data which is defined in the file, app/routes/events/sessions/list.js under the model hook of the route in order to display the correct content for the specified option.

Code containing the markup for the page in app/templates/events/sessions/list.hbs file

<div class="sixteen wide column">
  <table class="ui tablet stackable very basic table">
    <thead>
      <tr>
        <th>{{t 'State'}}</th>
        <th>{{t 'Title'}}</th>
        <th>{{t 'Speakers'}}</th>
        <th>{{t 'Track'}}</th>
        <th>{{t 'Short Abstract'}}</th>
        <th>{{t 'Submission Date'}}</th>
        <th>{{t 'Last Modified'}}</th>
        <th>{{t 'Email Sent'}}</th>
        <th></th>
        <th></th>
      </tr>
    </thead>
    <tbody>
      {{#each model as |session|}}
        <tr>
          <td>
            {{#if (eq session.state "confirmed")}}
              <div class="ui green label">{{t 'Confirmed'}}</div>
            {{else}}
              <div class="ui red label">{{t 'Not Confirmed'}}</div>
            {{/if}}
          </td>
          <td>
            {{session.title}}
          </td>
          <td>
            <div class="ui ordered list">
              {{#each session.speakers as |speaker|}}
                <div class="item">{{speaker.name}}</div>
              {{/each}}
            </div>
          </td>
          <td>
            {{session.track}}
          </td>
          <td>
            {{session.shortAbstract}}
          </td>
          <td>
            {{moment-format session.submittedAt 'dddd, DD MMMM YYYY'}}
          </td>
          <td>
            {{moment-format session.modifiedAt 'dddd, DD MMMM YYYY'}}
          </td>
          <td>
            {{session.emailSent}}
          </td>
          <td>
            <div class="ui vertical compact basic buttons">
              {{#ui-popup content=(t 'View') class='ui icon button' position='left center'}}
                <i class="unhide icon"></i>
              {{/ui-popup}}
              {{#ui-popup content=(t 'Edit') class='ui icon button' position='left center'}}
                <i class="edit icon"></i>
              {{/ui-popup}}
              {{#ui-popup content=(t 'Delete') class='ui icon button' position='left center'}}
                <i class="trash outline icon"></i>
              {{/ui-popup}}
              {{#ui-popup content=(t 'Browse edit history') class='ui icon button' position='left center'}}
                <i class="history icon"></i>
              {{/ui-popup}}
            </div>
          </td>
          <td>
            <div class="ui vertical compact basic buttons">
              {{#ui-dropdown class='ui icon bottom right pointing dropdown button'}}
                <i class="green checkmark icon"></i>
                <div class="menu">
                  <div class="item">{{t 'With email'}}</div>
                  <div class="item">{{t 'Without email'}}</div>
                </div>
              {{/ui-dropdown}}
              {{#ui-dropdown class='ui icon bottom right pointing dropdown button'}}
                <i class="red remove icon"></i>
                <div class="menu">
                  <div class="item">{{t 'With email'}}</div>
                  <div class="item">{{t 'Without email'}}</div>
                </div>
              {{/ui-dropdown}}
            </div>
          </td>
        </tr>
      {{/each}}
    </tbody>
  </table>
</div>

 

Code containing the model hook in app/routes/events/sessions/list.js to display the correct content. We access the dynamic portion of the URL using params.

import Ember from 'ember';

const { Route } = Ember;

export default Route.extend({
  titleToken() {
    switch (this.get('params.session_status')) {
      case 'pending':
        return this.l10n.t('Pending');
      case 'accepted':
        return this.l10n.t('Accepted');
      case 'confirmed':
        return this.l10n.t('Confirmed');
      case 'rejected':
        return this.l10n.t('Rejected');
    }
  },
  model(params) {
    this.set('params', params);
    return [{
      title         : 'Test Session 1',
      speakers      : [{ name: 'speaker 1', id: 1, organization: 'fossasia' }, { name: 'speaker 2', id: 1, organization: 'fossasia' }],
      track         : 'sample track',
      shortAbstract : 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
      submittedAt   : new Date(),
      modifiedAt    : new Date(),
      emailSent     : 'No',
      state         : 'confirmed'
    },
    {
      title         : 'Test Session 2',
      speakers      : [{ name: 'speaker 3', id: 1, organization: 'fossasia' }, { name: 'speaker 4', id: 1, organization: 'fossasia' }],
      track         : 'sample track',
      shortAbstract : 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
      submittedAt   : new Date(),
      modifiedAt    : new Date(),
      emailSent     : 'Yes',
      state         : 'confirmed'
    }];
  }
});

 

After the route is fully configured, we need to start linking it from the templates which mean we need to link it in our parent template, app/templates/events/view/sessions.hbs file using the {{link-to}} helper. The code for the linking looks like this:

    {{#tabbed-navigation isNonPointing=true}}
        {{#link-to 'events.view.sessions.index' class='item'}}
          {{t 'All'}}
        {{/link-to}}
        {{#link-to 'events.view.sessions.list' 'pending' class='item'}}
          {{t 'Pending'}}
        {{/link-to}}
        {{#link-to 'events.view.sessions.list' 'accepted' class='item'}}
          {{t 'Accepted'}}
        {{/link-to}}
        {{#link-to 'events.view.sessions.list' 'confirmed' class='item'}}
          {{t 'Confirmed'}}
        {{/link-to}}
        {{#link-to 'events.view.sessions.list' 'rejected' class='item'}}
          {{t 'Rejected'}}
        {{/link-to}}
      {{/tabbed-navigation}} 

 

The User Interface for the above code looks like this:

Fig. : The page containing all the accepted session

To conclude this, we can say the task of the route is to load the modal to display the data. For example, if we have the route this.route(‘sessions’);, the route might load all of the sessions for the app but we want only the particular type of session so the dynamic segments help to load the particular model and make it easier to load and display the data.

Reference: The link to the complete code is here. For getting more knowledge about dynamic segments please visit this.

Continue ReadingAdding dynamic segments to a route in Open Event Frontend Project

Adding a new Servlet/API to SUSI Server for Skill Wiki

Susi skill wiki is an editor to write and edit skill easily. It follows an API-centric approach where the Susi server acts as API server and a web front-end  act as the client for the API and provides the user interface. A skill is a set of intents. One text file represents one skill, it may contain several intents which all belong together.

The schema for storing a skill is as following:

Using this, one can access any skill based on four tuples parameters model, group, language, skill.  To achieve this on server side let’s create an API endpoint to list all skills based on given model, groups and languages. To check the source for this endpoint clone the susi_server repository from here.

git clone https://github.com/fossasia/susi_server.git

Have a look at documentation for more information about Susi Server.

The Servlet java file is placed in susi_server/ai/susi/server/api/cms/ListSkillService. To implement the endpoint we will use the HttpServlet class which provides methods, such as doGet and doPost, for handling HTTP-specific services.

In Susi Server an abstract class AbstractAPIHandler extending HttpServelets and implementing API handler interface is provided.  Next we will inherit our ListSkillService class from AbstractAPIHandler and implement APIhandler interface.

To implement our servlet we will be overriding 4 methods namely

  • Minimal Base User role 

public BaseUserRole getMinimalBaseUserRole() {
return BaseUserRole.ANONYMOUS;
}

This method tells the minimum Userrole required to access this servlet it can also be ADMIN, USER. In our case it is Anonymous. A User need not to log in to access this endpoint.

  • Default Permissions  

public JSONObject getDefaultPermissions(BaseUserRole baseUserRole) {
return null;
}

This method returns the default permission attached with base user role, our servlets has nothing to do with it, therefore we can simply return null for this case.

  • The API Path 

public String getAPIPath() {
return "/cms/getSkillList.json";
}

This methods sets the API endpoint path, it gets appended to base path which is 127.0.0.1:4000/cms/getSkillList.json for the local host and http://api.susi.ai/cms/getSkillList.json for the server.

  • The ServiceImpl method 

public ServiceResponse serviceImpl(Query call, HttpServletResponse response, Authorization rights, final JsonObjectWithDefault permissions) {

        String model_name = call.get("model", "general");
        File model = new File(DAO.model_watch_dir, model_name);
        String group_name = call.get("group", "knowledge");
        File group = new File(model, group_name);
        String language_name = call.get("language", "en");
        File language = new File(group, language_name);

        ArrayList fileList = new ArrayList();
        fileList =  listFilesForFolder(language, fileList);
        JSONArray jsArray = new JSONArray(fileList);

        JSONObject json = new JSONObject(true)
                .put("model", model_name)
                .put("group", group_name)
                .put("language", language_name)
                .put("skills", jsArray);
        return new ServiceResponse(json);

    }

    ArrayList listFilesForFolder(final File folder,  ArrayList fileList) {

        File[] filesInFolder = folder.listFiles();
        if (filesInFolder != null) {
            for (final File fileEntry : filesInFolder) {
                if (!fileEntry.isDirectory()) {
                    fileList.add(fileEntry.getName()+"");
                }
            }
        }
        return  fileList;
    }

To access any skill we need parameters model, group, language. We get this through call.get method where first parameter is the key for which we want to get the value and second parameter is the default value. Based on received model, group and language browse files in that folder and put them in Json array to return the Service Json response.
That’s all you have successfully implemented the API endpoint to list all the skills in given model group and language. Move on and test it.

And see the resultsTo access any skill we need  parameters model, group, language. We get this through call.get method where first parameter is the key for which we want to get the value and second parameter is the default value. Based on received model, group and language browse files in that folder and put them in Json array to return the Service Json response.

 You have  successfully implemented the API endpoint to list all the skills in given model group and language. Move on and test it.

It’s easy isn’t it you have learnt how to add an endpoint in the server, it’s time to go ahead and create more endpoints to enhance Susi Server, take a look and contribute to Susi Server.

Continue ReadingAdding a new Servlet/API to SUSI Server for Skill Wiki