Implementing User Permissions API on Open Event Frontend to View and Update User Permission Settings

This blog article will illustrate how the user permissions  are displayed and updated on the admin permissions page in Open Event Frontend, using the user permissions API. Our discussion primarily will involve the admin/permissions/index route to illustrate the process.

The primary end point of Open Event API with which we are concerned with for fetching the permissions  for a user is

GET /v1/user-permissions

First we need to create a model for the user-permissions, which will have the fields corresponding to the api, so we proceed with the ember CLI command:

ember g model user-permission

Next we define the model according to the requirements. The model needs to extend the base model class, and other than the name and description all the fields will be boolean since the user permissions frontend primarily consists of checkboxes to grant and revoke permissions. Hence the model will be of the following format.

import attr from 'ember-data/attr';
import ModelBase from 'open-event-frontend/models/base';

export default ModelBase.extend({
 name           : attr('string'),
 description    : attr('string'),
 unverifiedUser : attr('boolean'),
 anonymousUser  : attr('boolean')
});

Now we need to load the data from the api using this model, so will send a get request to the api to fetch the current permissions. This can be easily achieved via a store query in the model hook of the admin/permissions/system-roles route. It is important to note here, that findAll is preferred over an empty query. To quote the source of this information,

The reason findAll is preferred over query when no filtering is done is, query will always make a server request. findAll on the other hand, will not make a server request if findAll has already been used once somewhere before. It’ll re-use the data already available whenever possible.

model() {
   return this.get('store').findAll('user-permission');
 }

The user permissions form is not a separate component and is directly embedded in the route template hence, there is no need to explicitly pass the model, it will be available in the route template by default. And can be used as following:

{{#each model as |userPermission|}}
<tr>
  <td>
    {{userPermission.name}}
    <div class="muted text">
      {{userPermission.description}}
    </div>
  </td>
  <td>
     {{ui-checkbox label=(t 'Unverified User') checked=userPermission.unverifiedUser onChange=(action (mut userPermission.unverifiedUser))}}
  </td>
  <td>
    {{ui-checkbox label=(t 'Anonymous User') checked=userPermission.anonymousUser onChange=(action (mut userPermission.anonymousUser))}}
  </td>
</tr>
{{/each}}

In the template after mutating the model’s values according to whether the checkboxes are checked or not, the only thing left is triggering the update action in the controller which will be triggered with the default submit action of the form.

updatePermissions() {
     this.set('isLoading', true);
     this.get('model').save()
       .then(() => {
         this.set('isLoading', false);
         this.notify.success(this.l10n.t('User permissions have been saved successfully.'));
       })
       .catch(()=> {
         this.set('isLoading', false);
         this.notify.error(this.l10n.t('An unexpected error has occurred. User permissions not saved.'));
       });
   }

The controller action first sets the isLoading property to true. This adds the semantic UI class loading to the the form,  and so the form goes in the loading state, to let the user know the request is being processed. Then the save()  call occurs and this makes a PATCH request to the API to update the values stored inside the database. And if the PATCH request is successful, the .then() clause executes, which in addition to setting the isLoading as false, notifies the user that the settings have been saved  successfully using the notify service.

However, in case there is an unexpected error and the PATCH request fails, the .catch() executes. After setting isLoading to false, it notifies the user of the error via an error notification.

Resources

 

 

Introduction To Kotlin in SUSI Android App

Lately, we wrote some of the code of SUSI Android App in Kotlin. Kotlin is a very similar language to Java but with much more advantages than Java. It is easy to adapt and learn. There is no doubt that Kotlin is better than Java but with the announcement of Kotlin Support in Google IO’17 for Android development, Kotlin seems a decent way to write code for an Android App.

Advantages of Kotlin over Java

    1. Reduce Boilerplate Code: It helps making development of app faster as it reduces more than 20 percent of boilerplate code. Writing long statements again and again is a headache for developers. Kotlin comes to rescue in that situation.
    2. Removes Null Pointer Exception: Once a large company faced millions of dollars of loss due to null pointer exception. It causes crashes of apps more often than anything else. Thus Kotlin helps in Null checks and makes app free from Null pointer Exceptions.
    3. Interoperable with Java: Kotlin code and Java code are interoperable. Which means you can write half your code in kotlin and half in Java and it will work like a charm. You can call java methods from Kotlin code and vice versa. So, you can simply move your existing Java based app to Kotlin slowly making your app always running.
    4. Lambda and Inline functions: Yes, Kotlin also has functionalities from functional programming languages. Mainly and most widely used feature of those languages is Lambda functions.
    5. Direct Reference of Views by Id: You do not need to write findViewById(R.id.view_name) or use any other library like Butterknife for view binding. You can simply use the view by its id.
    6. No semicolon:  Last but not the least, you do not need to add a semicolon after each statement. In fact, you do not need to add semicolon at all.

Setting up Android Studio to work with Kotlin

If you have latest Android Studio Canary Version, there is already a build support for Kotlin in it. You need not do anything in that case. But if you don’t have the Canary version, you can add Kotlin Plugin in your Android Studio. Follow the below steps to do that.

  1. Install the Kotlin Plugin:

Android Studio → Preferences… →Plugins → Browse Repository → type “Kotlin” in search box → install

  1. Restart your Android Studio and Rebuild the project. Everything else is already set up in SUSI Android App but if you want to do it for your other apps, follow this link.

Implementation in SUSI Android App

So, I am not going to give unnecessary code but will point out specific things where Kotlin helped a lot to reduce unnecessary code and made the code compact.

1. Listeners:

Earlier with Java

Button signup = (Button) findViewById(R.id.sign_up);

signup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               startActivity(new Intent(LoginActivity.this, SignUpActivity.class));
            }
        });

