Create custom theme for SUSI chatbot web plugin

SUSI web plugin bot provides the features of SUSI as a chat window which users can plugin to their websites. They just need to copy the generated javascript code into their website and the SUSI bot plugin will be enabled. The user can customize the theme of the chatbot. This blog explains how the feature of applying custom theme is implemented.

Accepting user’s input

The react component of our concern is BotBuilderPages/Design.js. We use material-ui-color-picker component to accept user’s choice of color.

<ColorPicker
  className='color-picker'
  style={{display:'inline-block',float:'left'}}
  name='color'
  defaultValue={ this.state[component.component] }
  onChange={(color)=>
   this.handleChangeColor(component.component,color) }
/>

 

Similarly, there is a text field which accepts the url of an image. The values are stored in the component’s state variables.

Storing settings in server

The design settings are stored in the text format:

This forms part of the skill’s text file. When the user clicks on “save and deploy” button, the complete skill gets send to the server through the following API:

let settings = {
      async: true,
      crossDomain: true,
      url:
        urls.API_URL +
        '/cms/' +
        (this.state.updateSkillNow ? 'modifySkill.json' : 'createSkill.json'),
      method: 'POST',
      processData: false,
      contentType: false,
      mimeType: 'multipart/form-data',
      data: form,
    };

    $.ajax(settings)
      .done(function(response) {
        // successfully saved in server
      });

 

In the server, the skill is saved in susi_private_skill_data directory. Also, the design and configuration settings are stored in chatbot.json file.

Applying the settings to the bot

Now, in the susi-chatbot.js file, the custom theme settings are applied to the bot. The function getTheme() fetches the theme settings from the server via an ajax request. Then the function applyTheme() is executed which applies the theme to the chatbot.

$(".susi-sheet-content-container").css("background-color",botbuilderBackgroundBody);
if(botbuilderBodyBackgroundImg){
$(".susi-sheet-content-container").css("background-image","url("+botbuilderBodyBackgroundImg+")");
}

 

Similarly, other theme variables are applied as well. Thus we have customised the theme of the SUSI chatbot plugin.

Result:

Resources

 

Continue Reading

Use of Flux Architecture in SUSI.AI

SUSI Web Chat is based on Flux, a React.js Architecture. It provides a simple way for implementing many features in SUSI Web Chat. This blog post explains how Flux Architecture works, and also how it is used in SUSI Web Chat to implement the feature of switching between Light and Dark themes.

What is Flux?

Flux is a micro-architecture for software application development. It is the application architecture that Facebook uses for building client-side web applications. It complements React’s composable view components by utilizing a unidirectional data flow.

Flux Overview

As can be seen from the above diagram, Flux has four main components:

Component Description
Actions Helper methods that pass data to the Dispatcher.
Dispatcher Receives these Actions and broadcast payloads to registered callbacks.
Stores The Stores that are registered to the Dispatcher will update the Views accordingly.
Views  Views are actually React Components that grab the state from the stores and then pass it down to the child components.

How these 4 components work together?

  • Application Initialisation:
    1. Stores let the registered Dispatcher know that they want to be notified whenever an action comes in.
    2. Then the controller views ask the stores for the latest state.
    3. When the stores give the state to the controller views, they pass that state along to their child views to render.
    4. The controller views also ask the stores to keep them notified when state changes so that they can re-render accordingly.
  • The Data Flow:

Once the setup is done, the application is ready to accept user input. So let us trigger an action by having the user make a change.

    1. The view tells the action creator to prepare an action.
    2. The action creator formats the action and sends it off to the Dispatcher.
    3. The Dispatcher dispatches the action off to all of the stores in sequence. Then the store decides whether it cares about this action or not, and changes the state accordingly.
    4. Once it’s done changing state, the store lets its subscribed view controllers know.
    5. Those view controllers will then ask the store to give them the updated state.
    6. After the store gives it the state, the view controller will tell its child views to re-render based on the new state.

