Zooming Feature in the Phimpme Android’s Camera

The Phimpme Android application comes with a complete package of camera, Edit images, sharing and gallery functionalities. It has a well featured and fully functional camera with all the capabilities that a user expects from a camera application. One such feature in the Phimpme Android application is the zooming functionality. It provides the user the option to zoom in using the pinch gesture of the fingers or the user can select the settings to zoom in from the volume buttons. In this tutorial, I will be explaining how I achieved the zooming functionality in the Phimpme Android app.

Step 1

The first thing we need to do is to check whether the device will support the zoom in functionality or not to avoid random crashes while runtime of the application and while performing the zoom action in case the camera of the device doesn’t support this feature. This can be done by the following lines of code:

Camera.Parameters params = mCamera.getParameters();
Boolean supports = params.isZoomSupported();

Step 2

Now after getting the camera parameters and checking whether the camera supports the zoom in functionality, we need to add the touch listener to the surface view of the camera so that we can get the touch locations and the finger spacing of the user to get the pinch to zoom in functionality. This can be done using the following line of code.

surfaceView.setOnTouchListener(this);

Whenever the user touches the screen this touch listener gives a callback to the overridden onTouchEvent method and passes the MotionEvent to the function. The motion event object in Android handles the movement reports. Now in the onTouchEvent method, we calculate the finger spacing between the two fingers and calculate the approximate amount by which the user wants to zoom in. The finger spacing can be calculated using the following lines of code.

float x = event.getX(0) - event.getX(1);
   float y = event.getY(0) - event.getY(1);
   return FloatMath.sqrt(x * x + y * y);

After getting the finger spacing we need to cancel the auto focus of the camera before performing the zoom action so that the application does not crash. This can be achieved by a single line of code below.

mCamera.cancelAutoFocus();

Step 3

The final step is to set the zoom level in the camera application by calculating the zoom level by using the finger spacing. For this, first we need to get the max zoom level supported by the device so that we do not apply the zoom level that is not supported by the device. The calculation of max zoom level and setting of the desired zoom level by the user can be performed by using the following lines of code.

int maxZoom = params.getMaxZoom();
   int zoom = params.getZoom();
   float newDist = getFingerSpacing(event);
   if (newDist > mDist) {
       //zoom in
       if (zoom < maxZoom)
           zoom++;
   } else if (newDist < mDist) {
       //zoom out
       if (zoom > 0)
           zoom--;
   }
   mDist = newDist;
   params.setZoom(zoom);

This is how we have achieved the functionality of zooming in and clicking pictures in the Phimpme Android application. To get the full source code and to know how to use the volume control buttons to zoom in/out, please refer to the Phimpme Android repository.

Resources

  1. GitHub – Open camera source code : https://github.com/almalence/OpenCamera
  2. Android developer’s guide – MotionEvents in Android : https://developer.android.com/reference/android/view/MotionEvent.html
  3. StackOverflow – Pinch to zoom functionality : https://stackoverflow.com/questions/8120753/android-camera-preview-zoom-using-double-finger-touch
  4. GitHub – Phimpme Android repository : https://github.com/fossasia/phimpme-android
Continue ReadingZooming Feature in the Phimpme Android’s Camera

Creating SharedPreferences Util in Open Event Android

In the Open Event Android we have the fragment for schedule, speakers which has the option to sort the list. Schedule Fragment have the option to sort by Title, Tracks and  Start Time. Speakers Fragment has the option to sort by Name, Organization and Country. If the user preferred to sort by name then it should always sort the list by name whenever the user uses the app. For this we need to store user preference for sorting list. Another part of the app like Live feed, About fragment also needs to store event id, facebook page id/name etc.

In Android there is a SharedPreferences class to store key value pair in the App specific storage. To store data in SharedPreferences we need to create SharedPreferences Object in different activities and fragment. In this post I explain how to create SharedPreferences Util which can be used to store key value pairs from all over the App.

1. Create SharedPreferencesUtil Class

The first step is to create SharedPreferncesUtil.java file which will contain static SharedPreferences object.

public class SharedPreferencesUtil {
    ...
}

2. Create static objects

Create static SharedPreferences and SharedPreferences.Editor object in the SharedPreferncesUtil.java file.

private static SharedPreferences sharedPreferences;
private static SharedPreferences.Editor editor;

3. Initialize objects