Now, with Kotlin

fun signUp() {
   sign_up.setOnClickListener { startActivity(Intent([email protected]LoginActivity, SignUpActivity::class.java)) }
}

2. Models

With Java

public class MapData {

    private double latitude;
    private double longitude;
    private double zoom;

    public MapData(double latitude, double longitude, double zoom) {
        this.latitude = latitude;
        this.longitude = longitude;
        this.zoom = zoom;
    }

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }

    public double getZoom() {
        return zoom;
    }

    public void setZoom(double zoom) {
        this.zoom = zoom;
    }
}

With Kotlin

class MapData (var latitude: Double, var longitude: Double, var zoom: Double) 

3. Constructor

With Java

public class LoginPresenter {
    private LoginActivity loginActivity;
    public LoginPresenter(loginActivity: LoginActivity){
        this.loginActivity = loginActivity;
    }
}

With Kotlin

class LoginPresenter(loginActivity: LoginActivity) {
}

Summary

So, this blog was to give you an idea about Kotlin programming language, it’s advantages over java and information how you can set it up on your Android Studio so as to help you a little in understanding the codebase of SUSI Android App a little more.

Resources

  1. Official Kotlin Guide for Syntax Reference and further learning  https://kotlinlang.org/docs/reference/
  2. Blog by Elye on Setting up Kotlin on Android Studio https://android.jlelse.eu/setup-kotlin-for-android-studio-1bffdf1362e8
  3. Youtube Video tutorial by Derek Banas on Kotlin https://www.youtube.com/watch?v=H_oGi8uuDpA

API Error Handling in the Open Event Organizer Android App

Open Event Organizer is an Android App for Organizers and Entry Managers. Open Event API server acts as a backend for this App. So basically the App makes data requests to the API and in return, the API performs required actions on the data and sends back the response to the App which is used to display relevant info to the user and to update the App’s local database. The error responses returned by the API need to parse and show the understandable error message to the user.

The App uses Retrofit+OkHttp for making network requests to the API. Hence the request method returns a Throwable in the case of an error in the action. The Throwable contains a string message which can be get using the method named getMessage. But the message is not understandable by the normal user. Open Event Organizer App uses ErrorUtils class for this work. The class has a method which takes a Throwable as a parameter and returns a good error message which is easier to understand to the user.

