RSSAmplifier

Blog

Saket Narayan

A wild developer appears. He works at <a href="https://square.com/">Square</a>. Find him on <a rel="me" href="https://twitter.com/saketme">Twitter</a> and <a rel="me" href="https://bsky.app/profile/saket.me">Bluesky</a>.

saket.meRSS feed ↗24 posts

Latest posts

Writing interactive screenshot tests in Compose UI with Touch Robot

These are some examples of real issues that were happening at Block. Each of them was frustrating because we were regularly shipping broken experiences to customers despite having sufficient test coverage. We had screenshot tests using Paparazzi, but they were mostly static snapshots that verified layout correctness. We had connected device tests, but they ran […] The post Writing interactive…

Generating rich link previews 10x faster

unfurl is one of my favorite open source libraries. Not because it’s clever or complex, but because it’s a tiny kotlin library that does one thing well: generate rich link previews by extracting their social metadata. You can try out its demo on your computer: brew install saket/repo/unfurl unfurl https://dog.ceo If you’ve ever pasted a […] The post Generating rich link previews 10x faster…

The pursuit of fast feedback loops

Sebastian Sellmair from JetBrains recently showed off a prototype of hot-reloading Compose UI code for deploying changes without rebuilding the project. It looks exciting and I want it to succeed. At the same time, I’ve learned to be cautiously optimistic about hot-reload solutions. Google has tried this multiple times: their first attempt (Instant Run) was […] The post The pursuit of fast…

Building a sub-sampling image viewer for Compose UI

How do you display a 100mb image on Android without running into OutOfMemoryError? You can’t. But you can cheat. For years Android developers have used Dave Morrissey’s excellent library, subsampling-scale-image-view for displaying large bitmaps with deep zoom. It optimizes memory usage by loading lower resolution bitmaps whenever possible and avoiding loading parts of the original […] The post…

Drawing custom text spans in Compose UI

While exploring how text paragraphs are rendered in Compose UI, I nerd sniped myself into porting squiggly underlines from Sam Ruston’s Buzzkill app. Sam’s animation was implemented using TextView custom spans, but Compose UI does not offer any alternatives for them yet. While our friends at Google are prototyping text modifiers (first, second), I figured […] The post Drawing custom text spans in…

Graduating from View IDs

I found an old screen in Cash App today that wasn’t retaining its scroll position across configuration changes. A peek into git history revealed that the author forgot to assign an ID to its scrollable layout for enabling state restoration. And would you even blame them? Sure, View IDs are necessary, but maintaining them manually […] The post Graduating from View IDs appeared first on Saket…

Great teams merge fast

One of the many things I was constantly amazed about during my first few weeks at Square/Cash App was seeing how fast this team shipped code. All members of the Android team (and likely other platforms as well) were merging to the main git branch multiple times every day. This was in stark contrast to […] The post Great teams merge fast appeared first on Saket Narayan .

Avoiding fake italic and bold text on Android

Changing line heights in Android using LineHeightSpan has this ugly side-effect where the cursor ends up being very tall, extending till the full line height instead of just the text height. I've decided to go to extreme lengths to fix this over the next few days. For science. pic.twitter.com/2tWLvDq1rz — Saket Narayan (@Saketme) November 24, […] The post Avoiding fake italic and bold text on…

Reinventing the dial-up modem

While working on a healthcare app called Simple at my previous company, we wanted to improve how nurses follow up with their patients. The aim was to replace traditional paper registers + landline phones with the app, which could intelligently suggest patients who are potentially at risk based on their medical history, age, and other […] The post Reinventing the dial-up modem appeared first on…

Building a gesture driven Reddit app

An exploratory talk that showcases how Android can deliver a beautiful experience to the user using material design principles and various framework APIs like gestures and spans. This talk walks the user through a collection of concrete examples of custom UI components and their implementations in my gesture driven Reddit app, Dank. Recreating Google Inbox’s […] The post Building a gesture driven…

Sunsetting Dank

I’ve been trying to write this post for a while, but I kept throwing my words in the bin in hopes that things will improve. I believe it’s now time to put an end to this. I started building Dank as a side project in January 2017. It was my playground for exploring Android. It […] The post Sunsetting Dank appeared first on Saket Narayan .

Smoothly reacting to keyboard visibility changes in Android

When people use Dank, one of the terms they use to describe it is fluid. The app makes a good use of motion to indicate changes on the screen, but I think one of my favorite reasons why the app feels fluid is because it handles keyboard changes smoothly. When the soft keyboard is shown, […] The post Smoothly reacting to keyboard visibility changes in Android appeared first on Saket Narayan .