Now after creating objects initialize them in the static block. The code inside static block is executed only once: The first time you make an object of that class or the first time you access a static member of that class.

static {
        sharedPreferences = OpenEventApp.getAppContext().getSharedPreferences(ConstantStrings.FOSS_PREFS, Context.MODE_PRIVATE);
        editor = sharedPreferences.edit();
}

 

Here make sure to use the Application context to avoid a memory leak. The getSharedPreferences() method takes two arguments name of the shared preference and mode. Here we are using Context.MODE_PRIVATE File creation mode where the created file can only be accessed by the calling application.

4. Add methods

Now create static methods to store data so that we can use these methods directly from the other activities or classes. Here I am only adding methods for integer you can add more methods for String, long, boolean etc.

public static void putInt(String key, int value) {
        editor.putInt(key, value).apply();
}

public static int getInt(String key, int defaultValue) {
        return sharedPreferences.getInt(key, defaultValue);
}

5. Use SharedPreferencesUtil class

Now we are ready to use this Util class to store key value pair in SharedPreferences.

SharedPreferencesUtil.putInt(ConstantStrings.PREF_SORT, sortType);

Here the putInt() methods take two arguments one the key and second the value. To get the stored value use getInt() method.

SharedPreferencesUtil.getInt(ConstantStrings.PREF_SORT, 0);

To know more how I solved this issue in Open Event Project visit this link.

Continue ReadingCreating SharedPreferences Util in Open Event Android

Adding JSON API support to ember-models-table in Open Event Front-end

Open Event Front-end project uses ember-models-table for handling all the table components in the application. Although ember-models-table is great for handling server requests for operations like pagination, sorting & filtering, but it does not support JSON API used in the Front-end project.

In this blog we will see how we integrated JSON API standards to ember-models-table. Lets see how we added support for JSON API to table and made requests to the Open Event Orga-server.

Adding JSON API support for filtering & sorting

The JSON API specs follow a strict structure for supporting meta data & filtering options, the server expects an array of objects for specifying the name of the field, operation and the value for filtering. The name attribute specifies the column for which we need to apply the filter. eg we use `name` for the events name in the. `op` attribute specifies the operation to be used for filtration, `val` attribute is used to provide a value for comparison. You can check the list of all the supported operations here.

For implementation of filter we will check if the column filter is being used i.e if the filter string is empty or not, if the string is not empty we add a filter object of the column using the specified specs, else we remove the filter object of the column.

if (filter) {
  query.filter.pushObject({
    name : filterTitle,
    op   : 'ilike',
    val  : `%${filter}%`
  });
} else {
  query.filter.removeObject({
    name : filterTitle,
    op   : 'ilike',
    val  : `%${filter}%`
  });
}

For sort functionally we need to pass a query parameter called `sort` which is a string value in the URL. Sorting can be done in ascending or descending order for which the server expects different values. We pass `sort=name` & `sort=-name` for sorting in ascending order & descending order respectively.

const sortSign = {
  none : '',
  asc  : '-',
  desc : ''
};
let sortedBy = get(column, 'sortedBy');
if (typeOf(sortedBy) === 'undefined') {
  sortedBy = get(column, 'propertyName');
}

Adding support for pagination

The pagination in JSON API is implemented using query parameters `page[size]` & `page[number]` which specify the size of the page & the current page number respectively eg

page[size]=10&page[number]=1

This will load the first ten events from the server in the application.

Once the data is loaded in the application we calculate the number of pages to be rendered. The response from the server has attached meta-data which contains the total number of the events in the following structure:

meta: {
  count: 100
}

We calculate the number of pages by dividing the total count by the size of the page. We check if the number of items is greater than the pageSize, and calculate the number of the pages using the formula `items / pagesize + (items % pagesize ? 1 : 0)`. If the items are less than the pageSize we do not have to calculate the pages and we simply hide the pagination in the footer.

if (pageSize > items) {
  this.$('.pagination').css({
    display: 'none'
  });
} else {
  this.$('.pagination').removeAttr('style');
  pages = parseInt((items / pageSize));
  if (items % pageSize) {
    pages = pages + 1;
  }
}

Adding dynamic routing support to ember-models-table

