5.3 KiB
CollabTable Android App
A collaborative table management Android application built with Jetpack Compose and Material 3.
Features
- Create and manage multiple tables
- Add custom fields to tables (name, link, price, category, etc.)
- Add items with values for each field
- Beautiful Material 3 design with dynamic colors
- Local Room database for offline support
- Automatic synchronization with server (WebSocket-first with HTTP fallback)
- Soft delete support (items can be recovered on server)
- Optimized large table scrolling (stable row ordering + debounced updates)
Architecture
- UI Layer: Jetpack Compose with Material 3
- Business Logic: ViewModels with Kotlin Coroutines
- Data Layer: Room database + Retrofit for API calls
- Navigation: Jetpack Navigation Compose
Prerequisites
- Android Studio Hedgehog or later
- Android SDK 26 (Android 8.0) or higher
- JDK 17
Building the Project
- Clone the repository
- Open the
CollabTableAndroidfolder in Android Studio - Wait for Gradle sync to complete
- Run the app on an emulator or physical device
Server Configuration
The app includes a Settings screen where you can configure the server URL:
- Tap the Settings icon (⚙️) in the top bar of the Tables screen
- Enter your server URL
- Tap "Save"
Default URLs:
- Android Emulator:
http://10.0.2.2:3000/api/ - Physical Device:
http://YOUR_COMPUTER_IP:3000/api/(replace YOUR_COMPUTER_IP with your actual IP address)
Note: Make sure to include /api/ at the end of the URL.
Project Structure
app/src/main/java/com/collabtable/app/
├── data/
│ ├── api/ # Retrofit API interfaces and client
│ ├── dao/ # Room DAOs
│ ├── database/ # Room database
│ ├── model/ # Data models
│ └── repository/ # Repository pattern for data access
├── ui/
│ ├── navigation/ # Navigation setup
│ ├── screens/ # UI screens and ViewModels
│ └── theme/ # Material 3 theme
├── CollabTableApplication.kt
└── MainActivity.kt
Key Technologies
- Jetpack Compose: Modern declarative UI toolkit
- Material 3: Latest Material Design guidelines
- Room: Local SQLite database
- Retrofit: REST API client (fallback)
- OkHttp WebSocket: Real-time sync channel
- Kotlin Coroutines: Asynchronous programming
- Flow: Reactive data streams
Usage
Creating a Table
- Tap the + button on the main screen
- Enter a table name
- Tap "Save"
Adding Fields
- Open a table
- Tap the + icon in the top bar
- Enter a field name (e.g., "Name", "Price", "Category")
- Tap "Add"
Adding Items
- After adding fields, tap the floating + button
- Fill in values for each field
- Values are saved automatically as you type
Exporting a Table
In the Tables overview screen each table row includes an Export icon between Edit and Delete. Tap it to open a dialog, choose a format (currently only CSV), then confirm. A CSV file with all visible columns and item values is saved to the app-specific external files directory (Android/data/<package>/files/). A toast displays the full path. Additional formats (JSON, XLSX, etc.) can be added in the same dialog later.
Performance Notes (Large Tables)
For very large tables the app applies several optimizations:
- Rows are kept in their original creation order rather than sorting by last update timestamp. This prevents the entire list from resorting after each edit and reduces scroll jank.
- Rapid successive database emissions are coalesced (debounced ~75ms) before updating the UI state, lowering unnecessary recompositions during bulk edits or sync bursts. Further planned improvements:
- Incremental paging for extremely large datasets
- Horizontal virtualization for very wide column sets If you encounter sluggishness with tens of thousands of rows, enable server-side filtering/sorting to reduce client load.
Column Content Alignment
In the Edit Column dialog you can choose how each column's cell content is aligned (Left, Center, Right) via a single connected Material 3 segmented button group. The selection persists per list/field and updates immediately when you save changes. To adjust later, open the Manage Columns dialog or edit the field again.
Deleting
- Tap the delete icon next to any table, field, or item
- Confirm the deletion
Synchronization
The app uses a WebSocket-first sync strategy with an HTTP fallback:
- WebSocket (
/api/ws): Sends asyncmessage with local changes and receives deltas plus the newserverTimestamp. - HTTP (
POST /api/sync): Used automatically as a fallback if the WS exchange fails.
Behavior:
- Sends local changes since the last sync and receives server changes since the last known timestamp.
- Timestamps are used to resolve conflicts (latest wins).
- If the server is protected with
SERVER_PASSWORD, the app sendsAuthorization: Bearer <password>for both HTTP and WebSocket.
To trigger sync programmatically, call SyncRepository.performSync().
Building for Release
- Update the version in
app/build.gradle - Create a keystore for signing
- Build the release APK:
./gradlew assembleRelease
License
MIT