Motion in android

So earlier this year I attended a talk where the speaker wanted to introduce us to meaningful motion in android apps and he convinced us to use this in our apps as well. Motion came in with Material design, actually not really came but became popular with Material design and since google has added the same kind of motions to their apps as well, developers have started using it.

I love motion, not only does it boost engagement but it’s instantly noticeable. Think of the apps you use that feature motion design and how pleasing, satisfying, fluent and natural they feel to experience. Eg. Zomato, Play music etc.

Now think of some apps that don’t use any kind of motions and you’ll realise they look a bit boring and you as users will always prefer apps with some kind of motion.

Touch

So firstly let’s discover the feedback on touch. It helps to communicate to the user in a visual form that some interaction has been made. But also keep in mind that this animation should be enough for them to gain clarity and encourage further explorations and not distract them.

For adding backgrounds you can use the following :

  • ?android:attr/selectableItemBackground — Show a ripple effect within the bounds of the view.
  • ?android:attr/selectableItemBackgroundBorderless — Show a ripple effect extending the bounds of the view.

View Property Animator

Introduced in API 12, this allows us to perform animated operations (in parallel) on a number of view properties using a single Animator instance

Some of the parameters that can be added to a view are as follows :

  • alpha() -Set the alpha value to be animated to
  • scaleX() & scaleY()— Scales the view on it’s X and / or Y axis
  • translationZ() — Translates the view on its Z axis
  • setDuration()— Sets the duration of the animation
  • setStartDelay() — Sets the delay on the animation
  • setInterpolator() — Sets the animation interpolator
  • setListener() — Set a listener for when the animation starts, ends, repeats or is cancelled.

Now let’s write some code on how to do this on a button for example:

mButton.animate().alpha(1f)
.scaleX(1f)        
.scaleY(1f)        
.translationZ(10f)        
.setInterpolator(new FastOutSlowInInterpolator())        .setStartDelay(200)        
.setListener(new Animator.AnimatorListener() {            
@Override            
public void onAnimationStart(Animator animation) { }             
@Override            
public void onAnimationEnd(Animator animation) { }             
@Override            
public void onAnimationCancel(Animator animation) { }             
@Override            
public void onAnimationRepeat(Animator animation) { }        
})        
.start();

Note : Use ViewCompat class to implement the ViewPropertyAnimator from Android API version 4 and up

Object Animator

Similar to the ViewPropertyAnimator, the ObjectAnimator allows us to perform animations on various properties of the target view (both in code and XML resource files). However, there a couple of differences:

  • The ObjectAnimator only allows animations on a single property per instance e.g.Scale X followed by Scale Y.
  • However, it allows animations on a custom Property e.g. A view’s foreground colour.

Her we need to set the evaluator, set the delay and call start().

private void animateForegroundColor(@ColorInt final int targetColor) {   
    ObjectAnimator animator = ObjectAnimator.ofInt(YOUR_VIEW, FOREGROUND_COLOR, Color.TRANSPARENT, targetColor);                    animator.setEvaluator(new ArgbEvaluator()); animator.setStartDelay(DELAY_COLOR_CHANGE); animator.start();}

Interpolators

An Interpolator can be used to define the rate of change for an animation, meaning the speed, acceleration and behaviour during animating can be altered. Some of them are :

These are some of the basics. there are a lot of other things like

  • Window transitions(Explode, fade, slide etc.)
  • Shared element Transitions
  • Other custom transitions
  • Animated Vector drawables

you can play around with these for a better understanding but be sure to actually try everything on a device/emulator since you’ll get to actually see the changes in the UI and in turn understand better.

Using Partial in Handlebars and Reusing Code

Open Event Webapp uses handlebar partials for optimizing code. We can reuse a template using Handlebars partial.

How to use Handlebars partial ?

To use Handlebars partial, we have to follow some easy steps:

Step 1: In the .hbs file containing code, register your partial by using function Handlebars.registerPartial 

Handlebars.registerPartial('myPartial', '{{name}}')

Step 2: Calling the partial

{{> myPartial }}

In Open-Event Webapp we have made partials for common templates like navbar and footer.