We may want to use the ember-models-table for dynamic routes like `events/list` route, where we load live, drafted & past events based on the current route. The ember-models-table by default do not support the dynamic routes. To add this we override the didReceiveAttrs() method of the component which is executed every time the component updates. We add reset the pageSize, currentPageNumber and the content of the table, as the routes change.

didReceiveAttrs() {
  set(this, 'pageSize', 10);
  set(this, 'currentPageNumber', 1);
  set(this, 'filteredContent', get(this, 'data'));
}

The result of this we now have tables supporting JSON API in the Open Event Front-end application

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

Resources

Continue ReadingAdding JSON API support to ember-models-table in Open Event Front-end

Implementation of Speech UI in Susper

Recently, we have implemented a speech recognition feature in Susper where user could search by voice but it does not have an attractive UI. Google has a good user experience while recording the voice. We have implemented a similar Speech UI in Susper,

How we have implemented this?

  1. First we made a component speechtotext. It takes care of all the styling and functional changes of the speech UI and rendering the speech and any instructions required for the user. https://github.com/fossasia/susper.com/tree/master/src/app/speechtotext
  2. Initially when user clicks on the microphone in the search bar, it triggers the speechRecognition()

searchbar.component.html

<div class="input-group-btn">
 <button class="btn btn-default" id="speech-button" type="submit">
   <img src="../../assets/images/microphone.png" class="microphone" (click)="speechRecognition()"/>
 </button>

searchbar.component.ts

speechRecognition() {
 this.store.dispatch(new speechactions.SearchAction(true));
}

3) This dispatches an action speechaction.SearchAction(true), the app.component.ts is subscribed to this action and whenever this action is triggered the app component will open the speechtotext component.

Speechtotext.component.ts

Speech to text component on getting initialised calls the speech service’s record function which activates standard browser’s speech API

constructor(private speech: SpeechService) {
 
 this.speechRecognition();
}
speechRecognition() {
 this.speech.record('en_US').subscribe(voice => this.onquery(voice));
}

On recording the user’s voice and converting it to text, the text is sent to the onquery method as input and the recognised text is sent to other components through ngrx store.

onquery(event: any) {
 this.resettimer();
 this.store.dispatch(new queryactions.QueryServerAction({ 'query': event, start: 0, rows: 10, search: true }));
 this.message = event;
}

We have some UI text transitions where the user is shown with messages like ‘Listening…’ ,‘Speak Now’ and ‘Please check your microphone’ which are handle by creating a timer observable in angular.

ngOnInit() {
 this.timer = Observable.timer(1500, 2000);
 this.subscription = this.timer.subscribe(t => {
   this.ticks = t;

   if (t === 1) {
     this.message = "Listening...";
   }
   if (t === 4) {
     this.message = "Please check your microphone and audio levels.";
     this.miccolor = '#C2C2C2';
   }
   if (t === 6) {
     this.subscription.unsubscribe();
     this.store.dispatch(new speechactions.SearchAction(false));
   }
 });
}

The related PR regarding speech to text is at https://github.com/fossasia/susper.com/issues/624 .

With this now we have achieved a good UI for handling requests on Speech.

Resources:

Continue ReadingImplementation of Speech UI in Susper

Binding Images Dynamically in Open Event Orga App

In Open Event Orga App (Github Repo), we used Picasso to load images from URLs and display in ImageViews. Picasso is easy to use, lightweight, and extremely configurable but there has been no new release of the library since 2015. We were using Picasso in binding adapters in order to dynamically load images using POJO properties in the layout XML itself using Android Data Binding. But this configuration was a little buggy.

The first time the app was opened, Picasso fetched the image but it was not applied to the ImageView. When the device was rotated or the activity was resumed, it loaded just fine. This was a critical issue and we tried many things to fix it but none of it quite fit our needs. We considered moving on to other Image Loading libraries like Glide, etc but it was too heavy on the size and functionality for our needs. The last resort was to update the library to develop version using Sonatype’s snapshots Repository. Now, the Picasso v2.6.0-SNAPSHOT is very stable but not released to the maven central repository, and a newer develop version v3.0.0-SNAPSHOT was launched too. So we figured we should use that. This blog will outline the steps to include the develop version of Picasso, configuring it for our needs and making it work with Android Data Binding.

Setting up Dependencies

Firstly, we need to include the sonatype repository in the repositories block of our app/build.gradle

repositories {
   ...
   maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}

 

Then we need to replace the Picasso dependency entry to this:

