Skip to main content

Command Palette

Search for a command to run...

How I Created a Versatile Mobile Toolkit App

Updated
9 min read
How I Created a Versatile Mobile Toolkit App

Introduction

In a world where we constantly switch between dozens of single-purpose apps, I wanted to build something different—a single, beautifully designed mobile application that bundles everyday utility tools into one cohesive experience. That idea became Toolify, a React Native toolkit app packing 11 fully functional tools.

Toolify isn't just a collection of simple forms; it's a versatile powerhouse that integrates a sleek dark UI, a modular architecture, and complex native device capabilities—handling everything from hardware sensors like the compass to real-time network benchmarks—all within one runtime.

In this article, I walk through the entire journey—from the initial concept and technology choices to the architecture, design system, and the implementation details of each tool.


The Vision

The goal was simple: create a Swiss-army-knife mobile app that feels native, looks premium, and works offline. Instead of cluttering your home screen with a compass app, a calculator, a unit converter, a password generator, and a stopwatch, Toolify brings them all under one roof with a consistent, polished experience.


Technology Stack

Choosing the right technology was critical for balancing development speed with native performance. Here is what I went with and why:

Technology Purpose Why?
React Native + Expo SDK 54 Cross-platform development Access to native APIs without writing native code; managed workflow and EAS updates.
TypeScript Language Type safety and vastly improved developer experience/maintainability.
React Navigation 7 Navigation Native stack navigation between tools for a natural feel.
Zustand State Management Lightweight, powerful, and simpler than Redux; native support for persistence.
Lucide React Native Iconography Beautiful, consistent, and customizable icon set.
expo-sensors Hardware Access Unified API for the Magnetometer (Compass) and Accelerometer (Bubble Level).
react-native-svg Data Visualization Resolution-independent rendering for custom gauges, compass dials, and QR codes.
AsyncStorage Local Storage Persistent storage for user data (like tasks), integrated via Zustand middleware.

Other essential Expo libraries (expo-camera, expo-clipboard, expo-image-picker) were used to unlock specific device features as needed.


Architecture and Project Structure

A key principle was modularity. To ensure the app could scale to 11 tools (and beyond) without becoming a maintenance nightmare, each tool lives in its own self-contained module directory.

src/
├── components/          # Shared UI components (e.g., ToolCard, CustomButton)
├── constants/
│   └── theme.ts         # Centralized design tokens (colors, spacing, typography)
├── modules/             # Feature modules - one self-contained directory per tool
│   ├── bmiCalculator/
│   ├── calculator/
│   ├── compass/
│   │   ├── CompassScreen.tsx
│   │   └── CompassDial.tsx # SVG component
│   ├── taskManager/
│   │   ├── store.ts     # Zustand store with persistence
│   │   └── TaskManagerScreen.tsx
│   └── ... (other tools)
├── navigation/
│   └── RootNavigator.tsx # Central navigation configuration
└── screens/
    └── HomeScreen.tsx    # The tool grid dashboard

Why This Structure Works

  • Separation of Concerns: Each module owns its UI, logic, and (where needed) its own state store. There is zero coupling between tools.

  • Scalability: Adding a new tool is trivial. I create a folder under src/modules/, register a new route in RootNavigator.tsx, and add a card to the HomeScreen.tsx. Zero refactoring required.

  • Discoverability: The folder structure is self-documenting. You can see every feature of the app at a glance.


The Design System

Consistency was non-negotiable. Every screen, card, and button draws from a single source of truth in src/constants/theme.ts:

export const Theme = {
  colors: {
    background: '#121212', // Deep charcoal
    surface: '#1E1E1E', // Card background
    surfaceLight: '#2C2C2C', // Inputs and hover states
    primary: '#00E5FF', // Electric Blue accent
    text: '#FFFFFF',
    textSecondary: '#A0A0A0',
    border: '#333333',
    success: '#03DAC6',
  },
  spacing: { xs: 4, s: 8, m: 16, l: 24, xl: 32 },
  radii: { m: 8, l: 12, xl: 20, round: 9999 },
  typography: {
    h1: { fontSize: 32, fontWeight: 'bold' },
    body: { fontSize: 16, fontWeight: 'normal' },
  },
};

Screenshot of the Home Screen grid showing the design system in action

