Snackbar Implementation in PSLab Android App

In PSLab android app we have developed the functionality of logging sensor data in CSV format. We can start and stop the data recording using the save button in the upper right corner of the menu bar and toast message was shown to notify the user for logging status whether it is started or stopped but it leads to some problem like:-

  • The user doesn’t know where the logged file has been created in the external storage.
  • If the user accidentally clicked on the save button the data logging will start the user have to manually go the storage location and delete the recently created unwanted CSV file.

What’s the solution?

The solution to both these problem is solved by implementing Snackbar instead of Toast message.

According to Material Design documentation:-

The Snackbar widget provides brief feedback about an operation through a message at the bottom of the screen. Snackbar disappears automatically, either after a timeout or after a user interaction elsewhere on the screen, and can also be swiped off the screen.

Snackbar can also offer the ability to perform an action, such as undoing an action that was just taken or retrying an action that had failed.

 

Figure 1 shows a Snackbar sample
(Source: – https://material.io/develop/android/components/snackbar/ )

 

To implement the Snackbar in our Android app I started by creating a custom snack bar class which contains all the code to create and show the Snackbar on the screen.

public class CustomSnackBar {

   public static void showSnackBar(@NonNull CoordinatorLayout holderLayout,  
                                   @NonNull String displayText,
                                   String actionText, 
                                   View.OnClickListener clickListener){
       
   Snackbar snackbar =     
              Snackbar.make(holderLayout,displayText,Snackbar.LENGTH_LONG)
              .setAction(actionText, clickListener);

  //do your customization here
}

The custom class contains a static method ‘showSnackBar()’ having parameters:

Parameter Return Type Description
holderLayout CoordinatorLayout Container layout in which the snack bar will be shown at the bottom (should not be null)
displayText String Text to be displayed in the content of Snackbar (should not be null)
actionText String Clickable text which has some action associated with it
clickListener View.OnClickListener On click listener specifying an action to be performed when actionText is clicked

 

Inside the method, I called the static make()  method provided by the Snackbar class and passed holderlayout, displayText and duration of Snackbar in this case Snackbar.LENGTH_LONG as parameters.

Then I called setAction() and passed in the actionText and the clickListener as parameters in it to set the action text. If we pass in null no action text will be generated.

Then, if we want to changes the action text color we can do that by calling setActionTextColor() and passing in the desired color.

snackbar.setActionTextColor(ContextCompat.getColor(holderLayout.getContext(), R.color.colorPrimary));

And if we want to change the content text color then we need to first get the view then we need to get the instance of TextView containing the content text using findViewById() and passing android.support.design.R.id.snackbar_text which is default ID for context TextView, and then call setTextColor() to set the desired color.

View sbView = snackbar.getView();
   TextView textView =     
             sbView.findViewById(android.support.design.R.id.snackbar_text);
       textView.setTextColor(Color.WHITE);
   }

So, now our Snackbar engine is complete now we need to call CustomSnackBar class static method showSnackbar() in our sensor data logger.

For doing this I replaced all the instances of the Toast message with the ‘CustomSnackBar’ by passing in the desired messages that were being passed in Toast message.

But I still need to find the location of our stored CSV file and a method to delete the current generated CSV file.

For that, I did below modification to the CSVLogger class in PSLab android app.

public class CSVLogger {
   private static final String CSV_DIRECTORY = "PSLab";
   public CSVLogger(String category) {
       this.category = category;
       setupPath();
   }
   /*Below methods are included at the bottom of the class */
   public String getCurrentFilePath() {
       return Environment.getExternalStorageDirectory().getAbsolutePath() +
               File.separator + CSV_DIRECTORY + File.separator + category;
   }
   public void deleteFile() {
       csvFile.delete();
   }
}

Now for passing the location of the stored file and implementing delete option, I called the below method when the CSV logging is stopped by the user:

CustomSnackBar.showSnackBar((CoordinatorLayout) parent.findViewById(R.id.cl),

                    “CSV File stored at” + " " +lux_logger.getCurrentFilePath(),
  
                    “DELETE”,

                    new View.OnClickListener() {
                              Override
                              public void onClick(View view) {
                                             lux_logger.deleteFile();    
                              });

By doing this I get a Snackbar as shown in Figure 2, clicking on the “DELETE” text deletes the current CSV file.

Figure 2 shows snackbar showing file stored location and delete option

 

So, implementing Snackbar helped to make the app interactive and keeps user notified and control the data logging.

Resources

  1. https://www.journaldev.com/10324/android-snackbar-example-tutorial – Android SnackBar example implemetation tutorial
  2. https://material.io/develop/android/components/snackbar/ – Android Material Desing implementation of Snackbar.
Continue ReadingSnackbar Implementation in PSLab Android App

Attendee Form Builder in Open Event Frontend

The Open-Event-Frontend allows the event organiser to create tickets for his or her event. Other uses can buy these tickets in order to attend the event. When buying a ticket we ask for certain information from the buyer. Ideally the event organizer should get to choose what information they want to ask from the buyer. This blog post goes over the implementation of the attendee form builder in the Open Event Frontend.

Information to Collect

The event organizer can choose what details to ask from the order buyer. In order to specify the choices, we present a table with the entries of allowed fields that the organizer can ask for. Moreover there is an option to mark the field as required and hence making it compulsory for the order buyer to add that information in order to buy the tickets.

Route

The route is mainly responsible for fetching the required custom forms.

async model() {
    let filterOptions = [{
      name : 'form',
      op   : 'eq',
      val  : 'attendee'
    }];

    let data = {
      event: this.modelFor('events.view')
    };
    data.customForms = await data.event.query('customForms', {
      filter       : filterOptions,
      sort         : 'id',
      'page[size]' : 50
    });

    return data;
  }

If they don’t exist then we create them in afterModel hook. We check if the size of the list of custom forms sent from the server is 3 or not. If it is 3 then we create the additional custom forms for the builder. Upon creating an event, the server automatically creates 3 custom forms for the builder. These 3 forms are firstName, lastName and email.

afterModel(data) {
    /**
     * Create the additional custom forms if only the compulsory forms exist.
     */
    if (data.customForms.length === 3) {
      let customForms = A();
      for (const customForm of data.customForms ? data.customForms.toArray() : []) {
        customForms.pushObject(customForm);
      }

      const createdCustomForms = this.getCustomAttendeeForm(data.event);

      for (const customForm of createdCustomForms ? createdCustomForms : []) {
        customForms.pushObject(customForm);
      }

      data.customForms = customForms;
    }
  }

Complete source code for reference can be found here.

Component Template

The component template for the form builder is supposed to show the forms and other options to the user in a presentable manner. Due to pre-existing components for handling custom forms, the template is extremely simple. We just loop over the list of custom forms and present the event organizer with a table comprising of the forms. Apart from the forms the organizer can specify the order expiry time. Lastly we present a save button in order to save the changes.

<form class="ui form {{if isLoading 'loading'}}"  {{action 'submit' data on='submit'}} autocomplete="off">
  <h3 class="ui dividing header">
    <i class="checkmark box icon"></i>
    <div class="content">
      {{t 'Information to Collect'}}
    </div>
  </h3>
  <div class="ui two column stackable grid">
    <div class="column">
      <table class="ui selectable celled table">
        <thead>
          <tr>
            {{#if device.isMobile}}
              <th class="center aligned">
                {{t 'Options'}}
              </th>
            {{else}}
              <th class="right aligned">
                {{t 'Option'}}
              </th>
              <th class="center aligned">
                {{t 'Include'}}
              </th>
              <th class="center aligned">
                {{t 'Require'}}
              </th>
            {{/if}}
          </tr>
        </thead>
        <tbody>
          {{#each data.customForms as |field|}}
            <tr class="{{if field.isIncluded 'positive'}}">
              <td class="{{if device.isMobile 'center' 'right'}} aligned">
                <label class="{{if field.isFixed 'required'}}">
                  {{field.name}}
                </label>
              </td>
              <td class="center aligned">
                {{ui-checkbox class='slider'
                              checked=field.isIncluded
                              disabled=field.isFixed
                              onChange=(action (mut field.isIncluded))
                              label=(if device.isMobile (t 'Include'))}}
              </td>
              <td class="center aligned">
                {{ui-checkbox class='slider'
                              checked=field.isRequired
                              disabled=field.isFixed
                              onChange=(action (mut field.isRequired))
                              label=(if device.isMobile (t 'Require'))}}
              </td>
            </tr>
          {{/each}}
        </tbody>
      </table>
    </div>
  </div>
  <h3 class="ui dividing header">
    <i class="options box icon"></i>
    <div class="content">
      {{t 'Registration Options'}}
    </div>
  </h3>
  <div class="field">
    <label>{{t 'REGISTRATION TIME LIMIT'}}</label>
    <div class="{{unless device.isMobile 'two wide'}} field">
      {{input type='number' id='orderExpiryTime' value=data.event.orderExpiryTime min="1" max="60" step="1"}}
    </div>
  </div>
  <div class="ui hidden divider"></div>
  <button type="submit" class="ui teal submit button" name="submit">{{t 'Save'}}</button>
</form>

 

Component

The component is responsible for saving the form. It also provides runtime validations to ensure that the entries entered in the fields of the form are valid.

import Component from '@ember/component';
import FormMixin from 'open-event-frontend/mixins/form';

export default Component.extend(FormMixin, {
  getValidationRules() {
    return {
      inline : true,
      delay  : false,
      on     : 'blur',
      fields : {
        orderExpiryTime: {
          identifier : 'orderExpiryTime',
          rules      : [
            {
              type   : 'integer[1..60]',
              prompt : this.get('l10n').t('Please enter a valid registration time limit between 1 to 60 minutes.')
            }
          ]
        }
      }
    };
  },
  actions: {
    submit(data) {
      this.onValid(() => {
        this.save(data);
      });
    }
  }
});

References

 

Continue ReadingAttendee Form Builder in Open Event Frontend

Redirecting to Previous Route in Ember

The Open-Event-Frontend allows the event organiser to create tickets for his or her event. Other uses can buy these tickets in order to attend the event. In order to make the user experience smooth, we redirect the user to their previous route when they successfully login into their account. This blog explains how we have achieved this functionality in the project.

Insight

We have two different cases to handle in order to solve this problem:

  1. The user was in route A and wanted to move to route B. Here route A doesn’t require authorization and route B requires authorization. In this case, we would like to direct the user to the login route and once they are done, redirect them back to route B.
  2. The user was in route A and directly entered the login route using the login button. In this case we want to direct them back to the route A after successful login.

We use Ember-simple-auth in order to manage authentication in the project. Not only does it make it easy to manage authentication, it also handles the case 1 for us out of the box. So now the simplified problem is to redirect the user back to the previous route if they entered the login route directly using the web address or the login button.

Approach

If we can somehow store the previous route visited by a user, then we can easily redirect them back once they are logged in.

We will add a custom property in the session service called previousRouteName which will store the URL of the previous route visited by the user. We will make use of the willTransition hook in the application.js file. This hook is called everytime the user transitions from one route to another which makes it suitable for us to update the previousRouteName.

actions: {
    willTransition(transition) {
      transition.then(() => {
        let params = this._mergeParams(transition.params);
        let url;

        // generate doesn't like empty params.
        if (isEmpty(params)) {
          url = transition.router.generate(transition.targetName);
        } else {
          url = transition.router.generate(transition.targetName, params);
        }
        // Do not save the url of the transition to login route.
        if (!url.includes('login')) {
          this.set('session.previousRouteName', url);
        }
      });
    }
  }

_mergeParams is a helper function which makes use of merge function of the Lodash library.

/**
   * Merge all params into one param.
   * @param params
   * @return {*}
   * @private
   */
  _mergeParams(params) {
    return merge({}, ...values(params));
  },

Now we’re done with saving the URL of the previous route. All that remains is to trigger the redirect once the user has successfully logged in. We will use the sessionAuthenticated hook which is triggered everytime the user logs in.

sessionAuthenticated() {
    if (this.get('session.previousRouteName')) {
      this.transitionTo(this.get('session.previousRouteName'));
    } else {
      this._super(...arguments);
    }
  },

If the previous route variable is set, we redirect to it otherwise we can the super method and let Ember-simple-auth handle case 1 mentioned earlier for us.

References

Continue ReadingRedirecting to Previous Route in Ember

My Tickets in Open Event Frontend

The Open-Event-Frontend allows the event organiser to create tickets for his or her event. Other uses can buy these tickets in order to attend the event. The My tickets section lists all the tickets that have been bought by a user. This blog post explains how it has been implemented in the project.

Route

The My-Tickets list route has three responsibilities:

  1. Showing appropriate title according to the current tab.
  2. Setting the filter options according to the tab.
  3. Fetching the data from the store according to the filter options.

The title of the route is decided by the following snippet:

titleToken() {
    switch (this.get('params.ticket_status')) {
      case 'upcoming':
        return this.get('l10n').t('Upcoming');
      case 'past':
        return this.get('l10n').t('Past');
      case 'saved':
        return this.get('l10n').t('Saved');
    }
  },

The second and the third requirement is satisfied inside the model hook. We define the filterOptions according to the current tab and then make the request to fetch the data accordingly. The following code snippet is responsible for this:

model(params) {
    this.set('params', params);
    let filterOptions = [{
      name : 'completed-at',
      op   : 'ne',
      val  : null
    }];
    if (params.ticket_status === 'upcoming') {
      filterOptions.push(
        {
          name : 'event',
          op   : 'has',
          val  : {
            name : 'starts-at',
            op   : 'ge',
            val  : moment().toISOString()
          }
        });
    } else if (params.ticket_status === 'past') {
      filterOptions.push(
        {
          name : 'event',
          op   : 'has',
          val  : {
            name : 'ends-at',
            op   : 'lt',
            val  : moment().toISOString()
          }
        }
      );
    }

    return this.get('authManager.currentUser').query('orders', {
      include : 'event',
      filter  : filterOptions
    });
  }

Template

The template of the My tickets list is extremely simple. We simply loop over all the orders and use the order-card component to display each of them. The order-card component is discussed in detail later. If there are no orders under the user, we show the appropriate message.

<div class="row">
  <div class="sixteen wide column">
    {{#if model}}
      {{#each model as |order|}}
        {{#order-card order=order}}
        {{/order-card}}
        <div class="ui hidden divider"></div>
      {{/each}}
    {{else}}
      <div class="ui disabled header">{{t 'No tickets found'}}</div>
    {{/if}}
  </div>
</div>

Order-card Component

The order card component is responsible for handling a single order and showing its details in as a card. In order to decide whether the order is a paid order or not, we have defined a computed property inside the order-card.js file.

import Component from '@ember/component';
import { computed } from '@ember/object';
import { isEqual } from '@ember/utils';

export default Component.extend({
  isFreeOrder: computed('order', function() {
    const amount = this.get('order.amount');
    return amount === null || isEqual(amount, '0');
  })
});

The template for the component contains the event logo aligned to the left in the card. We show the event details such as the name, location and start date on the right. Below the event details we show the order details such as the order amount, currency, the identifier and the date and time on which the order was completed. Below is the full code for reference:

<div class="event wide ui grid row">
  {{#unless device.isMobile}}
    <div class="ui card three wide computer six wide tablet column">
      <a class="image" href="#">
        {{widgets/safe-image src=(if order.event.originalImageUrl order.event.originalImageUrl order.event.originalImageUrl)}}
      </a>
    </div>
  {{/unless}}
  <div class="ui card thirteen wide computer ten wide tablet sixteen wide mobile column">
    <a class="main content" href="#">
      {{#smart-overflow class='header'}}
        {{order.event.name}}
      {{/smart-overflow}}
      <div class="meta">
        <span class="date">
          {{moment-format order.event.startsAt 'ddd, DD MMMM YYYY, h:mm A'}}
        </span>
      </div>
      {{#smart-overflow class='description'}}
        {{order.event.shortLocationName}}
      {{/smart-overflow}}
    </a>
    <div class="extra content small text">
      <span>
        <span>
          {{#if isFreeOrder}}
            {{t 'Free'}}
          {{else}}
            {{order.event.paymentCurrency}}{{order.amount}}
          {{/if}}
          {{t 'order'}}
        </span>
        <span>#{{order.identifier}}</span>
        <span>{{t 'on'}} {{moment-format order.completedAt 'MMMM DD, YYYY h:mm A'}}</span>
      </span>
    </div>
  </div>
</div>

References

Continue ReadingMy Tickets in Open Event Frontend

Implementing Badgename Update Functionality

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay has many features related to enhancement in generation of badges. It gives choice of uploading data entries i.e by CSV or manually. There are options available for choosing Badge Background and font specifications. Now the next important thing from User perspective is that there should be a feature in My badges panel where user can see all badges & other details  and should be able to edit them if he want to, so moving forward with this feature I have implemented Badge Name update functionality in the frontend.

In this blog, I will be discussing how I implemented Update Badge Name functionality in my Pull Request so that the User can change his Badge Name  at any point of time in my badges panel.

Let’s get started and understand it step by step.

Step 1:

Create Badge Name component with Ember CLI.

$ ember g component badge-name

 

Step 2:

Make changes in Handlebar of Badge Name. We will be using semantic UI form for making the changes in Handlebars.

<form class="ui form" {{action 'updateBadgeName' on="change"}}>
    
class="ui icon input"> class="pen square icon"> {{input type="text" value=badge.badge_name }}
</form>

 

We have used action on submitting the Form for changing and updating the Badgename in Database.

Step 3:

We will now define the action in badge name JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
import Ember from 'ember';
const { inject } = Ember;
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  notifications : inject.service('notification-messages'),
  actions       : {
    updateBadgeName() {
      this.get('sendBadgeName')(this.get('badge'));
    },
    didRender() {
      this.$('.ui.form')
        .form({
          inline : true,
          delay  : false,
          fields : {
            Name: {
              identifier : 'Name',
              rules      : [
                {
                  type   : 'empty',
                  prompt : 'Please enter a valid Badge Name'
                }
              ]
            }
          }
        });
    }
  }
});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
  routing       : service('-routing'),
  notifications : service('notification-messages'),
  actions       : {
    updateBadgeName(badge) {
      badge.save()
        .then(() => this.get('notifications').success('Badge Name Successfully Updated!', {
          autoClear     : true,
          clearDuration : 1500
        }));
    }
  }
});

 

Now, I am done with doing all the changes in Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

  • My Badges Panel

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk

 

Continue ReadingImplementing Badgename Update Functionality

Implementing Different Alignment for Different Line

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay comes with many features for customising the process of generation of Badges. Now to provide more freedom to the user in generation of badges, I have worked on feature which will provide user more freedom in choosing different text alignment  for different lines and create badges more creatively.

In this Blog, I will be discussing how I implemented different text alignment for Different Line in Badgeyay Backend in my Pull Request.

To implement different text alignment for Different Line feature,  first, the component in SVG that is determining the text alignment of the label has to be identified. The label that determines the text on the badge is the <text> label and within it, the label that determines the properties of the text is <tspan>. So mainly we need to alter the properties in the tspan.

The property that determines the font type for the badge is text-align and its default value is set to start(right alignment). If the property in the labels changed, then we can see the corresponding changes in the PDF generated from the svg.

Now the challenges were:

  • To Determine the text-align value from the frontend.
  • Using the same for the text-align in SVG..
  • Changing the built SVG accordingly.

In this Blog, I will be dealing with changing the SVG in Backend according to text-align property provided by the User in the Frontend.

 def change_text_align(self,
                          filename,
                          badge_size,
                          paper_size,
                          align_1, // Values from Frontend
                          align_2,
                          align_3,
                          align_4,
                          align_5):

        """
            Module to change Text Alignment of each badge line
                :param `filename` - svg file to modify.
                :param `align_1` - Text Alignment to be applied on first line
                :param `align_2` - Text Alignment to be applied on Second line
                :param `align_3` - Text Alignment to be applied on Third line
                :param `align_4` - Text Alignment to be applied on Fourth line
                :param `align_5` - Text Alignment to be applied on Fifth line
        """
// Storing the Values passed altogether in a list.
        align = [1, align_1, align_2, align_3, align_4, align_5]
// Selecting the dimension config based on the parameters passed in the function.
        dimensions = badge_config[paper_size][badge_size]
        if config.ENV == 'LOCAL':
            filename = 'static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        else:
            filename = os.getcwd() + '/api/static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        tree = etree.parse(open(os.path.join(self.APP_ROOT, filename), 'r'))
        element = tree.getroot()

        for idx in range(1, dimensions.badges + 1):

            for row in range(1, 6):
                //Selecting the text element with the ID
                _id = 'Person_color_{}_{}'.format(idx, row)
                path = element.xpath(("//*[@id='{}']").format(_id))[0]
                style_detail = path.get("style")
                style_detail = style_detail.split(";")

                for ind, i in enumerate(style_detail):
                    if i.split(':')[0] == 'text-align':
                        style_detail[ind] = "text-align:" + align[row]
                style_detail = ';'.join(style_detail)
                text_nodes = path.getchildren()
                path.set("text-align", style_detail)

                for t in text_nodes:
                    text_style_detail = t.get("style")
                    text_style_detail = text_style_detail.split(";")
 // Fill the text-align argument of the selected object by changing the value of text-align.
                    text_style_detail[-1] = "text-align:" + align[row]
                    text_style_detail = ";".join(text_style_detail)
                    t.set("style", text_style_detail)

        etree.ElementTree(element).write(filename, pretty_print=True)
        print("Text Alignment Saved!")

 

After all the changes, the Updated SVG is used for Badge Generation with different text-align embedded.

Now, we are done with implementation of different text alignment  for Different Line in Badgeyay Backend.

Resources:

  1. Extracting map information from the SVG –  Link
  2. LXML documentation – Link
  3. Parsing the SVG – Link
  4. Badgeyay Repository – Link
  5. Issue Link – Link
  6. Pull Request Link – Link
Continue ReadingImplementing Different Alignment for Different Line

Implementing Different Font Type for Different Line

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay comes with many features for customising the process of generation of Badges. Now to provide more freedom to the user in generation of badges, I have worked on feature which will provide user more freedom in choosing font types for different lines and create badges more creatively.

In this Blog, I will be discussing how I implemented Different Font types for Different Line in Badgeyay Backend in my Pull Request.

To implement Different Font type for Different Line feature,  first, the component in SVG that is determining the font of the label has to be identified. The label that determines the text on the badge is the <text> label and within it, the label that determines the properties of the text is <tspan>. So mainly we need to alter the properties in the tspan.

The property that determines the font type for the badge is font-family and its default value is set to sans-serif. If the property in the labels changed, then we can see the corresponding changes in the PDF generated from the svg.

Now the challenges were:

  • To Determine the font-type value from the frontend.
  • Using the same for the font-type in SVG..
  • Changing the built SVG accordingly.

In this Blog, I will be dealing with changing the SVG in Backend according to Font type provided by the User in the Frontend.

  def change_font_family(self,
                           filename,
                           badge_size,
                           paper_size,
                           Font_1, // Values from Frontend
                           Font_2, 
                           font_3,
                           font_4,
                           font_5):

        """
            Module to change Font Family of each badge lines
                :param `filename` - svg file to modify.
                :param `font_1` - Family to be applied on first line
                :param `font_2` - Family to be applied on Second line
                :param `font_3` - Family to be applied on Third line
                :param `font_4` - Family to be applied on Fourth line
                :param `font_5` - Family to be applied on Fifth line
        """
// Storing the Values passed altogether in a list.
        font = [1, font_1, font_2, font_3, font_4, font_5]
// Selecting the dimension config based on the parameters passed in the function.
        dimensions = badge_config[paper_size][badge_size]
        if config.ENV == 'LOCAL':
            filename = 'static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        else:
            filename = os.getcwd() + '/api/static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        tree = etree.parse(open(os.path.join(self.APP_ROOT, filename), 'r'))
        element = tree.getroot()

        for idx in range(1, dimensions.badges + 1):

            for row in range(1, 6):
               //Selecting the text element with the ID
                _id = 'Person_color_{}_{}'.format(idx, row)
                path = element.xpath(("//*[@id='{}']").format(_id))[0]
                style_detail = path.get("style")
                style_detail = style_detail.split(";")

                for ind, i in enumerate(style_detail):
                    if i.split(':')[0] == 'font-family':
                        style_detail[ind] = "font-family:" + font[row]
                style_detail = ';'.join(style_detail)
                text_nodes = path.getchildren()
                path.set("font-family", style_detail)

                for t in text_nodes:
                    text_style_detail = t.get("style")
                    text_style_detail = text_style_detail.split(";")
  // Fill the font family argument of the selected object by changing the value of font-family.
                    text_style_detail[-1] = "font-family:" + font[row]
                    text_style_detail = ";".join(text_style_detail)
                    t.set("style", text_style_detail)

        etree.ElementTree(element).write(filename, pretty_print=True)
        print("Font Family Saved!")

 

After all the changes, the Updated SVG is used for Badge Generation with different font type embedded.

Now, we are done with implementation of Different Font type for Different Line in

Badgeyay Backend.

Resources:

  1. Extracting map information from the SVG –  Link
  2. LXML documentation – Link
  3. Parsing the SVG – Link
  4. Badgeyay Repository – Link
  5. Issue Link – Link
  6. Pull Request Link – Link
Continue ReadingImplementing Different Font Type for Different Line

Implementing Different Font Size for Different Line

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay comes with many features for customising the process of generation of Badges. Now to provide more freedom to the user in generation of badges, I have worked on feature which will provide user more freedom in choosing font sizes for different lines and create badges more creatively.

In this Blog, I will be discussing how I implemented Different Font Size for Different Line in Badgeyay Backend in my Pull Request.

To implement Different Font Size for Different Line feature,  first, the component in SVG that is determining the font size of the label has to be identified. The label that determines the text on the badge is the <text> label and within it, the label that determines the properties of the text is <tspan>. So mainly we need to alter the properties in the tspan.

The property that determines the font size for the badge is font-size and its default value is set to 31.25 px. If the property in the labels changed, then we can see the corresponding changes in the PDF generated from the svg.

Now the challenges were:

  • To Determine the font-size value from the frontend.
  • Using the same for the font-size in SVG..
  • Changing the built SVG accordingly.

In this Blog, I will be dealing with changing the SVG in Backend according to Font Size provided by the User in the Frontend.

def change_font_size(self,
                         filename,
                         badge_size,
                         paper_size,
                         Font_size_1, // Values from Frontend
                         font_size_2,
                         font_size_3,
                         font_size_4,
                         font_size_5):

        """
   Module to change size of each badge lines
   :param `filename` - svg file to modify.
   :param `font_size_1` - Size to be applied on first line
   :param `font_size_2` - Size to be applied on Second line
   :param `font_size_3` - Size to be applied on Third line
   :param `font_size_4` - Size to be applied on Fourth line
   :param `font_size_5` - Size to be applied on Fifth line
        """
// Storing the Values passed altogether in a list.
        font_size = [1, font_size_1, font_size_2, font_size_3, font_size_4, font_size_5]
// Selecting the dimension config based on the parameters passed in the function.
        dimensions = badge_config[paper_size][badge_size]
        if config.ENV == 'LOCAL':
            filename = 'static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        else:
            filename = os.getcwd() + '/api/static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        tree = etree.parse(open(os.path.join(self.APP_ROOT, filename), 'r'))
        element = tree.getroot()

        for idx in range(1, dimensions.badges + 1):

            for row in range(1, 6):
                 //Selecting the text element with the ID
                _id = 'Person_color_{}_{}'.format(idx, row)                 path = element.xpath(("//*[@id='{}']").format(_id))[0]
                style_detail = path.get("style")
                style_detail = style_detail.split(";")

                for ind, i in enumerate(style_detail):
                    if i.split(':')[0] == 'font-size':
                        style_detail[ind] = "font-size:" + font_size[row]
                style_detail = ';'.join(style_detail)
                text_nodes = path.getchildren()
                path.set("font-size", style_detail)

                for t in text_nodes:
                    text_style_detail = t.get("style")
                    text_style_detail = text_style_detail.split(";")
   // Fill the font size argument of the selected object by changing the value of font-size.
                    text_style_detail[-1] = "font-size:" + font_size[row]
                    text_style_detail = ";".join(text_style_detail)
                    t.set("style", text_style_detail)

        etree.ElementTree(element).write(filename, pretty_print=True)
        print("Font Size Saved!")

 

 

After all the changes, the Updated SVG is used for Badge Generation with different font size embedded

Now, we are done with implementation of Different Font Size for Different Line in

Badgeyay Backend.

Resources:

  1. Extracting map information from the SVG –  Link
  2. LXML documentation – Link
  3. Parsing the SVG – Link
  4. Badgeyay Repository – Link
  5. Issue Link – Link

Pull Request Link – Link

Continue ReadingImplementing Different Font Size for Different Line

Implementing Password Update Functionality

The Badgeyay  Ember JS frontend has many features like Login and Sign up features and Login with OAuth and most important, the badge generation feature is also up and running. Now the next important thing from User perspective is that there should be a settings panel where user can see its account details like username, Email & password and he should be able to change them if he want to.

I have implemented the setting panel in Badgeyay where user can see his account details. In this blog, I will be discussing how I implemented Update Password functionality in my Pull Request so that the User can change his Password at any point of time.

Let’s get started and understand it step by step.

Step 1:

Generate User Password component with help of ember cli.

Step 2:

Make changes in Handlebar of User Password. We will be using semantic UI form for making the changes in Handlebars.

<h2 class="ui header">Password</h2>
<h5 class="ui dividing header">Change your password.</h5>
<form class="ui form" {{action 'updateUserPassword' on="submit"}}>
    
class="field"> New Password
class="fields">
class="ten wide field"> {{input type="password" id="newPassword" name=newPassword value=user.password}}
</div> </div>
class="field"> Verify Password
class="fields">
class="ten wide field"> {{input type="password" id="newPasswordVerify" name=newPasswordVerify placeholder="Re-enter Password"}}
</div> </div> <button type="submit" class="ui basic orange button" tabindex="0"> Save Changes </button> </form>

 

We have used action on submitting the Form for changing and updating the Password in Database and Firebase.

Step 3:

We will now define the action in user component JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  actions: {
    updateUserPassword() {
      let password = this.get('newPassword');
      this.get('sendUserPassword')(password);
    }
  },
  didRender() {
    this.$('.ui.form')
      .form({
        inline : true,
        delay  : false,
        fields : {
          newPassword: {
            identifier : 'newPassword',
            rules      : [
              {
                type   : 'empty',
                prompt : 'Please enter a password'
              },
              {
                type   : 'minLength[6]',
                prompt : 'Your password must have at least {ruleValue} characters'
              }
            ]
          },
          newPasswordVerify: {
            identifier : 'newPasswordVerify',
            rules      : [
              {
                type   : 'match[newPassword]',
                prompt : 'Passwords do not match'
              }
            ]
          }
        }
      });
  }
});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

.......
export default Controller.extend({
  routing : service('-routing'),
  notify  : service('notify'),
  uid     : '',
  actions : {
...............
   updateUserPassword() {
      this.get('user').save()
        .then(() => this.get('notify').success('Password Successfully Updated!'))
    }
  }
});

 

Step 5:

We have configured the frontend for sending the details to backend. Now, we have to edit the endpoint so that if Password changes in params, It should change the password and send the response with the updated user schema.

api/controllers/registerUser.py
...............
   if 'password' in data.keys():
        user.password = data['password']
        update_firebase_password(user.id, user.password)
        user.save_to_db()

 

Now, I am done with doing all the changes in backend API and Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

  • User password Panel

Now, we are done with implementation of Update password Functionality.

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk
Continue ReadingImplementing Password Update Functionality

Implementing User-name Update Functionality

The Badgeyay  Ember JS frontend has many features like Login and Sign up features and Login with OAuth and the most important, the badge generation feature is also up and running. Now the next important thing from User perspective is that there should be a settings panel where user can see its account details like username, Email & password and he should be able to change them if he want to.

I have implemented the setting panel in Badgeyay where user can see his account details. In this blog, I will be discussing how I implemented Update Username functionality in my Pull Request so that the User can change his username at any point of time.

Let’s get started and understand it step by step.

Step 1:

Generate User account component with help of ember cli.

$ ember g component user-component/user-account

 

Step 2:

Make changes in Handlebar of User Account. We will be using semantic UI form for making the changes in Handlebars.

// user-account.hbs

<h2 class="ui dividing header">Account</h2>
<form class="ui form" {{action 'updateUserName' on="submit"}}>
    
class="ui field"> Username
class="ui fields">
class="ten wide field"> {{input type="text" id="profileName" name=profileName value=user.username}}
</div> </div>
class="ui field"> Email
class="ui fields">
class="ten wide disabled field"> {{input type="email" name=email value=user.email}}
</div> </div> <button type="submit" class="ui basic orange button" tabindex="0" >Save Changes</button> </form>

 

We have used action on submitting the Form for changing and updating the username in Database and Firebase.

Step 3:

We will now define the action in user component JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  actions: {
    updateUserName() {
      let profileName = this.get('profileName');
      this.get('sendUserName')(profileName);
    }
  },
  didRender() {
    this.$('.ui.form')
      .form({
        inline : true,
        delay  : false,
        fields : {
          username: {
            identifier : 'profileName',
            rules      : [
              {
                type   : 'empty',
                prompt : 'Please enter a valid username'
              }
            ]
          }
        }
      });
}});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

…….
export default Controller.extend({
  routing : service('-routing'),
  notify  : service('notify'),
  uid     : '',
  actions : {
…………...
   updateUserName(profileName) {
      const _this = this;
      const user = this.get('store').peekAll('user');
      user.forEach(user_ => {
        _this.set('uid', user_.get('id'));
      });
      _this.get('user').save();
      _this.get('notify').success('Username Successfully Updated!');
    }
  }
});

 

Step 5:

We have configured the frontend for sending the details to backend. Now, we have to edit the endpoint so that if username is change in params, It should change the username and send the response with the updated username.

api/controllers/registerUser.py
…………...
   if 'username' in data.keys():
        user.username = data['username']
        update_firebase_username(user.id, user.username)
        user.save_to_db()

 

Now, I am done with doing all the changes in backend API and Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

User Account Panel

Now, we are done with implementation of Update Username Functionality.

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk
Continue ReadingImplementing User-name Update Functionality