1. // Navbar template (navbar.hbs)

  
 <!-- Fixed navbar -->
 <nav class="navbar navbar-default navbar-fixed-top">
  <div class="container">
   <div class="navbar-header navbar-left pull-left">
    <a class="navbar-brand" href="{{ eventurls.main_page_url }}">
    {{#if eventurls.logo_url}}
    <img alt="{{eventurls.name}}" class="logo logo-dark" src="{{  eventurls.logo_url }}">
    {{else}}
    {{ eventurls.name }}
    {{/if}}
    </a>
   </div>
 <div class="navbar-header navbar-right pull-right">
   <ul style="margin-left:20px" class="nav navbar-nav pull-left">
   {{#sociallinks}}
   {{#if show}}
    <li class="pull-left"><a href="{{link}}" style="padding-right:0; padding-left:0;margin-left:15px"><i class="fa fa-lg fa-{{icon}}" aria-hidden="true" title="{{{icon}}}"></i></a></li>
   {{/if}}
   {{/sociallinks}}
   </ul>
 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse" style="margin-left:1em;margin-top:1em;">
   <span class="sr-only">Toggle navigation</span>
   <span class="icon-bar"></span>
   <span class="icon-bar"></span>
   <span class="icon-bar"></span>
 </button>
 </div>

 <div class="hidden-lg hidden-md hidden-sm clearfix"></div>
   <div class="collapse navbar-collapse">
    <ul class="nav navbar-nav navbar-right">
     <li class="navlink"><a id="homelink" href="index.html">Home</a>
     {{#if timeList}}
     <li class="navlink">
     <a id="schedulelink"href="schedule.html">
     Schedule</a>
     </li>
     {{/if}}
     {{#if tracks}}
     <li class="navlink">
      <a id="trackslink" href="tracks.html">Tracks</a>
    </li>
  {{/if}}
     {{#if roomsinfo}}
     <li class="navlink">
      <a id="roomslink" href="rooms.html">Rooms</a>   
     </li>
    {{/if}}
    {{#if speakerslist}}
    <li class="navlink">
      <a id="speakerslink" href="speakers.html">Speakers</a>
     </li>
    {{/if}}
   </ul>
     </div>
   </div>
 </nav>
//Compiling Template by providing path

2. const navbar = handlebars.compile(fs.readFileSync(__dirname + '/templates/partials/navbar.hbs').toString('utf-8'));
// Register Partial

3. handlebars.registerPartial('navbar', navbar);

AngularJS structure and directives

Today I am going to tell you how to build a well worked Angular JS structure, as well as to be able to maintain your app’s elements correctly. It’s a basic and most important thing to learn and remember before you start building your own website or app because in the early phases of a project the structure doesn’t matter too much, and many people tend to ignore it, but in the long term it will affect code maintainability. It also helps you to develop it quicker and solve bugs without any additional troubles.

I must admit that I was one of them who  had made this mistake and ignore AngularJS correct structure. The thing is that I had not known how to build Angular JS app correctly before I started coding CommonsNet, and I wanted to start and provide a real outcome as quickly as possible. But unfortunately my mistake has stoped me later. I have realised it this week while implementing a quite simple feature – adding HTML elements dynamically. It turned out that I had a trouble while adding them. I had’t known that it’s better not to manipulate DOM elements in Controllers, but instead do it in directives.

Let me to explain it step by step from lessons I’ve learned while refactoring CommonsNet code structure. Please note that I’m just sharing my experience in building rather a small project and I’m covering only a small part of that subject, so some of these tips may be first – useless if you want to build an extended one, and then – not enough if you want to learn more. I recommend you to find further resources.

AngularJS Structure

First of all please see at AngularJS structure provided below. It’s a very basic structure, but it’ is important to have in mind that you should follow that pattern while developing your own app. If you want to have an order in your files you should seperate them by directories and create different ones like: controllers, directives, services, js and views. This structure makes it very easy for the reader to visualize and conceptualize the concepts you are covering.

AngularJS structure.png

My CommonsNet structure differs a bit because I have one main js directory, and all subdirectories like directives, controllers and services  inside it. I think it’s also an acceptable solution. Imagine that I hadn’t had any directives or services directives’ files before last Wednesday…

Then,  it’s also recommended to put index.html at the root of front-end structure. The index.html file will primarily handle loading in all the libraries and Angular elements.

Next, controllers are main part of AngularJS apps. It always happens that developers when starting out tend to put too much logic in the controllers. It’s a bug. Controllers should never do DOM manipulation or hold DOM selectors, that’s where we use directives and ng-model. Likewise business logic should live in services, not controllers.

Data should also be stored in services, except where it is being bound to the $scope. Services are singletons that persist throughout the lifetime of the application, while controllers are transient between application states. So, if the controller is a coordinator between the view and the model, then the amount of the logic it has should be minimal.

Directives

Take a look at a very basic AngularJS directive. Let’s name this file appInfo.js as well as create an .html file appInfo.html as in example below.

Learn AngularJS 1.X   Codecademy.png

In this example we create a new directive called appInfo. It returns an object with three options – restrict, scope and templateURL

  1. restrict specifies how the directive will be used in the view. The 'E' means it will be used as a new HTML element.
  2. scope specifies that we will pass information into this directive through an attribute named info. The = tells the directive to look for an attribute named info in the <app-info> element, like this: The data in info becomes available to use in the template given by templateURL.
  3. templateUrl specifies the HTML to use in order to display the data in scope.info. Here we use the HTML in js/directives/appInfo.html.

Then we need to build a structure to directive in our appInfo.html

<h2 class="title">{{ info.title }}</h2> 
<p class="developer">{{ info.developer }}</p> 
<p class="price">{{ info.price | currency }}</p>

Of course <h2> and <p> are just examples. You can use here what you only want. The title and developer are controller $scope.elements. Let’s take a look at controller’s content.

$scope.apps = [ 
 { 
 title: 'MOVE', 
 developer: 'MOVE, Inc.', 
 price: 0.99 
 }, 
 { 
 title: 'Shutterbugg', 
 developer: 'Chico Dusty', 
 price: 2.99 
 }, 
]

In index.html we use only  ng-repeat to loop through app element in $scope.apps, and then app-info info=”app”

<div ng-repeat="app in apps">
     <app-info info="app"></app-info>
</div>

That’s it. It’s quite a simple example, but it helps me to refactor my code in CommonsNet project and avoid a long, boring, repetitive work while adding new elements to website. It also helps me to implement a feature I have mentioned above. I’am going to tell more about it in next blog post. Stay tuned!

Resources:

https://scotch.io/tutorials/angularjs-best-practices-directory-structure

https://www.codecademy.com/learn/learn-angularjs.

https://commonsnetblog.wordpress.com/

 

Using the new Awareness API

Google released the new Awareness API for everyone, a suite of signals concurring to gives the developer the context in which our user is, all as part of the Play Services 9.2.0, already available on Android devices around the globe.

This library combines 7 different feeds managing both the battery drain and the used memory, providing us with data such as user location, weather, time, headphones connection status, places, nearby beacons and currently performing activity.

INTRO

The Awareness API comes with two different versions, one is a callback based one (Fence API) and the other one is a polling based one (Snapshot API): while the first one will notify us when the conditions we specified are met, the second expects us to query the suite for the data from a unified interface.

There are 7 kinds of context that we can work with in Awareness API such as

Time — Local time at current user’s location

Location — Latitude/Longitude

Place — Places around user

Activity — Detected user activity (biking, walking, running, etc.)

Beacons — Check nearby beacon(s)

Headphones — Are headphones plugged in?

Weather — Current weather conditions

Now the Two set’s of API’s :

  • Snapshot API — Allows you to “request an information based on user’s context” as listed above.
  • Fence API — Allows you to “receive a signal when user’s context has changed and reaches the condition” through callback function, for example, if user moves closed to the specific coordinate with headphones plugged in, Fench API will call the registered BroadcastReceiver and let you do your job.

Getting started

  1. Create a project in https://console.developers.google.com (or in case you already have one, you can use it instead)
  2. And then browse to API Manager page and search for Awareness and click at Awareness API and Click Enable and wait until it finishes enabling

3. Go to Credentials tab and click at Create credentials -> API key -> Android key. Enter the name you project, for example, Android key and click Create (or if you have already created Android key previously, you could skip this step and use the existed one)

4. Add dependency in build.gradle

compile 'com.google.android.gms:play-services-contextmanager:9.2.0'

5. Open AndroidManifest.xml file and add meta-data to <application> tag like this:

        <meta-data
            android:name="com.google.android.awareness.API_KEY"
            android:value="YOUR_KEY" />
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="YOUR_KEY" />
        <meta-data
            android:name="com.google.android.nearby.messages.API_KEY"
            android:value="YOUR_KEY" />

We also need to add permissions for this:

6. Open AndroidManifest.xml

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />

Now we come to the actual java code. open your activity and initialise the GoogleApiClient in onCreate()

private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_layout);

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Awareness.API)
                .build();
        mGoogleApiClient.connect();
    }

So this ends the setup part. Now we move on to the actual data retrieval from the API.

Accessing Snapshot API

Awareness.SnapshotApi.getDetectedActivity(mGoogleApiClient)
                .setResultCallback(new ResultCallback<DetectedActivityResult>() {
                    @Override
                    public void onResult(@NonNull DetectedActivityResult detectedActivityResult) {
                        if (!detectedActivityResult.getStatus().isSuccess()) {
                            Log.e(TAG, "Could not get the current activity.");
                            return;
                        }
                        ActivityRecognitionResult ar = detectedActivityResult.getActivityRecognitionResult();
                        DetectedActivity probableActivity = ar.getMostProbableActivity();
                        Log.i(TAG, probableActivity.toString());
                    }
                });

This will return the most probable activity done by the user. We can get a particular activity like walking, running, driving as well by integers defined below

    public static final int IN_VEHICLE = 0;
    public static final int ON_BICYCLE = 1;
    public static final int ON_FOOT = 2;
    public static final int STILL = 3;
    public static final int UNKNOWN = 4;
    public static final int TILTING = 5;
    public static final int WALKING = 7;
    public static final int RUNNING = 8;

Similarly we can also get Headphone state, location, weather, beacon etc.

For example let’s see headphone state:

Awareness.SnapshotApi.getHeadphoneState(mGoogleApiClient)
                .setResultCallback(new ResultCallback<HeadphoneStateResult>() {
                    @Override
                    public void onResult(@NonNull HeadphoneStateResult headphoneStateResult) {
                        if (!headphoneStateResult.getStatus().isSuccess()) {
                            Log.e(TAG, "Could not get headphone state.");
                            return;
                        }
                        HeadphoneState headphoneState = headphoneStateResult.getHeadphoneState();
                        if (headphoneState.getState() == HeadphoneState.PLUGGED_IN) {
                            Log.i(TAG, "Headphones are plugged in.\n");
                        } else {
                            Log.i(TAG, "Headphones are NOT plugged in.\n");
                        }
                    }
                });

This is same as acquiring activity and headphoneState.getState() will give you if it is plugged in or not

Now we take a look at the Fence API

Fence is similar to the geofence but in addition to geofence, the fence API also allows us to set awareness conditions and check if both conditions are true.

We use a BroadcastReceiver

private static final String FENCE_RECEIVER_ACTION = "FENCE_RECEIVE";

    private HeadphoneFenceBroadcastReceiver fenceReceiver;
    private PendingIntent mFencePendingIntent;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        fenceReceiver = new HeadphoneFenceBroadcastReceiver();
        Intent intent = new Intent(FENCE_RECEIVER_ACTION);
        mFencePendingIntent = PendingIntent.getBroadcast(MainActivity.this,
                10001,
                intent,
                0);
    }

    private void registerFences() {
        // Create a fence.
    }

    private void unregisterFence() {
    }

    @Override
    protected void onStart() {
        super.onStart();
        registerFences();
        registerReceiver(fenceReceiver, new IntentFilter(FENCE_RECEIVER_ACTION));
    }

    @Override
    protected void onStop() {
        super.onStop();
        unregisterFences();
        unregisterReceiver(fenceReceiver);
    }

    class HeadphoneFenceBroadcastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {

        }

    }

Here when we get message in onReceive() and we can detect if headphone is connected or not. Something like this

FenceState fenceState = FenceState.extract(intent);

            Log.d(TAG, "Fence Receiver Received");

            if (TextUtils.equals(fenceState.getFenceKey(), "headphoneFenceKey")) {
                switch (fenceState.getCurrentState()) {
                    case FenceState.TRUE:
                        Log.i(TAG, "Fence > Headphones are plugged in.");
                        break;
                    case FenceState.FALSE:
                        Log.i(TAG, "Fence > Headphones are NOT plugged in.");
                        break;
                    case FenceState.UNKNOWN:
                        Log.i(TAG, "Fence > The headphone fence is in an unknown state.");
                        break;
                }
            }

So as you can see this is pretty straight forward and very useful. You can build so many apps with multiple fences. You can think of a lot of usecases for this and make a lot of amazing apps. Happy Tinkering with the Awareness API!

Integrating Travis CI and Codacy in PSLab Repositories

Continuous Integration Testing and Automated Code Review tools are really useful for developing better software, improving code and overall quality of the project. Continuous integration can help catch bugs by running tests automatically and to merge your code with confidence.

While working on my GsoC-16 project, my mentors guided and helped me to integrate Travis CI and Codacy in PSLab github repositories. This blog post is all about integrating these tools in my github repos, problems faced, errors occurred and the test results.

travisTravis CI is a hosted continuous integration and deployment system. It is used to build and test software projects hosted on github. There are two versions of it, travis-ci.com for private repositories, and travis-ci.org for public repositories.

Read : Getting started with Travis CI

Travis is configured with the “.travis.yml” file in your repository to tell Travis CI what to build. Following is the code from ‘.travis.yml‘ file in our PSLab repository. This repo contains python communication library for PSLab.

language: python
python:
  - "2.6"
  - "2.7"
  - "3.2"
  - "3.3"
  - "3.4"
# - "3.5"
# command to install dependencies
# install: "pip install -r requirements.txt"
# command to run tests
script: nosetests

With this code everything worked out of the box (except few initial builds which errored because of missing ‘requirements.txt‘ file) and build passed successfuly 🙂 🙂

Later Mario Behling added integration to FOSSASIA Slack Channel.

Slack notifications

Travis CI supports notifying  Slack channels about build results. On Slack, set up a new Travis CI integration. Select a channel, and you’ll find the details to paste into your ‘.travis.yml’. Just copy and paste the settings, which already include the proper token and you’re done.

The simplest configuration requires your account name and the token.

notifications:
  slack: '<account>:<token>'     
notifications:
  slack: fossasia:***tokenishidden****

Import errors in Travis builds of PSLab-apps Repository

PSLab-apps repository contains PyQt bases apps for various experiments. The ‘.travis.yml‘ file mentioned above gave several module import errors.

$ python --version
Python 3.2.5
$ pip --version
pip 6.0.7 from /home/travis/virtualenv/python3.2.5/lib/python3.2/site-packages (python 3.2)
Could not locate requirements.txt. Override the install: key in your .travis.yml to install dependencies.
0.33s$ nosetests
E
======================================================================
ERROR: Failure: ImportError (No module named sip)

The repo is installable and PSLab was working fine on popular linux distributions without any errors. I was not able to find the reason for build errors. Even after adding proper ‘requirements.txt‘ file,  travis builds errored.

On exploring the documentation I could figure out the problem.

Travis CI Environment uses separate virtualenv instances for each Python version. System Python is not used and should not be relied on. If you need to install Python packages, do it via pip and not apt. If you decide to use apt anyway, note that Python system packages only include Python 2.7 libraries (default python version). This means that the packages installed from the repositories are not available in other virtualenvs even if you use the –system-site-packages option. Therefore I was getting Import module errors.

This problem was solved by making following changes in the ‘.travis.yml‘ file

language: python

python:
  #- "2.6"
  - "2.7"
  #- "2.7_with_system_site_packages"
  - "3.2"
  #- "3.2_with_system_site_packages"
  - "3.3"
  - "3.4"
before_install:
    - sudo mkdir -p /downloads
    - sudo chmod a+rw /downloads
    - curl -L http://sourceforge.net/projects/pyqt/files/sip/sip-4.16.5/sip-4.16.5.tar.gz -o /downloads/sip.tar.gz 
    - curl -L http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.3/PyQt-x11-gpl-4.11.3.tar.gz -o /downloads/pyqt4.tar.gz
    # Builds
    - sudo mkdir -p /builds
    - sudo chmod a+rw /builds

install:
    - export DISPLAY=:99.0
    - sh -e /etc/init.d/xvfb start
    - sudo apt-get install -y libqt4-dev
    - sudo apt-get install -y mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev
#    - sudo apt-get install -y python3-sip python3-sip-dev python3-pyqt4 cmake
    # Qt4
    - pushd /builds
    # SIP
    - tar xzf /downloads/sip.tar.gz --keep-newer-files
    - pushd sip-4.16.5
    - python configure.py
    - make
    - sudo make install
    - popd
    # PyQt4
    - tar xzf /downloads/pyqt4.tar.gz --keep-newer-files
    - pushd PyQt-x11-gpl-4.11.3
    - python configure.py -c --confirm-license --no-designer-plugin -e QtCore -e QtGui -e QtTest
    - make
    - sudo make install
    - popd
 # - "3.5"
# command to install dependencies
#install: "pip install -r requirements.txt"
# command to run tests
script: nosetests

notifications:
  slack: fossasia:*****tokenishidden*******


codacy

Codacy is an automated code analysis and review tool that helps developers ship better software, faster. With Codacy integration one can get static analysis, code complexity, code duplication and code coverage changes in every commit and pull request.

Read : Integrating Codacy in github is here.

Codacy integration has really helped me to understand and enforce code quality standard. Codacy gives you impact of every pull request in terms of quality and errors directly into GitHub.

codacy check

Codacy also grades your project in different categories like Code Complexity, Compatibility, security, code style, error prone etc. to help you better understand the overall project quality and what are the areas you should improve.

Here is a screen-shot of Codacy review for PSLab-apps repository.

codacyreport

I am extremely happy to share that my learning adventure has got  Project Certification at ‘A’ grade. Project quality analysis shows that more than 90% of the work has A grade 🙂 🙂

Travis CI and Codacy Badges for my GSoC Repositories:

PSLab : Python Library for Communication with PSLab

Travis CI Badge         Codacy Badge

PSLab-apps : Qt based GUI applications for PSLab

Travis CI Badge         Codacy Badge

Pocket Science Lab : ExpEYES Programs, Sensor Plugins

Travis CI Badge         Codacy Badge

That’s all for now. Have a happy coding, testing and learning 🙂 🙂

Twitter Section Using loklak webtweets

In Open event web app, the user can provide URL of social links such as Twitter, Facebook etc in the event.json file inside the ZIP. The previous functionality was to use Twitter API and to generate a timeline showing the tweets of the twitter URL mentioned in event.json by user. But, it can be done by following another approach which reduces the third party dependency i.e Loklak-webtweets.

I have implemented the twitter section using loklak webtweets which can be done very easily.

Step 1:  Including necessary files from loklakwebtweets repository inside index.html. You can find them in js/ folder of this repository.

<script src="./dependencies/jquery.min.js"></script>
<script src="./dependencies/bootstrap.min.js" type="text/javascript"></script>
<script src="./dependencies/loklak-fetcher.js" type="text/javascript"></script>
 <script src="./dependencies/tweets.js" type="text/javascript"></script>

 

Step 2:  Specify the data source in HTML from which twitter data will be fetched. Here I have extracted the last word from the twitter URL provided by the user and passed it to HTML.

const sociallinks = Array.from(event.social_links);
 var twitter ="";
 sociallinks.forEach((link) => {
  if(link.name.toLowerCase() === "twitter") {
   twitter = link.link;
  }
 }) 
 const arrayTwitterLink = sociallink.split('/');
 const twitterLink = arrayTwitterLink[arrayTwitterLink.length - 1];
 
 const urls= {
   twitterLink: twitterLink,
   tweetUrl: twitter,
 };

This code will search twitter link in social links array present in event.json and get its last character which will be provided to data-from and data-query attribute of HTML.

 <section class="sponsorscont">
  <div class="tweet-row">
   <div class="col-sm-12 col-md-12 col-xs-12">
    <i class ="social_twitter fa fa-twitter"></i>
     <div class="tweets-feed" id="tweets" data-count=50 data-query="    {{{eventurls.twitterLink}}}" data-from="{{{eventurls.twitterLink}}}">
     <div class="arrow-up"></div>
      <p id="tweet" class="tweet">
       Loading...
     </p>
   <span style="margin-bottom: 20px;" id="dateTweeted"></span>
    <p>Follow<u>
    <b><a href="{{eventurls.tweetUrl}}"/>
     @{{eventurls.twitterLink}}</a>
    </b></u> for more updates</p> 
     </div> 
    </div>
  </div>
</section>

Step 3 : Now we just need to add styling so that it looks decent. For that, I have written some SASS.

.tweets-feed {
   color: $black;
   line-height: 30px;
   font-size: 20px;
   transition: opacity 0.2s linear;
   margin-bottom: 20px;
   height: 100px;
 
  a {
   color: $black;
   text-decoration: underline;
   font-weight: 700;
  } 

  #dateTweeted {
   font-size: 15px;
   display: block;
  }

}

.tweet-row {
   padding: 0 80px;
   margin-bottom: 80px;
   .social_twitter {
     font-size: 60px;
     margin-bottom: 12px;
  }
}

The output from the above code is a well designed Twitter section fetching tweets from the URL provided as a string in event.json by user.

tweet

 

Handling data in android

So this week I was working with getting some data from the sqlite database in android and someone who was a beginner in android also asked me to help him with the same. I asked him what he knew and he said that even after reading up a lot he wasn’t able to figure out what exactly to do with the data he wants to save and use in his app. I have seen that this is a problem with a lot of people starting to develop android apps. So, I decided to write a blog on how can you handle your data in your android apps.

Most of the android apps need to save data even if only to save some user preferences. So primarily there are 3 ways to save your data :

  1. In form of key values (SharedPreferences)
  2. Reading/Writing to files
  3. Writing to a database

So let’s go step by step. When we need to store just some preferences of the users like if they want notifications or what kind of theme they want : light or dark etc. So basically if we want to store a key value in the persitant storage of the app we can do that using SharedPreferences. To use sharedpreferences, we initialise the sharedpreference object like

SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

in oncreate and cache it. Then we just need to add or retrieve what we want using this cached SharedPreferences object. To Add a key value pair :

sharedPreferences.edit().putString("someKey", "someValue").apply();

Also you can put all kinds of stuff here. For example right now we added a string with key “someKey” and Value “someValue”. We can also add Booleans, Floats, Ints, Longs, StringSets etc.

To retrieve the same value we do something like this

sharedPreferences.getString("someKey", "DefaultValue");

Now if you want some logs or some values that can be exported and sent to your server, you should write them to files and maybe read some json inputs etc. as well.

Basically android has a File system similar to other platforms. All android devices have two file storage areas : “Internal” and “external” storage. The difference between them is as follows :

Internal :

  • Always available
  • Files saved here are accesible by only your app
  • When user uninstalls the app, system removes all your app’s files from internal storage

Best to use this when you want to be sure that neither the user nor the other app’s can access your files

External :

  • It’s not always available because user can mount external storage as USB storage and remove it as well
  • It’s readable by anything(Other apps, users etc.)
  • When you uninstall, system removes your app’s files from here only if you save them in the directory from getExternalFilesDir()

Now to read and write files, you need extra permissions

  • android.permission.WRITE_EXTERNAL_STORAGE
  • android.permission.READ_EXTERNAL_STORAGE

So now let’s get down to it. How do I save and read files in my app?

You first initialise the File object

File file = new File(context.getFilesDir(), filename);

This will create a file with filename in the internal storage. For external storage

first check if the storage is available, then just create a file using getExternalStoragePublicDirectory

File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;

This is for writing public files.

Now we move onto the most used part in an android app which is a database.Android has a built in SQLite database package which helps us in writing databases in files with syntax similar to SQL.

You need to add 2 classes which are mandatory and another class which basically helps you get organised. So the first is a Contract. This is where you actually write statements that will be executed later on to initialise or create the tables we want. For this make an a static abstract inner class that implements BaseColums like

public static abstract class Microlocation implements BaseColumns {
    public static final String TABLE_NAME = "microlocation";

    public static final String ID = "id";

    public static final String NAME = "name";

    public static final String LATITUDE = "latitude";

    public static final String LONGITUDE = "longitude";

    public static final String FLOOR = "floor";

    public static final String[] FULL_PROJECTION = {
            ID,
            NAME,
            LATITUDE,
            LONGITUDE,
            FLOOR

    };

    public static final String CREATE_TABLE =
            "CREATE TABLE " + TABLE_NAME
                    + " ("
                    + ID + INT_TYPE + PRIMARY_KEY + COMMA_SEP
                    + NAME + TEXT_TYPE + COMMA_SEP
                    + LATITUDE + REAL_TYPE + COMMA_SEP
                    + LONGITUDE + REAL_TYPE + COMMA_SEP
                    + FLOOR + INT_TYPE
                    + " );";

    public static final String DELETE_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;


}

Here we are making static final Strings for column names and then creating a static final String CREATE_TABLE which is basically a statement that creates the table Microlocation with the specified key, columns, data types etc.

After adding this structure for all the tables we want to have in our database, we move on to adding a DbHelper class that extends SQLiteOpenHelper which basically has two Abstract methods called onCreate(SQLiteDatabase db) and onUpgrade(SQLiteDatabase db) which are called when the database is created and database version is changed respectively. We call all our CREATE_TABLE static Strings in onCreate which in turn creates all the tables. Something like this :

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(DbContract.Speakers.CREATE_TABLE);
    db.execSQL(DbContract.Sponsors.CREATE_TABLE);
    db.execSQL(DbContract.Sessions.CREATE_TABLE);
    db.execSQL(DbContract.Tracks.CREATE_TABLE);
    db.execSQL(DbContract.Sessionsspeakers.CREATE_TABLE);
    db.execSQL(DbContract.Event.CREATE_TABLE);
    db.execSQL(DbContract.Microlocation.CREATE_TABLE);
    db.execSQL(DbContract.Versions.CREATE_TABLE);
    db.execSQL(DbContract.Bookmarks.CREATE_TABLE);
    db.execSQL(DbContract.EventDates.CREATE_TABLE);
}

You can also call DELETE_TABLE Strings in onUpgrade and the call onCreate again if you like but it’s not compulsory.

Now that you’re database is initialised, let’s add some records into it. For example I have to add a new Micrlocation I’d create a method in my data model where I’ll add a basic structure for the query and then format it with the values for a particular object of the model. Something, like this

public String generateSql() {
    String insertQuery = "INSERT INTO %s VALUES ('%d', %s, '%f', '%f', '%d');";
    return String.format(Locale.ENGLISH,
            insertQuery,
            DbContract.Microlocation.TABLE_NAME,
            id,
            DatabaseUtils.sqlEscapeString(StringUtils.optionalString(name)),
            latitude,
            longitude,
            floor);
}

and then I’d execute the string returned by the call

String query = model.generateSql();

by this

public void insertQuery(String query, DbHelper mDbHelper) {
    SQLiteDatabase db = mDbHelper.getWritableDatabase();
    db.beginTransaction();
    db.execSQL(query);
  
    db.setTransactionSuccessful();
    db.endTransaction();
}

Where db is just a SQLiteDatabase instance.

Now that we have records we want to retrieve them according to usage and for that we create helper methods. This is an example of the retrieving all the microlocations added to the database in ASCENDING order of NAME

public ArrayList<org.fossasia.openevent.data.Microlocation> getMicrolocationsList(SQLiteDatabase mDb) {
    String sortOrder = DbContract.Microlocation.NAME + ASCENDING;
    Cursor cursor = mDb.query(
            DbContract.Microlocation.TABLE_NAME,
            DbContract.Microlocation.FULL_PROJECTION,
            null,
            null,
            null,
            null,
            sortOrder
    );

    ArrayList<org.fossasia.openevent.data.Microlocation> microlocations = new ArrayList<>();
    org.fossasia.openevent.data.Microlocation microlocation;

    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
        microlocation = new org.fossasia.openevent.data.Microlocation(
                cursor.getInt(cursor.getColumnIndex(DbContract.Microlocation.ID)),
                cursor.getString(cursor.getColumnIndex(DbContract.Microlocation.NAME)),
                cursor.getFloat(cursor.getColumnIndex(DbContract.Microlocation.LATITUDE)),
                cursor.getFloat(cursor.getColumnIndex(DbContract.Microlocation.LONGITUDE)),
                cursor.getInt(cursor.getColumnIndex(DbContract.Microlocation.FLOOR))
        );
        microlocations.add(microlocation);
        cursor.moveToNext();
    }
    cursor.close();
    return microlocations;
}

First we create a cursor and then just iterate of the cursor to get microlocation objects and add them to an Arralist and return the Arraylist to the calling method.

So This are most of the things that are there to handling data in Android. Should be sufficient to get you started.

Sorry for the long post but the content couldn’t be made any smaller but I hope you gain something from this post. You can checkout implementations I have followed for the Open event project in the github repo https://github.com/fossasia/open-event-android. You can also write to me anytime on FB, Twitter, Email etc. and I’ll be happy to answer any queries. Adios!

References : 1) developers.android.com

2) https://github.com/fossasia/open-event-android

Responsive Image Overlay

Image overlay is a very common concept in front-end development. It is easy to implement but difficult when we deal it with different screen sizes, where we need to cover the image with the overlay each time the screen size is changed. I have gone through various blog posts when I need to implement the same for Open-event webapp and researched a solution that works for all screen sizes without any media query.

1234

How to add an overlay to an image ?

If we need four images in a single row nearly 300*300px.  The code below shows the markup.

image-holder : The parent class to take the image and overlay inside it.

background-image: This class takes image source.

responsive-overlay: This is the key point to make it responsive. Responsive-overlay contains a class hover-state to add overlay absolutely and a class social-links.

social-links: It adds content to hover-state.

 

<div class="image-holder">
  <img class="background-image" alt="" src="">
   <div class="responsive-overlay">
     <div class="hover-state text-center preserve3d">
       <div class="social-links vertical-align">

       </div>
     </div>
   </div>
 </div>

The styling is written with SASS in .scss file as shown below.

//overlayimage and backgroundshade can be set in config.scss

 .image-holder {
   position: relative;
   overflow: hidden;
   margin-bottom: 12px;

   .background-image {
     height: 300px;
     width: 300px;
     display: block;
     margin: 0 auto;
     background-color: $background-shade;
    }
 
   .responsive-overlay {
     @include responsiveoverlay;

    .preserve3d {
       height: 300px;
      }

    .hover-state {
     @include hoverstate;
     height: 300px;
     width: 300px;
    }

  @mixin responsiveoverlay {
     height: 100%;
     position: absolute;
     top: 0;
     width: 100%;
}

   @mixin hoverstate {
     background: $overlayimage;
     display: block;
     height: 300px;
     left: 0;
     margin: 0 auto;
     opacity: 0;
     position: relative;
     top: 0;
     -moz-transition: all 0.3s ease-out;
     -webkit-transition: all 0.3s ease-out;
     transition: all 0.3s ease-out;
     width: 300px;
     z-index: 2;
   }

This code will work for responsiveness as well. The main catch here is the responsive-overlay class which is made 100% in width but set to position absolute. The images which are 300 * 300 px in size will take an overlay of the same size because of hover-state class. Instead, if we adjust sizes of images in small screens the above code will adjust overlay on the image automatically.

Like, on tablets we can have an overlay like this.

345

And on mobile screen output is like that :

23

Conclusion

Responsiveness is easy if we follow correct concepts. Here, the concepts of absolute and relative positioning in CSS have done the magic. Now we can play by adding different contents and effect on hover following the same basics.

Multiple Tickets: Back-end

In my previous post I talked about approach for Multiple Ticket feature’s user-interface [Link]. In this post I’ll discuss about Flask back-end used for saving multiple tickets.

HTML Fields Naming

Since the number of Tickets a user creates is unknown to the server, details of tickets were needed to be sent as an array of values. So the server would accept the list of values and iterate over them. To send data as an array the naming had to include brackets. Below are some input fields used in tickets:

<tr>
    <td>
        <input type="hidden" name="tickets[type]">
        <input type="text" name="tickets[name]" class="form-control" placeholder="Ticket Name" required="required" data-uniqueticket="true">
        <div class="help-block with-errors"></div>
    </td>
    <td>
        <input type="number" min="0" name="tickets[price]" class="form-control"  placeholder="$" value="">
    </td>
    <td>
        <input type="number" min="0" name="tickets[quantity]" class="form-control" placeholder="100" value="{{ quantity }}">
    </td>
    <!-- Other fields -->
</tr>

At the server

When the POST request reaches the server, any of the above fields (say tickets[name]) would be available as a list. The Flask Request object includes a form dictionary that contains all the POST parameters sent with the request. This dictionary is an ImmutableMultiDict object, which has a getlist method to get array of elements.

For instance in our case, we can get tickets[name] using:

@expose('/create', methods=('POST', 'GET'))
def create_view(self):
    if request.method == 'POST':
        ticket_names = request.form.getlist('tickets[name]')

    # other stuff

The ticket_names variable would contain the list of all the Ticket names sent with the request. So for example if the user created three tickets at the client-side, the form would possibly look like:

<form method="post">
  <!-- Ticket One -->
  <input type="text" name="tickets[name]" class="form-control" value="Ticket Name One">
  <!-- Ticket Two -->
  <input type="text" name="tickets[name]" class="form-control" value="Ticket Name Two">
  <!-- Ticket Three -->
  <input type="text" name="tickets[name]" class="form-control" value="Ticket Name Three">

</form>

After a successful POST request to the server, ticket_names should contain ['Ticket Name One', 'Ticket Name Two', 'Ticket Name Three'].

Other fields, like tickets[type], tickets[price], etc. can all be extracted from the Request object.

Checkbox Fields

A problem arose when a checkbox field was needed for every ticket. In my case, a “Hide Ticket” option was needed to let the user decide if he wants the ticket to be shown at the public Events page.

Screenshot from 2016-08-13 12:39:29

The problem with checkboxes is that, for a checkbox of a particular name attribute, if it is not selected, POST parameters of the request made by the client will not contain the checkbox input field parameter. So if I define an input field as a checkbox with the following naming convention, and make a POST request to the server, the server will receive blah[] parameter only if the input element had been checked.

<input type="checkbox" name="blah[]" >

This creates a problem for “Hide ticket” checkboxes. For instance, at the client-side the user creates three tickets with the first and last tickets having their checkboxes selected, the server would get an array of two.

<form>
  <!-- Ticket One -->
  <input type="checkbox" name="tickets[hide]" checked>
  <!-- Ticket Two -->
  <input type="checkbox" name="tickets[hide]">
  <!-- Ticket Three -->
  <input type="checkbox" name="tickets[hide]" checked>

</form>
ticket_hide_opts = request.form.getlist('tickets[hide]')

ticket_hide_opts would be an array of length two. And there is no way to tell what ticket had its “Hide ticket” option checked. So for the hide checkbox field I had to define input elements with unique names to extract them at the server.

There is also a hack to overcome the unchecked-checkbox problem. It is by using a hidden field with the same name as the checkbox. You can read about it here: http://www.alexandrejoseph.com/blog/2015-03-03-flask-unchecked-checkbox-value.html.

Multiple Tickets: User Interface

An Event can have multiple tickets for different purposes. For instance an Arts Exhibition can have multiple Galleries. The Organizer might be interested in assigning a ticket (let’s assume paid) for each Gallery. The user can then buy tickets for the Galleries that he wishes to attend. The feature that Multiple Tickets really provide is exclusiveness. Let’s say Gallery1 has a shorter area (by land) than others. Obviously the Organizer would want fewer people to be present there than other Galleries. To do this, he can create a separate ticket for Gallery1 and specify a shorter sales period. He can also reduce the Maximum number of order that a user can make (max_order). If we would have implemented single ticket per event, this wouldn’t have been possible.

Tickets at Wizard

To handle multiple tickets at the wizard, proper naming of input tags was required. Since the number of tickets that can be created by the user was unknown to the server we had to send ticket field values as lists. Also at the client-side a way was required to let users create multiple tickets.

User Interface

A ticket can be of three types: Free, Paid and Donation. Out of these, only the Paid tickets need a Price. The Tickets holder could be a simple table, with every ticket being a table row. This became more complex afterwards, when more details about the ticket needed to be displayed. A ticket would then be two table rows with one of them (details) hidden.

Ticket holder can be a simple bootstrap table:

<table class="table tickets-table">
    <thead>
        <tr>
            <th>Ticket Name</th>
            <th>Price</th>
            <th>Quantity</th>
            <th>Options</th>
        </tr>
    </thead>
    <tbody>
      <!-- Ticket -->
      <tr>
        <!-- Main info -->
      </tr>
      <tr>
        <!-- More details (initially hidden) -->
      </tr>
      <!-- /Ticket -->
    </tbody>
</table>

To make ticket creation interactive, three buttons were needed to create the above three tickets. The type-name doesn’t not necessarily have to be shown to the user. It could be specified with the Price. For Paid ticket, the Price input element would be a number. For Free and Donation tickets, a Price input element wasn’t required. We could specify an element displaying one of the two types: Free or Donation.

Here’s the holder table with a Free Ticket and a Donation Ticket:

Screenshot from 2016-08-09 16:51:06

Since only the Price field is changing in the three types of tickets, I decided to create a template ticket outside of the form and create a JavaScript function to create one of the tickets by cloning the template.

A Free Ticket with its edit options opened up. You can see other details about the ticket in the second table row.

Screenshot from 2016-08-09 16:52:14

This is a simplified version of the template. I’ve removed common bootstrap elements (grid system) including some other fields.

<div id="ticket-template">
<tr>
    <td>
        <input type="hidden" name="tickets[type]">
        <input type="text" name="tickets[name]" class="form-control" placeholder="Ticket Name" required="required" data-uniqueticket="true">
        <div class="help-block with-errors"></div>
    </td>
    <td>
        <!-- Ticket Price -->
    </td>
    <td>
        <input type="number" min="0" name="tickets[quantity]" class="form-control" placeholder="100" value="{{ quantity }}">
    </td>
    <td>
        <div class="btn-group">
            <a class="btn btn-info edit-ticket-button" data-toggle="tooltip" title="Settings">
                <i class="glyphicon glyphicon-cog"></i>
            </a>
            <a class="btn btn-info remove-ticket-button" data-toggle="tooltip" title="Remove">
                <i class="glyphicon glyphicon-trash"></i>
            </a>
        </div>
    </td>
</tr>
<tr>
    <td colspan="4">
        <div class="row" style="display: none;">
            <!-- Other fields including Description, Sales Start and End time,
              Min and Max Orders, etc.
            -->
        </div>
    </td>
</tr>
</div>

Like I said, the Price element of ticket will make the type obvious for the user, so a type field does not need to be displayed. But the type field is required by the server. You can see it specified as hidden in the template.

The function to create a Ticket according to the type:

I’ve commented snippets to make it easy to understand.

function createTicket(type) {
    /* Clone ticket from template */
    var $tmpl = $("#ticket-template").children().clone();

    var $ticket = $($tmpl[0]).attr("id", "ticket_" + String(ticketsCount));
    var $ticketMore = $($tmpl[1]).attr("id", "ticket-more_" + String(ticketsCount));

    /* Bind datepicker and timepicker to dates and times */
    $ticketMore.find("input.date").datepicker();
    $ticketMore.find("input.time").timepicker({
        'showDuration': true,
        'timeFormat': 'H:i',
        'scrollDefault': 'now'
    });

    /* Bind iCheck to checkboxes */
    $ticketMore.find("input.checkbox.flat").iCheck({
        checkboxClass: 'icheckbox_flat-green',
        radioClass: 'iradio_flat-green'
    });

    /* Bind events to Edit (settings) and Remove buttons */
    var $ticketEdit = $ticket.find(".edit-ticket-button");
    $ticketEdit.tooltip();
    $ticketEdit.on("click", function () {
        $ticketMore.toggle("slow");
        $ticketMore.children().children(".row").slideToggle("slow");
    });

    var $ticketRemove = $ticket.find(".remove-ticket-button");
    $ticketRemove.tooltip();
    $ticketRemove.on("click", function () {
        var confirmRemove = confirm("Are you sure you want to remove the Ticket?");
        if (confirmRemove) {
            $ticket.remove();
            $ticketMore.remove();
        }
    });

    /* Set Ticket Type field */
    $ticket.children("td:nth-child(1)").children().first().val(type);

    /* Set Ticket Price field */
    var html = null;
    if (type === "free") {
        html = '';
    } else if (type === "paid") {
        html = '';
    } else if (type === "donation") {
        html = '';
    }
    $ticket.children("td:nth-child(2)").html(html);

    /* Append ticket to table */
    $ticket.hide();
    $ticketMore.children().children(".row").hide();
    $ticketsTable.append($ticket, $ticketMore);
    $ticket.show("slow");

    ticketsCount += 1;
  }

The flow is simple. Clone the template, bind events to various elements, specify type and price fields and then append to the ticket holder table.

Screenshot from 2016-08-09 17:00:59

We use the Datepicker and Timepicker JavaScript libraries for date and time elements. So fields using these widgets need to have methods called on the elements. Also, we use iCheck for checkboxes and radio buttons. Apart from these, the Edit-Ticket and Remove-Ticket buttons also need event handlers. Edit-Ticket button toggles the Ticket Details segment (second tr of a ticket). Remove-Ticket deletes the ticket. After the Price and Type fields are set, the ticket is appended to the holder table with slow animation.