Projects
Warehouse. Tablet app icon

Warehouse. Tablet

Sole developer · Nov 2018 – Jan 2019

An offline-capable Android tablet app for B2B field sales reps to browse a live warehouse catalog, build client orders, and submit them to a self-hosted back-office server - built solo in Java with a Realm-backed local cache and incremental delta sync. Built in 2018, never publicly released.

AndroidJavaB2BRealmOffline-first

Warehouse. Tablet is a B2B ordering tool for field sales agents, built for wholesale-distribution business. A rep configures the back-office server address on first run, logs in, and lands on a list of previously submitted orders they can refresh, open, or swipe to delete.

To start a new order the rep picks a client (and, where applicable, a contract or subcontract) from a two-level searchable picker, then browses a hierarchical category → product catalog of arbitrary depth - in list or grid view, with recursive search - seeing only products with live warehouse stock above zero. Quantities can be entered as a single decimal or as packages × units-per-package, with a custom widget auto-converting between the two and a running order total recalculating live. The rep can also open the client's financial ledger over a date range before reviewing the basket and submitting to the server.

The app is tablet-first and landscape-locked, with a permanently open side drawer and an adaptive 2-or-3-column grid - a classic master/detail tablet layout. It uses a hybrid navigation shell (a multi-activity router into a single-activity + fragments authorized zone driven by Android Navigation Components) and a cache-first data flow: the UI always reads from Realm while a data-fetcher utility pulls from the server, maps DTOs into Realm models, and fans results out over an EventBus that fragments subscribe to and re-render from. Realm is treated as a disposable cache - schema bumps wipe and re-fetch rather than migrate - with the on-premise server as the source of truth.

I designed and built the whole thing solo in Java for Android tablets. It was built in 2018 and only ever shared internally, never publicly released. It's a 2018-era codebase (Java rather than Kotlin, ButterKnife, Fabric/Crashlytics, Navigation Components in alpha): reasonable domain modeling and tablet UX for its time, not "modern Android" by today's standards.

Architecture & engineering highlights

  • Incremental (delta) sync engine - rather than re-downloading the full catalog, the data fetcher passes a cursor (max product transactionId, max stock id, max order code) so the server returns only records changed since the last sync. The cursors are derived from the Realm data itself, not from timestamps kept in preferences.
  • Durable offline order composition - a singleton PendingOrder record (PK fixed to 1) persists the entire in-progress order: selected client, contract type, per-product quantities, notes, and UI-restoration state (category breadcrumb path and scroll position). A half-built order survives navigation and app restarts, and on submit failure the draft is kept for manual retry.
  • Arbitrary-depth catalog and client trees with a Cyrillic-search workaround - products and clients are self-referential trees (parentId, treeLevel, isFolder, hasChildren) that drill down to any depth with up/to-root navigation. Because Realm's text search handled Cyrillic poorly, each model carries a precomputed lower-cased search field for reliable matching.
  • Custom package/unit quantity converter - a ConstraintLayout with two linked EditTexts and a factor: typing packages auto-computes units (×factor) and vice-versa (÷factor), with the reciprocal TextWatchers deliberately detached during programmatic updates to avoid infinite feedback loops.
  • Certificate/public-key-pinning infrastructure + legacy-TLS hardening - a full RSA X509TrustManager plus a TLS 1.2 SSLContext and Google Play Services ProviderInstaller patching to give Android 4.4 KitKat devices modern TLS.
  • Resilient auth around a quirky backend - the session is a GUID embedded in the URL path (no bearer header); the client pins a UTF-8 JSON content type and treats an empty 200 body as a synthetic 401, with a global force-logout on unauthorized responses, working around a backend that signals auth failure via empty bodies.
  • Network-state monitoring via a BroadcastReceiver plus a modern ConnectivityManager.NetworkCallback, posting sticky EventBus events so the UI reacts to online/offline and to an off→on "connection restored" transition.

Tech stack

Android & data

Java 8minSdk 19 (KitKat) / target 28Realm 5.7 (one DB file per user)Android Navigation Components 1.0 (alpha)greenrobot EventBusMultidexGradle 3.3 (dev / warehouse flavors)

Networking

VolleyGsonHandy URI TemplatesCustom APIRequests facadeRSA public-key pinning (PublicKeyManager)TLS 1.2 + ProviderInstaller back-port

UI

AndroidX AppCompat / MaterialConstraintLayoutRecyclerView + FlexibleAdapterButterKnifeGlide + RoundedImageViewTransitionsEverywhereSavvi date-range picker

Ops & build

Fabric / CrashlyticsTimberGoogle ServicesJUnit + Espresso (scaffolding, minimal coverage)

All rights belong to their respective owners.