compile 'com.squareup.picasso:picasso:3.0.0-SNAPSHOT'

 

Note that if you used Jake Wharton’s OkHttp3 Downloader for Picasso, you won’t need it now, so you need to remove it from the dependency block

And you need to use this to import the downloader

import com.squareup.picasso.OkHttp3Downloader;

 

Next, we set up our Picasso DI this way

Picasso providesPicasso(Context context, OkHttpClient client) {
   Picasso picasso = new Picasso.Builder(context)
       .downloader(new OkHttp3Downloader(client))
       .build();
   picasso.setLoggingEnabled(true);
   return picasso;
}

 

Set the singleton instance in our application:

Picasso.setSingletonInstance(picasso);

 

And we are ready to use it.

Creating Adapters

Circular Image Adapter

We show event logos as circular images, so we needed to create a binding adapter for that:

@BindingAdapter("circleImageUrl")
public static void bindCircularImage(ImageView imageView, String url) {
   if(TextUtils.isEmpty(url)) {
       imageView.setImageResource(R.drawable.ic_photo_shutter);
       return;
   }

   Picasso.with()
       .load(Uri.parse(url))
       .error(R.drawable.ic_photo_shutter)
       .placeholder(R.drawable.ic_photo_shutter)
       .transform(new CircleTransform())
       .tag(MainActivity.class)
       .into(imageView);
}

 

If the URL is empty, we just show the default photo, and otherwise we load the image into the view using standard CircleTransform

Note that there is no context argument in the with method. This was implemented in Picasso recently where they removed the need for context for loading images. Now, they use a Dummy ContentProvider to get application context, which is inspired by how Firebase does it.

Now, we can just normally use this binding in layout to load the event thumbnail like this

<ImageView
   android:layout_width="@dimen/image_small"
   android:layout_height="@dimen/image_small"
   android:contentDescription="@string/event_thumbnail"
   app:circleImageUrl="@{event.thumbnailImageUrl}" />

 

This gives us a layout like this:

Next we need to load the header image with a deafult image.

Default Image Adapter

For this, we write a very simple adapter without CircleTransform

@BindingAdapter(value = { "imageUrl", "placeholder" }, requireAll = false)
public static void bindDefaultImage(ImageView imageView, String url, Drawable drawable) {
   if(TextUtils.isEmpty(url)) {
       if (drawable != null)
           imageView.setImageDrawable(drawable);
       return;
   }

   RequestCreator requestCreator = Picasso.with().load(Uri.parse(url));

   if (drawable != null) {
       requestCreator
           .placeholder(drawable)
           .error(drawable);
   }

   requestCreator
       .tag(MainActivity.class)
       .into(imageView);
}

 

As imageUrl or placeholder can be null, we check for both, and setting correct images if they are not. We use this in our header layout with both the url and default image we need to show:

<ImageView
   android:scaleType="centerCrop"
   app:imageUrl="@{ event.largeImageUrl }"
   app:placeholder="@{ @drawable/header }"
   android:contentDescription="@string/event_background" />

 

And this gives us a nice dynamic header like this:

This wraps up the blog on Picasso’s latest develop version and Binding Adapters. If you want to know more about Picasso and Android Data Binding, check these links:

Continue ReadingBinding Images Dynamically in Open Event Orga App

Implementation of Colour Picker in Phimpme Android Application

In Phimpme Android Project, we have used Color Picker palette which has a various implementation in the project such as changing the theme color of the application, to choose the color for the text while editing an image.

Making XML Layout to choose the specific color from the color palette

The main aim was to provide Line of color, and the user can simply slide through the different colors. A single line should contain all the main colors. I took help of the Open Source project to arrange the layout of the colors. We will display the Color palette in a cardview.

<RelativeLayout
   android:id="@+id/container_edit_text"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   android:padding="@dimen/big_spacing">
   <uz.shift.colorpicker.LineColorPicker
       xmlns:app="http://schemas.android.com/apk/res-auto"
       android:id="@+id/color_picker_accent"
       android:layout_width="match_parent"
       android:layout_height="60dp"
       app:orientation="horizontal"
       app:selectedColorIndex="0" />
</RelativeLayout>

Inflating the list with the colors