So this is how Flux works. Now let us see an example of Flux being used in SUSI Web Chat.

Use of Flux Architecture to Switch Between Themes in SUSI Web Chat

Different Flux components used in SUSI Web Chat:

  1. Actions – Settings.actions.js
  2. Dispatcher – ChatAppDispatcher.js
  3. Store – UserPreferencesStore.js
  4. View – MessageSection.react.js

Let us now see in detail how we are able to switch themes:
In the MessageSection.react.js file, we have the following functions to handle theme change:

handleThemeChanger = () => {
    //code
    this.applyLightTheme();
}

applyLightTheme = () =>{
    //code
    Actions.settingsChanged(settingsChanged);
}

 
Hence, the view tells the action creator to prepare an action.
Now, the settingsChanged() function in Settings.actions.js file is called as follows:

export function settingsChanged(settings) {
    ChatAppDispatcher.dispatch({
    type: ActionTypes.SETTINGS_CHANGED,
    settings
});
    //code
}

 
Hence, the process of invoking the callbacks is initiated through the dispatch() method, which takes a data payload object as its sole argument.

Now, as the UserPreferencesStore is registered with the ChatAppDispatcher, it receives the actions dispatched by the Dispatcher. It checks for the type of action, and with the help of switch cases, executes the code for the corresponding action type accordingly. In this case, the states inside the Store are updated with the new state which the User wants to switch to.

UserPreferencesStore.dispatchToken = ChatAppDispatcher.register(action => {
    switch (action.type) {
        //code
        case ActionTypes.SETTINGS_CHANGED: {
            let settings = action.settings;
            //code
            UserPreferencesStore.emitChange();
            break;
        }
        //code
    }
});

 
This is how Flux Architecture is facilitating the switching of themes in SUSI Web Chat.

Resources

 

Continue Reading

LXQT Panel theme for Meilix

Panel theming is available via the LXQt Configuration Center –> LXQt Appearance –> LXQt Theme. For Meilix we have attempted making the light color theme with some new things like taskbar manager to highlight the active window and hover actions.

Meilix taskbar in panel

Theme folders of LXQT is in the directory /usr/share/lxqt/themes/.

Meilix LXQT theme directory

For theming the panel we start by creating a lxqt-panel.qss this file is like a style sheet for LXQt panel.

LXQtPanel #BackgroundWidget {
        background:rgba(240, 240, 240, 100%);
}

QToolTip {
        border-radius: 4px;
        border: 1px solid rgba(155, 155, 155, 100%);
        background:rgba(240, 240, 240, 100%);
        padding: 2px;
        margin: 0px;
        color: #313639;
}

 

Where we are defining the values of property like background for LXQTPanel1 which is the primary panel but if we want to theme the second panel differently then we need to use LXQTPanel2 and if we require same theme then no need to add the property for second panel it will take the property of panel 1 only,

We can define appearance of things like tooltip using QToolTip , LXQtPanelPlugin for plugins area and property of widgets like calendar using QCalendarWidget like

QCalendarWidget #qt_calendar_navigationbar,
QCalendarWidget #qt_calendar_navigationbar * {
    background:rgba(240, 240, 240, 100%);
    color: rgba(54, 54, 54, 100%);
}
QCalendarWidget QToolButton {
    margin: 3px;
    border-radius: 4px;
    border: 1px solid transparent;
    padding: 4px;
} 

 

We can also add or change the icons like the default icon for LXQt main menu it the LXQT logo but we want it to be something else like the logo of Meilix. We can add the path of the icon in the QSS file like

#MainMenu {
        qproperty-icon: url(mainmenu.svg);
}

 

To check all the changes made in LXQT panel theme without restart or logout and login again we can use the following commands.

killall lxqt-panel
lxqt-panel

Resources

Continue Reading

Creation of Icon Pack for Meilix

An icon theme is a set of icons that have common looks and feel. The user can select the icon theme that they want to use, and all apps use icons from the theme if a particular icon is not available in theme the fallback theme is used .