Introducing InboxRecyclerView, a library for building expandable descendant navigation

When Google released Inbox for Android some 4 years ago, their UI was rad. I was obsessed with the navigation transition, where emails expanded from their list item when clicked, pushing all other items out of the screen. When pulled downwards, the emails collapsed back to their positions. I wanted to recreate this UI. I […] The post Introducing InboxRecyclerView, a library for building expandable…

Designing a flick dismissible image viewer

While working on Dank, my primary goal was to ensure that user generated content on Reddit receive as much attention in the app as possible, while letting the UI take a back-seat. As part of this experience, all images and videos in Dank are flick-dismissible so that the user can browse through high quality cat […] The post Designing a flick dismissible image viewer appeared first on Saket Narayan…

Persistence as the single source of truth

Simple is better than complex. Complex is better than complicated. In the world of Android, where all sources of information and user interactions are asynchronous, UI state can become hard to reason about, especially in large apps. This is not only difficult to maintain but also increases complexity with the addition of every new feature. […] The post Persistence as the single source of truth…

This is your next Reddit app &#8212; Dank

After spending more than a year, I’m happy to announce that my Reddit app — Dank is finally ready for the world to see. You’re going to love it. It’s a fresh experience for Reddit on Android. Scroll to the bottom for the download link. The first thing you’re going to notice is that Dank […] The post This is your next Reddit app — Dank appeared first on Saket Narayan .

Band-aiding legacy networking libraries with Retrofit and OkHttp

When Uncommon was brought in to refactor a big legacy app last year, we found ourselves in a strange situation. Our client was maintaining a common library for handling networking — HTTP, FCM, MQTT — across all apps under their brand. This library (let’s call it SadLibrary) had an API that was badly designed and dated, but not using […] The post Band-aiding legacy networking libraries with…

Simplifying DiffUtil with RxJava

One of my favorite parts of RxJava is that no matter how complex a state management usecase is, there’s always an operator for that™. During a recent code cleanup, I found a very cool usecase of RxJava’s scan() and compose() operators for simplifying the usually verbose DiffUtil implementation. I had been delaying writing this post […] The post Simplifying DiffUtil with RxJava appeared first on…

The lesser known world of spans

Do you know what’s common between the blinking cursor, hyperlinks and text highlighting in TextViews? They’re all implemented using spans. Spans are tiny objects that Android uses heavily across the framework. If you’ve worked with text styling such as bold or italics, then you’re already familiar with the basic usages of spans. But they are […] The post The lesser known world of spans appeared…

Android Nougat and rate limiting of notification updates

While working on a feature for downloading images in my app, I ran into a strange issue where progress notifications were never reaching 100%. Knowing that the framework is usually not wrong, I started suspecting my own skills (as usual). To make matters worse, nobody was able to reproduce the issue in a sample project I shared with other […] The post Android Nougat and rate limiting of…

Displaying HTML tags on TextView the right way

While going through the codebase of a former client, I found that I was using four different ways for showing HTML on Android. This made me realize that I didn’t really know what the correct way of showing them is and I’ve always hammered my way using trial & error until the HTML tags have showed up. Embarrassed, I decided to explore how […] The post Displaying HTML tags on TextView the right way…

Tips for Android Nougat&#8217;s bundled notifications

I’ve been working on implementing bundled notifications in my app, which is by far one of my favourite features about Android 7.0 Nougat. While the official guide is good enough for understanding how they work, I’ve constantly found myself running into behaviours that were not easy to find in the documentation. This post is an attempt to summarise […] The post Tips for Android Nougat’s bundled…

A better way to handle links in TextView

There are two ways of “linkifying” URLs in a TextView. First, as an XML attribute: <TextView ... android:autoLink="phone|web" /> and second, programmatically: TextView textView = (TextView) findViewById(R.id.text1); Linkify.addLinks(textView, Linkify.PHONE_NUMBERS | LINKIFY.WEB_URLS); In both the cases, the framework internally registers a LinkMovementMethod on the TextView that handles…

Deflating the LayoutInflater

Android developers spend a lot of time writing XML layouts every day. This talk will explain how Android’s LayoutInflater works. By the end of this talk, you will have an understanding of how XML gibberish gets converted to Views in Java, how AppCompat is able to back-port Material Design for pre-Lollipop devices auto-magically and how […] The post Deflating the LayoutInflater appeared first on…