We will inflate the list with all basic colors such as Red, Purple, Blue, Light Blue, Green, Yellow, Orange, Deep orange, Brown, Blue Gray. getAccentColors() function returns the specific color HEXCODE. A color code is six string length long code combination consisting of numbers and alphabets which are stored in the colors.xml resource file. For example, the color code for black is  #000000 and for white #FFFFFF.  

public static int[] getAccentColors(Context context){
   return new int[]{
           ContextCompat.getColor(context, R.color.md_red_500),
           ContextCompat.getColor(context, R.color.md_purple_500),
           ContextCompat.getColor(context, R.color.md_deep_purple_500),
           ContextCompat.getColor(context, R.color.md_blue_500),
           ContextCompat.getColor(context, R.color.md_light_blue_500),
           ContextCompat.getColor(context, R.color.md_cyan_500),
           ContextCompat.getColor(context, R.color.md_teal_500),
           ContextCompat.getColor(context, R.color.md_green_500),
           ContextCompat.getColor(context, R.color.md_yellow_500),
           ContextCompat.getColor(context, R.color.md_orange_500),
           ContextCompat.getColor(context, R.color.md_deep_orange_500),
           ContextCompat.getColor(context, R.color.md_brown_500),
           ContextCompat.getColor(context, R.color.md_blue_grey_500),
   };
}

Implementation of ColorPicker to change the Text color in the Edit Image Activity

Color Palette is implemented the followings steps:

 First,                                                                                                                                        A dialog box is made. This dialog will help to display the color palette.

 Second,                                                                                                                                We need to inflate the dialog box with color_picker_accent XML file we created  in the resource folder.

 Third,                                                                                                                                    We set the dialog box with the line of colors.

 Fourth,                                                                                                                                Get the selected color code. To get the selected color code we used the class  LineColorPicker. The color_picker_accent sends an id for the selected color,  where all the color code is stored.   

final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());
final View dialogLayout = getActivity().getLayoutInflater().inflate(R.layout.color_piker_accent, null);
final LineColorPicker colorPicker = (LineColorPicker) dialogLayout.findViewById(R.id.color_picker_accent);
final TextView dialogTitle = (TextView) dialogLayout.findViewById(R.id.cp_accent_title);
dialogTitle.setText(R.string.text_color_title);
colorPicker.setColors(ColorPalette.getAccentColors(activity.getApplicationContext()));
changeTextColor(WHITE);

In when a user selects a particular color he can either choose OK and CANCEL

When user selects OK

We implemented onClick event to change the color of the text by using the function changeTextColor() which accepts color code as the parameter.

dialogBuilder.setPositiveButton(getString(R.string.ok_action).toUpperCase(), new DialogInterface.OnClickListener() {
   public void onClick(DialogInterface dialog, int which) {
       changeTextColor(colorPicker.getColor());
   }
});

When user selects Cancel

When the user selects cancel, we have set the default color of the text that is White.

dialogBuilder.setNeutralButton(getString(R.string.cancel).toUpperCase(), new DialogInterface.OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
       changeTextColor(WHITE);
       dialog.cancel();
   }
});

changeTextColor function

It accepts the color code. We used this color to change the text color by using the inbuilt function setBackgroundColor() and setTextColor().

private void changeTextColor(int newColor) {
   this.mTextColor = newColor;
   mTextColorSelector.setBackgroundColor(mTextColor);
   mTextStickerView.setTextColor(mTextColor);
}

Conclusion

In this way, it provides a rich user experience. It adds vibrant colors in the application. A quick way to choose the color from the variety of option.

Github

https://github.com/fossasia/phimpme-android

Resources

Continue ReadingImplementation of Colour Picker in Phimpme Android Application

Scaling the logo of the generated events properly in Open Event Webapp

In the Facebook Developer Conference, the logo was too small

27190158-334a5446-5211-11e7-95e8-9690dfe8312e.png

In the Open Tech Summit Event, the logo was too long and increased the height of the navigation bar

77dc9fb0-3966-11e7-92c3-d6321dc98ac7.png

We decide some constraints regarding the width and the height of the logo. We don’t want the width of the logo to exceed greater than 110 pixels in order to not let it become too wide. It would look odd on small and medium screen if barely passable on bigger screens. We also don’t want the logo to become too long so we set a max-height of 45 pixels on the logo. So, we apply a class on the logo element with these properties

.logo-image {
 max-width: 110px;
 max-height: 45px;
}