An icons theme is only a mapping. Given an arrangement of indexes to search for icons in and a theme name it maps from icon name and icon size to an icon filename.

Icon in Meilix are stored in /usr/share/icons/meilix.

We need to create a index.theme file which tells the LXQT desktop where the icons for a particular application or mime type are located

[Icon Theme]
Name=Meilix
DisplayDepth=32
DesktopDefault=48
DesktopSizes=16,22,32,48,64,128,256
ToolbarDefault=22
ToolbarSizes=16,22,32,48
MainToolbarDefault=22
MainToolbarSizes=16,22,32,48
SmallDefault=16
SmallSizes=16,22,32,48
PanelDefault=32
PanelSizes=16,22,32,48,64,128,256
DialogDefault=32
DialogSizes=16,22,32,48,64,128,256

#################################
#   Fallback icon theme to use  #
#################################
Inherits=oxygen

 

After defining the icon theme name and sizes we next define the fallback icon theme to use icons from in case of missing icons so we have chosen Oxygen icon theme which is very similar to Meilix icon theme to have a consistent looks and feel.

We further define the different types of icons with their locations , resolution and type.

Meilix icon theme use four different sizes 16 , 22 , 24 ,32 ,64 and two types scalable for svg icons and fixed for png icons.

[actions/32]
Size=32
Context=Actions
Type=Fixed

[actions/48]
Size=48
Context=Actions
Type=Fixed

#  Apps

[apps/16]
Size=16
Context=Applications
Type=Fixed

[apps/22]
Size=22
Context=Applications
Type=Fixed

 

Meilix Icon pack directory structure

Adding more icons to theme

To append a custom icon to Meilix icon theme xdg-icon-resource can be used. This will resize and copy the icon to /share/icons/meilix. With this method, custom emblems can also be added. Examples:

$ xdg-icon-resource install --size 64 --context --theme meilix emblems meilix-example.png --mode system # add as emblem
$ xdg-icon-resource install --size 64 --theme meilix meilix-example.png --mode system # add as normal icon

Mime type icons

file managers get definitions from /usr/share/mime/ . Calling an icon according to the definition found there and copying it to /share/icons/meilix will cause the file manager to display the custom mime type icon.

Creating a custom icon for text files (*.txt)

# grep txt /usr/share/mime/globs | egrep -o '.+\/[^:]+' | tr '/' '-'
application-x-kate ;# rename your icon according to this output
xdg-icon-resource install --size 64 --context mimetypes --theme meilix application-x-kate.png --mode system

Resources

Continue Reading

Using Day Night Theme in SUSI Android

SUSI is an artificial intelligence for interactive chat bots. It provides response to the user in most intuitive way. Therefore we thought why not implement the option to give theme preference to the user to make it more interactive. It will also help in increasing the user’s interest towards the application.

We tried out different themes and then finally decided to settle for the newly announced Day Night Theme for the SUSI Android App (https://github.com/fossasia/susi_android). This theme is provided by AppCompat 23.2.0 . With the help of this theme we can switch between Theme.AppCompat.Light (light) and Theme.AppCompat (dark) based on the user preference and time of day. For default the theme is set to the light theme and it can be easily changed from the settings. Thus it allows the user to change the theme according to his or her mood which looks very intuitive.

How to use this theme?

To use the Day Night theme is quite simple. We just need to extend our default theme to that of Theme.AppCompat.DayNight. The declaration is done as shown below in the screenshot.

<style name="MyTheme" parent="Theme.AppCompat.DayNight">

  <!-- Blah blah -->

</style>

Now to enable different features of the theme in our application we need to call AppCompatDelegate.setDefaultNightMode(). It takes one of the following values as the parameter.

  • MODE_NIGHT_NO. This is for the day (light) theme.
  • MODE_NIGHT_YES.This is for the night (dark) theme.
  • MODE_NIGHT_AUTO. It automatically changes between the above two themes based on the time of day.
  • MODE_NIGHT_FOLLOW_SYSTEM (default). This theme is dependent on the system settings of the user mobile phone.

We can set one of these parameters at the time of calling the function to fix the theme of the application in the following way.

static {

AppCompatDelegate.setDefaultNightMode(

          AppCompatDelegate.MODE_NIGHT_...);

}

The theme inside an activity is set at the time time of calling onCreate() method. Therefore we cannot change the theme from any other place inside our activity apart from onCreate(). If we want to set it inside our activity but outside the onCreate() method then we have to call the recreate() function to recreate the whole activity which will implement the selected theme.Let us look at the example.

public class MyActivity extends AppCompatActivity {

 public void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      if (savedInstanceState == null) {

          // Set the local night mode to some value

          getDelegate().setLocalNightMode(

                  AppCompatDelegate.MODE_NIGHT_...);

          // Now recreate for it to take effect

          recreate();

      }

  }

}

