Understanding PN Junctions with the Pocket Science Lab

The boundary layer between two thin films of a semiconducting material with Positive type and Negative type doping is referred to as a P-N junction, and these are one of the fundamental building blocks of electronics. These junctions exhibit various properties that have given them a rather indispensable status in modern day electronics.

The PSLab’s various measurement tools enable us to understand these devices, and in this blog post we shall explain some uses of PN junctions, and visualize their behaviour with the PSLab.

One might easily be confused and assume that a positive doping implies that the layer has a net positive charge, but this is not the case. A positive doping involves replacing a minute quantity of the semiconductor molecules with atoms from the next column in the periodic table. These atoms such as phosphorus are also charge neutral, but the number of available mobile charge carriers effectively increases.

A diode as a half-wave rectifier

A diode is basically just a PN junction. An ideal diode conducts electricity in one direction offering a path of zero resistance, and it is a perfect insulator in the other direction. In practice, we may observe some additional properties.

Figure : The circuit used for making the half-wave rectifier and studying it. A bipolar sinusoidal signal is input to a diode, and the output voltage is monitored. The 1uF capacitor is used to filter the output signal and make it more or less constant, but it has not been used while obtaining the data shown in the following image

Figure : A diode used as a half-wave rectifier. The input waveform shown in green was passed through a forward biased diode, and monitored by CH2 (red trace ) .

We can observe that only the positive half of the signal passes through the diode. It can also be observed , that since this is not an ideal diode, the conducted portion has lost some amplitude. This loss is a consequence of the forward threshold voltage of the PN junction, and in case of this diode, it is around 0.6 Volts. This threshold voltage depends on the band structure of the diode , and in the next section we shall examine this voltage for various diodes.

Measurement of Current-Voltage Characteristics of diodes

In practice, diodes only start conducting in the forward direction after a certain threshold potential difference is present. This voltage, also known as the barrier potential, depends on the band gap of the diode, and we shall measure it to determine how the electrical properties affect the externally visible physical properties of the diode.

A programmable voltage output of the PSLab (PV1) will be increased in small steps starting from 0 Volts, and a voltmeter input (CH3) will be used to determine the point when the diode starts conducting. The presence of a known resistor between PV1 and CH3 acts as a current limiter, and also enables us to calculate the current flow using some elementary application of the Ohm’s law. I = (PV1-CH3)/1000 .


The following image shows I-V characteristics of various diodes ranging from Schottky to Light Emitting Diodes (LEDs).

It may be interesting to note that the frequency of the light emitted by LEDs is directly proportional to the threshold voltage. In case of the white LED, it is almost similar to the blue LED because white LEDs are composed of blue LEDs, and a phosphor coating that partially converts blue light to yellow. The combination results in white light.

Zener diodes

Zener diodes are a special variant of diodes that also conduct electricity in the the reverse direction once a certain threshold has been crossed. This threshold can be determined during the manufacturing process, and zener diodes with breakdown voltages such as 3.3V , 5.6V , 6.8V etc are commercially available.

In the following image, the I-V characteristics of a 3.3V zener diode have been measured with the PSLab . As can be observed, the diode starts to conduct small amounts of current from around 2V itself, but significant current flow is usually present once the rated voltage is achieved.

In the forward direction, the zener appears to behave as a regular diode.

Resources
Continue ReadingUnderstanding PN Junctions with the Pocket Science Lab

Datewise splitting of the Bookmarks in the Homescreen of Open Event Android

In the Open Event Android app we had already incorporated bookmarks in the homescreen along with an improved UI. Now there was scope for further improvement in terms of user experience. The bookmarks were already sorted date wise but we needed to place them under separate date headers. In this blog I will be talking about how this was done in the app.

Initial Design
Current Design

 

 

 

 

 

 

 

 

Initially the user had no way of knowing which session belonged to which day. This could be fixed with a simple addition of a header indicating the day each bookmark belonged to. One way to do this was to add a day header and then get the bookmarks for each day and so on. But this proved to be difficult owing to the fact the number of days could be dynamic owing to the fact that this is a generic app. Another issue was that adding change listeners for the realm results to the bookmarks list for each day produced view duplication and other unexpected results whenever the bookmark list changed. So another approach was chosen that was to get all the bookmarks first and then add the date header and traverse through the bookmarks and only add sessions which belong to the date for which the date header was added earlier.

Bookmark Item Support in GlobalSearchAdapter

The main reason why we are reusing the GlobalSearchAdapter is that we have already defined a DIVIDER type in this adapter which can be reused as the date header.

We needed to initialize a constant for the Bookmark type.

private final int BOOKMARK = 5; //Can be any number

Then we add the Bookmark type in the getItemViewType() function which would return a constant that we defined earlier to indicate that in the filteredResultList we have an object of type Bookmark.