The dark theme with an electric blue accent (#00E5FF) gives the app a modern, tech-forward aesthetic. Every component references Theme directly—eliminating magic numbers, inconsistent padding, and color drift.

The navigation bar also inherits from this theme by extending React Navigation's DarkTheme:

// in RootNavigator.tsx
const AppTheme = {
  ...DarkTheme,
  colors: {
    ...DarkTheme.colors,
    primary: Theme.colors.primary,
    background: Theme.colors.background,
    card: Theme.colors.surface,
    text: Theme.colors.text,
    border: Theme.colors.border,
  },
};

Deep Dive: Implementing the 11 Tools

The core challenge of Toolify was implementing 11 distinct feature sets while maintaining a unified architecture. Here is how some of the key tools were built.

1. Calculator (Basic and Scientific)

Side-by-side screenshots of Basic and Scientific Calculator modes

The calculator supports two modes toggled via a simple segment control: Basic arithmetic and Scientific functions (trig, logs, powers).

The expression is built as a string as the user taps buttons. To evaluate it, I created a prepareExpression() function that transforms human-readable notation into JavaScript-compatible math calls (e.g., sin( becomes Math.sin(, ^ becomes **). The final string is evaluated using a sandboxed new Function() call for safety.

2. Unit Converter

This tool supports Length, Weight, and Temperature with instant conversion as you type.

Length and Weight use a base-unit conversion strategy: everything converts to/from a base unit (meters or grams) using a central multiplier map. This avoids \(N^2\) conversion formulas. Temperature, however, requires explicit formulas (e.g., Celsius to Fahrenheit), which are handled separately.

3. Hardware Sensors: Compass and Bubble Level

Screenshot of the Compass (showing SVG dial) and Bubble Level (showing green 'level' state)

These tools utilize the device’s hardware sensors via expo-sensors.

  • Compass: Uses the Magnetometer. We calculate the heading via atan2(y, x) from the raw data. To ensure a premium feel, we apply a low-pass filter (smoothing the data by blending 80% new reading with 20% previous) to reduce jitter, and handle the "wrap-around" logic to prevent sharp jumps when crossing the 359°\(\rightarrow\)0° boundary. The dial is a custom SVG that rotates smoothly.

  • Bubble Level: Uses the Accelerometer to measure tilt on the X and Y axes. The UI renders a dynamic SVG "bubble" that moves within a circular gauge, changing color (Green/Orange/Red) based on the degree of tilt.

4. Task Manager (Persistent To-Do List)

This is a full CRUD (Create, Read, Update, Delete) task manager.

State is managed by Zustand using the persist middleware backed by AsyncStorage. This means the user's tasks are automatically saved locally and survive app restarts without requiring any manual "Save" logic. The store defines a clean, type-safe interface for all operations:

interface TaskState {
  tasks: Task[];
  addTask: (title: string) => void;
  toggleTask: (id: string) => void;
  editTask: (id: string, newTitle: string) => void;
  deleteTask: (id: string) => void;
}

5. Internet Speed Test (Real Network Benchmarks)

screenshot of the Speed Test gauge animating during a download test

This is a genuine, active speed test that measures three distinct metrics against Cloudflare's speed test endpoints:

  1. Ping: Measures the median latency of 5 rapid requests.

  2. Download: Tracks real-time Mbps while downloading a 10MB file.

  3. Upload: Measures throughput while POSTing 2MB of data.

The UI features a semicircular SVG gauge that animates during the test. To provide real-time updates, the download test uses a ReadableStream reader, calculating speed as chunks arrive rather than waiting for the entire 10MB file to complete.

Other Tools

  • QR Tools: Dual-mode tool using expo-camera for scanning and react-native-qrcode-svg (styled with our primary theme color) for generation.

  • Password Generator: Generates cryptographically random passwords with configurable length and character sets.

  • Stopwatch & Timer: Handles complex timing logic (laps, split times) with proper interval management. We use useRef for the timer interval ID to ensure it persists across renders without triggering unnecessary re-updates.

  • BMI Calculator: Straightforward health tool with color-coded results.

  • Text Scanner: A manual transcription assistant. Users capture an image of text (via camera or gallery) and can transcribe it into an editable field, providing a convenient reference layout.


Performance Considerations and Edge Cases

A utility app must be robust. We prioritized performance and handling edge cases throughout development:

  • Sensor Lifecycles: Sensor subscriptions (60ms interval for Compass, 80ms for Level) are aggressively cleaned up useEffect return functions to prevent memory leaks and battery drain.

  • Hardware Fallbacks: Both the Compass and Bubble Level check for sensor availability on mount, displaying friendly error messages on simulators or devices lacking the required hardware.

  • Error Handling: The Speed Test includes 30-second timeouts via AbortController and catches network failures gracefully. The Calculator handles NaN, Infinity, and expression errors without crashing.

  • UX Details: KeyboardAvoidingView is used consistently (e.g., BMI Calculator, Task Manager) to ensure inputs are never obscured on iOS.


Building and Deployment

Toolify is configured for EAS Build with a streamlined configuration:

  • Android Package: com.toolify.app

  • Full edge-to-edge display support.

  • Orientation locked to Portrait.

  • Adaptive icons for Android and tablet support for iOS.

  • New Architecture enabled for React Native 0.81.5.


Lessons Learned and Next Steps

  1. Start with the Design System: Defining colors, spacing, and typography upfront saved enormous time and ensured visual consistency across 11 distinct screens.

  2. Modular Architecture Pays Off: Working on one tool without touching any other file made development fast and conflict-free.

  3. Hardware Sensors Require Real Devices: Many sensor features cannot be fully tested on simulators. Building graceful fallbacks from day one was essential.

Toolify is designed to grow. Some ideas for the future include a camera-based Color Picker, a Sound Meter using the microphone, and a Ruler/Measurement tool utilizing AR.

Conclusion

Building Toolify proved that a well-architected React Native app can deliver a premium, native-feeling experience across a wide range of device capabilities—from hardware sensors and cameras to complex network benchmarks and persistent storage. By investing in a solid design system and a modular architecture early on, adding new tools became a predictable, low-risk, and enjoyable process.


Toolify is built with React Native 0.81.5, Expo SDK 54, and TypeScript 5.9.