Revamping Meesho’s Android App UI: Implementation Takeaways

A tech perspective into our app redesign project and some challenges we faced along the way.

Joel Fernandes
Meesho Tech
8 min readMar 15, 2021

--

Design System is an essential guideline and the key to building a consistent user experience in a product. With a set of rules and principles to operate on, it helps define and create reusable components and UI elements in the system which can be used to build more complex designs easily.

Over the years, Meesho has evolved into a complex app with lakhs of entrepreneurs transacting on a daily basis. We wanted to make their shopping experience on Meesho simpler than ever. In Q4 2020, our design and product team got to the core of this problem and conceptualized a design system called Mesh.

Understanding the Mesh Design System

Keeping Meesho entrepreneurs in mind, the Mesh design system was idealised with the core objective of providing a clean and visually appealing user experience, and to standardize design elements across the app. From a tech perspective, we developed the mesh design based on the Atomic Design Methodology, authored by web designer Brad Frost.

App design comparison

Apart from the improved UX, this structured design system added advantages such as:

  • Efficient maintenance of UI code: Core UI components code is now decoupled from business logic, hence making it easier to update and test.
  • Because of reusable components, developers can provide accurate dev estimates.
  • Cuts down on code redundancy: No more redundant view/layout files as the library is the single source of truth.

Let’s now look at some collective insights, learnings and key takeaways from our Android team while implementing and integrating this design system.

How we built the Mesh Design library?

Mesh is a standalone Android library that is built on top of Material Design Components (MDC). Virtually every component inside Mesh extends MDC, and the primary reason why we chose this approach was to avoid bloat and complexity of creating custom views.

In a nutshell, we followed the KISS principle (Keeping it Short and Simple)

Additionally, this approach allowed us to easily adapt universal changes in the system. With the help of AppCompatViewInflater, component instances can be replaced at inflation time with minimal changes to the codebase under the hood.

Some key learnings while designing Mesh Components

Components were created using the idea of Composite/Compound Views by inflating them and without having to worry about view lifecycle methods — onMeasure, onLayout or onDraw.

The following are some challenges we faced while implementing the Mesh components and how we overcame them:

Dynamic Button Styling for a Multi-Info CTA

Structurally-speaking, designing this multi-info CTA component is pretty straightforward. However, the challenging part of implementing it was to provide dynamic button styling (i.e. capability of changing the button style at runtime).

We implemented this by creating attribute references and then mapped using enums. At runtime, if a button’s style needs to be changed, the corresponding enum value has to be passed. It internally resolves to an AttrRes and gets passed to defStyleAttr in MaterialButton’s three parameter constructor to (re)create the button. We had to follow this approach since the Android’s framework has a limitation that does not apply all the attributes of a given style.

Left: Multi-info CTA | Right: Code snippet for dynamic button styling

Abstraction Logic for Mesh Bottomsheet’s Complex Use Cases

We wanted to minimize the variations a bottomsheet could have. The design team standardised this by restricting it to three styles. Using a builder pattern, this component was implemented by extending BottomSheetDialogFragment and an abstract class MeshBottomSheetFragment was created to handle all the possible use cases of the three styles that were defined.

As for the abstraction logic, our task was quite challenging here since the use cases were more complex as the APIs and features had to be dynamic and configurable. In the sample image, the content area is dynamic in nature, however, the underlying component is provided by the library. The client only needs to pass the layout to the component and handle their callbacks accordingly. This was achieved by inflating the content view into a ViewGroup container.

Left: Mesh Bottomsheet | Right: Demo usage of Bottomsheet component

No Data Binding, yet keeping it Compatible

The library is designed to be as lightweight as possible, with dependencies constrained to the minimum. Given an app that uses data-binding or Jetpack Compose, the library will be highly compatible with minimum or no changes at all. For example, apps with data binding enabled can easily use setters exposed by components and molecules

Setters to enable data binding

Final Design Integration with Meesho App: Challenges & Solutions