@Override
 public int getItemViewType(int position) {
    if (filteredResultList.get(position) instanceof Track) {
        return TRACK;
    }

    //Other Cases here
    } else if(filteredResultList.get(position) instanceof Session){
        return BOOKMARK;
    } else {
        return 1;
    }
 }

Now we create the viewholder if the list item is of the type Session which in this case will be a bookmark.

@Override
 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    RecyclerView.ViewHolder resultHolder = null;
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    //Other cases for Track,Location etc
 case BOOKMARK:
    View bookmark = inflater.inflate(R.layout.item_schedule, parent, false);
    resultHolder = new DayScheduleViewHolder(bookmark,context);
    break;
   //Some code
 
 }

Now we do the same in onBindViewHolder(). We bind the contents of the object to the ViewHolder here by calling the bindSession() function. We also pass in an argument which is our database repository i.e realmRepo here.

@Override
 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    switch (holder.getItemViewType()) {
     //Other cases handled here

case BOOKMARK:
    DayScheduleViewHolder bookmarkTypeViewHolder = (DayScheduleViewHolder) holder;
    Session bookmarkItem = (Session) getItem(position);
    bookmarkTypeViewHolder.setSession(bookmarkItem);
    bookmarkTypeViewHolder.bindSession(realmRepo);
    break;
 }

Updating the AboutFragment

private GlobalSearchAdapter bookMarksListAdapter;
 private List<Object> mSessions = new ArrayList<>();

Earlier the DayScheduleAdapter was being used to display the list of bookmarks. Now we are reusing the GlobalSearchAdapter. Now we have also converted mSessions into a list of objects from a list of sessions.

Now we initialize the adapter so that we can start adding our date headers.

bookMarksListAdapter = new GlobalSearchAdapter(mSessions, getContext());
 bookmarksRecyclerView.setAdapter(bookMarksListAdapter);

In this function loadEventDates() we are storing the all the dates for the event. For example the list for the FOSSASIA17 sample stores the dates in the dateList as [2017-03-17,2017-03-18,2017-03-19]. We fetch the event dates by calling the getEventDateSync() function which has been defined in our Realm Database.

private void loadEventDates() {
 
    dateList.clear();
    RealmResults<EventDates> eventDates = realmRepo.getEventDatesSync();
    for (EventDates eventDate : eventDates) {
        dateList.add(eventDate.getDate());
    }
 }

Now we move on to the core logic of the feature which is to get the date headers to work correctly.

  • Fetch the list of bookmarks from the local Realm database asynchronously.
  • Remove any existing changeListeners to the bookmarkResult.
  • Add a changeListener to our list of results to notify us of the completion of the query or changes in the bookmark list.
  • After this is done, inside the changeListener we first clear the mSessions
  • We now traverse through our date list and compare it with the session startDate which we can obtain by calling the getStartDate(). If the date match occurs for the first time we add a date header after converting the date string into another format using the DateUtils class. So the function formatDay() of DateUtils converts 2017-03-17 to 17 Mar. This format is easily more readable.
  • Repeat for all dates.
private void loadData() {
    loadEventDates();
 
    bookmarksResult = realmRepo.getBookMarkedSessions();
    bookmarksResult.removeAllChangeListeners();
    bookmarksResult.addChangeListener((bookmarked, orderedCollectionInnerChangeSet) -> {
 
        mSessions.clear();
        for (String eventDate : dateList) {
            boolean headerCheck = false;
            for(Session bookmarkedSession : bookmarked){
                if(bookmarkedSession.getStartDate().equals(eventDate)){
                    if(!headerCheck){
                        String headerDate = "Invalid";
                      try {
                       headerDate = DateUtils.formatDay(eventDate);
                      }
                      catch (ParseException e){
                            e.printStackTrace();
                      }
                        mSessions.add(headerDate);
                        headerCheck = true;
                    }
                    mSessions.add(bookmarkedSession);
                }
            }
            bookMarksListAdapter.notifyDataSetChanged();
            handleVisibility();
        }
    });
 }

So, this is how the date-wise organization for the bookmarks in the homescreen was done.

Resources

Continue ReadingDatewise splitting of the Bookmarks in the Homescreen of Open Event Android

Showing Offline and Online Status in SUSI Web Chat

A lot of times while chatting on SUSI Web Chat, one does not receive responses, this could either be due to no Internet connection or a down server.

For a better user experience, the user needs to be notified whether he is connected to the SUSI Chat. If one ever loses out on the Internet connection, SUSI Web Chat will notify you what’s the status through a snack bar.

Here are the steps to achieve the above:-

  1. The first step is to initialize the state of the Snackbar and the message.
this.state = {
snackopen: false,
snackMessage: 'It seems you are offline!'
}
  1. Next, we add eventListeners in the component which will bind to our browser’s window object. While this event can be added to any component in the App but we need it in the MessageSection particularly to show the snack bar.