But simply using these properties doesn’t work properly in some cases as shown in the above screenshots. An alternative approach is to resize the logo appropriately during the generation process itself. There are many different ways in which we can resize the logo. One of them was to scale the logo to a fixed dimension during the generation process. The disadvantage of that approach was that the event logo comes in different size and shapes. So resizing them to a fixed size will change its aspect ratio and it will appear stretched and pixelated. So, that approach is not feasible. We need to think of something different.  After a lot of thinking, we came up with an algorithm for the problem. We know the height of the logo would not be greater than 45px. We calculate the appropriate width and height of the logo, resize the image, and calculate dynamic padding which we add to the anchor element (inside which the image is located) if the height of the image comes out to be less than 45px. This is all done during the generation of the app. Note that the default padding is 5px and we add the extra pixels on top of it. This way, the logo doesn’t appear out of place or pixelated or extra wide and long. The detailed steps are mentioned below

  • Declare variable padding = 5px
  • Get the width, height and aspect ratio of the image.
  • Set the height to 45px and calculate the width according to the aspect ratio. If the width <= 110px, then directly resize the image and no change in padding is necessary
  • If the width > 110px, then make width constant to 110px and calculate height according to the aspect ratio. It will surely come less than 45px. Subtract the difference = (45 – height), divide it by 2 and add it to the padding variable.
  • Apply padding variable on the anchor tag. Now every logo should be displayed nicely and we have fixed the height of the navigation bar = 55px for all cases.

Here is an excerpt of the code. The whole work and discussion can be viewed here

var optimizeLogo = function(image, socket, done) {
 sharp(image).metadata(function(err, metaData) {
   if(err) {
     return done(err);
   }
   var width = metaData.width;
   var height = metaData.height;
   var ratio = width/height;
   var padding = 5;
   var diffHeight = 0;

   height = 45;
   width = Math.floor(45 * ratio);
   if (width > 110) {
     width = 110;
     height = Math.floor(width/ratio);
     diffHeight = 45 - height;
     padding = padding + (diffHeight)/2;
   }
   sharp(image).resize(width, height).toFile(image + '.new', function(err, info) {
     return done(null, padding);
   });
 });
};

It solved the problem. Now the logos of all the events were displaying properly. They were neither too wide, long or short. Here are some screenshots to show the improvements.

Facebook Developer Conference

27262455-d3558540-5474-11e7-852e-ef98888ef647.png

Open Tech Summit 2017

27262033-6f9d2df8-546c-11e7-811b-e35f849072eb.png

Resources:

Continue ReadingScaling the logo of the generated events properly in Open Event Webapp

Implementing Copyright API in Open Event Frontend

This article illustrates how the copyright details have been displayed in the Open Event Frontend project using the Open Event Orga API. The API endpoints which will be mainly focussing on for fetching the copyright details are:

GET /v1/event-copyright/{event_copyright_id}

The events have copyrights which give the creator of the event exclusive rights for its use and distribution. In the Open Event application, the copyright details can be seen on the public event page. The public event page contains the events details like description, venue, tickets, speakers, sponsors along with the copyright details and these details are present on the public/index route in the application. Apart from index route, we have multiple subroutes to display the detailed information of speakers, sessions and schedule. The one thing which remains common to all the public event pages is the copyright information. Most of the time the copyright details are event specific so they are nested within the event model so if we want to display them we need to fetch the event model first.

The code to fetch the event model looks like this:

model(params) {
return this.store.findRecord('event', params.event_id, { include: 'social-links, event-copyright' });
}

If we try to comprehend the code then we can see that ‘event-copyright’ details are included inside the model. The reason behind this is the fact that the copyright information is not specific to a particular route and is displayed on the all the public event pages. After fetching the copyright details the next step we need to perform is to display them on the event’s index page.

The code to display the copyright details looks like this:

{{#if model.event.copyright}}
  <div class="copyright">
    {{public/copyright-item copyright=model.event.copyright}}
  </div>
{{/if}}

In the first line, we have an if conditional statement which verifies whether the copyright data exists or not. If the data does not exist then the copyright class will not be visible on the page and if the model is not empty then it will be displayed with the help of model.event.copyright which is responsible for displaying the fetched data on the page.

If we see in the third line, we have called an another template ‘copyright-item’ which is responsible for how the data will look or in simpler words the UI of the copyright data.

The code which determines UI of the copyright details looks like this:

<img src="{{copyright.logoUrl}}" class="copyright-image" alt="{{copyright.licence}}">
<br>
<div class='copyright text'>
  <p>
    {{t 'This event is licenced under'}} <a href="{{copyright.licenceUrl}}"> {{copyright.licence}} </a>.
  </p>
</div>

In the first line of code, we are providing the src to the image which is stored in ‘logoUrl’ variable of the copyright object. If we hover the image we can see the copyright license which is stored in the ‘license’ variable. Then finally we have copyright license’s URL which is stored under ‘licenceUrl’ variable of copyright object. The resulting UI from the above source code looks like this :

Fig. 1: The user interface of the copyright details

Now we need to test whether the copyright details are completely displayed or not. To test it we created an integration test in which we created a sample ember object to check the correctness of the code. The sample ember object for copyright details looks like this:

To view the complete code regarding the copyright API integration check this.

const copyright = EmberObject.create({
  holder     : 'Creative Commons',
  holderUrl  : 'https://creativecommons.org',
  licence    : 'Public Domain Dedication (CC0)',
  licenceUrl : 'https://creativecommons.org/publicdomain/zero/1.0/',
  year       : 2007,
  logoUrl    : 'http://image.ibb.co/gt7q7v/pdd.png'
});

To conclude, this is how we integrated copyright information inside the Open Event Frontend project using the Open Event Orga API efficiently.

Resources:

Image Source : https://libsource.com/understanding-creative-commons-licensing/

Continue ReadingImplementing Copyright API in Open Event Frontend

Ember Mixins used in Open Event Frontend

This post will illustrate how ember mixins are used in the Open Event Frontend to avoid code duplication and to keep it clean to reduce code complexity.

The Open Event application needs forms at several places like at the time of login, for the creation of the event, taking the details of the user, creating discount codes for tickets etc. Every form performs similar actions which taking input and finally storing it in the database. In this process, a set of things keep executing in the background such as continuous form validation which means checking inputted values to ensure they are correctly matched with their type as provided in the validation rules, popping out an error message in case of wrong inputted values, etc. which is common to all the forms. The only thing which changes is the set of validation rules which are unique for every form. So let’s see how we solved this issue using Ember Mixins.

While writing the code, we often run into the situation where we need to use the similar behaviour in different parts of the project. We always try not to duplicate the code and keep finding the ways to DRY ( Don’t Repeat Yourself ) up the code. In Ember, we can share the code in the different parts of the project using Ember.Mixins.

While creating the forms, we mostly have differing templates but the component logic remains same. So we created a mixin form.js which contains all the properties which are common to all the forms. The code mixin contains can be reused throughout different parts of the application and is not a concern of any one route, controller, component, etc. The mixins don’t get instantiated until we pass them into some object, and they get created in the order of which they’re passed in. The code for form.js mixin looks like this.

export default Mixin.create({
  autoScrollToErrors : true,
  autoScrollSpeed    : 200,

  getForm() {
    return this.get('$form');
  },

  onValid(callback) {
    this.getForm().form('validate form');
    if (this.getForm().form('is valid')) {
      callback();
    }
  },
  
  didRender() {
      const $popUps = this.$('.has.popup');
      if ($popUps) {
        $popUps.popup({
          hoverable: true
        });
      }
      let $form = this.$('.ui.form');
      if ($form) {
        $form = $form.first();
        if (this.get('getValidationRules') && $form) {
          $form.form(merge(defaultFormRules, this.getValidationRules()));
        }
      },
  didInsertElement() {
    $.fn.form.settings.rules.date = (value, format = FORM_DATE_FORMAT) => {
      if (value && value.length > 0 && format) {
        return moment(value, format).isValid();
      }
      return true;
    };
  }

The complete code can be seen here.

Let’s start understanding the above code. In the first line, we created a mixin via Ember.Mixin.create() method. We have then specified the property ‘autoScrollToErrors’ to true so in case if there is some error, the form will automatically scroll to the error. The property ‘autoScrollSpeed’ specifies the speed with which the form will auto scroll to show the error. ‘getForm()’ method helps in getting the object which will be passed to the mixin. In ‘onValid()’ method we’re validating the form and passing the callbacks if it is correctly validated. We then have ‘didRender()’ method which renders the popups, checkboxes and form rules. The popups help in showing the errors on the form. In this method, we’re fetching the validation rules which are written in child/subclasses which are using this mixin to create the form.  The validation rules help in validating the form and tells if the value inputted is correct or not. In most of the forms, we have a field which asks for some specific date. The piece of code under ‘didInsertElement()’ helps in validating the date and returns true if it is correct. We have ‘willDestroyElement()’ method which destroys the popup if the window is changed/refreshed.

Let see the use case of the above form mixin. At the time of login, we see a form which asks for the user’s credentials to validate if the user is already registered or not. To create that login form we use form mixin. The code for login-form.js looks like this.

export default Component.extend(FormMixin, {
getValidationRules() {
  
fields : {
        identification: {
          identifier : 'email',
          rules      : [
            {
              type   : 'empty',
              prompt : this.l10n.t('Please enter your email ID')
            },
            {
              type   : 'email',
              prompt : this.l10n.t('Please enter a valid email ID')
            }
          ]
        },
        password: {
          identifier : 'password',
          rules      : [
            {
              type   : 'empty',
              prompt : this.l10n.t('Please enter your password')
            }
          ]
        }
      }
   }
});

The complete code can be found here.

We can see that in above code we are creating the form by extending our FormMixin which means that the form will have all the properties which are part of mixin along with the properties which remain unique to this class. Since the validation rules remain unique per form so we’re also providing the rules (easy to comprehend) which will help in validating the fields.

This is how our forms look like after and before applying validation rules.

Fig. 1: Login form before applying validation rules

          Fig. 2: Login form after applying validation rules

To sum it up, we can say that mixins are of great use when we want to keep our code DRY or reduce the code duplication. It helps in removing the unnecessary inheritance keeping it short. The code written using mixin is lesser complex and easily understandable.

References:

Continue ReadingEmber Mixins used in Open Event Frontend

Adding Build Type option in the Apk Generator of the Open Event Android App

The apk-generator provided ability to the event organiser to build an apk from a single click by providing the necessary json/binary files. However it gave only one type of apk where on the other hand the Open Event Android was available with apk of different build versions.

Recently the functionality of the apk generator of the Open Event Android App was enhanced where the user is asked to select an option for build type either Google Play or FDroid which generates the apk according to that selected type.

The main difference in the googleplay apk and fdroid apk is the inclusion of googleplay libraries which aren’t included in the app/build.gradle file in case of fdroid build.

To include support for build type the following files for the apk-generator had to be changed:

  1. app/views/__init__.py
  2. app/tasks/__init__.py
  3. app/static/js/main.js
  4. app/generator/generator.py
  5. scripts/build.sh
  6. app/templates/index.html

Changes to the files

  • app/templates/index.html

This file was where the changes to the UI of the apk-generator showing build type option to the user were made. With this the user was presented with an option to choose build type among googleplay and fdroid apart from the rest of the essential information.

  • scripts/build.sh

The android app supported two different flavours one for google play and the other for fdroid. This required the build script to be modified according to the build type selected by the user during the filling of form.

If user selected “Google Play” or “Fdroid”, the script would look something like this:

#!/bin/bash
./gradlew assemblegoogleplayRelease --info
echo "signing"
jarsigner -keystore ${KEYSTORE_PATH} -storepass ${KEYSTORE_PASSWORD} app/build/outputs/apk/app-googleplay-release-unsigned.apk ${KEY_ALIAS}
echo "zipaligning"
${1}/zipalign -v 4 app/build/outputs/apk/app-$2-release-unsigned.apk release.apk
echo "done"

Where $2 is googleplay or fdroid depending on what build type the user has selected while building the apk from the apk generator.

  • app/views/__init__.py and app/tasks/__init__.py

These files were modified by adding another parameter for supporting the two build type options in the desired functions.

  • app/static/js/main.js

This is where the option selected by the user was taken and accordingly the apk corresponding to the build type option selected was made available to the user. The code for it was shown as follows:

$buildTypeRadio.change(
   function () {
       if (this.checked) {
           enableGenerateButton(true);
           buildType = $(this).val();
       }
  }
);

This was how the option to display build type option to the user was incorporated. This gave the user the ability to install different build versions of an apk, thus making it more useful from the user point of view.

Related Links:

Continue ReadingAdding Build Type option in the Apk Generator of the Open Event Android App