In an earlier post, I set up HttpResponseValidator to intercept error responses and map them into a sealed ApiResponse type. That worked well for handling errors after they happen. This post goes a step further: preventing unauthorized requests from ever reaching the network using a Ktor Custom Plugin. This handles errors after they occur. I am now preventing unauthorized requests from reaching the network using a Ktor Custom Plugin. The Trakt API includes both public and authenticated endpoints.
Crash reporting is one of those things you don’t think about until your app is in production and users are hitting issues you can’t reproduce. I recently added Firebase Crashlytics to TvManiac, a Kotlin Multiplatform project that targets both Android and iOS. The project already had a Logger interface backed by Kermit, used across the app for console debugging. The goal was to layer crash reporting on top of that without touching any of the existing consumers.
In a previous post, I walked through setting up background tasks in KMP for token refresh. After that post, I added two more background tasks: library sync and episode notifications. Same pattern, same structure. That’s when I noticed a gap in my implementation. I subsequently added two more background tasks for library sync and episode notifications using the same pattern. This revealed a gap in the implementation. Each new task required copy pasting registration, scheduling, and execution boilerplate with slight variations.
In my previous article, I covered building a design system in SwiftUI that mirrors Jetpack Compose’s MaterialTheme. I mentioned that with this foundation in place, adding dynamic themes would be straightforward. Well, I recently implemented exactly that, and I wanted to share how the design system made this possible with minimal platform-specific code. This foundation simplifies the implementation of dynamic themes with minimal platform specific code. Android iOS Motivation for dynamic themes I implemented dynamic themes to provide users with personality options beyond standard light and dark modes.
Intro While building Tv Maniac, a Kotlin Multiplatform project, I needed consistent styling across Android and iOS. On Android, Jetpack Compose gives us MaterialTheme out of the box. On iOS? We have to build our own. This article walks through the approach I took to create a design system in SwiftUI that mirrors the ergonomics of Compose theming. If you’d like to see the code, here’s the pull request. The Problem In Jetpack Compose, accessing design tokens is straightforward:
Intro If you’ve built apps that rely on authentication tokens, you’ve likely dealt with the challenge of keeping those tokens fresh. Tokens expire, and if your user opens the app after being away for a while, they might get hit with an unexpected logout. Not a great experience. Background tasks solve this problem. They allow your app to do work even when it’s not in the foreground—refreshing tokens, syncing data, or fetching updates.
In Part 1, I walked through different approaches for handling environment variables in Kotlin Multiplatform projects. Fast forward a couple of years, and I’ve learned quite a bit about what works at scale and what doesn’t. In this article, I’ll share how I evolved my configuration approach in Tv-Maniac and why I eventually moved to a custom BuildConfig plugin. The Problem with YAML Files The YAML based approach I described in Part 1 worked well initially, but as the project grew, some pain points became apparent:
In my previous post, I walked through publishing Gradle plugins to Maven Central. While that worked, the manual process was tedious. Every release meant updating versions, creating tags, running publish commands, and writing release notes. Today, we’re eliminating all that toil by automating the entire release pipeline with GitHub Actions. What is Continuous Delivery(CI/CD)? Continuous Delivery (CD) is the practice of automating software releases so that code can be deployed to production at any time.
Intro If you’ve been following my TvManiac journey, you know I’m a fan of keeping things modular and reusable. Recently, I hit a point where my Gradle build logic grew into a collection of 10 specialized plugins. They were working great as a local includeBuild, but I started thinking — what if I could publish these plugins and use them like any other dependency? This article walks through my journey of transforming local Gradle plugins into published Maven Central artifacts.
Testing in projects can quickly become complex, especially when managing dependencies across different platforms. In this post, I’ll share my journey of refactoring TvManiac’s test infrastructure from manually creating fake presenter factories to using proper dependency injection with kotlin-inject-anvil to create a test component that wires the fixtures for us. The complete implementation is available in the TvManiac. Let’s jump right in. The Problem: Manual Test Doubles Previously, our tests looked like this.