The window object listens to any online offline activity of the browser.

  1. In the file MessageSection.react.js, inside the function componentDidMount()
  1. We initialize window listeners in our constructor section and bind them to the function handleOnline and handleOffline to set states to the opening of the SnackBar.
// handles the Offlines event
window.addEventListener('offline', this.handleOffline.bind(this));  

// handles the Online event
window.addEventListener('online', this.handleOnline.bind(this));
  1. We then create the handleOnline and handleOffline functions which sets our state to make the Snackbar open and close respectively.
// handles the Offlines event
window.addEventListener('offline', this.handleOffline.bind(this));  

// handles the Online event
window.addEventListener('online', this.handleOnline.bind(this));
  1. Next, we create a Snackbar component using the material-ui snackbar component.

The Snackbar is visible as soon as the the snackopen state is set to true with the message which is passed whether offline or online.

<Snackbar
       autoHideDuration={4000}
       open={this.state.snackopen}
       message={this.state.snackMessage}
 />

To get access to the full code, go to the repository https://github.com/fossasia/chat.susi.ai

Resources

Continue ReadingShowing Offline and Online Status in SUSI Web Chat

Hotword Detection in SUSI Android App using Snowboy

Hotword Detection is as cool as it sounds. What exactly is hotword detection? Hotword detection is a feature in which a device gets activated when it listens to a specific word or a phrase. You must have said “OK Google” or “Hey Cortana” or “Siri” or “Alexa” at least once in your lifetime. These all are hotwords which trigger the specific action attached to them. That specific action can be anything.

Implementing hotword detection from scratch in SUSI Android is not an easy task. You have to define language model, train the model and do various other processes before implementing it in Android. In short, not feasible to implement that along with the code of our Android app. There are many open source projects on hotword detection and speech recognition. They already have done what we need and we can make use of it. One such project is Snowboy. According to Snowboy GitHub repo “Snowboy is a DNN based hotword and wake word detection toolkit.”

Img src: https://snowboy.kitt.ai/

In SUSI Android App, we have used Snowboy for hotword detection with hotword as “susi” (pronounced as ‘suzi’). In this blog, I will tell you how Hotword detection is implemented in SUSI Android app. So, you can just follow the steps and you will be able to implement it in your application too or if you want to contribute in SUSI android app, it may help you a little in knowing the codebase better.

Pre Processing before Implementation

1. Generating Hotword Model

The start of implementation of hotword detection begins with creating a hotword model from snowboy website https://snowboy.kitt.ai/dashboard . Just log in and search for susi and then train it by saying “susi” thrice and download the susi.pmdl file.

There are two types of models:

  1. .pmdl : Personal Model
  2. .umdl : Universal Model

The personal model is specifically trained for you and is instantly available for you to download once you train the hotword by your voice. On the other hand, the Universal model is trained by minimum 500 hundred people and is only available once it is trained. So, we are going to use personal model for now since training of universal model is not yet completed.

Img src: https://snowboy.kitt.ai/

2. Adding some predefined native binary files in your app.

Once you have downloaded the susi.pmdl file and you need to copy some already written native binary file in your app.

    1. In your assets folder, make a directory named snowboy and add your downloaded susi.pmdl file along with this file in it.
    2. Copy this folder and add it in your  /app/src/main/java folder as it is. These are autogenerated swig files. So, don’t change it unless you know what you are doing.
    3. Also, create a new folder in your /app/src/main folder called jniLibs and add these files to it.

Implementation in SUSI Android App

Check out the implementation of Hotword detection in SUSI Android App here

You now have everything ready. Now you just need to implement some code in your MainActivity and you are good to go. Initiate Hotword detection in the app by using below written code snippet. The call initHotword() method from your onCreate method in MainActivity. Make sure you have given permission to RECORD_AUDIO and WRITE_EXTERNAL_STORAGE.