To take care of the text colors in our app we can set textColor attribute as

?android:attr/textColorPrimary

Now let us look at the implementation in Susi Android

In Susi Android we are providing user the option to select either the dark or the light theme in the settings.

 
The code for the implementation is as below

@Override

protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);



  prefs = getSharedPreferences(Constant.THEME, MODE_PRIVATE);

  if(prefs.getString(Constant.THEME,"Dark").equals("Dark")) {

      AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);

  }

  else {

      AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);

  }



  setContentView(R.layout.activity_main);

}

The result output for the light theme is

To learn more about themes in Android you can refer to this link.

Resources

Continue Reading

Working with Absolute Positioning

During the past week, I have done a lot of work for making the feature that allow the users to view the schedule of events according to track and time. The toughest part was to have a headstart to think of the mockup that fulfills this criterion.

After the mockup, I started coding it and realized that I have to add CSS by using Javascript. The frontend needs to calculate the top of each pop-up that appears when the track is hovered and to append the box just below it.

a

The interesting part was to calculate the top each time the element is hovered and to place the box at the right position by using jQuery.

Position Absolute 

The difficulty becomes maximum when we use “position : absolute “. As, it takes the element out of the layer. The element with absolute positioning is difficult to handle when it comes to responsiveness. Here also the pop-overs showing the speakers are to be made with absolute positioning.

The code snippet shows the calculation for exact position of the pop-up box.

$(document).ready(function(){

 $('.pop-box').hide();
 $('.item').hover(function (event) {

 event.preventDefault();
 event.stopPropagation();
 var track = $(event.target);
 var link = track.children(0);
 var offset =$(link).offset();

 var position= offset.top-link.height()-30;
 if( $(window).width()<600){
 var position= offset.top-link.height()-48; 
 }
 if(offset.top){
 
 $('.pop-box').hide();
 var p=$(this);
 $(p).next().show();
 var posY = event.pageY;
 nextOfpop=$(p).next();
 
 var toptrack = position ;

 $(nextOfpop).css({'top':toptrack
                 });

 $(document).mouseup(function (e)
 {
 var container = $(".pop-box");

  if (!container.is(e.target) 
  && container.has(e.target).length === 0 && (e.target)!=$('html').get(0)) 
   {
   container.hide();
   }
   });
  });
 })

This code sets the value of top of the pop-over in the variable position and copy it to toptrack that is passed to CSS to adjust the top dynamically.

Responsiveness for top

I was struggling a whole day to find out the best possible way for the responsiveness of track page. Obviously, the difficult part was the recalculation of top with the screen-size. Currently I have used $window.width() to check the width of screen and adjust the top on mobile. But, it will include more complexity when it is done for other screen sizes rather than mobile.

 if( $(window).width()<600){
 var position= offset.top-link.height()-48; 
 }

The tracks page is ready now with both light and dark theme.

10.png

That’s how the position absolute is handled with jQuery. To remove the complexity, all the CSS except the calculation of top is written with SASS.

Continue Reading
Close Menu