Relevant code:

public final class ErrorUtils {

   public static final int BAD_REQUEST = 400;
   public static final int UNAUTHORIZED = 401;
   public static final int FORBIDDEN = 403;
   public static final int NOT_FOUND = 404;
   public static final int METHOD_NOT_ALLOWED = 405;
   public static final int REQUEST_TIMEOUT = 408;

   private ErrorUtils() {
       // Never Called
   }

   public static String getMessage(Throwable throwable) {
       if (throwable instanceof HttpException) {
           switch (((HttpException) throwable).code()) {
               case BAD_REQUEST:
                   return "Something went wrong! Please check any empty field if a form.";
               case UNAUTHORIZED:
                   return "Invalid Credentials! Please check your credentials.";
               case FORBIDDEN:
                   return "Sorry, you are not authorized to make this request.";
               case NOT_FOUND:
                   return "Sorry, we couldn't find what you were looking for.";
               case METHOD_NOT_ALLOWED:
                   return "Sorry, this request is not allowed.";
               case REQUEST_TIMEOUT:
                   return "Sorry, request timeout. Please retry after some time.";
               default:
                   return throwable.getMessage();
           }
       }
       return throwable.getMessage();
   }
}

ErrorUtils.java
app/src/main/java/org/fossasia/openevent/app/common/utils/core/ErrorUtils.java

All the error codes are stored as static final fields. It is always a good practice to follow a making the constructor private for a utility class to make sure the class is never initialized anywhere in the app. The method getMessage takes a Throwable and checks if it is an instance of the HttpException to get an HTTP error code. Actually, there are two exceptions – HttpException and IOException. The prior one is returned from the server. In the method by using the error codes, relevant good error messages are returned which are shown to the user in a snackbar layout.

It is always a good practice to show a more understandable user-friendly error messages than simply the default ones which are not clear to the normal user.

Links:
1. List of the HTTP Client Error Codes – Wikipedia Link
2. Class Throwable javadoc

Parsing SUSI.AI Blog Feed

Our SUSI.AI web chat is improving every day.Recently we decided to add a blog page to our SUSI.AI web chat to show all the latest blogs related to SUSI.AI. These blogs are written by our developer team. We have the following feed from which we need to parse the information of blogs and display:

http://blog.fossasia.org/tag/susi-ai/feed/

This feed is in RSS (Really Simple Syndication) format. We decided to use Google feed API service to parse this RSS content, but that service is now deprecated. Then we decided to convert this RSS into JSON format and then we will parse the information.
We have used the rss2json API for converting our RSS content into JSON. We make an ajax call to this API for fetching the JSON content:

$.ajax({
        url: 'https://api.rss2json.com/v1/api.json',
        method: 'GET',
        dataType: 'json',
        data: {
            'rss_url': 'http://blog.fossasia.org/tag/susi-ai/feed/',
            'api_key': api_key: '0000000000000000000000000000000000000000', // put your api key here,
            'count': 50
        }
        }).done(function (response) {
            if(response.status !== 'ok'){ throw response.message; }
            this.setState({ posts: response.items, postRendered: true});
        }.bind(this));

Explanation:

  • URL: This is base URL of API to which we are making calls in order to fetch JSON data.
  • rss_url: This is the URL of RSS feed which needs to be converted into JSON format.
  • api_key: This is the key, which can be generated after making an account on the website
  • count: Count of feed items to return, the default is 20.

The converted JSON response looks like:

This can be checked here.

Now we have used cards of material-ui to show the content of this JSON response. On the success of our ajax call, we update the array(named as posts) present in the initial state of our component with response.items( an array containing information of blogs).

We map through each element in an array named posts and return the corresponding card, containing relevant information in it. We parsed the following information from JSON:

  • Name of the author: posts.author
  • Title of the blog: posts.title
  • Link to blog on WordPress: posts.link

Publish date of the blog:
The publish date is in this format: “2017-08-05 09:05:27” (example), we need to format this date. We used following code to do that:

let date = posts.pubDate.split(' ');
let d = new Date(date[0]);
dateFormat(d, 'dddd, mmmm dS, yyyy') // dateFormat is an npm package

This converts “2017-08-05 09:05:27” to “Saturday, August 5th, 2017”.

Description and Featured Images of the blog:
We needed to show a short description of the blog and a featured image. There is an element in our posts array with name description that contains HTML, starting from featured image and followed by a short description. We needed to convert this HTML into simple text for using this. I used htmlToText npm package for this purpose:
let description = htmlToText.fromString(posts.description).split(‘…’);
description variable now contains simple text. A simple example :

[https://blog.fossasia.org/wp-content/uploads/2017/08/image2-768×442.png] Our SUSI.AI Web Chat has many static pages like Overview, Devices, Team and Support.We have separate CSS files for each component. Recently, we faced a problem regarding design pattern where CSS files of one component were affecting another component. This blog is all about solving this issue and we take an example of distortion

Now, this text contains both link for featured image and our short description text. For getting the link for featured image, I have used regex(Regular Expression) in the following code and saved the link in the variable image and for short description I have used the split function :

let text = description[0].split(']');
let image = susi // temporary image for initialisation
let regExp = /\[(.*?)\]/;
let imageUrl = regExp.exec(description[0]);
if(imageUrl) {
   image = imageUrl[1]
}

After successfully parsing this information from JSON, we can have cards with details and card looks like this:

As we need all this to be rendered when the component mounts, so we put our ajax call inside componentDidMount() function of our react component.

Resources:

How to Implement Feedback System in SUSI iOS

The SUSI iOS app provides responses for various queries but the response is always not accurate. To improve the response, we make use of the feedback system, which is the first step towards implementing Machine Learning on the SUSI Server. The way this works is that for every query, we present the user with an option to upvote or downvote the response and based on that a positive or negative feedback is saved on the server. In this blog, I will explain how this feedback system was implemented in the SUSI iOS app.

Steps to implement:

We start by adding the UI which is two buttons, one with a thumbs up and the other with a thumbs down image.

textBubbleView.addSubview(thumbUpIcon)
textBubbleView.addSubview(thumbDownIcon)
textBubbleView.addConstraintsWithFormat(format: "H:[v0]-4-[v1(14)]-2-[v2(14)]-8-|", views: timeLabel, thumbUpIcon, thumbDownIcon)
textBubbleView.addConstraintsWithFormat(format: "V:[v0(14)]-2-|", views: thumbUpIcon)
textBubbleView.addConstraintsWithFormat(format: "V:[v0(14)]-2-|", views: thumbDownIcon)
thumbUpIcon.isUserInteractionEnabled = true
thumbDownIcon.isUserInteractionEnabled = true

Here, we add the subviews and assign constraints so that these buttons align to the bottom right next to each other. Also, we enable the user interaction for these buttons.

We know that the user can rate the response by pressing either of the buttons added above. To do that we make an API call to the endpoint below:

BASE_URL+'/cms/rateSkill.json?'+'model='+model+'&group='+group+'&skill='+skill+’&language’+language+’&rating=’+rating

Here, the BASE_URL is the url of the server, the other three params model, group, language and skill are retrieved by parsing the skill location parameter we get with the response. The rating is positive or negative based on which button was pressed by the user. The skill param in the response looks like this:

skills:
[
"/susi_skill_data/models/general/entertainment/en/quotes.txt"
]

Let’s write the method that makes the API call and responds to the UI that it was successful.

if let accepted = response[ControllerConstants.accepted] as? Bool {
  if accepted {
    completion(true, nil)
    return
  }
  completion(false, ResponseMessages.ServerError)
  return
}

Here after receiving a response from the server, we check if the `accepted` variable is true or not. Based on that, we pass `true` or `false` to the completion handler. Below the response we actually receive by making the request.

{
session: {
identity: {
type: "host",
name: "23.105.140.146",
anonymous: true
}
},
accepted: true,
message: "Skill ratings updated"
}

Finally, let’s update the UI after the request has been successful.

if sender == thumbUpIcon {
thumbDownIcon.tintColor = UIColor(white: 0.1, alpha: 0.7)
thumbUpIcon.isUserInteractionEnabled = false
thumbDownIcon.isUserInteractionEnabled = true
feedback = "positive"
} else {
thumbUpIcon.tintColor = UIColor(white: 0.1, alpha: 0.7)
thumbDownIcon.isUserInteractionEnabled = false
thumbUpIcon.isUserInteractionEnabled = true
feedback = "negative"
}
sender.tintColor = UIColor.hexStringToUIColor(hex: "#2196F3")

Here, we check the sender (the thumbs up or down button) and based on that pass the rating (positive or negative) and update the color of the button.

Below is the app in action with the feedback system.

Resources:

Using Mosquitto as a Message Broker for MQTT in loklak Server

In loklak server, messages are collected from various sources and indexed using Elasticsearch. To know when a message of interest arrives, users can poll the search endpoint. But this method would require a lot of HTTP requests, most of them being redundant. Also, if a user would like to collect messages for a particular topic, he would need to make a lot of requests over a period of time to get enough data.

For GSoC 2017, my proposal was to introduce stream API in the loklak server so that we could save ourselves from making too many requests and also add many use cases.

Mosquitto is Eclipse’s project which acts as a message broker for the popular MQTT protocol. MQTT, based on the pub-sub model, is a lightweight and IOT friendly protocol. In this blog post, I will discuss the basic setup of Mosquitto in the loklak server.

Installation and Dependency for Mosquitto

The installation process of Mosquitto is very simple. For Ubuntu, it is available from the pre installed PPAs –

sudo apt-get install mosquitto

Once the message broker is up and running, we can use the clients to connect to it and publish/subscribe to channels. To add MQTT client as a project dependency, we can introduce following line in Gradle dependencies file –

compile group: 'net.sf.xenqtt', name: 'xenqtt', version: '0.9.5'

[SOURCE]

After this, we can use the client libraries in the server code base.

The MQTTPublisher Class

The MQTTPublisher class in loklak would provide an interface to perform basic operations in MQTT. The implementation uses AsyncClientListener to connect to Mosquitto broker –

AsyncClientListener listener = new AsyncClientListener() {
    // Override methods according to needs
};

[SOURCE]

The publish method for the class can be used by other components of the project to publish messages on the desired channel –

public void publish(String channel, String message) {
    this.mqttClient.publish(new PublishMessage(channel, QoS.AT_LEAST_ONCE, message));
}

[SOURCE]

We also have methods which allow publishing of multiple messages to multiple channels in order to increase the functionality of the class.

Starting Publisher with Server

The flags which signal using of streaming service in loklak are located in conf/config.properties. These configurations are referred while initializing the Data Access Object and an MQTTPublisher is created if needed –

String mqttAddress = getConfig("stream.mqtt.address", "tcp://127.0.0.1:1883");
streamEnabled = getConfig("stream.enabled", false);
if (streamEnabled) {
    mqttPublisher = new MQTTPublisher(mqttAddress);
}

[SOURCE]

The mqttPublisher can now be used by other components of loklak to publish messages to the channel they want.

Adding Mosquitto to Kubernetes

Since loklak has also a nice Kubernetes setup, it was very simple to introduce a new deployment for Mosquitto to it.

Changes in Dockerfile

The Dockerfile for master deployment has to be modified to discover Mosquitto broker in the Kubernetes cluster. For this purpose, corresponding flags in config.properties have to be changed to ensure that things work fine –

sed -i.bak 's/^\(stream.enabled\).*/\1=true/' conf/config.properties && \
sed -i.bak 's/^\(stream.mqtt.address\).*/\1=mosquitto.mqtt:1883/' conf/config.properties && \

[SOURCE]

The Mosquitto broker would be available at mosquitto.mqtt:1883 because of the service that is created for it (explained in later section).

Mosquitto Deployment

The Docker image used in Kubernetes deployment of Mosquitto is taken from toke/docker-kubernetes. Two ports are exposed for the cluster but no volumes are needed –

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: mosquitto
  namespace: mqtt
spec:
  ...
  template:
    ...
    spec:
      containers:
      - name: mosquitto
        image: toke/mosquitto
        ports:
        - containerPort: 9001
        - containerPort: 8883

[SOURCE]

Exposing Mosquitto to the Cluster

Now that we have the deployment running, we need to expose the required ports to the cluster so that other components may use it. The port 9001 appears as port 80 for the service and 1883 is also exposed –

apiVersion: v1
kind: Service
metadata:
  name: mosquitto
  namespace: mqtt
  ...
spec:
  ...
  ports:
  - name: mosquitto
    port: 1883
  - name: mosquitto-web
    port: 80
    targetPort: 9001

[SOURCE]

After creating the service using this configuration, we will be able to connect our clients to Mosquitto at address mosquitto.mqtt:1883.

Conclusion

In this blog post, I discussed the process of adding Mosquitto to the loklak server project. This is the first step towards introducing the stream API for messages collected in loklak.

These changes were introduced in pull requests loklak/loklak_server#1393 and loklak/loklak_server#1398 by @singhpratyush (me).

Resources

Implementing Speakers Call API in Open Event Frontend

This article will illustrate how to display the speakers call details on the call for speakers page in the Open Event Frontend project using the Open Event Orga API. The API endpoints which will be mainly focussing on for fetching the speaker call details are:

GET /v1/speakers-calls/{speakers_call_id}

In the case of Open Event, the speakers are asked to submit their proposal beforehand if they are interested in giving some talk. For the same purpose, we have a section on the event’s website called as Call for Speakers on the event’s public page where the details about the speakers call are present along with the button Submit Proposal which redirects to the link where they can upload the proposal if the speakers call is open. Since the speakers call page is present on the event’s public page so the route which will be concerned with will be public/index route and its subroute public/index/cfs in the application. As the call for speakers details are nested within the events model so we need to first fetch the event and then from there we need to fetch the speaker-calls detail from the model.

The code to fetch the event model looks like this:

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

The above model takes care of fetching all the data related to the event but, we can see that speakers call is not included as the parameter. The main reason behind this is the fact that the speakers is not required on each of the public route, rather it is required only for the subroute public/index/cfs route. Let’s see how the code for the speaker-call modal work to fetch the speaker calls detail from the above event model.  

model() {
    const eventDetails = this.modelFor('public');
    return RSVP.hash({
      event        : eventDetails,
      speakersCall : eventDetails.get('speakersCall')
    });
}

In the above code, we made the use of this.modelFor(‘public’) to make the use of the event data fetched in the model of the public route, eliminating the separate API call for the getting the event details in the speaker call route. Next, using the ember’s get method we are fetching the speakers call data from the eventDetails and placing it inside the speakersCall JSON object for using it lately to display speakers call details in public/index subroute.

Until now, we have fetched event details and speakers call details in speakers call subroute but we need to display this on the index page of the sub route. So we will pass the model from file cfs.hbs to call-for-speakers.hbs the code for which looks like this:

{{public/call-for-speakers speakersCall=model.speakersCall}}  

The trickiest part in implementing the speakers call is to check whether the speakers call is open or closed. The code which checks whether the call for speaker has to be open or closed is:

isOpen: computed('startsAt', 'endsAt', function() {
     return moment().isAfter(this.get('startsAt')) && moment().isBefore(this.get('endsAt'));
})

In the above-computed property isOpen of speakers-call model, we are passing the starting time and the ending time of the speakers call. We are then comparing if the starting time is after the current time and the current time is before the ending time than if both conditions satisfy to be true then the speakers call is open else it will be closed.  

Now, we need a template file where we will define how the user interface for call-for-speakers based on the above property, isOpen. The code for displaying UI based on its open or closed status is

  {{#if speakersCall.isOpen}}
    <a class="ui basic green label">{{t 'Open'}} </a>
    <div class="sub header">
      {{t 'Call for Speakers Open until'}} {{moment-format speakersCall.endsAt 'ddd, MMM DD HH:mm A'}}
    </div>
  {{else}}
    <a class="ui basic red label">{{t 'Closed'}}</a>
  {{/if}}

In the above code, we are checking is the speakersCall is open then we show a label open and display the date until which speakers call is opened using the moment helper in the format “ddd, MMM DD HH:mm A” else we show a label closed. The UI for the above code looks like this.

Fig. 1: The heading of speakers call page when the call for speakers is open

The complete UI of the page looks like this.

Fig. 2: The user interface for the speakers call page

The entire code for implementing the speakers call API can be seen here.

To conclude, this is how we efficiently fetched the speakers call details using the Open-Event-Orga speakers call API, ensuring that there is no unnecessary API call to fetch the data.  

Resources:

Updating Settings Activity With MVP Architecture in SUSI Android

SUSI Android app includes settings that allow users to modify app features and behaviours. For example, SUSI Android allows users to specify whether they want voice output i.e text to speech irrespective of input type.

Currently different settings available in SUSI Android are:

Settings                                          Use
Enter As Send It allows users to specify whether they want to use action button of soft keyboard as carriage return or send message
Mic Input It allows users to specify whether they want to use speech for input type or not. User can also use keyboard to provide input.
Speech Always It allows users to specify whether they want speech output i.e text to speech irrespective of input type
Speech Output It allows users to specify whether they want speech output in case of speech input or not.
Select Server It allows user to specify whether they want to use default susi_server or their own server.
Language It allows users to select text to speech engine language.

Android’s standard architecture isn’t always sufficient, especially in the case of complex applications that need to be tested regularly. So we need an architecture that can improve the app’s testability and MVP(Model View Presenter) architecture is one of the best options for that.

Working with MVP architecture to show settings

MVP architecture creates three layers: Model, View and Presenter. Use of each layer is described below

  • Model: The Model holds the business logic of the application. It controls how data can be created, stored, and modified.
  • View: The View is a UI that displays data and routes user actions to the Presenter.
  • Presenter: Presenter is a mediator between View and Model. It retrieves data from the Model and shows it in the View. It also processes user actions forwarded to it by the View.

Steps followed to implement MVP architecture are:

1. I first created three interfaces: ISettingsView, ISettingModel and  ISettingsPresenter. These classes contain all the important functions we needed in model, presenter and view. Presenter’s interaction with model is handled by  ISettingModel and presenter’s interaction with view is handled by ISettingsPresenter and ISettingView.

  1. I created model, view and presenter class i.e SettingModel, SettingsPresenter and SettingsActivity and implemented ISettingModel, ISettingsPresenter and ISettingsView in SettingModel, SettingPresenter and SettingsActivity respectively so that presenter can communicate with both model and view.
class SettingsPresenter(fragmentActivity: FragmentActivity): ISettingsPresenter, ISettingModel.onSettingFinishListener
class SettingsActivity : AppCompatActivity(), ISettingsView
class SettingModel: ISettingModel
  1. After that, I created ChatSettingsFragment class. It is a PreferenceFragment class which resides in SettingsActivity and contains all settings.
class ChatSettingsFragment : PreferenceFragmentCompat() 

How Presenter communicates with Model and View

As already mentioned presenter’s interaction with view is handled by ISettingsView and ISettingsPresenter. So first I created object of ISettingsPresenter in ChatSettingsFragment, which is part of view, as shown below

lateinit var settingsPresenter: ISettingsPresenter
settingsPresenter = SettingsPresenter(activity)

And used it to call method of presenter, SettingsPresenter

settingsPresenter.sendSetting(Constant.ENTER_SEND, newValue.toString())

After that, I created an object of ISettingsView in SettingsPresenter, so that it can communicate with view, SettingsActivity.

Presenter’s interaction with model is handled by ISettingModel. So first I created an object of SettingModel class which implemented ISettingModel and then used it to call methods of SettingModel.

var settingModel: SettingModel = SettingModel()
settingModel.sendSetting(key, value, this)

Here the third parameter in the sendSetting method is ISettingModel.onSettingFinishListener which is part of ISettingModel. SettingModel used it to communicate with SettingsPresenter as shown below

override fun sendSetting(key: String, value: String, listener: ISettingModel.onSettingFinishListener) {

settingResponseCall.enqueue(object : Callback<ChangeSettingResponse> {

 override fun onResponse(call: Call<ChangeSettingResponse>?, response:

Response<ChangeSettingResponse>) {

          listener.onSuccess(response)

      }

  })

}

onSuccess method present in SettingsPresenter.

Reference

Shorten the Travis build time of Meilix

Meilix is a lubuntu based script. It uses Travis to compile and deploy the iso as Github Release. Normally Travis took around 17-21 minutes to build the script and then to deploy the iso on the page. It is quite good that one gets the iso in such a small interval of time but if we would able to decrease this time even more then that will be better.

Meilix script consists of basically 2 tests and 1 deploy:

The idea behind reducing the time of Meilix building is to parallely run the tests which are independent to each other. So here we run the build.sh and aptRepoUpdater.sh parallely to reduce the time upto some extent.
This pictures denotes that both the tests are running parallely and Github Releases is waiting for them to get complete successfully to deploy the iso.

Let’s see the code through which this made possible:

jobs:
  include:
    - script: ./build.sh
    - script: 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./scripts/aptRepoUpdater.sh; fi'
    - stage: GitHub Release
      script: echo "Deploying to GitHub releases ..."

Here we included a job section in which we wrote the test which Travis has to carry out parallely. This will run both the script at the same time and can help to reduce the time.
After both the script run successfully then Github Release the iso.

Here we can see that we are only able to save around 30-40 seconds and that much matters a lot in case if we have more than 1 build going on the same time.

Links to follow:
Travis guide to build stages

Firefox Customization for Meilix

Meilix a lightweight operating system can be easily customized. This article talks about the way one must proceed to customize the configuration of Firefox of Meilix or on its own Linux distro and how to copy the configuration file of Firefox directly to the home folder of the user.
Meilix script contains a pref.js file which is responsible for providing the configuration. This file contains various function through which one can edit them according to its need to get the required configuration of its need.

Let’s see an example:

user_pref("browser.startup.homepage", "http://www.google.com/cse/home?cx=partner-pub-6065445074637525:8941524350");

This line is used to set the browser startup page and it can be edited according to user choice to find the same page whenever he starts his Firefox.

There are several lines too which can be edited to make the required changes.

How does this work?

This is the Mozilla User Preference file and should be placed in the location /home/user_name/.mozilla/firefox/*.default/prefs.js. It actually controls the attributes of Firefox preference and set the command from here to change it.

How to use it?

One can directly go and edit it according to the choice to use it.

How meilix script uses it to change the user preference?

As we can see that .mozilla folder should be under the home directory, therefore we copy the .mozilla to the the skel folder, so that it gets automatically copied to the home location and we would be able to use.
There is also a shell script which comes in handy to implement the browser startup page and the script even copies the configuration file.

1.#!/bin/bash

2.# firefox
3.# http://askubuntu.com/questions/73474/how-to-install-firefox-addon-from-command-line-in-scripts
4.for user_name in `ls /home/`
5.do
  6.preferences_file="`echo /home/$user_name/.mozilla/firefox/*.default/prefs.js`"
  7.if [ -f "$preferences_file" ]
  8.then
    9.echo "user_pref(\"browser.startup.homepage\", \"https://google.com/\");" >> $preferences_file
  10.fi
11.done

This file is taken from here. And it used in Meilix to run the script to set the default startup page in Firefox. This will be taken input from the user end from the Meilix Generator webapp and it will change the line 9 url according to the input given by the user.
On line 3, *.default will set automatically by the script itself, it generated randomly.
After that, the script will copy the prefs.js in its location and it will implement the changes.

Links to follow:

Firefox-preference guide
Firefox-editing-configuration