private void initHotword() {
   if (ActivityCompat.checkSelfPermission(this,
           Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
       ActivityCompat.checkSelfPermission(this,
           Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
       AppResCopy.copyResFromAssetsToSD(this);

       recordingThread = new RecordingThread(new Handler() {
           @Override
           public void handleMessage(Message msg) {
               MsgEnum message = MsgEnum.getMsgEnum(msg.what);
               switch(message) {
                   case MSG_ACTIVE:
                       //HOTWORD DETECTED. NOW DO WHATEVER YOU WANT TO DO HERE
                       break;
                   case MSG_INFO:
                       break;
                   case MSG_VAD_SPEECH:
                       break;
                   case MSG_VAD_NOSPEECH:
                       break;
                   case MSG_ERROR:
                       break;
                   default:
                       super.handleMessage(msg);
                       break;
               }
           }
       }, new AudioDataSaver());
   }
}

In the above code under case, MSG_ACTIVE add your code which needs to be executed once hotword is detected. Now, hotword detection is initiated and you just have to start recording and stop recording whenever you want.

To start recording : (can be written in onStart() method)

if(recordingThread !=null && !isDetectionOn) {
    recordingThread.startRecording();
    isDetectionOn = true;
}

To stop recording : (can be written in onStop() method)

if(recordingThread !=null && isDetectionOn){
   recordingThread.stopRecording();
   isDetectionOn = false;
}

So, this this is the simple process to add hotword detection feature in your app.

Though this is great and will word wonderfully for you but it has a little problem and a solution which is discussed below.

Problems for now and future steps

As mentioned above, the susi.pmdl model is a personal model and only trained for your voice. So, it will work wonderfully for you and for people with a similar voice like you but not for everyone. There are two ways to make this solve this problem:

  1. Replace susi.pmdl with susi.umdl: This is very easy way to fix this problem. But to get the susi.umdl file at least 500 people have to train susi hotword on snowboy website. Once that target is achieved, you can download susi.umdl file and replace it with susi.pmdl file and you are good to go.
  2. Train and obtain susi.pmdl file for each user: Right now you trained and used your own personal model for everyone but there is a way you can use every user’s own personal model in the app. Now hotword will be trained by the user himself in the app. Snowboy provides a training API http://docs.kitt.ai/snowboy/#api-v1-train to train the hotword and getting personal model. Quoting snowboy docs “You can define truly customized hotword for each of your end customer. Just ask them to say the hotword 3 times and a model will be trained on the fly!”

Resources

  1. Official docs of Snowboy hotword detection http://docs.kitt.ai/snowboy/#introduction
  2. Code for snowboy hotword detection. It contains readme files which give very nice description about the project. https://github.com/kitt-ai/snowboy
  3. This readme file of snowboy which guides on how to set up snowboy in an android app https://github.com/Kitt-AI/snowboy/blob/master/examples/Android/README.md
Continue ReadingHotword Detection in SUSI Android App using Snowboy

Handlebars.js used in Open Event Web App

I recently started working in the Open Event Webapp project. One of the initial issues that I took up was a trivial UI bug. It was about adding sponsor names beneath sponsor images for better representation. The issue can be found here. On reading up the code base and exploring the project a bit, I came across a new template – Handlebars.js. Handlebars is a template which has it’s base with the Mustache templating language. One of the early discoveries that I made with Handlebars.js was the use of {{ }} and {{{ }}} and the basic difference between them. In general, all Handlebar.js expressions, just like in Mustache templating, are written between {{ }} or {{{ }}} type of brackets. That is how I learned to identify and distinguish Handlebars from core HTML, even though they are inter-linked. The official Handlebars documentation describes Handlebars expressions in the following way:

A handlebars expression is a {{, some contents, followed by a }} ”

Getting started with Handlebars.js

Installation:

For a basic Linux installation, type the following in your command line:

npm install --save handlebars

Including Handlebars in HTML:

<script src="handlebars-v4.0.10.js"></script>

Handlebars templates are often stored in .hbs files for better readability and accessibility. The Open Event Webapp project consists of a handlebars .hbs file for each of the tracks, events, rooms, schedule, sessions and speakers templates. These can be found here, that is under src/backend/templates folder.

Difference between {{ }} and {{{ }}}: 

Handlebars enables developers to print raw HTML tags or code with the help of {{{ }}}. On the contrary, if you don’t want to print HTML (which is usually the case), use {{ }}. For better understanding, let’s take an example.

If our JS has an object that looks something like:

$(function () {
   var templateScript = $("#title-template").html();

   var temp = Handlebars.compile(templateScript);

var Title= {
“title”: <a> Handlebars</a>
}

Then, HTML of the following kind will help to distinguish the {{ }} and {{{ }}} brackets.

<script id=”title-template” type=”text/x-handlebars-template”>
{{title}}
{{{title}}}
</script>

//the first line will contain an anchor tag with the name “Handlebars”
//the second line will contain “<a>Handlebars</a>”

Block helpers in Handlebars:

Block helpers are identified by a ‘ #’ and they help to define and access custom iterators.

Handlebars allow calling JavaScript functions with the help of ‘helpers’. It doesn’t allow direct JavaScript code in the HTML with templates. We can create our own helpers using Handlebars.registerHelper () in our JavaScript. We generally pass a function to the helper. A good example was provided in the Handlebars.js documentation:

Handlebars.registerHelper('noop', function(options) {
  return options.fn(this);
});

By default, Handlebars helpers take the current context as the context to pass(“this”). Other fields are overshadowed. Incase, we want to access one of the fields that is masked by the default “this” context, we have to use a path reference.

Iterations using helpers:

Helpers can be a great way  to iterate over lists or objects. I will demonstrate it with an example from the Open Event Webapp project. To display all the sponsors of an event in the home page of the event Webapp, we use the following handlebars code, where we iterate over the object list “sponsorpics” that we have. It looks something like this:

{'1': ['Oreilly', 'Amazon'], '2': ['Huawei', 'Google'],'3': ['RedHat', 'GitHub']}
     
{{#if eventurls.sponsorsection}}
<div class="sponsor-container">
       <section class="sponsorscont">
         <div class="row sponsor-row">
           <div class="col-sm-12 col-md-12 col-xs-12 text-center">
             <h1 class="section-header">Proudly supported by</h1><br>
           </div>
         </div>
         <div class="row">
           <div class="col-sm-10 col-sm-offset-1">



             <div class="row">
               {{#each sponsorpics}}
                 {{#each this}}
                   <div class="{{{divclass}}}">
                     <div class=" {{{sponsorimg}}} text-center">
                       <a href="{{{url}}}" data-toggle="tooltip" title="{{{type}}}">
                         <img class="lazy centre {{{imgsize}}}" alt="{{{name}}}" data-original="{{{logo}}}">
                       </a>
                       {{{name}}}
                     </div>
                   </div>
                 {{/each}}
               {{/each}}
             </div> <!-- sponsor-row -->
           </div>
         </div>
       </section>
     </div>
   {{/if}}

For your reference, you can view a sample Webapp for the OSCON 2017 event here.
For further information, please refer to Handlebars.js .
An interesting tutorial about Handlebars in 10 mins or less can be found here.

Continue ReadingHandlebars.js used in Open Event Web App

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 Pinterest Integration in Phimpme Android

After establishing Facebook and Twitter share in Phimpme, our next goal was to integrate more social networking sites. Pinterest is an ideal website for us as it is widely used among various photography enthusiasts. Our goal was to share the image on the Pinterest website without the use of any other native android application.

Note: First, we added Phimpme app in the developer section https://developers.pinterest.com/apps/. This step is crucial as it generates APP ID and it is necessary for authentication.

Adding Pinterest option in Accounts Activity in Phimpme

In accounts activity, we have added a list of accounts that we have integrated in a Recyclerview. Currently, we have integrated Facebook and Twitter. We need to add Pinterest App icon and Pinterest option in the Recyclerview.

To add Pinterest app icon I downloaded the icon from iconfinder in SVG format. Using SVG format allows icon to resize itself according to the screen sizes of the users. We saved the icon file name as ic_pinterest_black.xml

Pinterest icon SVG:

<vector android:height="24dp" android:viewportHeight="32.0"
   android:viewportWidth="32.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="#231F20" android:pathData="M16,0.27C7.16,0.27 0,7.43 0,16.27c0,6.55 3.94,12.18 9.58,14.65c-0.05,-1.12 -0.01,-2.46 0.28,-3.67c0.31,-1.3 2.06,-8.72 2.06,-8.72s-0.51,-1.02 -0.51,-2.53c0,-2.37 1.37,-4.14 3.08,-4.14c1.46,0 2.16,1.09 2.16,2.4c0,1.46 -0.93,3.65 -1.41,5.68c-0.4,1.7 0.85,3.08 2.53,3.08c3.03,0 5.07,-3.89 5.07,-8.51c0,-3.51 -2.36,-6.13 -6.66,-6.13c-4.85,0 -7.88,3.62 -7.88,7.66c0,1.39 0.41,2.38 1.05,3.14c0.29,0.35 0.34,0.49 0.23,0.89C9.51,20.37 9.33,21.08 9.26,21.36c-0.11,0.4 -0.44,0.55 -0.8,0.4c-2.23,-0.91 -3.28,-3.36 -3.28,-6.11c0,-4.55 3.83,-9.99 11.44,-9.99c6.11,0 10.13,4.42 10.13,9.16c0,6.28 -3.49,10.97 -8.63,10.97c-1.73,0 -3.35,-0.93 -3.91,-1.99c0,0 -0.93,3.69 -1.13,4.4c-0.34,1.23 -1,2.46 -1.61,3.43C12.9,32.04 14.43,32.27 16,32.27c8.84,0 16,-7.16 16,-16S24.84,0.27 16,0.27z"/>
</vector>

We made an array of all the accounts list in the Accounts Activity. I added Pinterest in the array list. This array list is inflated in the Accounts Activity.

public static String[] accountName = {"Facebook", "Twitter", "Drupal", "NextCloud", "Wordpress", "Pinterest"};

To add the icon the recyclerview, we have to get the resource id from the drawable folder and then set is in the recyclerview. We have done it dynamically so that we don’t have to fetch the id of every accounts icons.

Integer id = getContext().getResources().getIdentifier(context.getString(R.string.ic_) +
               (accountName[position].toLowerCase()) + "_black"
       , context.getString(R.string.drawable)
       , getContext().getPackageName());

holder.accountAvatar.setImageResource(id);

Importing Pinterest SDK in Phimpme project

To import the Pinterest SDK in the project, please download the Pinterest SDK from the link: http://assets.pinterest.com/sdk/android-pdk.tar. Go to File->import new module->Import Gradle Project. Build the project, if there is any error resolve the error and then build Gradle again.

compile project(‘:pdk’)

Add APP ID in the manifest file of the project

We need to add the APP ID that was generated while making the app the Pinterest in the manifest folder of the Phimpme Android. In the case of Phimpme, we have added the APP ID in the intent filter in the Accounts Activity. This is necessary for the interaction of the Phimpme with the Pinterest website.

<activity
   android:name=".accounts.AccountActivity"
   android:screenOrientation="portrait"
   android:theme="@style/Theme.AppCompat.NoActionBar">
   <intent-filter>
       <action android:name="android.intent.action.VIEW" />
       <category android:name="android.intent.category.DEFAULT" />
       <category android:name="android.intent.category.BROWSABLE" />
       <data android:scheme="pdk4910600717739247160" />
   </intent-filter>
</activity>

Establishing Pinterest authentication in Accounts Activity

First, we need to import all the necessary class from the Pinterest SDK. These class includes callback functions, PDKClient which manages the interface between the Phimpme app and the Pinterest website. We need to pass the APP ID in the PDKClient function as an argument and also the view in the onConnect function in PDKClient.

pdkClient = PDKClient.configureInstance(this, getResources().getString(R.string.pinterest_app_id));
pdkClient.onConnect(this);
pdkClient.setDebugMode(true);

Before signing In we need to check if we are already signed in or not. This is how we have done in  Phimpme app. If the app is already signed In a Toast will pop up showing that it already signed In.

if (accountPresenter.checkAlreadyExist(accountName[5])) {
   Toast.makeText(this, R.string.already_signed_in,
           Toast.LENGTH_SHORT).show();
}

Authentication happens in these following steps:

Adding permissions in the List                                                                                These include the following permissions:

  • Read permission
  • Write permission
  • Read relationship
  • Write relationship
List scopes = new ArrayList<String>();
scopes.add(PDKClient.PDKCLIENT_PERMISSION_READ_PUBLIC);
scopes.add(PDKClient.PDKCLIENT_PERMISSION_WRITE_PUBLIC);
scopes.add(PDKClient.PDKCLIENT_PERMISSION_READ_RELATIONSHIPS);
scopes.add(PDKClient.PDKCLIENT_PERMISSION_WRITE_RELATIONSHIPS);

Passing the view, scope array and PDKCallback as arguments in the login function

I have passed the view, scope array list and PDKCallback as arguments in the login function in PDKClient class. This will initiate the authentication process and the user will be redirected to the Pinterest web page after the user has filled up the credentials properly and logged in to the Pinterest the user will be redirected to the Phimpme accounts page. If the user has logged In successfully onSuccess function with being called where PDKResponse will pass an argument. This response object can be used to fetch the username of the logged In user or the Pin and the BoardID of the user.

@Override
public void onSuccess(PDKResponse response) {
   Log.d(getClass().getName(), response.getData().toString());

   // Begin realm transaction
   realm.beginTransaction();

   // Creating Realm object for AccountDatabase Class
   account = realm.createObject(AccountDatabase.class,
           accountName[5]);


   // Writing values in Realm database
   account.setUsername(String.valueOf(response.getUser()));

   // Finally committing the whole data
   realm.commitTransaction();

   Toast.makeText(AccountActivity.this, R.string.success, Toast.LENGTH_SHORT).show();
}

If the user fails to log in to the account onFailure function will be called and a Toast will pop up.

@Override
public void onFailure(PDKException exception) {
   Log.e(getClass().getName(), exception.getDetailMessage());
   Toast.makeText(AccountActivity.this, R.string.fail, Toast.LENGTH_SHORT).show();
}

Inserting the credentials to the Realm Database

We have used the Realm database to store all the accounts credentials in one place. This is necessary for the maintenance and to check if the user is logged or not. AccountName array holds the list of the name which is added to the database.

// Begin realm transaction
realm.beginTransaction();

// Creating Realm object for AccountDatabase Class
account = realm.createObject(AccountDatabase.class,
       accountName[5]);


// Writing values in Realm database
account.setUsername(String.valueOf(response.getUser()));

// Finally committing the whole data
realm.commitTransaction();

Conclusion

Now, users can login into the Pinterest from the Accounts Activity. After authenticating the users, we can use the authentication to share the image from the app to the Pinterest website.

Github

Resources

Continue ReadingAdding Pinterest Integration in Phimpme Android

Advanced configurations in Yaydoc’s Web UI

Yaydoc’s User Interface consists of a form with three required fields; the user’s email address, git repository’s URL, and a theme for the generated website. Specific values of these fields are the minimum requirement to generate documentation for a project. There are certain other configuration variables for whom we assumed default values. Among these, we assumed `docs/` directory or the directory specified in the `yaydoc.yml` configuration file as the default path for the documentation. Also, `Default Branch` is assumed as the branch to generate documentation website. However, this cannot guarantee the generation of docs for every other project. These configurations can have different values based on a project.

Thus, there was a need to include certain input values for advanced configuration. The addition of these configurations in the UI doesn’t compel the user to specify them. In our attempt to improve user’s experience, we show the default values to the user when they are specifying custom values for these configurations.

If the user doesn’t specify a value for the repository’s branch, a default value is retrieved from Github’s Repository Components API, taking repository’s URL from the required input as the input URL.

/**
 * Setting the branch name with `default_branch` attriburte from
 * Github’s Repository Components API
 * @param gitUrl: URL of the github repository
 */
setDefaultBranchName: function (gitUrl) {
  var owner = gitUrl.split(“/”)[3] || ‘’;
  var repository = gitUrl.split(“/”)[4] || ‘’).split(‘.’)[0] || ‘’;
  $.get(‘https://api.github.com/repos/’ + owner + ‘/’ + repository, {
    headers: {“User-Agent”: “Yaydoc”}
  }).complete(function (data) {
    $(“#target_branch”).val(data.responseJSON.default_branch);
  });
}

There are certain cases in which the design of the Web User Interface could have been confusing. Since we are displaying all the advanced configurations at once, it could’ve appeared to the users that they are specifying empty values for the other. Thus to handle this, inputs were enabled on toggle when a checkbox beside them was checked. This was achieved making following changes in the front end of the code.

/**
 * Toggle editing of Branch Name input
 */
$(“#btnEditBranch”).click(function () {
  styles.toggleEditing(“target_branch”);
  ....
  ....
});

/**
 * Toggle Enabling/Disabling an input tag
 * @param id: `id` attribute of input tag
 */
toggleEditing: function (id) {
  const input = $(‘#’ + id);
  if (input.attr(‘disabled’)) {
    input.removeAttr(‘disabled’);
    $(‘#checkbox_’ + id).removeClass(‘glyphicon-unchecked’).addClass(‘glyphicon-check’);
  } else {
    input.attr(‘disabled’, ‘disabled’);
    $(‘checkbox_’ + id).removeClass(‘glyphicon-check’).addClass(‘glyphicon-unchecked’);
  }
}

Introducing advanced configurations to the User Interface has opened the possibility for even more projects to generate and deploy docs with much lesser constraints. One of our main aim for this project is to have a fairly simple UI and UX and we hope to bring further updated to achieve that.

Resources:

  1. Github’s Repository API: https://developer.github.com/v3/repos/
  2. jQuery’s AJAX Requests: https://api.jquery.com/jquery.get
Continue ReadingAdvanced configurations in Yaydoc’s Web UI

Maintaining Aspect Ratio of Images while Uploading in Open Event Frontend

In Open Event Frontend, we are using the image-upload at many places such as the cover photo of the event on the create event page, also at the system images (in the admin routes) where the user gets to change the image uploaded by him earlier, and also at the ‘profile’ route where the user can change his photo. But at different places, different dimensions of photos are needed since we are keeping standard in Open Event Frontend.

Therefore the image needs to be in a size with the correct ratio at the time of uploading. We are using the cropper component  for achieving this. The cropper is a modal which pops up after the image upload modal so that a user can crop the image according to the aspect ratio kept specific for that purpose. It looks as follows:

While dealing with an issue in Open Event Frontend, we had to have change in aspect ratio for ‘avatar’ images, unlike the other images. So, we had to modify our cropper modal so as to have different aspect ratios for different images when needed.

We solved the above problem as follows:

In our image-modal, we pass the aspect ratio as a parameter. So in our case, we wanted to set the aspect ratio 1:1 for the ‘avatar’ images only. Following is the code snippet of what we wanted:

{{widgets/forms/image-upload
needsCropper=true
label=(t 'Update Image')
id='user_image'
aspectRatio=(if (eq subTopic.name 'avatar') (array 1 1))
icon='photo'
hint=(t 'Select Image')
maxSizeInKb=10000
helpText=(t 'For Cover Photos : 300x150px (2:1 ratio) image.
For Avatar Photos : 150x150px (1:1 ratio) image.')}}

Thus, we passed the ‘aspectRatio’ as a parameter to the ‘image-upload’ modal. The image-upload further calls the cropper modal and passes ‘aspectRatio’.

{{#if needsCropper}}
{{modals/cropper-modal isOpen=cropperModalIsShown imgData=imgData onImageCrop=(action 'imageCropped') aspectRatio=aspectRatio}}
{{/if}}

Thus, we can use the passed param i.e ‘aspectRatio’ in our cropper to modify the logic for the aspect ratio. Following is what we did so as to obtain the aspect Ratio of 1:1 for ‘avatar’ images only. The default aspect ratio for all other images is 2:1.

onVisible() {
let viewPort = {};
let factor = 150;
const aspectRatio = this.getWithDefault('aspectRatio', [2, 1]);
viewPort.width = aspectRatio[0] * factor;
viewPort.height = aspectRatio[1] * factor;
viewPort.type = 'square';
this.$('.content').css('height', '300px');
this.$('img').croppie({
customClass : 'croppie',
viewport : viewPort,
boundary : {
height: 250
}
});
},

As shown above, we have kept a multiplying factor which is fixed. According to the aspect ratio specified, we calculate and set the width and height in the viewport object.

Thus, following is the thing (Aspect Ratio 1:1 ) we achieved for the ‘avatar’ images:


Resources
Official Ember JS guide: https://guides.emberjs.com/v1.10.0/templates/actions/

Blog on making our own modals: http://ember.guru/2014/master-your-modals-in-ember-js

Source code: https://github.com/sumedh123/open-event-frontend/tree/system-images

Continue ReadingMaintaining Aspect Ratio of Images while Uploading in Open Event Frontend

Uploading images to Dropbox from the Phimpme App

The Phimpme Android application along with the camera, gallery and image editing features offers the option to upload images to many social media and cloud storages without having to install several other applications. As we can see from the screenshot below, Phimpme application contains a user-friendly accounts screen to connect to the accounts using a username and password so that we can upload photos from the share screen to that particular account later on.

One such famous cloud storage is the Dropbox and in this tutorial, I am explaining how I implemented the account authentication and image uploading feature to Dropbox in the Phimpme Android application.

Step 1

The first thing we need to do is to create an application in the Dropbox application console and to get the app key and the API secret key which we will require later on for the authentication purposes. To create an application on the Dropbox application console page,

  1. Go to this link. It will open a page as depicted in the screenshot below:
  2. Now click on the Dropbox API option.
  3. Click on App folder – access to a single folder created specifically for your app.
  4. Write the name of your application and press the create app button.

After this, we will be redirected to the page which will contain all the keys required to authenticate and upload photos.

Step 2

After getting the keys, the next thing we need to do is install the Dropbox SDK. To do this:

  1. Download the Android SDK from this link and extract it.
  2. Copy the dropbox-android-sdk-1.6.3.jar and json_simple-1.1.jar file to the libs folder.
  3. Click on the add as library button by right clicking on the jar files added.
  4. Copy the below-mentioned code in the AndroidManifest.xml file which defines the dropbox login activity within a new activity tag.
android:name="com.dropbox.client2.android.AuthActivity"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:configChanges="orientation|keyboard">
<intent-filter>
     <!-- Change this to be db- followed by your app key -->
         <data android:scheme="db-app_key" />
         <action android:name="android.intent.action.VIEW" />
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

In the 7th line of the code snippet, replace the app_key with the key you received from following the step 1.

Step 3

After setting up everything, we need to extract the access token for the user to upload the photos in that particular account. To do this, we can make use of the below code snippet, which uses the dropbox SDK we installed in step 2 to create an object named mDBApi and initialises it to authenticate the user.

private DropboxAPI<AndroidAuthSession> mDBApi;AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
AndroidAuthSession session = new AndroidAuthSession(appKeys);
mDBApi = new DropboxAPI<AndroidAuthSession>(session);

After initialisation in the onCreate method of the activity, we can authenticate the user using the following line of code.

mDBApi.getSession().startOAuth2Authentication(MyActivity.this);

This will open up a window where the user will be prompted to login to their dropbox account. After the login is finished, we will be taken back to the activity which made the authentication call, so in the onResume method, we need to get the access token of the user which will be used later on to upload the images using the following code snippet provided below:

mDBApi.getSession().finishAuthentication();
String accessToken = mDBApi.getSession().getOAuth2AccessToken();

After we have stored the access token, we can upload the selected image to the Dropbox using the following line of code.

File file = new File("working-draft.jpg");
FileInputStream inputStream = new FileInputStream(file);
Entry response = mDBApi.putFile("/magnum-opus.jpg", inputStream,
                              file.length(), null, null);

For more information on uploading and retrieving data from the Dropbox account, you can go to the dropbox developer guide and for working example refer to the Phimpme Android repository in the resources below.

Resources

  1. Phimpme Repo : Phimpme Android github repository.
  2. Dropbox official documentation : https://www.dropbox.com/developers-v1/core/start/android
  3. Dropbox application console : https://www.dropbox.com/developers/apps
  4. Stackoverflow example to upload image on Dropbox : https://stackoverflow.com/questions/10827371/upload-photo-to-dropbox-by-android
Continue ReadingUploading images to Dropbox from the Phimpme App