Skip to content
abuenoben showroom

Cuadrilla: work offline.

Teams, tasks and photographs saved on the device. When the connection returns, you choose when to synchronize.

Save offline and synchronize later

Airplane mode, persisted changes, process shutdown, reopening with the photo available, connection failure and recovery.

Application walkthrough. 48 s.
What this journey shows

Airplane mode, persisted changes, process shutdown, reopening with the photo available, connection failure and recovery.

Does your team need a mobile app?

We can define workflows, data that must remain available offline and each platform’s integrations before agreeing the scope.

Discuss a mobile project
Screens and platforms

Daily work on Android.

Each task brings together its assignee, status and photographs. Changes are saved on the device so work can continue without a connection.

Organise work and attach a photo

Team, assignee, task status and import through the Android photo picker.

Application walkthrough. 59 s.
What this journey shows

Team, assignee, task status and import through the Android photo picker.

Application screenshots

Cuadrilla on Android: tasks and assignees. North Team task list with status, filters and assignees.
Tasks and assignees
North Team task list with status, filters and assignees.
Cuadrilla on Android: team members. Team members, roles and open tasks.
Team members
Team members, roles and open tasks.
Cuadrilla on Android: a photo within the task. Status, assignee and attached photograph.
A photo within the task
Status, assignee and attached photograph.
View all application screens and states
Cuadrilla on Android: find a task. Local search for the term material.
Find a task
Local search for the term material.
Cuadrilla on Android: view the photo. Viewer displaying the photograph saved with the task.
View the photo
Viewer displaying the photograph saved with the task.
Cuadrilla on Android: change status offline. Task marked done with airplane mode enabled and server tunnel removed.
Change status offline
Task marked done with airplane mode enabled and server tunnel removed.
Cuadrilla on Android: reopen without losing the photo. Photograph available after closing and reopening offline.
Reopen without losing the photo
Photograph available after closing and reopening offline.
Cuadrilla on Android: changes waiting to be shared. After connection failure, local changes are retained and the remote revision is unchanged.
Changes waiting to be shared
After connection failure, local changes are retained and the remote revision is unchanged.
Cuadrilla on Android: synchronization confirmed. Connectivity restored and manual sync completed; local and remote states verified equal.
Synchronization confirmed
Connectivity restored and manual sync completed; local and remote states verified equal.
Cuadrilla on Android: dark theme. The same application using the system dark theme.
Dark theme
The same application using the system dark theme.
Cuadrilla on Android: 320 dp and 200% font scale. Narrow-width, dark-theme and enlarged-text check; content scrolls.
320 dp and 200% font scale
Narrow-width, dark-theme and enlarged-text check; content scrolls.
Cuadrilla on Android: tablet-width navigation. 600 dp width: navigation rail and additional content space.
Tablet-width navigation
600 dp width: navigation rail and additional content space.

iOS: shared UI, with native platform adapters.

The project includes a SwiftUI host, a Compose screen exposed through UIViewController, UIKit camera integration, PHPicker and the Darwin HTTP client. Screens and rules are shared; system permissions and pickers have platform-specific implementations.

Teams, tasks and photographs on iPhone

What this journey shows

Team selection, task browsing, assignee selection and task detail with a photograph.

Application screenshots

iOS: Task list
Task list
iOS: Team members
Team members
iOS: Task with a photograph
Task with a photograph
Architecture and limits

What is shared and where the boundaries sit.

Kotlin Multiplatform shares the model, validation, persistence, change merging and HTTP client. Compose Multiplatform shares the screens. Android and iOS hosts provide application entry points and system integrations.

PartTechnologyResponsibility
InterfaceCompose Multiplatform · Material 3Tasks, teams, forms, detail, photo viewer and settings.
Operations and stateAppController · Coroutines · StateFlowRun asynchronous operations, observe data and report results or errors.
Rules and writesWorkspaceRepository · MutexValidate changes and publish state only after persistence succeeds.
Local persistenceOkio · JSON · Base64 JPEGPrivate workspace snapshot, using a temporary file and atomic rename.
CommunicationKtor client · OkHttp / DarwinFetch and send the workspace when the user taps Synchronize.
Optional serverPython HTTP · SQLiteOne workspace with a shared key and revision checked within a transaction.

One shared codebase, clear boundaries

One shared codebase, clear boundaries. Screens, state, validation and persistence live in the Kotlin Multiplatform module.
Screens, state, validation and persistence live in the Kotlin Multiplatform module.

What is shared and what is native

What is shared and what is native. Two mobile hosts. JVM runs shared-module tests; there is no desktop application.
Two mobile hosts. JVM runs shared-module tests; there is no desktop application.

Architecture decisions

Persist before confirming
The repository writes to disk before updating the UI. A network failure is not part of a local write, and a disk failure is not presented as a saved change.
A bounded snapshot
The JSON snapshot keeps data and photographs together: up to 12 MB, 500 tasks, 30 teams and 50 members per team. For many photos or incremental updates, the next step would be a local database with separate image files.
User-triggered sharing
Synchronization is manual. It compares the last synchronized baseline, local state and remote state to retain independent changes and detect incompatible edits to the same record.
Saving and synchronization

From local work to shared changes.

A task belongs to a team and can be assigned to one of its members. It has a title, description, status, priority, optional due date and up to six photos. Removing a member keeps their tasks and clears the assignment.

Tasks and photos independent of temporary source links

  1. Create or edit a task and its assignee.
  2. Open the system camera or picker and import a JPEG up to 1280 px and 900 KB.
  3. Validate the new workspace, write a temporary file and rename it atomically.
  4. Update the UI and read that state on reopening, including photos, with no server required.

From a task to a photo available offline

From a task to a photo available offline. Confirmation follows persistence: network access is not part of a local write.
Confirmation follows persistence: network access is not part of a local write.

Synchronization with revisions and visible conflicts

  1. Tap Synchronize and fetch the remote workspace and revision.
  2. Compare base, local and remote versions per team or task. Independent changes are merged.
  3. If a record has incompatible changes, show both versions and ask which to keep. That choice may discard the other version.
  4. Send only when there are changes to share. SQLite checks the revision in a transaction; HTTP 409 requires fetching and merging again.
  5. After remote confirmation, persist the new local baseline. If the network fails, retain local work for another attempt.

Share changes without blind overwrites

Share changes without blind overwrites. Manual sync compares base, local and remote versions; conflicts are detected per team or task.
Manual sync compares base, local and remote versions; conflicts are detected per team or task.

A complete workflow, online and offline.

  1. Organize teams and assign each task to a person.
  2. Add photographs from the camera or gallery and save them with the task.
  3. Change task status and keep working offline.
  4. Close and reopen the application with tasks and photographs preserved.
  5. Reconnect and synchronize changes with the other devices.

Local persistence and synchronization are independent operations. The team shares a server address and workspace key; each person chooses when to send and receive changes from Settings.