Testing Presenter of MVP in Loklak Wok Android

Imagine working on a large source code, and as a new developer you are not sure whether the available source code works properly or not, you are surrounded by questions like, Are all these methods invoked properly or the number of times they need to be invoked? Being new to source code and checking manually already written code is a pain. For cases like these unit-tests are written. Unit-tests check whether the implemented code works as expected or not. This blog post explains about implementation of unit-tests of Presenter in a Model-View-Presenter (MVP) architecture in Loklak Wok Android.

Adding Dependencies to project

In app/build.gradle file

defaultConfig {
   testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

dependencies {
   androidTestCompile 'org.mockito:mockito-android:2.8.47'
   androidTestCompile 'com.android.support:support-annotations:25.3.1'
   androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'

Setup for Unit-Tests

The presenter needs a realm database and an implementation of LoklakAPI interface. Along with that a mock of the View is required, so as to check whether the methods of View are called or not.

The LoklakAPI interface can be mocked easily using Mockito, but the realm database can’t be mocked. For this reason an in-memory realm database is created, which will be destroyed once all unit-test are executed. As the presenter is required for each unit-test method we instantiate the in-memory database before all the tests start i.e. by annotating a public static method with @BeforeClass, e.g. setDb method.

public static void setDb() {
   RealmConfiguration testConfig = new RealmConfiguration.Builder()
   mDb = Realm.getInstance(testConfig);


NOTE: The in-memory database should be closed once all unit-tests are executed. So, for closing the databasse we create a public static method annotated with @AfterClass, e.g. closeDb method.

public static void closeDb() {


Now, before each unit-test is executed we need to do some setup work like instantiating the presenter, a mock instance of API interface generated  by using mock static method and pushing in some sample data into the database. Our presenter uses RxJava and RxAndroid which depend on IO scheduler and MainThread scheduler to perform tasks asynchronously and these schedulers are not present in testing environment. So, we override RxJava and RxAndroid to use trampoline scheduler in place of IO and MainThread so that our test don’t encounter NullPointerException. All this is done in a public method annotated with @Before e.g. setUp.

public void setUp() throws Exception {
   // mocking view and api
   mMockView = mock(SuggestContract.View.class);
   mApi = mock(LoklakAPI.class);

   mPresenter = new SuggestPresenter(mApi, mDb);

   queries = getFakeQueries();
   // overriding rxjava and rxandroid
   RxJavaPlugins.setIoSchedulerHandler(scheduler -> Schedulers.trampoline());
   RxAndroidPlugins.setMainThreadSchedulerHandler(scheduler -> Schedulers.trampoline());



Some fake suggestion queries are created which will be returned as observable when API interface is mocked. For this, simply two query objects are created and added to a List after their query parameter is set. This is implemented in getFakeQueries method.

private List<Query> getFakeQueries() {
   List<Query> queryList = new ArrayList<>();

   Query linux = new Query();

   Query india = new Query();

   return queryList;


After that, a method is created which provides the created fake data wrapped inside an Observable as implemented in getFakeSuggestionsMethod method.

private Observable<SuggestData> getFakeSuggestions() {
   SuggestData suggestData = new SuggestData();
   return Observable.just(suggestData);


Lastly, the mocking part is implemented using Mockito. This is really simple, when and thenReturn static methods of mockito are used for this. The method which would provide the fake data is invoked inside when and the fake data is passed as a parameter to thenReturn. For example, stubSuggestionsFromApi method

private void stubSuggestionsFromApi(Observable observable) {

Finally, Unit-Tests

All the tests methods must be annotated with @Test.

Firstly, we test for a successful API request i.e. we get some suggestions from the Loklak Server. For this, getSuggestions method of LoklakAPI is mocked using stubSuggestionFromApi method and the observable to be returned is obtained using getFakeSuggestions method. Then, loadSuggestionFromAPI method is called, the one that we need to test. Once loadSuggestionFromAPI method is invoked, we then check whether the method of the View are invoked inside loadSuggestionFromAPI method, this is done using verify static method. The unit-test is implemented in testLoadSuggestionsFromApi method.

public void testLoadSuggestionsFromApi() {

   mPresenter.loadSuggestionsFromAPI("", true);



Similarly, a failed network request for obtaining is suggestions is tested using testLoadSuggestionsFromApiFail method. Here, we pass an IOException throwable – wrapped inside an Observable – as parameter to stubSuggestionsFromApi.

public void testLoadSuggestionsFromApiFail() {
   Throwable throwable = new IOException();

   mPresenter.loadSuggestionsFromAPI("", true);


Lastly, we test if our suggestions are saved in the database by counting the number of saved suggestions and asserting that, in testSaveSuggestions method.

public void testSaveSuggestions() {
   int count = mDb.where(Query.class).findAll().size();
  // queries is the List that contains the fake suggestions
   assertEquals(queries.size(), count);


Handling Data Requests in Open Event Organizer Android App

Open Event Organizer is a client side application of Open Event API Server created for event organizers and entry managers. The app maintains a local database and syncs it with the server when required. I will be talking about handling data requests in the app in this blog.

The app uses ReactiveX for all the background tasks including data accessing. When a user requests any data, there are two possible ways the app can perform. The one where app fetches the data directly from the local database maintained and another where it requests data from the server. The app has to decide one of the ways. In the Organizer app, AbstractObservableBuilder class takes care of this. The relevant code is:

final class AbstractObservableBuilder<T> {

   private final IUtilModel utilModel;
   private boolean reload;
   private Observable<T> diskObservable;
   private Observable<T> networkObservable;


   private Callable<Observable<T>> getReloadCallable() {
       return () -> {
           if (reload)
               return Observable.empty();
               return diskObservable
                   .doOnNext(item -> Timber.d("Loaded %s From Disk on Thread %s",
                       item.getClass(), Thread.currentThread().getName()));

   private Observable<T> getConnectionObservable() {
       if (utilModel.isConnected())
           return networkObservable
               .doOnNext(item -> Timber.d("Loaded %s From Network on Thread %s",
                   item.getClass(), Thread.currentThread().getName()));
           return Observable.error(new Throwable(Constants.NO_NETWORK));

   private <V> ObservableTransformer<V, V> applySchedulers() {
       return observable -> observable

   public Observable<T> build() {
       if (diskObservable == null || networkObservable == null)
           throw new IllegalStateException("Network or Disk observable not provided");

       return Observable
               .flatMap(items -> diskObservable.toList())
               .flattenAsObservable(items -> items)


DiskObservable is a data request to the local database and networkObservable is a data request to the server. The build function decides which one to use and returns a correct observable accordingly. The class object takes a boolean field reload which is used to decide which observable to subscribe. If reload is true, that means the user wants data from the server, hence networkObservable is returned to subscribe. Also switchIfEmpty in the build method checks whether the data fetched using diskObservable is empty, if found empty it switches the observable to the networkObservable to subscribe.

This class object is used for every data access in the app. For example, this is a code snippet of the gettEvents method in EventRepository class.

public Observable<Event> getEvents(boolean reload) {
   Observable<Event> diskObservable = Observable.defer(() ->

   Observable<Event> networkObservable = Observable.defer(() ->
           .flatMapIterable(events -> events));

   return new AbstractObservableBuilder<Event>(utilModel)


1. Documentation of ReactiveX API
2. Github repository link of RxJava – Reactive Extension for JVM

Implement Internationalization in SUSI Android With Weblate

When you build an Android app, you must consider about users for whom you are building an app. It may be possible that you users are from the different region. To support the most users your app should show text in locale language so that user can use your app easily. Our app SUSI Android is also targeting users from different regions. Internationalization is a way that ensures our app can be adapted to various languages without requiring any change to source code. This also allows projects to collaborate with non-coders more easily and plugin translation tools like Weblate.

Benefits of using Internationalization are:

  • It reduces the time for localization i.e it will localize your app automatically.
  • It helps us to keep and maintain only single source code for different regions.

To achieve Internationalization in Android app you must follow below steps:

  • Move all the required contents of your app’s user interface into the resource file.
  • Create new directories inside res to add support for Internationalization. Each directory’s name should follow rule <resource type>-(language code). For example values-es contains string resource for es language code i.e Spanish.
  • Now add different locale content in the respective folder.

We need to create separate directories for different locale because to show locale specific content, Android check specific folder i.e res/<resource type>-(language code) like res/values-de and show content from that folder. That’s why we need to move all the required content into resource file so that each required content can be shown in the specific locale.

How Internationalization is implemented in SUSI Android

In SUSI Android there is not any locale specific image but only string. So I created only locale specific value resource folder to add locale specific strings. To create locale specific values folder I follow the above-mentioned rule i.e <resource type>-(language code).

After that, I added specific language string in the respective folder.

Instead of hard-coded strings, we used strings from string.xml file so that it will change automatically according to the region.




In absence of resource directory for any specific locale, Android use default resource directory.

Integrate Weblate in SUSI Android

Weblate is a web based translation tool. The best part of Weblate is its tight version control integration which makes it easy for translators to contribute because translator does not need to fork your repo and send pull request for each change but Weblate handle this part i.e translator translate strings of the project in Weblate site and Weblate will send pull request for those changes.

Weblate can host your free software projects for free but it depends on them. Here is the link of SUSI Android project hosted on Weblate. If your project is good then they can host your project for free. But for that, you have to apply from this link and select ask for hosting. Now fill up form as shown in below picture.

Once your project is hosted on Weblate, they will email you about it. After that, you have to integrate Weblate in your project so that Weblate can automatically push translated strings to your project and also Weblate get notify about changes in your repository. Here is the link on how to add Weblate service and Weblate user to your project.

If it is not possible to host your project on Weblate for free then you can host it by own. You can follow below steps:

  • First, we deploy Weblate on our localhost using the installation guide given on Weblate site. I install Weblate from git. I cloned latest source code using Git
git clone https://github.com/WeblateOrg/weblate.git
  • Now change directory to where you cloned weblate source code and install all the required dependencies and optional dependencies using code
pip install -r requirements.txt


pip install -r requirements-optional.txt
  • After doing that we copy weblate/settings_example.py to weblate/settings.py. Then we configure settings.py and use the following command to migrate the settings.
./manage.py migrate
  • Now create an admin using following command.
./manage.py createadmin
  • After that add a project from your Admin dashboard (Web translations-> Projects-> Add Project) by filling all details.
  • Once the project is added, we add the component (Web translations-> Components-> Add Component) to link our Translation files.
  • To change any translation we make changes and push it to the repository where our SSH key generated from Weblate is added. A full guide to do that is mentioned in this link.


Service Workers in Loklak Search

Loklak search is a web application which is built on latest web technologies and is aiming to be a progressive web application. A PWA is a web application which has a rich, reliable, fast, and engaging web experience, and web API which enables us to get these are Service Workers. This blog post describes the basics of service workers and their usage in the Loklak Search application to act as a Network Proxy to and the programmatical cache controller for static resources.

What are Service Workers?

In the very formal definition, Matt Gaunt describes service workers to be a script that the browser runs in the background, and help us enable all the modern web features. Most these features include intercepting network requests and caching and responding from the cache in a more programmatical way, and independent from native browser based caching. To register a service worker in the application is a really simple task, there is just one thing which should be kept in mind, that service workers need the HTTPS connection, to work, and this is the web standard made around the secure protocol. To register a service worker

if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed 🙁
console.log('ServiceWorker registration failed: ', err);

This piece of javascript, if the browser supports, registers the service worker defined by sw.js. The service worker then goes through its lifecycle, and gets installed and then it takes control of the page it gets registered with.

What does service workers solve in Loklak Search?

In loklak search, service workers currently work as a, network proxy to work as a caching mechanism for static resources. These static resources include the all the bundled js files and images. These bundled chunks are cached in the service workers cache and are responded with from the cache when requested. The chunking of assets have an advantage in this caching strategy, as the cache misses only happen for the chunks which are modified, and the parts of the application which are unmodified are served from the cache making it possible for lesser download of assets to be served.

Service workers and Angular

As the loklak search is an angular application we, have used the @angular/service-worker library to implement the service workers. This is simple to integrate library and works with the, CLI, there are two steps to enable this, first is to download the Service Worker package

npm install --save @angular/service-worker

And the second step is to enable the service worker flag in .angular-cli.json

"apps": [
      // Other Configurations
      serviceWorker: true

Now when we generate the production build from the CLI, along with all the application chunks we get, The three files related to the service workers as well

  • sw-register.bundle.js : This is a simple register script which is included in the index page to register the service worker.
  • worker-basic.js : This is the main service worker logic, which handles all the caching strategies.
  • ngsw-manifest.json : This is a simple manifest which contains the all the assets to be cached along with their version hashes for cache busting.

Future enhancements in Loklak Search with Service Workers

The service workers are fresh in loklak search and are currently just used for caching the static resources. We will be using service workers for more sophisticated caching strategies like

  • Dynamically caching the results and resources received from the API
  • Using IndexedDB interface with service workers for storing the API response in a structured manner.
  • Using service workers, and app manifest to provide the app like experience to the user.


Resources and Links

How to use Realm in SUSI Android to Save Data

Sometimes we need to store information on the device locally so that we can use information offline and also query data faster. Initially, SQLite was only option to store information on the device. But working with SQLite is difficult sometimes and also it makes code difficult to understand. Also, SQL queries take a long time. But now we have realm a better alternative of SQLite. The Realm is a lightweight mobile database and better substitute of SQLite. The Realm has own C++ core and store data in a universal, table-based format by a C++ core. This allows Realm to allow data access from multiple languages as well as a range of queries. In this blog post, I will show you why we used Realm and how we save data in SUSI Android using Realm.

“How about performance? Well, we’re glad you asked 🙂 For all the API goodness & development productivity we give you, we’re still up to 100x faster than some SQLite ORMs and on average ~10x faster than raw SQLite and common ORMs for typical operations.” (compare: https://blog.realm.io/realm-for-android/)

Advantages of Realm over SQLite are following:

  • It is faster than SQLite as explained on the Realm blog. One of the reasons realm is faster than SQLite is, the traditional SQLite + ORM abstraction is leaky because ORM simply converts  Objects and their methods into SQL statements. Realm, on the other hand, is an object database, meaning your objects directly reflect your database.
  • It is easier to use as it uses objects for storing data. When we use SQLite we need boilerplate code to convert values to and from the database, setting up mappings between classes and tables, fields and columns, foreign keys, etc. Whereas in Realm data is directly exposed as objects and can be queried without any conversion.


To include this library in your project you need

  • Android studio version 1.5.1 or higher.
  • JDK version 7.0 or higher.
  • Android API level 9 or higher.

How to use realm in Android

To use Realm in your project we must add the dependency of the library in build.gradle(project) file 

 dependencies {
       classpath “io.realm:realm-gradle-plugin:3.3.1”

and build.gradle(module) file.

apply plugin: realm-android
dependencies {
compile io.realm:android-adapters:1.3.0

Now you have to instantiate Realm in your application class. Setting a default configuration in your Application class, will ensure that it is available in the rest of your code.

RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this)

Now we need to create a model class. A model class is use to save data in Realm and retrieve saved data and it must extend RealmObject class. For eg.

public class Person extends RealmObject {
   private String name;
   public String getName() {
       return name;
   public void setName(String name) {
       this.name = name;

Field in the model class uses to define columns. For eg. ‘name’ is a column name. Method like setName() use to save data  and getName() use to retrieve saved data.

Now create an instance of the Realm in the activity where you want to use it. It will be used to read data from the Realm and write data to the Realm.

Realm realm = Realm.getInstance(this);

Before you start a new transaction you must call beginTransaction(). It will open database.


To write data to the Realm you need to create an instance of the model class. createObject used to create an instance of RealmObject class. Our model class is RealmObject type so we use createObject() to create an instance of the model class.

Person person = realm.createObject(Person.class);

Write data to realm.


And after it you must call commitTransaction(). commitTransaction() use to end transaction.


Reading data from Realm is easier than writing data to it. You need to create an instance of the Realm.

Realm realm = Realm.getInstance(this);

To create query use where the method and pass the class of object you want to query. After creating query you can fetch all data using findAll() method.



Showing only Logged-in Accounts in the Sharing Page of Phimpme Android

In Phimpme Android application, users can edit their pictures and share them to a number of platforms ranging from social networking sites like Facebook, Twitter etc to cloud storage and image hosting sites like Box, Dropbox, Imgur etc.

Desired flow of the application

According to the flow of the application, the user has to add an account first i.e. log in to the particular account that needs to be connected to the application. After that when the user enters the share page for sharing the image, a button corresponding to the connected account is visible in that page which on clicking will share the image to that platform directly.

What was happening previously?

The list of accounts which is present in the account manager of Phimpme Android application is also getting displayed in the share image page. As the list is large, it is difficult for the user to find the connected account from the list. There is not even an indicator whether a particular account is connected or not. On clicking the button corresponding to the non-connected account, an error dialog instructing the user to log in from the account manager first, will get displayed.

How we solved it?

We first thought of just adding an indicator on the buttons in the accounts page to show whether it is connected or not. But this fix solves only a single issue. Find the connected account in that large list will be difficult for the user even then. So we decided to remove the whole list and show only the accounts which are connected previously in account manager. This cleans the flow of the accounts and share in  Phimpme Android application

When a user logins from the account manager, the credentials, tokens and other details corresponding to that accounts gets saved in database. We used realm database for saving the details in our application. As the details are present in this database, the list can be dynamically generated when the user opens share image page. We implemented a function in Utils class for getting the list of logged in accounts. Its implementation is shown below.

public static boolean checkAlreadyExist(AccountDatabase.AccountName s) {

   Realm realm = Realm.getDefaultInstance();

   RealmQuery<AccountDatabase> query = realm.where(AccountDatabase.class);

   query.equalTo("name", s.toString());

   RealmResults<AccountDatabase> result1 = query.findAll();

   return (result1.size() > 0);


public static ArrayList<AccountDatabase.AccountName> getLoggedInAccountsList(){

   ArrayList<AccountDatabase.AccountName> list = new ArrayList<>();

   for (AccountDatabase.AccountName account : AccountDatabase.AccountName.values()){

       if (checkAlreadyExist(account))



   return list;


Additional changes

There are few accounts which don’t need authentication. Those accounts need their respective application to be installed in the user’s device. So for adding those accounts to the list, we added another function which checks whether a particular package is installed in user’s device or not. Using that it adds the account to the list. The implementation for checking whether a package is installed or not is shown below.

public static boolean isAppInstalled(String packageName, PackageManager pm) {

   boolean installed;

   try {

       pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);

       installed = true;

   } catch (PackageManager.NameNotFoundException e) {

       installed = false;


   return installed;




Functionality and Customization of the Meilix Metapackage meilix-default-settings

Meilix has is made of build file and metapackages. Build file is responsible for executing commands and successfully implementing the work of metapackages.

Metapackages in Meilix
Name of metapackages used in Meilix are: meilix-artwork, meilix-default-settings.


meilix-default-settings have 3 major folders debian, etc and usr and a Makefile. We are only concerned with etc and usr folder here.
etc and usr folders are folders in which if changes are made that can be seen the ISO. One can assume this as two folders present in the root folder of a Linux Distro.

Its directory is like this:


meilix-artwork has 1 main folder named as usr which contain share folder in which plymouth configuration is made. One can make changes here and it will directly seen in the Linux Distro.

Its directory looks like this:

How these meta packages actually work?
To get the answer one has to jump into the debian folder of any of the metapackage. It contains a control file. This contains information of the metapackages.

Source: meilix-default-settings
Section: x11
Priority: extra
Maintainer: meilix <vanhonit@gmail.com>
Build-Depends: debhelper (>= 8.0.0)
Standards-Version: 3.9.2
Homepage: http://mbm.vn

Package: meilix-default-settings
Architecture: all
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: default settings for meilix
 Various system settings tailored for meilix.

One can update the metapackage from here and tweak with its depends. One come to know about the maintainer of the metapackage which can contacted in case of any issue. We can also know for which architecture this metapackage is made and about its description.
The whole debian does the work but after making any changes in the metapackage, it needs to be rebuild which is performed by debuild.sh. This is how a metapackages in Meilix works.

Linux MetapackagesMatthartley from linux.com
Creating a MetapackageAjmitch from askubuntu.com

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


Creating Custom Borders for Widgets and Layouts in PSLab Android

User Interface (UI) is one of the most important part of any software development. In PSLab Android App while developing the UI, custom borders are used for various widgets and layouts. This makes the UI look more appealing and widgets and layouts look more highlighted.

In Android, we can do a range of border customization. We can make border rounded, define its thickness and even change its color. Let’s see how to achieve this.

First, go to drawable folder in the tree view on the left size of the Android studio. Then go to new and click on Drawable resource file.

Then a New Resource File dialog box will appear. Type the filename and then click OK.

After this, a new XML file is created. Now we can write the code for creating custom borders. For this, we have to define few elements.

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

Shape Drawables allows defining background, borders, and gradients for the Views.

<solid android:color="#FFFFFF"/>

Here we are setting the background color of the widget/layout to which the border is applied to.

<stroke android:width="3dip" android:color="#B1BCBE" />

Now we are applying the 3dip width to the border and set its color. This shape requires the <stroke> element to define the width and color of the line.

<corners android:radius="10dip"/>

In order to make the corners of the border round, <corner> element is used to define the radius of the corners. We are taking it to be 10dip.

<padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />

The padding is expressed in pixels for the left, top, right and bottom parts of the view. Padding is used to offset the content of the view by a specific number of pixels.

After applying this border on a layout we get the following results.

Similarly making following changes in the element values help us to make border for the Text View

<solid android:color="@android:color/white" />
<stroke android:width="1dip" android:color="#ffcdd2" />
<corners android:radius="2dp"/>

Other examples

Control Activity

Logical Analyzer Activity


  1. Stack Overflow Solution to How to make a layout with rounded corners?
  2. Youtube Video on How to create a layout with rounded corner borders in Android? by Sylvain Saurel

Implementing Direct URL in loklak Media Wall

Direct URL is a web address which redirects the user to the preset customized media wall so that the media wall can directly be used to be displayed on the screen. Loklak media wall provides direct URL which has information related to customizations set by the user included in the web address. These customizations, as the query parameters are detected when the page is initialized and actions are dispatched to make changes in the state properties, and hence, the UI properties and the expected behaviour of media wall.

In this blog, I would be explaining how I implemented direct URL in loklak media wall and how customizations are detected to build on initialization of component, a customized media wall.

Flow Chart


Media Wall Direct URL effect

This effect detects when the WALL_GENERATE_DIRECT_URL action is dispatched and creates a direct URL string from all the customization state properties and dispatches a side action WallShortenDirectUrlAction() and stores direct URL string as a state property. For this, we need to get individual wall customization state properties and create an object for it and supply it as a parameter to the generateDirectUrl() function. Direct URL string is returned from the function and now, the action is dispatched to store this string as a state property.

generateDirectUrl$: Observable<Action>
= this.actions$
.map(([action, state]) => {
return {
query: state.mediaWallQuery.query,
wallBackground: state.mediaWallCustom.wallBackground
.map(queryObject => {
const configSet = {
queryString: queryObject.query.displayString,
wallBackgroundColor: queryObject.wallBackground.backgroundColor
const shortenedUrl = generateDirectUrl(configSet);
return new mediaWallDirectUrlAction.WallShortenDirectUrlAction(shortenedUrl);

Generate Direct URL function

This function generates Direct URL string from all the current customization options value. Now,  keys of the object are separated out and for each element of the object, it checks if there is some current value for the elements and it then first parses the value of the element into URI format and then, adds it to the direct URL string. In such a way, we are creating a direct URL string with these customizations provided as the query parameters.

export function generateDirectUrl(customization: any): string {
const shortenedUrl = ;const activeFilterArray: string[] = new Array<string>();
let qs = ;
Object.keys(customization).forEach(config => {
if (customization[config] !== undefined && customization[config] !== null) {
if (config !== ‘blockedUser’ && config !== ‘hiddenFeedId’) {
qs += `${config}=${encodeURIComponent(customization[config])}&`;
else {
if (customization[config].length > 0) {
qs += `${config}= ${encodeURIComponent(customization[config].join(‘,’))}&`;
qs += `ref=share`;
return qs;

Creating a customized media wall

Whenever the user searches for the URL link on the web, a customized media wall must be created on initialization. The media wall component detects and subscribes to the URL query parameters using the queryParams API of the ActivatedRoute. Now, the values are parsed to a required format of payload and the respective actions are dispatched according to the value of the parameters. Now, when all the actions are dispatched, state properties changes accordingly. This creates a unidirectional flow of the state properties from the URL parameters to the template. Now, the state properties that are supplied to the template are detected and a customized media wall is created.

private queryFromURL(): void {
.subscribe((params: Params) => {
const config = {
queryString: params[‘queryString’] || ,
imageFilter: params[‘imageFilter’] || ,
profanityCheck: params[‘profanityCheck’] || ,
removeDuplicate: params[‘removeDuplicate’] || ,
wallHeaderBackgroundColor: params[‘wallHeaderBackgroundColor’] || ,
wallCardBackgroundColor: params[‘wallCardBackgroundColor’] || ,
wallBackgroundColor: params[‘wallBackgroundColor’] ||
}public setConfig(configSet: any) {
if (configSet[‘displayHeader’]) {
const isTrueSet = (configSet[‘displayHeader’] === ‘true’);
this.store.dispatch(new mediaWallDesignAction.WallDisplayHeaderAction(isTrueSet));
if (configSet[‘queryString’] || configSet[‘imageFilter’] || configSet[‘location’]) {
if (configSet[‘location’] === ‘null’) {
configSet[‘location’] = null;
const isTrueSet = (configSet[‘imageFilter’] === ‘true’);
const query = {
displayString: configSet[‘queryString’],
queryString: ,
routerString: configSet[‘queryString’],
filter: {
video: false,
image: isTrueSet
location: configSet[‘location’],
timeBound: {
since: null,
until: null
from: false
this.store.dispatch(new mediaWallAction.WallQueryChangeAction(query));

Now, the state properties are rendered accordingly and a customized media wall is created. This saves a lot of effort by the user to change the customization options whenever uses the loklak media wall.