Once we had the Mesh library ready, our next biggest challenge was to integrate it into our app. All the UI elements in the app’s codebase had to be replaced with components provided by Mesh library, refactor UI logic, and remove all existing redundancies. It certainly was a time consuming task, but our Android team came together and achieved this in less than four weeks.

The following are some integration challenges we encountered:

Font Metrics differed between Licensed and Demo fonts

Mesh design uses Mier-B font. All text headings and body styles were defined in text_styles.xml with line-height and baseline-height values provided with each style.

At the time of development, the library used a test/demo font that was provided by the vendor. Towards the end when we obtained the licensed version, the text styling implementation broke. Line-height and baseline-height had gone for a toss. What we learnt was that the the test font and licensed font did not have the same font metrics.

Demo vs Licensed font

To resolve this, on API 21 and above, Android provides a feature called setElegantTextHeight(boolean). This setting was enabled in conjunction with includeFontPadding = false to get the most accurate results.

Key Learning: Demo fonts have limited glyph support and font metrics could vary with the licensed font. Make sure to always use a licensed font when implementing text styles

As a result of this font issue, we were restricted to use style instead of textAppearance. In order to incorporate them, we had to replace all android:textAppearance="@style/TextAppearance.*” with style="@style/TextStyle.Mesh.*”. We wrote a lint check detector using the LayoutDetector API that checked for all usages of textAppearances. Additionally, we also needed to remove all usages of vertical paddings from TextViews.

Lint checker for vertical padding

Removing & Replacing the existing icons from our codebase

All icons were imported as VectorDrawable with standardised 20x20 size. This was primarily done to avoid icon duplications in the codebase. Icons fell under the Atoms category of Atomic Design Methodology, and hence they were all referenced from the library. Icons used with compound drawables were upscaled/downscaled accordingly using Android’s Drawable#setBounds

Icons comparison

The challenging task was to remove existing icons from the codebase and replace/reference them with library icons. Yet again the lint LayoutDetector API came handy here — A simple detector was written to check for all icon drawable resources that could be replaced with library icons.

Keeping Design Libraries as local module during development

Library components were manually (dev) tested on different platforms ensuring that it was backward compatible since the minimum SDK version was set to API 16 (Jelly Bean). Integration testing with the app was done with the help of the QA team. Along with the library, a sample demo app was built in parallel. This was done to showcase/demo the API usages and also enabled the design team to review the components implementation.

Having said that, one key learning we had here was that we decoupled the library way too ahead of time. Instead we should’ve added it as a local module during the development phase and separated it out as a library at the time of release. The pain point here was that we had to constantly make library releases at the time of integration with an additional overhead of bumping up the library version on the app side.

Early User Adoption Metrics

The app redesign has been received exceptionally well by our entrepreneurs. Our early adopters have given positive feedback and the metrics portray the same story. During our initial experimental stage, we rolled out the new app to 40% of the Android user base and we’ve witnessed a significant rise in new users placing their very first order, as well as existing users engaging with the app more than usual. That’s a big win!

There are many upsides of having a design system, however, what mattered to us the most were:

  • Giving our entrepreneurs the best cohesive experience in their reselling journey.
  • Developers can focus more on business logic and spend less time on building layouts or custom views. Goes along with our team motto, i.e. Speed Over Perfection.
  • It also ensures UI designers to reuse atoms and molecules from the design system, thereby preventing any UI inconsistency.

Having witnessed great early adoption metrics, we’re hopeful towards our 10x growth journey in 2021. But first, let’s celebrate this milestone!

This blog was co-authored by Pavan PM, Vibin Reddy, and Ashok Lingadurai.

Solving Meesho’s Big Data Requirements using Delta Lake

Handling API requests at scale using Meesho’s in-house Edge Proxy service

Are you looking to join a dynamic group of engineers obsessed with scaling up? Then Meesho is the right place for you. Click here to find openings.

--

--