diff --git a/docs/activities.md b/docs/activities.md new file mode 100644 index 0000000..72fb3f2 --- /dev/null +++ b/docs/activities.md @@ -0,0 +1,202 @@ +# Activities - Comments and Likes + +Activities allow users to interact with assets in shared albums through comments and likes. This creates a social layer for collaborative photo sharing. + +## Activity Types + +### Comment +A text-based reaction attached to an album or specific asset: +- **id**: Unique identifier +- **assetId**: Optional - if set, comment is on specific asset; otherwise on album +- **comment**: The text content +- **createdAt**: Timestamp when comment was created +- **user**: The user who created the comment + +### Like +A simple thumbs-up reaction: +- **id**: Unique identifier +- **assetId**: Optional - if set, like is on specific asset; otherwise on album +- **createdAt**: Timestamp when like was created +- **user**: The user who liked + +## Activity Statistics + +The app can fetch activity statistics for an album: +- **comments**: Number of comments on the album + +## API Endpoints + +### Get All Activities +Fetch all activities for an album, optionally filtered to a specific asset. + +**Request:** +``` +GET /activities?albumId={albumId}&assetId={assetId} +``` + +**Response:** +```json +[ + { + "id": "activity-uuid", + "albumId": "album-uuid", + "assetId": "asset-uuid", + "comment": "Great photo!", + "type": "comment", + "createdAt": "2024-01-15T10:30:00Z", + "user": { + "id": "user-uuid", + "name": "John Doe", + "email": "john@example.com" + } + } +] +``` + +### Create Activity +Add a new comment or like. + +**Request:** +``` +POST /activities +{ + "albumId": "album-uuid", + "assetId": "asset-uuid", + "type": "comment", + "comment": "Great photo!" +} +``` + +**Response:** The created activity object + +### Delete Activity +Remove an activity (comment or like). + +**Request:** +``` +DELETE /activities/{id} +``` + +### Get Activity Statistics +Get comment count for an album. + +**Request:** +``` +GET /activities/statistics?albumId={albumId}&assetId={assetId} +``` + +**Response:** +```json +{ + "comments": 5 +} +``` + +## UI Components + +### Activities Page + +The main activities page displays all activities for an album or asset. + +**Layout:** +``` ++----------------------------------+ +| [Back] Album Name | ++----------------------------------+ +| | +| [Avatar] User • 2 hours ago | +| Comment text here | +| | +| [Thumbs Up] User • 1 hour ago | +| | +| [Avatar] User • 30 min ago | +| Another comment | +| | +| ... (scrollable list) | +| | ++----------------------------------+ +| [Avatar] [Text Input] [Like] | ++----------------------------------+ +``` + +**Behaviors:** +- List scrolls to show all activities +- New comments auto-scroll to bottom +- Activities can be dismissed by swiping (if user has permission) + +### Activity Tile + +Each activity is displayed as a tile: + +**Comment Tile:** +- User avatar on the left +- Username and relative time ("2 hours ago") in header +- Comment text as subtitle +- If viewing from album page: thumbnail of asset on right (tappable) + +**Like Tile:** +- Thumbs up icon on the left (colored with primary theme color) +- Username and relative time +- If on specific asset: shows asset thumbnail + +### Activity Text Field + +Input area at bottom of activities page: + +**Components:** +- Current user's avatar on the left +- Text input field in center +- Like/unlike button on the right + +**States:** +- **Enabled**: User can type comments and toggle like +- **Disabled**: Shows message "Activities are disabled" (when album owner disables activities) + +**Like Button States:** +- **Not liked**: Outline thumbs up icon +- **Liked**: Filled thumbs up icon in primary color + +**Behaviors:** +- Keyboard shows automatically when page opens +- Pressing "Send" on keyboard submits comment +- Tapping outside unfocuses input +- Like button toggles current user's like on/off + +### Dismissible Activity + +Activities can be swiped to delete if user has permission: +- Activity author can delete their own activities +- Album owner can delete any activity + +**Swipe Animation:** +- Red background appears +- Trash icon shown +- Activity slides away when dismissed + +## Permission Rules + +| Action | Who Can Perform | +|--------|-----------------| +| Add comment | Any album member (if activities enabled) | +| Add like | Any album member (if activities enabled) | +| Delete own activity | Activity author | +| Delete any activity | Album owner | +| Disable activities | Album owner | + +## Localization Strings + +| Key | Usage | +|-----|-------| +| `say_something` | Placeholder text in comment input | +| `shared_album_activities_input_disable` | Shown when activities are disabled | + +## Navigation + +When viewing activities from album page and tapping an activity with an asset: +1. Build asset viewer route +2. Navigate to full-screen asset viewer +3. Show the specific asset the activity references + +--- + +[Previous: Partners](partners.md) | [Next: Background Services](background-services.md) diff --git a/docs/api-reference.md b/docs/api-reference.md new file mode 100644 index 0000000..a8f2741 --- /dev/null +++ b/docs/api-reference.md @@ -0,0 +1,607 @@ +# API Reference + +The mobile app communicates with the server through a REST API and WebSocket connection. This document covers all API endpoints used by the app. + +## API Service Structure + +The API is organized into domain-specific sub-APIs: + +| API | Purpose | +|-----|---------| +| authenticationApi | Login, logout, session management | +| usersApi | User profile and settings | +| assetsApi | Asset CRUD operations | +| albumsApi | Album management | +| searchApi | Smart search and filters | +| partnersApi | Partner sharing | +| sharedLinksApi | External share links | +| activitiesApi | Comments and likes | +| peopleApi | Face recognition and people | +| memoriesApi | Memory lane feature | +| trashApi | Trash management | +| serverApi | Server info and config | +| oauthApi | OAuth authentication | +| downloadApi | Asset downloads | +| syncApi | Data synchronization | + +## Authentication + +### Login + +``` +POST /auth/login +Content-Type: application/json + +{ + "email": "user@example.com", + "password": "password123" +} + +Response: +{ + "accessToken": "jwt-token", + "userId": "user-uuid", + "userEmail": "user@example.com", + "name": "John Doe", + "isAdmin": false, + "profileImagePath": "/path/to/image" +} +``` + +### Logout + +``` +POST /auth/logout +Authorization: Bearer {token} + +Response: 204 No Content +``` + +### Validate Token + +``` +POST /auth/validateToken +Authorization: Bearer {token} + +Response: +{ + "authStatus": true +} +``` + +### Change Password + +``` +POST /auth/change-password +Authorization: Bearer {token} +Content-Type: application/json + +{ + "password": "current-password", + "newPassword": "new-password" +} +``` + +## OAuth + +### Get OAuth Config + +``` +GET /oauth/config + +Response: +{ + "enabled": true, + "autoRegister": true, + "autoLaunch": false, + "buttonText": "Login with SSO" +} +``` + +### Start OAuth Flow + +``` +POST /oauth/authorize +Content-Type: application/json + +{ + "redirectUri": "app://oauth-callback", + "codeChallenge": "challenge-string", + "codeChallengeMethod": "S256" +} + +Response: +{ + "url": "https://oauth-provider.com/authorize?..." +} +``` + +### Complete OAuth + +``` +POST /oauth/callback +Content-Type: application/json + +{ + "url": "app://oauth-callback?code=auth-code", + "codeVerifier": "verifier-string" +} + +Response: +{ + "accessToken": "jwt-token", + "userId": "user-uuid", + ... +} +``` + +## Assets + +### Get All Assets + +``` +GET /assets?updatedAfter={timestamp}&updatedBefore={timestamp} +Authorization: Bearer {token} + +Response: +[ + { + "id": "asset-uuid", + "ownerId": "user-uuid", + "checksum": "sha1-hash", + "fileCreatedAt": "2024-01-15T10:30:00Z", + "fileModifiedAt": "2024-01-15T10:30:00Z", + "type": "IMAGE", + "originalFileName": "IMG_1234.jpg", + "isFavorite": false, + "isArchived": false, + "isTrashed": false, + "thumbhash": "base64-thumbhash", + "exifInfo": { ... } + } +] +``` + +### Upload Asset + +``` +POST /assets +Authorization: Bearer {token} +Content-Type: multipart/form-data + +Form fields: +- assetData: File binary +- deviceAssetId: Device-specific ID +- deviceId: Device identifier +- fileCreatedAt: Original creation time +- fileModifiedAt: Original modification time +- duration: Video duration (if applicable) +- isFavorite: Boolean +- isArchived: Boolean +- isVisible: Boolean + +Response: +{ + "id": "asset-uuid", + "duplicate": false +} +``` + +### Get Asset Info + +``` +GET /assets/{id} +Authorization: Bearer {token} + +Response: Asset object +``` + +### Update Asset + +``` +PUT /assets/{id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "isFavorite": true, + "isArchived": false, + "description": "Updated description" +} +``` + +### Delete Assets + +``` +DELETE /assets +Authorization: Bearer {token} +Content-Type: application/json + +{ + "ids": ["asset-uuid-1", "asset-uuid-2"], + "force": false +} +``` + +### Get Asset Thumbnail + +``` +GET /assets/{id}/thumbnail?size={thumbnail|preview} +Authorization: Bearer {token} + +Response: Image binary +``` + +### Get Asset Original + +``` +GET /assets/{id}/original +Authorization: Bearer {token} + +Response: Original file binary +``` + +### Get Video Playback + +``` +GET /assets/{id}/video/playback +Authorization: Bearer {token} + +Response: Video stream +``` + +### Check Duplicates + +``` +POST /assets/bulk-upload-check +Authorization: Bearer {token} +Content-Type: application/json + +{ + "assets": [ + { + "id": "device-asset-id", + "checksum": "sha1-hash" + } + ] +} + +Response: +{ + "results": [ + { + "id": "device-asset-id", + "action": "accept|reject", + "reason": "duplicate" + } + ] +} +``` + +## Albums + +### Get All Albums + +``` +GET /albums?shared={true|false} +Authorization: Bearer {token} + +Response: +[ + { + "id": "album-uuid", + "ownerId": "user-uuid", + "albumName": "Vacation 2024", + "createdAt": "2024-01-15T10:30:00Z", + "assetCount": 50, + "shared": true, + "albumThumbnailAssetId": "asset-uuid" + } +] +``` + +### Create Album + +``` +POST /albums +Authorization: Bearer {token} +Content-Type: application/json + +{ + "albumName": "New Album", + "assetIds": ["asset-uuid-1", "asset-uuid-2"] +} + +Response: Album object +``` + +### Get Album Details + +``` +GET /albums/{id} +Authorization: Bearer {token} + +Response: Album object with assets +``` + +### Update Album + +``` +PATCH /albums/{id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "albumName": "Updated Name", + "activityEnabled": true +} +``` + +### Delete Album + +``` +DELETE /albums/{id} +Authorization: Bearer {token} +``` + +### Add Assets to Album + +``` +PUT /albums/{id}/assets +Authorization: Bearer {token} +Content-Type: application/json + +{ + "ids": ["asset-uuid-1", "asset-uuid-2"] +} +``` + +### Remove Assets from Album + +``` +DELETE /albums/{id}/assets +Authorization: Bearer {token} +Content-Type: application/json + +{ + "ids": ["asset-uuid-1", "asset-uuid-2"] +} +``` + +### Add Users to Album + +``` +PUT /albums/{id}/users +Authorization: Bearer {token} +Content-Type: application/json + +{ + "sharedUserIds": ["user-uuid-1"], + "albumUserRoles": [{"userId": "user-uuid-1", "role": "editor"}] +} +``` + +## Search + +### Smart Search + +``` +POST /search/smart +Authorization: Bearer {token} +Content-Type: application/json + +{ + "query": "beach sunset", + "page": 1, + "size": 100, + "type": "IMAGE" +} + +Response: +{ + "assets": { + "items": [...], + "total": 150, + "count": 100 + } +} +``` + +### Metadata Search + +``` +POST /search/metadata +Authorization: Bearer {token} +Content-Type: application/json + +{ + "originalFileName": "IMG", + "city": "New York", + "make": "Apple", + "takenAfter": "2024-01-01", + "takenBefore": "2024-12-31" +} +``` + +### Get Search Suggestions + +``` +GET /search/suggestions?query={text}&type={type} +Authorization: Bearer {token} + +Response: +["suggestion1", "suggestion2", ...] +``` + +## Partners + +### Get Partners + +``` +GET /partners?direction={shared-by|shared-with} +Authorization: Bearer {token} + +Response: +[ + { + "id": "user-uuid", + "email": "partner@example.com", + "name": "Partner Name", + "inTimeline": true + } +] +``` + +### Create Partnership + +``` +POST /partners/{userId} +Authorization: Bearer {token} + +Response: Partner object +``` + +### Update Partnership + +``` +PUT /partners/{userId} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "inTimeline": true +} +``` + +### Remove Partnership + +``` +DELETE /partners/{userId} +Authorization: Bearer {token} +``` + +## Shared Links + +### Create Shared Link + +``` +POST /shared-links +Authorization: Bearer {token} +Content-Type: application/json + +{ + "type": "ALBUM|INDIVIDUAL", + "albumId": "album-uuid", + "assetIds": ["asset-uuid"], + "allowUpload": false, + "allowDownload": true, + "showMetadata": true, + "password": "optional-password", + "expiresAt": "2024-12-31T23:59:59Z" +} + +Response: +{ + "id": "link-uuid", + "key": "share-key", + "url": "https://server/share/share-key" +} +``` + +### Get My Shared Links + +``` +GET /shared-links/me +Authorization: Bearer {token} + +Response: Array of shared links +``` + +### Delete Shared Link + +``` +DELETE /shared-links/{id} +Authorization: Bearer {token} +``` + +## Server + +### Get Server Info + +``` +GET /server/info +Authorization: Bearer {token} + +Response: +{ + "version": "1.2.3", + "diskAvailable": "50 GB", + "diskSize": "100 GB", + "diskUsagePercentage": 50 +} +``` + +### Get Server Features + +``` +GET /server/features +Authorization: Bearer {token} + +Response: +{ + "clipEncode": true, + "facialRecognition": true, + "map": true, + "trash": true, + "oauth": true, + "oauthAutoLaunch": false, + "passwordLogin": true +} +``` + +### Get Server Config + +``` +GET /server/config + +Response: +{ + "loginPageMessage": "Welcome", + "trashDays": 30, + "isInitialized": true +} +``` + +### Ping Server + +``` +GET /server/ping + +Response: +{ + "res": "pong" +} +``` + +## Error Responses + +All endpoints may return error responses: + +``` +{ + "error": "Error Type", + "statusCode": 400, + "message": "Detailed error message" +} +``` + +Common status codes: +- 400: Bad Request +- 401: Unauthorized +- 403: Forbidden +- 404: Not Found +- 500: Internal Server Error + +--- + +[Previous: Data Models](data-models.md) | [Next: Local Storage](local-storage.md) diff --git a/docs/background-services.md b/docs/background-services.md new file mode 100644 index 0000000..41ecc6d --- /dev/null +++ b/docs/background-services.md @@ -0,0 +1,261 @@ +# Background Services + +The app runs various background services to sync photos, perform backups, and maintain data consistency without requiring user interaction. + +## Background Backup Service + +The background backup service automatically uploads photos to the server when the app is not in the foreground. + +### Platform Channel Communication + +The app uses platform-specific channels to communicate with native background services: + +**Channel Name:** `immich/foregroundChannel` + +**Methods:** + +| Method | Direction | Purpose | +|--------|-----------|---------| +| `initialized` | Native → App | Notify app that background service started | +| `start` | App → Native | Start background backup | +| `stop` | App → Native | Stop background backup | +| `updateNotification` | App → Native | Update progress notification | +| `systemStop` | Native → App | System stopped the service | + +### Notification Structure + +Background backup shows progress notifications: + +**Notification Data:** +```json +{ + "title": "Backup Progress", + "content": "Uploading photo 5 of 100", + "progress": 5, + "max": 100, + "indeterminate": false, + "isDetail": true +} +``` + +**Notification Types:** +- **Total Progress**: Overall backup progress (X of Y files) +- **Single Progress**: Current file upload progress (percentage) +- **Error Notification**: Shows when upload fails + +### Background Service Lifecycle + +``` +App Backgrounded + │ + ▼ +┌─────────────────┐ +│ Service Starts │ +│ (initialized) │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Check Conditions│ +│ - WiFi required?│ +│ - Charging? │ +└────────┬────────┘ + │ + ┌────┴────┐ + │ │ + ▼ ▼ + Proceed Wait + │ + ▼ +┌─────────────────┐ +│ Find Upload │ +│ Candidates │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Upload Files │◄──────┐ +│ One by One │ │ +└────────┬────────┘ │ + │ │ + ▼ │ +┌─────────────────┐ │ +│ Update Notif. │───────┘ +│ Progress │ +└────────┬────────┘ + │ + ┌────┴────┐ + │ │ + ▼ ▼ + More Complete + Files │ + │ ▼ + │ ┌─────────────────┐ + └───►│ Service Stops │ + └─────────────────┘ +``` + +### Settings + +| Setting | Description | Default | +|---------|-------------|---------| +| `backgroundBackup` | Enable/disable background backup | false | +| `backupRequireWifi` | Only backup on WiFi | true | +| `backupRequireCharging` | Only backup while charging | false | +| `backupTriggerDelay` | Minutes before starting backup | 30 | +| `backgroundBackupTotalProgress` | Show total progress notification | true | +| `backgroundBackupSingleProgress` | Show per-file progress | false | + +### Error Handling + +**Grace Period for Notifications:** +- Errors don't immediately show notification +- `uploadErrorNotificationGracePeriod` setting controls delay (default: 2 uploads) +- Prevents notification spam for transient errors + +**Error Recovery:** +- Service tracks `backupFailedSince` timestamp +- Retries on next service run +- User notified after grace period exceeded + +## Sync Service + +Keeps local database synchronized with server. + +### Sync Operations + +1. **Asset Sync**: Download remote asset metadata +2. **Album Sync**: Sync album memberships and contents +3. **User Sync**: Sync user and partner information + +### Sync Flow + +``` +┌─────────────────┐ +│ Sync Trigger │ +│ (App Start / │ +│ WebSocket) │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Fetch Remote │ +│ Changes (ETag) │ +└────────┬────────┘ + │ + ┌────┴────┐ + │ │ + ▼ ▼ + Changes No + Found Changes + │ │ + ▼ │ +┌─────────────────┐ +│ Process Deltas │ +│ - New assets │ +│ - Updated assets│ +│ - Deleted assets│ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Update Local DB │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Refresh UI │ +└─────────────────┘ +``` + +### ETag-Based Sync + +The app uses ETags to efficiently detect changes: + +1. Store ETag from last sync +2. Send ETag in request header +3. If server returns 304 (Not Modified), skip sync +4. If server returns new data, update local cache and ETag + +### Remote Asset Removal + +When assets are deleted on server: +1. Receive list of deleted asset IDs +2. Remove from local database +3. Update timeline display +4. Keep local-only assets intact (if any) + +## WebSocket Events for Background Sync + +Real-time events that trigger sync operations: + +| Event | Action | +|-------|--------| +| `on_upload_success` | Add new asset to timeline | +| `on_asset_delete` | Remove asset from local DB | +| `on_asset_trash` | Move asset to trash | +| `on_asset_restore` | Restore asset from trash | +| `on_asset_update` | Refresh asset metadata | +| `on_asset_hidden` | Remove from visible timeline | + +## Foreground Upload Service + +For uploads while app is visible: + +### Features +- Shows upload progress in UI +- Can be paused/cancelled by user +- Uses foreground service notification +- Continues if user switches apps briefly + +### Progress Tracking + +``` +Upload State: +- totalCount: Total files to upload +- completedCount: Successfully uploaded +- failedCount: Failed uploads +- currentFile: File being uploaded +- currentProgress: 0-100 percentage +``` + +## App Lifecycle Integration + +### On App Resume +1. Reconnect WebSocket +2. Refresh authentication +3. Trigger quick sync +4. Resume any pending uploads + +### On App Pause +1. Start background service (if enabled) +2. Save current state +3. Disconnect WebSocket (after delay) + +### On App Terminate +1. Complete current upload (if possible) +2. Schedule background task +3. Clean up resources + +## Battery Optimization + +The background service is designed to be battery-efficient: + +- **Batching**: Groups multiple uploads +- **Debouncing**: Waits before processing WebSocket events (5 second debounce) +- **Conditions**: Respects WiFi and charging requirements +- **Scheduling**: Uses system job scheduler when possible + +## Debug Logging + +Enable advanced troubleshooting in settings to see detailed logs: + +| Log Level | What's Logged | +|-----------|---------------| +| INFO | Service start/stop, sync complete | +| WARNING | Retry attempts, partial failures | +| SEVERE | Errors, failed uploads | + +--- + +[Previous: Activities](activities.md) | [Next: WebSocket](websocket.md) diff --git a/docs/data-models.md b/docs/data-models.md new file mode 100644 index 0000000..e8ec76d --- /dev/null +++ b/docs/data-models.md @@ -0,0 +1,308 @@ +# Data Models + +Core data structures used throughout the application. + +## Asset + +The fundamental unit representing a photo or video. + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| id | Integer | Local database ID (auto-increment) | +| remoteId | String? | Server-side UUID | +| localId | String? | Device media library ID | +| checksum | String | SHA1 hash (base64 encoded) | +| thumbhash | String? | Compact image placeholder hash | +| ownerId | Integer | Hash of owner's user ID | +| fileCreatedAt | DateTime | When file was originally created | +| fileModifiedAt | DateTime | When file was last modified | +| updatedAt | DateTime | Last server update timestamp | +| durationInSeconds | Integer | Video duration (0 for images) | +| type | AssetType | image, video, audio, or other | +| width | Integer? | Image/video width in pixels | +| height | Integer? | Image/video height in pixels | +| fileName | String | Original filename | +| livePhotoVideoId | String? | ID of video component for live photos | +| isFavorite | Boolean | Marked as favorite | +| isArchived | Boolean | Hidden from main timeline | +| isTrashed | Boolean | In trash (pending deletion) | +| isOffline | Boolean | Server asset not accessible | +| stackId | String? | ID of stack this asset belongs to | +| stackPrimaryAssetId | String? | Primary asset in the stack | +| stackCount | Integer | Number of assets in stack | +| visibility | Enum | timeline, archive, hidden, locked | + +### Asset Types + +``` +AssetType: +- other: Unknown file type +- image: Photo (JPEG, PNG, HEIC, etc.) +- video: Video file (MP4, MOV, etc.) +- audio: Audio file +``` + +### Asset State + +Describes where asset data comes from: + +``` +AssetState: +- local: Only exists on device +- remote: Only exists on server +- merged: Exists on both (synced) +``` + +### Asset Visibility + +``` +AssetVisibilityEnum: +- timeline: Visible in main timeline +- archive: In archive (hidden from timeline) +- hidden: Hidden (private) +- locked: In locked folder (PIN protected) +``` + +### Computed Properties + +| Property | Description | +|----------|-------------| +| isLocal | Has local device ID | +| isRemote | Has server ID | +| isImage | Type is image | +| isVideo | Type is video | +| isMotionPhoto | Has live photo video component | +| aspectRatio | Width / height ratio | +| duration | Duration as time object | +| name | Filename without extension | +| storage | Current asset state | +| isFlipped | EXIF indicates rotation 90/270 | +| orientatedWidth | Width accounting for rotation | +| orientatedHeight | Height accounting for rotation | + +## Album + +Collection of assets. + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| id | Integer | Local database ID | +| remoteId | String? | Server-side UUID | +| name | String | Album name | +| createdAt | DateTime | Creation timestamp | +| modifiedAt | DateTime | Last modification | +| startDate | DateTime? | Earliest asset date | +| endDate | DateTime? | Latest asset date | +| lastModifiedAssetTimestamp | DateTime? | When assets last changed | +| shared | Boolean | Is shared with others | +| ownerId | Integer | Owner's user ID hash | +| owner | User | Owner user object | +| activityEnabled | Boolean | Comments/likes allowed | +| isRemote | Boolean | Exists on server | +| assetCount | Integer | Number of assets | + +### Album Types + +- **Regular Album**: User-created collection +- **Shared Album**: Shared with other users +- **Partner Album**: Virtual album showing partner's assets + +## User + +Represents an app user. + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| id | String | Unique user UUID | +| email | String | User's email address | +| name | String | Display name | +| profileImagePath | String? | URL to profile picture | +| isAdmin | Boolean | Has admin privileges | +| memoryEnabled | Boolean | Show memories feature | +| avatarColor | Color | Generated avatar color | +| quotaUsageInBytes | Integer | Storage used | +| quotaSizeInBytes | Integer? | Storage quota (null = unlimited) | +| inTimeline | Boolean | Show in partner timeline | +| isPartnerSharedBy | Boolean | Sharing with current user | +| isPartnerSharedWith | Boolean | Current user shares with them | + +## ExifInfo + +Metadata extracted from images. + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| assetId | Integer | Associated asset ID | +| make | String? | Camera manufacturer | +| model | String? | Camera model | +| lens | String? | Lens used | +| fNumber | Float? | Aperture f-stop | +| focalLength | Float? | Focal length in mm | +| iso | Integer? | ISO sensitivity | +| exposureTime | String? | Shutter speed | +| latitude | Float? | GPS latitude | +| longitude | Float? | GPS longitude | +| city | String? | Location city | +| state | String? | Location state/province | +| country | String? | Location country | +| description | String? | Image description/caption | +| dateTimeOriginal | DateTime? | Original capture time | + +### Computed Properties + +| Property | Description | +|----------|-------------| +| hasCoordinates | Has valid GPS data | +| isFlipped | Orientation is 90 or 270 degrees | + +## Activity + +Comment or like on shared album. + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| id | String | Activity UUID | +| assetId | String? | Specific asset (null = album-level) | +| comment | String? | Comment text (null for likes) | +| createdAt | DateTime | When activity was created | +| type | ActivityType | comment or like | +| user | User | User who created activity | + +### Activity Types + +``` +ActivityType: +- comment: Text comment +- like: Thumbs up reaction +``` + +## Search Filters + +Parameters for searching assets. + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| context | String? | Text to search | +| filename | String? | Search by filename | +| personIds | List | Filter by people | +| location | SearchLocationFilter? | City/state/country | +| camera | SearchCameraFilter? | Make/model | +| date | SearchDateFilter? | Date range | +| display | SearchDisplayFilters? | Archive/favorite/trash | +| mediaType | AssetType? | Image/video filter | + +### Location Filter + +``` +SearchLocationFilter: +- city: String? +- state: String? +- country: String? +``` + +### Camera Filter + +``` +SearchCameraFilter: +- make: String? +- model: String? +``` + +### Date Filter + +``` +SearchDateFilter: +- takenAfter: DateTime? +- takenBefore: DateTime? +``` + +### Display Filters + +``` +SearchDisplayFilters: +- isArchived: Boolean? +- isFavorite: Boolean? +- isNotInAlbum: Boolean? +``` + +## Memory + +"On this day" memories feature. + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| id | String | Memory UUID | +| title | String | Display title | +| assets | List | Assets in this memory | +| yearsAgo | Integer | How many years ago | + +## Backup Album + +Local album selected for backup. + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| id | String | Device album ID | +| name | String | Album name | +| selection | BackupSelection | include, exclude, or none | +| lastBackup | DateTime? | Last successful backup time | + +## Store Keys + +Key-value storage for app state and settings. + +### Key Categories + +**Authentication:** +- serverUrl, serverEndpoint +- accessToken +- currentUser + +**Backup:** +- autoBackup, backgroundBackup +- backupRequireWifi, backupRequireCharging +- backupTriggerDelay +- backupFailedSince + +**Display:** +- themeMode, primaryColor +- dynamicTheme, colorfulInterface +- tilesPerRow, dynamicLayout +- groupAssetsBy + +**Cache:** +- thumbnailCacheSize +- imageCacheSize +- albumThumbnailCacheSize + +**Features:** +- syncAlbums +- betaTimeline +- enableHapticFeedback + +**Map:** +- mapThemeMode +- mapShowFavoriteOnly +- mapIncludeArchived +- mapwithPartners +- mapRelativeDate + +--- + +[Previous: WebSocket](websocket.md) | [Next: API Reference](api-reference.md) diff --git a/docs/error-handling.md b/docs/error-handling.md new file mode 100644 index 0000000..c2f27bc --- /dev/null +++ b/docs/error-handling.md @@ -0,0 +1,344 @@ +# Error Handling + +The app implements comprehensive error handling to provide a robust user experience. + +## Error Architecture + +``` +┌─────────────────────────────────────────┐ +│ UI Layer │ +│ (Shows error messages to user) │ +└─────────────────┬───────────────────────┘ + │ +┌─────────────────▼───────────────────────┐ +│ State Management │ +│ (Catches errors, updates state) │ +└─────────────────┬───────────────────────┘ + │ +┌─────────────────▼───────────────────────┐ +│ Service Layer │ +│ (Logs errors, returns defaults) │ +└─────────────────┬───────────────────────┘ + │ +┌─────────────────▼───────────────────────┐ +│ Repository Layer │ +│ (Handles API/DB errors) │ +└─────────────────────────────────────────┘ +``` + +## Error Logger Mixin + +Services use a standardized error handling pattern: + +### Guard Error + +Wraps async operations and returns result or error: + +``` +Input: Async function +Output: AsyncValue + - AsyncData(result) on success + - AsyncError(error, stackTrace) on failure + +Behavior: +1. Execute async function +2. If success → return AsyncData with result +3. If exception → log error, return AsyncError +``` + +### Log Error + +Executes operation and returns default on failure: + +``` +Input: + - Async function + - Default value + - Error message + +Output: T (result or default) + +Behavior: +1. Execute async function +2. If success → return result +3. If exception → log error, return default value +``` + +## Log Levels + +| Level | Value | Usage | +|-------|-------|-------| +| ALL | 0 | All messages | +| FINEST | 300 | Extremely detailed | +| FINER | 400 | Very detailed | +| FINE | 500 | Detailed tracing | +| CONFIG | 700 | Configuration info | +| INFO | 800 | General information | +| WARNING | 900 | Potential problems | +| SEVERE | 1000 | Serious failures | +| SHOUT | 1200 | Critical errors | +| OFF | 2000 | No logging | + +Default level: INFO (800) + +## API Error Handling + +### HTTP Error Responses + +| Status Code | Meaning | Handling | +|-------------|---------|----------| +| 400 | Bad Request | Show validation error | +| 401 | Unauthorized | Redirect to login | +| 403 | Forbidden | Show access denied | +| 404 | Not Found | Show not found message | +| 409 | Conflict | Handle duplicate | +| 500 | Server Error | Show generic error | + +### Network Errors + +| Error Type | Handling | +|------------|----------| +| No Connection | Show offline message | +| Timeout | Retry with backoff | +| SSL Error | Check certificate settings | +| DNS Failure | Check server URL | + +### Error Response Format + +```json +{ + "error": "ErrorType", + "statusCode": 400, + "message": "Human-readable error message" +} +``` + +## Authentication Errors + +### Login Failures + +| Error | Message | Action | +|-------|---------|--------| +| Wrong credentials | "Incorrect email or password" | Show error, stay on login | +| Account locked | "Account temporarily locked" | Show lockout message | +| Server unavailable | "Cannot connect to server" | Check server URL | + +### Session Expiration + +1. API returns 401 +2. Clear local token +3. Navigate to login +4. Show "Session expired" message + +### OAuth Errors + +| Error | Handling | +|-------|----------| +| User cancelled | Return to login silently | +| Invalid state | Show security error | +| Token exchange failed | Show error, retry option | + +## Upload Errors + +### Upload Failure Handling + +``` +Upload Attempt + │ + ▼ + Success? + │ │ + Yes No + │ │ + ▼ ▼ + Done Retry? + │ │ + Yes No (max retries) + │ │ + ▼ ▼ + Retry Mark Failed + │ + ▼ + Add to Error Queue + │ + ▼ + Grace Period Check + │ + ┌────┴────┐ + │ │ + Within Exceeded + │ │ + ▼ ▼ + Silent Show Notification +``` + +### Error Grace Period + +- Don't immediately notify on upload failures +- Wait for `uploadErrorNotificationGracePeriod` failures +- Then show notification +- Prevents spam for transient errors + +### Duplicate Detection + +When server returns duplicate error: +1. Mark local asset as backed up +2. Don't show error to user +3. Continue with next asset + +## Download Errors + +| Error | Handling | +|-------|----------| +| Asset not found | Show "Photo not available" | +| Permission denied | Show access error | +| Storage full | Show storage warning | +| Network error | Offer retry | + +## Sync Errors + +### Sync Failure Recovery + +1. Log sync error +2. Keep existing local data +3. Schedule retry +4. Show sync indicator if prolonged + +### Conflict Resolution + +When local and remote conflict: +1. Remote data takes precedence +2. Merge where possible +3. Log conflict details + +## UI Error Display + +### Snackbar Messages + +For transient errors: +``` +┌────────────────────────────────────┐ +│ Error message here [RETRY]│ +└────────────────────────────────────┘ +``` + +- Auto-dismiss after 3-5 seconds +- Optional action button +- Non-blocking + +### Dialog Messages + +For critical errors requiring action: +``` +┌─────────────────────────────────┐ +│ Error Title │ +├─────────────────────────────────┤ +│ │ +│ Detailed error description │ +│ with helpful guidance. │ +│ │ +├─────────────────────────────────┤ +│ [OK] [RETRY] │ +└─────────────────────────────────┘ +``` + +### Inline Errors + +For form validation: +``` +┌─────────────────────────────────┐ +│ Email │ +│ ┌───────────────────────────┐ │ +│ │ invalid-email │ │ +│ └───────────────────────────┘ │ +│ ⚠ Please enter a valid email │ +└─────────────────────────────────┘ +``` + +### Empty States + +When no data due to error: +``` +┌─────────────────────────────────┐ +│ │ +│ [Error Icon] │ +│ │ +│ Something went wrong │ +│ │ +│ [Try Again] │ +│ │ +└─────────────────────────────────┘ +``` + +## Localization Keys + +Common error message keys: + +| Key | Usage | +|-----|-------| +| `error_generic` | Unknown error occurred | +| `error_network` | Network connection error | +| `error_server` | Server error | +| `error_unauthorized` | Not authorized | +| `error_not_found` | Resource not found | +| `error_upload_failed` | Upload failed | +| `error_download_failed` | Download failed | + +## Debug Logging + +### Enable Advanced Troubleshooting + +When enabled in settings: +- Log all API requests/responses +- Log state changes +- Log error stack traces +- Log sync operations + +### Log Output + +Logs include: +- Timestamp +- Logger name (component) +- Log level +- Message +- Error object (if applicable) +- Stack trace (if applicable) + +### Viewing Logs + +- Settings → Advanced → Export Logs +- Share log file for support + +## Error Recovery Patterns + +### Automatic Retry + +For transient failures: +``` +Attempt 1 + ↓ + Fail → Wait 1s → Attempt 2 + ↓ + Fail → Wait 2s → Attempt 3 + ↓ + Fail → Give Up +``` + +### Manual Retry + +User-triggered retry: +1. Show error with retry button +2. User taps retry +3. Clear error state +4. Repeat operation + +### Graceful Degradation + +When feature unavailable: +1. Disable affected UI elements +2. Show explanation +3. Continue with available features + +--- + +[Previous: Settings](settings.md) | [Next: UI Components](ui-components.md) diff --git a/docs/local-storage.md b/docs/local-storage.md new file mode 100644 index 0000000..2c3f98a --- /dev/null +++ b/docs/local-storage.md @@ -0,0 +1,326 @@ +# Local Storage + +The app uses multiple storage mechanisms to persist data locally for offline access and performance. + +## Storage Overview + +``` +┌─────────────────────────────────────────┐ +│ Local Storage │ +├─────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ Key-Value │ │ Database │ │ +│ │ Store │ │ (Isar) │ │ +│ └─────────────┘ └─────────────┘ │ +│ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ Image │ │ Secure │ │ +│ │ Cache │ │ Storage │ │ +│ └─────────────┘ └─────────────┘ │ +│ │ +└─────────────────────────────────────────┘ +``` + +## Key-Value Store + +Simple key-value storage for settings and small data. + +### Store Service + +The Store service provides typed access to stored values: + +``` +// Get a value with default +value = Store.get(StoreKey.themeMode, "system") + +// Get a value (nullable) +value = Store.tryGet(StoreKey.accessToken) + +// Save a value +Store.put(StoreKey.themeMode, "dark") + +// Delete a value +Store.delete(StoreKey.accessToken) +``` + +### Store Keys + +| Key | Type | Description | +|-----|------|-------------| +| version | Integer | Store schema version | +| assetETag | String | Last sync ETag | +| currentUser | User | Logged in user object | +| deviceId | String | Unique device identifier | +| deviceIdHash | Integer | Hashed device ID | +| serverUrl | String | Server URL | +| serverEndpoint | String | API endpoint URL | +| accessToken | String | Authentication token | +| autoBackup | Boolean | Auto backup enabled | +| backgroundBackup | Boolean | Background backup enabled | +| backupRequireWifi | Boolean | Require WiFi for backup | +| backupRequireCharging | Boolean | Require charging for backup | +| backupTriggerDelay | Integer | Minutes before backup starts | +| backupFailedSince | DateTime | When backup started failing | + +### User Settings Keys + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| loadPreview | Boolean | true | Load preview images | +| loadOriginal | Boolean | false | Load full resolution | +| themeMode | String | "system" | light/dark/system | +| primaryColor | String | Default | Theme accent color | +| dynamicTheme | Boolean | false | Use dynamic colors | +| colorfulInterface | Boolean | true | Colorful UI elements | +| tilesPerRow | Integer | 4 | Grid columns | +| dynamicLayout | Boolean | false | Dynamic grid layout | +| groupAssetsBy | Integer | 0 | Grouping mode | +| storageIndicator | Boolean | true | Show storage indicator | +| loopVideo | Boolean | true | Loop video playback | +| autoPlayVideo | Boolean | true | Auto-play videos | +| enableHapticFeedback | Boolean | true | Haptic feedback | + +### Cache Size Keys + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| thumbnailCacheSize | Integer | 10000 | Max thumbnail cache entries | +| imageCacheSize | Integer | 350 | Max preview cache entries | +| albumThumbnailCacheSize | Integer | 200 | Max album thumbnail entries | + +## Database (Isar) + +Embedded NoSQL database for structured data. + +### Collections + +#### Assets Collection + +Stores all asset metadata: + +``` +Assets: +- id: Auto-increment primary key +- remoteId: Indexed (unique hash) +- localId: Indexed (unique hash) +- ownerId + checksum: Composite unique index +- All asset properties +``` + +**Indexes:** +- `remoteId` - Fast lookup by server ID +- `localId` - Fast lookup by device ID +- `ownerId, checksum` - Composite unique constraint + +#### Albums Collection + +Stores album information: + +``` +Albums: +- id: Auto-increment primary key +- remoteId: Indexed +- name, dates, ownership info +- Links to assets and users +``` + +#### Backup Albums Collection + +Tracks device albums selected for backup: + +``` +BackupAlbum: +- id: Device album ID (primary key) +- name: Album name +- selection: include/exclude/none +- lastBackup: Last backup timestamp +``` + +#### Duplicated Assets Collection + +Tracks already-uploaded assets: + +``` +DuplicatedAsset: +- id: Device asset ID +- Prevents re-upload of same file +``` + +#### ETag Collection + +Stores sync ETags for incremental updates: + +``` +ETag: +- id: User ID +- assetCount: Number of assets +- time: Last sync time +``` + +#### Device Asset Collections + +Platform-specific asset tracking: + +**Android:** +``` +AndroidDeviceAsset: +- id: Asset ID +- hash: Content hash +``` + +**iOS:** +``` +IOSDeviceAsset: +- id: Asset ID +- hash: Content hash +- modifiedTime: Modification timestamp +``` + +### Database Operations + +**Read Operations:** +``` +// Find asset by remote ID +asset = db.assets.where().remoteIdEqualTo(id).findFirst() + +// Get all assets for user +assets = db.assets.filter().ownerIdEqualTo(userId).findAll() + +// Get assets in date range +assets = db.assets.filter() + .fileCreatedAtBetween(start, end) + .findAll() +``` + +**Write Operations:** +``` +// Insert/update asset +db.writeTxn(() => db.assets.put(asset)) + +// Delete by remote IDs +db.writeTxn(() => db.assets.deleteAllByRemoteId(ids)) + +// Batch insert +db.writeTxn(() => db.assets.putAll(assets)) +``` + +## Image Cache + +Caches downloaded images for performance. + +### Cache Layers + +``` +┌─────────────────┐ +│ Memory Cache │ ← Hot images (limited size) +├─────────────────┤ +│ Disk Cache │ ← Persistent storage +└─────────────────┘ +``` + +### Cache Types + +| Type | Purpose | Default Size | +|------|---------|--------------| +| Thumbnail | Grid view thumbnails | 10,000 entries | +| Preview | Full-screen previews | 350 entries | +| Album Thumbnail | Album cover images | 200 entries | + +### Cache Management + +**Clear All Cache:** +- Remove all cached thumbnails +- Remove all cached previews +- Free up storage space + +**Cache Invalidation:** +- By asset ID when asset is deleted +- By album ID when album changes +- Manual clear from settings + +## Secure Storage + +For sensitive data that needs encryption. + +### Stored Securely + +| Data | Usage | +|------|-------| +| Access Token | Authentication | +| SSL Client Certificate | mTLS authentication | +| SSL Certificate Password | Certificate decryption | +| Custom Headers | Proxy authentication | + +### SSL Client Certificate Storage + +``` +SSLClientCertStoreVal: +- data: Certificate binary (base64 encoded) +- password: Certificate password + +Operations: +- save(): Persist to secure storage +- load(): Retrieve from secure storage +- delete(): Remove from secure storage +``` + +## Storage Location + +### Per-Platform Paths + +**Android:** +- Database: `/data/data/{app}/databases/` +- Cache: `/data/data/{app}/cache/` +- Secure: Android Keystore + +**iOS:** +- Database: `~/Library/Application Support/` +- Cache: `~/Library/Caches/` +- Secure: iOS Keychain + +## Data Migration + +When upgrading the app, data may need migration: + +### Version Tracking +- Store version in `StoreKey.version` +- Compare with expected version +- Run migration steps if needed + +### Migration Steps +1. Read current version +2. Apply migrations sequentially +3. Update version number +4. Verify data integrity + +## Cleanup Operations + +### Free Up Space + +Remove local copies of backed-up assets: + +**Settings:** +- `cleanupKeepFavorites`: Keep favorite assets +- `cleanupKeepMediaType`: Keep photos/videos/both +- `cleanupKeepAlbumIds`: Keep assets in specific albums +- `cleanupCutoffDaysAgo`: Only remove older than X days + +### Clear Cache + +Remove cached images without affecting synced data: +- Thumbnails +- Previews +- Album covers + +### Full Reset + +Remove all local data: +1. Clear database +2. Clear cache +3. Clear settings +4. Return to login screen + +--- + +[Previous: API Reference](api-reference.md) | [Next: Settings](settings.md) diff --git a/docs/settings.md b/docs/settings.md new file mode 100644 index 0000000..845a557 --- /dev/null +++ b/docs/settings.md @@ -0,0 +1,326 @@ +# Settings + +The app provides extensive customization through the settings page. + +## Settings Structure + +``` +Settings +├── Preferences +├── Timeline Display +├── Asset Viewer +├── Backup +├── Free Up Space +├── Networking +├── Notifications +├── Language +├── Advanced +└── Sync Status (Beta) +``` + +## Settings Page Layout + +**Mobile Layout:** +List of settings cards, each navigates to a sub-page. + +**Tablet Layout:** +Split view with category list on left, selected settings on right. + +``` +┌──────────────────────────────────────────┐ +│ Settings │ +├──────────────┬───────────────────────────┤ +│ │ │ +│ Preferences │ [Selected Category │ +│ Timeline │ Settings Content] │ +│ Asset Viewer │ │ +│ Backup │ │ +│ ... │ │ +│ │ │ +└──────────────┴───────────────────────────┘ +``` + +## Preferences + +General app behavior settings. + +### Theme Settings + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Theme Mode | Light / Dark / System | System | App color scheme | +| Primary Color | Color presets | Default | Accent color | +| Dynamic Theme | On / Off | Off | Use system dynamic colors | +| Colorful Interface | On / Off | On | Apply color to more UI elements | + +### Interaction Settings + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Haptic Feedback | On / Off | On | Vibration on interactions | + +### Read-Only Mode + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Enable Read-Only | On / Off | Off | Disable modifications | + +When enabled: +- Cannot edit assets +- Cannot delete assets +- Cannot create albums +- Can still browse and view + +## Timeline Display + +Customize how photos appear in the timeline. + +### Grid Layout + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Tiles Per Row | 2-6 | 4 | Number of columns | +| Dynamic Layout | On / Off | Off | Variable tile sizes | +| Show Storage Indicator | On / Off | On | Show local/remote icon | + +### Grouping + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Group Assets By | None / Day / Month | Day | How to group photos | + +### Album Sort + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Album Sort Order | Title / Created / Modified | Modified | Sort albums by | +| Sort Direction | Ascending / Descending | Descending | Sort order | +| Album View | List / Grid | List | Album display style | + +## Asset Viewer + +Settings for the full-screen photo/video viewer. + +### Image Loading + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Load Preview | On / Off | On | Load preview quality | +| Load Original | On / Off | Off | Load full resolution | +| Prefer Remote | On / Off | Off | Prefer server image | + +### Video Settings + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Auto Play | On / Off | On | Play video automatically | +| Loop Video | On / Off | On | Repeat video | +| Load Original Video | On / Off | Off | Load full quality video | + +### Navigation + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Tap to Navigate | On / Off | Off | Tap sides to go prev/next | + +## Backup Settings + +Control automatic photo backup. + +### Foreground Backup + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Enable Backup | On / Off | Off | Upload photos to server | +| Use Cellular (Photos) | On / Off | Off | Upload photos on cellular | +| Use Cellular (Videos) | On / Off | Off | Upload videos on cellular | + +### Background Backup + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Background Backup | On / Off | Off | Upload when app closed | +| Require WiFi | On / Off | On | Only on WiFi | +| Require Charging | On / Off | Off | Only when charging | +| Trigger Delay | Minutes | 30 | Wait before starting | + +### Notification Settings + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Total Progress | On / Off | On | Show overall progress | +| Single Progress | On / Off | Off | Show per-file progress | +| Error Grace Period | Number | 2 | Errors before notification | + +### Album Selection + +Select which device albums to back up: + +``` +┌─────────────────────────────────┐ +│ Backup Albums │ +├─────────────────────────────────┤ +│ [✓] Camera Roll │ +│ [✓] Screenshots │ +│ [ ] Downloads │ +│ [ ] WhatsApp Images │ +│ [−] Excluded Album │ +└─────────────────────────────────┘ + +[✓] = Include in backup +[ ] = Not selected +[−] = Explicitly excluded +``` + +## Free Up Space + +Remove local copies of backed-up assets. + +### Filter Options + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Keep Favorites | On / Off | On | Don't remove favorites | +| Keep Media Type | All / Photos / Videos | All | Which to keep | +| Keep in Albums | Album list | None | Keep assets in albums | +| Cutoff Days | Number | All | Only remove older than | + +### Cleanup Process + +1. Calculate removable assets +2. Show preview of space to be freed +3. Confirm with user +4. Remove local files +5. Keep server copies intact + +## Networking + +Network and connection settings. + +### Server Configuration + +| Setting | Description | +|---------|-------------| +| Server URL | Primary server address | +| Local Endpoint | LAN server address | +| Preferred WiFi | WiFi name for local endpoint | +| External Endpoints | List of external addresses | + +### Auto Endpoint Switching + +When enabled: +1. Check current WiFi name +2. If matches preferred WiFi → use local endpoint +3. Otherwise → use external endpoint +4. Fall back on connection failure + +### SSL/TLS Settings + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Allow Self-Signed | On / Off | Off | Accept self-signed certs | +| Client Certificate | File | None | mTLS client certificate | + +### Custom Headers + +Add custom HTTP headers for proxy authentication: + +``` +Header Name: X-Custom-Auth +Header Value: token123 +``` + +## Notifications + +Control app notifications. + +| Setting | Description | +|---------|-------------| +| Backup Progress | Show backup progress notifications | +| Backup Complete | Notify when backup finishes | +| Backup Errors | Notify on upload failures | + +## Language + +Change app display language. + +- System default +- Manual language selection +- List of supported languages + +## Advanced + +Developer and troubleshooting options. + +### Troubleshooting + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Advanced Logging | On / Off | Off | Detailed debug logs | +| Log Level | Info-Severe | Info | Minimum log level | + +### Platform-Specific + +**Android:** +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Manage Local Media | On / Off | Off | Request full media access | +| Photo Manager Filter | On / Off | On | Custom media filtering | + +**iOS:** +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Ignore iCloud Assets | On / Off | Off | Skip iCloud-only photos | + +### Experimental + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| Beta Timeline | On / Off | On | Use new timeline sync | +| Sync Albums | On / Off | Off | Sync device albums | + +### Cache Management + +- Clear thumbnail cache +- Clear preview cache +- View cache size +- Reset all caches + +### Data Management + +- Export logs +- Reset settings +- Clear local data +- Sign out and clear + +## Sync Status (Beta) + +When beta timeline is enabled, shows sync status: + +### Status Information + +- Last sync time +- Sync state (idle/syncing/error) +- Number of synced assets +- Pending changes + +### Actions + +- Force full sync +- Reset sync state +- View sync logs + +## Settings Persistence + +Settings are saved to local storage immediately on change: + +1. User changes setting +2. Update in-memory state +3. Persist to Store +4. Reflect in UI + +Settings sync is local-only - each device maintains its own settings. + +--- + +[Previous: Local Storage](local-storage.md) | [Next: Error Handling](error-handling.md) diff --git a/docs/theming.md b/docs/theming.md new file mode 100644 index 0000000..a47aeb8 --- /dev/null +++ b/docs/theming.md @@ -0,0 +1,331 @@ +# Theming + +The app supports comprehensive theming to match user preferences and system settings. + +## Theme Structure + +``` +Theme +├── Color Scheme (light/dark) +├── Typography +├── Component Themes +└── Custom Extensions +``` + +## Color Schemes + +### Light Theme Colors + +| Color Role | Usage | +|------------|-------| +| primary | Main accent color, active elements | +| onPrimary | Text/icons on primary color | +| surface | Background color | +| onSurface | Text on surface | +| surfaceContainer | Card backgrounds | +| surfaceContainerHigh | Elevated surfaces | +| surfaceContainerHighest | Highest elevation | +| outline | Borders, dividers | +| error | Error states | + +### Dark Theme Colors + +Same roles as light theme but with dark-appropriate values: +- Surface colors are dark grays +- Primary colors may be adjusted for contrast +- Text colors are light + +### Surface Color Scale + +``` +Light Mode: +surfaceContainerLowest → #FFFFFF (white) +surfaceContainerLow → #F3F3F3 +surfaceContainer → #EEEEEE +surfaceContainerHigh → #E8E8E8 +surfaceContainerHighest → #E2E2E2 +surface → #F9F9F9 +surfaceDim → #DADADA +surfaceBright → #F9F9F9 + +Dark Mode: +surfaceContainerLowest → #0E0E0E +surfaceContainerLow → #1B1B1B +surfaceContainer → #1F1F1F +surfaceContainerHigh → #242424 +surfaceContainerHighest → #2E2E2E +surface → #131313 +surfaceDim → #131313 +surfaceBright → #353535 +``` + +## Theme Modes + +### System (Default) + +Follows device system setting: +- Automatically switches with system +- Respects scheduled dark mode + +### Light Mode + +Always uses light theme: +- Bright backgrounds +- Dark text +- Suitable for outdoor use + +### Dark Mode + +Always uses dark theme: +- Dark backgrounds +- Light text +- Reduces eye strain at night +- Saves battery on OLED screens + +## Primary Color Options + +The app offers color presets: + +| Name | Primary Color | Usage | +|------|---------------|-------| +| Default | Blue | Standard app color | +| Red | #F44336 | Bold accent | +| Green | #4CAF50 | Nature theme | +| Purple | #9C27B0 | Elegant | +| Orange | #FF9800 | Warm | +| Pink | #E91E63 | Playful | +| Teal | #009688 | Cool | +| Custom | User-defined | Any color | + +## Dynamic Theme + +When enabled (and supported by platform): + +1. Extract colors from wallpaper +2. Generate harmonious palette +3. Apply as app theme + +**Platform Support:** +- Android 12+ (Material You) +- iOS (limited support) + +## Colorful Interface + +### Enabled (Default) + +Primary color applied to: +- App bar titles +- Active navigation items +- Buttons +- Links +- Accent elements + +### Disabled + +More subtle appearance: +- Neutral app bars +- Reduced color usage +- Focus on content + +## Typography + +### Font Family + +Default: "GoogleSans" (or system font for unsupported locales) + +**Unsupported Locales:** +Languages that need special character support fall back to system fonts. + +### Text Styles + +| Style | Size | Weight | Usage | +|-------|------|--------|-------| +| displayLarge | 18 | SemiBold | Large headings | +| displayMedium | 14 | SemiBold | Medium headings | +| displaySmall | 12 | SemiBold | Small headings | +| titleLarge | 26 | SemiBold | Page titles | +| titleMedium | 18 | SemiBold | Section titles | +| titleSmall | 16 | SemiBold | Card titles | +| bodyLarge | 16 | Normal | Main text | +| bodyMedium | 14 | Normal | Body text | +| bodySmall | 12 | Normal | Captions | + +## Component Themes + +### App Bar + +``` +AppBarTheme: +- titleTextStyle: Primary color, 18px, SemiBold +- backgroundColor: Surface color +- foregroundColor: Primary color +- elevation: 0 (flat) +- centerTitle: true +``` + +### Navigation Bar + +``` +NavigationBarTheme: +- backgroundColor: Surface container (dark) or surface (light) +- labelTextStyle: 14px, Medium weight +- indicatorColor: Primary with opacity +``` + +### Buttons + +**Elevated Button:** +``` +- backgroundColor: Primary color +- foregroundColor: White (light) or Black (dark) +- shape: Rounded rectangle +``` + +### Input Fields + +``` +InputDecorationTheme: +- border: Rounded (15px radius) +- focusedBorder: Primary color +- enabledBorder: Outline variant color +- labelStyle: Primary color +``` + +### Cards/Dialogs + +``` +- backgroundColor: Surface container +- shape: Rounded corners (10px) +- elevation: Subtle shadow +``` + +### Chips + +``` +ChipTheme: +- side: No border +- shape: Stadium (pill shape) +``` + +### Progress Indicators + +``` +ProgressIndicatorTheme: +- Circular: Gap at 3px +- Linear: Rounded track +``` + +### Bottom Sheet + +``` +BottomSheetTheme: +- backgroundColor: Surface container +- shape: Rounded top corners +``` + +### Snackbar + +``` +SnackBarTheme: +- backgroundColor: Surface container highest +- contentTextStyle: Primary color, bold +``` + +## Custom Theme Extensions + +### Secondary Surface Color + +Additional surface variant for secondary text: +``` +onSurfaceSecondary: Slightly faded text color +``` + +Used for: +- Timestamps +- Secondary labels +- Placeholder text + +## Decolorized Surfaces + +To prevent primary color from tinting surfaces: + +The app uses static surface colors instead of seed-generated ones. This ensures: +- Neutral backgrounds +- Consistent appearance +- No unexpected color shifts + +## Theme Application + +### Build Theme Data + +``` +Inputs: +- ColorScheme (light or dark) +- Locale (for font selection) + +Process: +1. Select base color scheme +2. Apply typography with locale font +3. Configure component themes +4. Add custom extensions + +Output: +Complete theme data for the app +``` + +### Theme Switching + +``` +User changes theme setting + │ + ▼ +Store new preference + │ + ▼ +Rebuild theme data + │ + ▼ +Notify UI to rebuild + │ + ▼ +App repaints with new theme +``` + +## Accessibility + +### Contrast Ratios + +Theme colors maintain WCAG contrast ratios: +- Normal text: 4.5:1 minimum +- Large text: 3:1 minimum + +### Color Independence + +UI doesn't rely solely on color: +- Icons accompany colors +- Text labels included +- Patterns/shapes differentiate + +### System Font Scaling + +Typography respects system text size settings. + +## Platform Considerations + +### Android + +- Material 3 design language +- Dynamic color extraction (12+) +- Edge-to-edge content +- System navigation theming + +### iOS + +- Cupertino adaptations where needed +- System font for locales +- Safe area handling +- Native-feeling interactions + +--- + +[Previous: UI Components](ui-components.md) | [Back to Index](README.md) diff --git a/docs/ui-components.md b/docs/ui-components.md new file mode 100644 index 0000000..89140f6 --- /dev/null +++ b/docs/ui-components.md @@ -0,0 +1,444 @@ +# UI Components + +Reusable UI components used throughout the app. + +## Asset Display Components + +### Thumbnail Tile + +Displays a single asset thumbnail in grids. + +**Properties:** +- asset: Asset to display +- showStorageIndicator: Show local/remote badge +- onTap: Tap handler +- onLongPress: Long press handler (selection) +- isSelected: Selection state + +**Visual States:** +``` +Normal: Selected: +┌──────────┐ ┌──────────┐ +│ │ │ ┌──────┐ │ +│ [Image] │ │ │Image │✓│ +│ │ │ └──────┘ │ +│ [●] │ │ [●] │ +└──────────┘ └──────────┘ + └─ Storage └─ Checkmark + indicator overlay +``` + +**Storage Indicators:** +- Cloud icon: Remote only +- Device icon: Local only +- Cloud+Device: Both (merged) + +**Overlay Badges:** +- Video duration (bottom left) +- Stack count (bottom right) +- Favorite heart (top right) + +### Thumbnail Image + +Loads and displays asset images with progressive loading. + +**Loading States:** +1. Show thumbhash placeholder (blurred) +2. Load thumbnail quality +3. Optionally load preview quality +4. Optionally load original + +**Caching:** +- Uses image cache +- Key: asset ID + quality level +- Respects cache size limits + +### Asset Grid + +Displays assets in a scrollable grid. + +**Properties:** +- assets: List of assets +- tilesPerRow: Column count (2-6) +- onAssetTap: Individual tap handler +- onSelectModeChanged: Selection mode callback +- enableMultiSelect: Allow multi-selection + +**Features:** +- Virtualized scrolling (only renders visible items) +- Grouped by date with section headers +- Pull-to-refresh support +- Drag to scroll with date indicator + +### Draggable Scrollbar + +Custom scrollbar with date indicator. + +**Components:** +``` +┌─────────────────────────┬─┐ +│ │▲│ +│ ├─┤ +│ [Asset Grid] │ │ +│ │█│← Thumb +│ │ │ ┌──────────┐ +│ │ │ │ Jan 2024 │← Date bubble +│ │ │ └──────────┘ +│ │ │ +│ ├─┤ +│ │▼│ +└─────────────────────────┴─┘ +``` + +**Behaviors:** +- Drag thumb to fast scroll +- Date bubble shows current position +- Auto-hide when not interacting +- Haptic feedback on date changes + +## Navigation Components + +### Bottom Navigation Bar + +Main app navigation. + +**Tabs:** +``` +┌─────────────────────────────────────┐ +│ [Photos] [Search] [Sharing] [Library] │ +│ ● ○ ○ ○ │ +└─────────────────────────────────────┘ +``` + +**States:** +- Selected: Filled icon + label +- Unselected: Outline icon + +### App Bar + +Standard navigation header. + +**Variants:** + +Default: +``` +┌─────────────────────────────────────┐ +│ [←] Title [⋮] │ +└─────────────────────────────────────┘ +``` + +Selection mode: +``` +┌─────────────────────────────────────┐ +│ [✕] 3 selected [Share][⋮] │ +└─────────────────────────────────────┘ +``` + +### Tab Bar + +Secondary navigation within screens. + +``` +┌─────────────────────────────────────┐ +│ Albums │ Shared │ │ +│ ────────── ────────────── │ +└─────────────────────────────────────┘ +``` + +## Form Components + +### Text Input + +Standard text field with decorations. + +**States:** +- Enabled: Normal appearance +- Focused: Primary color border +- Error: Red border + error message +- Disabled: Grayed out + +**Layout:** +``` +┌─────────────────────────────────────┐ +│ Label │ +│ ┌───────────────────────────────┐ │ +│ │ [Icon] Placeholder text [X] │ │ +│ └───────────────────────────────┘ │ +│ Helper or error text │ +└─────────────────────────────────────┘ +``` + +### Search Bar + +Specialized input for search. + +``` +┌─────────────────────────────────────┐ +│ ┌───────────────────────────────┐ │ +│ │ [🔍] Search photos... [X] │ │ +│ └───────────────────────────────┘ │ +└─────────────────────────────────────┘ +``` + +**Features:** +- Search icon prefix +- Clear button when has text +- Debounced input for API calls + +### Settings Tiles + +Various settings input components. + +**Switch Tile:** +``` +┌─────────────────────────────────────┐ +│ Setting Title [═══] │ +│ Description text │ +└─────────────────────────────────────┘ +``` + +**Slider Tile:** +``` +┌─────────────────────────────────────┐ +│ Setting Title 4 │ +│ ──────●──────────────────────── │ +└─────────────────────────────────────┘ +``` + +**Radio Tiles:** +``` +┌─────────────────────────────────────┐ +│ ○ Option 1 │ +│ ● Option 2 (selected) │ +│ ○ Option 3 │ +└─────────────────────────────────────┘ +``` + +**Button Tile:** +``` +┌─────────────────────────────────────┐ +│ [Icon] Action Title [>] │ +│ Description │ +└─────────────────────────────────────┘ +``` + +## User Interface + +### User Circle Avatar + +Displays user profile picture or initials. + +**Properties:** +- user: User object +- size: Diameter in pixels + +**Rendering:** +1. If user has profile image → show image +2. Otherwise → show initials on colored background +3. Avatar color derived from user ID + +**Sizes:** +- Small: 30px (comments, lists) +- Medium: 44px (activity tiles) +- Large: 80px (profile page) + +### User List Tile + +Displays user in a list. + +``` +┌─────────────────────────────────────┐ +│ [Avatar] User Name │ +│ user@email.com │ +└─────────────────────────────────────┘ +``` + +## Feedback Components + +### Loading Indicators + +**Circular Progress:** +- Indeterminate: Spinning animation +- Determinate: Shows percentage + +**Linear Progress:** +``` +┌─────────────────────────────────────┐ +│ ████████░░░░░░░░░░░ 40% │ +└─────────────────────────────────────┘ +``` + +**Skeleton Loader:** +``` +┌──────┐ ┌──────┐ ┌──────┐ +│░░░░░░│ │░░░░░░│ │░░░░░░│ +│░░░░░░│ │░░░░░░│ │░░░░░░│ +└──────┘ └──────┘ └──────┘ +``` + +### Snackbar + +Temporary notification at bottom. + +``` +┌─────────────────────────────────────┐ +│ Message text here [ACTION]│ +└─────────────────────────────────────┘ +``` + +**Types:** +- Info: Default colors +- Success: Green tint +- Error: Red tint +- Warning: Orange tint + +### Dialog + +Modal overlay for confirmations. + +``` +┌─────────────────────────────────────┐ +│ │ +│ ┌───────────────────────────────┐ │ +│ │ Dialog Title │ │ +│ ├───────────────────────────────┤ │ +│ │ │ │ +│ │ Dialog content goes here │ │ +│ │ │ │ +│ ├───────────────────────────────┤ │ +│ │ [Cancel] [Confirm] │ │ +│ └───────────────────────────────┘ │ +│ │ +└─────────────────────────────────────┘ + (dimmed background) +``` + +### Bottom Sheet + +Slides up from bottom. + +``` +┌─────────────────────────────────────┐ +│ │ +│ │ +│ (main content) │ +│ │ +├─────────────────────────────────────┤ +│ ─────── (drag handle) │ +│ │ +│ Bottom sheet content │ +│ │ +│ [Action 1] │ +│ [Action 2] │ +│ [Action 3] │ +│ │ +└─────────────────────────────────────┘ +``` + +**Behaviors:** +- Drag handle to resize/dismiss +- Can expand to full screen +- Dismissible by dragging down + +## Photo Viewer Components + +### Top Control Bar + +Overlay controls on asset viewer. + +``` +┌─────────────────────────────────────┐ +│ [←] filename.jpg [♡] [⋮] │ +└─────────────────────────────────────┘ +``` + +**Actions:** +- Back: Return to grid +- Favorite: Toggle favorite +- More: Show action menu + +### Bottom Control Bar + +Additional actions for current asset. + +``` +┌─────────────────────────────────────┐ +│ [Share] [Archive] [Delete] [More] │ +└─────────────────────────────────────┘ +``` + +### EXIF Panel + +Shows metadata when expanded. + +``` +┌─────────────────────────────────────┐ +│ Details │ +├─────────────────────────────────────┤ +│ 📅 January 15, 2024 3:30 PM │ +│ 📷 iPhone 15 Pro │ +│ 🔧 f/1.8 1/120s ISO 100 │ +│ 📍 New York, United States │ +└─────────────────────────────────────┘ +``` + +## Map Components + +### Map View + +Displays assets on a map. + +**Features:** +- Cluster markers for grouped assets +- Tap cluster to zoom +- Tap marker to show asset +- Map style (light/dark/satellite) + +### Map Settings Sheet + +Filter controls for map. + +``` +┌─────────────────────────────────────┐ +│ Map Settings │ +├─────────────────────────────────────┤ +│ Show favorites only [═══] │ +│ Include archived [═══] │ +│ Include partner photos [═══] │ +│ │ +│ Time Range: │ +│ [All Time ▼] │ +└─────────────────────────────────────┘ +``` + +## Album Components + +### Album Thumbnail + +Album preview with cover image. + +``` +┌─────────────────────────────────────┐ +│ ┌───────────────────────────────┐ │ +│ │ │ │ +│ │ [Cover Image] │ │ +│ │ │ │ +│ └───────────────────────────────┘ │ +│ Album Name │ +│ 50 items │ +└─────────────────────────────────────┘ +``` + +### Album App Bar + +Album-specific header with actions. + +``` +┌─────────────────────────────────────┐ +│ [←] Album Name [Share] [⋮] │ +└─────────────────────────────────────┘ +``` + +--- + +[Previous: Error Handling](error-handling.md) | [Next: Theming](theming.md) diff --git a/docs/websocket.md b/docs/websocket.md new file mode 100644 index 0000000..cb82a09 --- /dev/null +++ b/docs/websocket.md @@ -0,0 +1,291 @@ +# WebSocket - Real-Time Updates + +The app maintains a WebSocket connection to receive real-time updates from the server, enabling instant synchronization when changes occur. + +## Connection Management + +### Connection Setup + +**WebSocket URL:** `{server-origin}/socket.io` + +**Transport:** WebSocket (not polling) + +**Options:** +- Auto-reconnection enabled +- Force new connection on each connect +- Custom WebSocket connector for SSL support + +### Connection Lifecycle + +``` +┌─────────────────┐ +│ User Logged In │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Build Socket │ +│ with Auth │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ Reconnect +│ Connect │◄───────────┐ +└────────┬────────┘ │ + │ │ + ▼ │ +┌─────────────────┐ │ +│ onConnect │ │ +│ - Set connected │ │ +│ - Start listen │ │ +└────────┬────────┘ │ + │ │ + ▼ │ +┌─────────────────┐ │ +│ Listen Events │ │ +└────────┬────────┘ │ + │ │ + ┌────┴────┐ │ + │ │ │ + ▼ ▼ │ + Event Error/ │ + Received Disconnect │ + │ │ │ + ▼ └────────────────┘ +┌─────────────────┐ +│ Process Event │ +└─────────────────┘ +``` + +### Connection States + +| State | Description | +|-------|-------------| +| Disconnected | Not connected to server | +| Connected | Active WebSocket connection | +| Reconnecting | Attempting to restore connection | + +## Event Types + +### Asset Events + +| Event Name | Payload | Action | +|------------|---------|--------| +| `on_upload_success` | Asset JSON | Add new asset to timeline | +| `on_asset_delete` | Asset ID | Remove asset from local DB | +| `on_asset_trash` | Asset IDs array | Move assets to trash | +| `on_asset_restore` | - | Refresh all assets | +| `on_asset_update` | - | Refresh asset metadata | +| `on_asset_stack_update` | - | Refresh stacked assets | +| `on_asset_hidden` | Asset ID | Remove from visible timeline | + +### Server Events + +| Event Name | Payload | Action | +|------------|---------|--------| +| `on_config_update` | - | Refresh server features and config | +| `on_new_release` | Version info | Show update notification | + +### Beta Timeline Events + +| Event Name | Payload | Action | +|------------|---------|--------| +| `AssetUploadReadyV1` | Asset data | Sync new upload to timeline | +| `AssetEditReadyV1` | Edit data | Sync asset edit | + +## Pending Changes System + +Events are batched to prevent UI thrashing: + +### Change Types + +``` +PendingAction: +- assetDelete: Asset was deleted +- assetUploaded: New asset uploaded +- assetHidden: Asset hidden from timeline +- assetTrash: Asset moved to trash +``` + +### Processing Flow + +``` +┌─────────────────┐ +│ Event Received │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Add to Pending │ +│ Changes List │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Start Debounce │ +│ Timer (500ms) │ +└────────┬────────┘ + │ + ▼ + More Events? + │ │ + Yes No + │ │ + ▼ ▼ + Reset ┌─────────────────┐ + Timer │ Process Batch │ + │ │ - Uploads │ + └───►│ - Deletes │ + │ - Hidden │ + │ - Trash │ + └─────────────────┘ +``` + +### Debouncing + +**Standard Debounce:** 500ms +- Waits 500ms after last event before processing +- Prevents rapid UI updates during bulk operations + +**Batch Debounce:** 5 seconds (max 10 seconds) +- For upload events +- Batches multiple uploads together +- Maximum wait time of 10 seconds + +## Event Handlers + +### Upload Success Handler + +When a new asset is uploaded (from web or another device): + +1. Receive asset JSON data +2. Add to pending changes +3. After debounce: + - Parse asset response + - Create local Asset object + - Add to local database + - Update timeline display + +### Asset Delete Handler + +When an asset is permanently deleted: + +1. Receive asset ID +2. Add to pending changes +3. After debounce: + - Remove from local database + - Update timeline display + +### Asset Trash Handler + +When assets are moved to trash: + +1. Receive array of asset IDs +2. Add to pending changes +3. After debounce: + - Mark assets as trashed in local DB + - Remove from main timeline + - Refresh asset list + +### Asset Hidden Handler + +When an asset is hidden (moved to locked folder): + +1. Receive asset ID +2. Add to pending changes +3. After debounce: + - Remove from local database + - Asset only visible in locked folder + +### Config Update Handler + +When server configuration changes: + +1. Receive event (no payload) +2. Immediately refresh: + - Server features + - Server configuration + +### Release Update Handler + +When a new server version is available: + +1. Receive version payload: + ```json + { + "serverVersion": {"major": 1, "minor": 2, "patch": 3}, + "releaseVersion": {"major": 1, "minor": 3, "patch": 0} + } + ``` +2. Parse version info +3. Update server info provider +4. Show update notification if applicable + +## WebSocket State + +``` +WebsocketState: +- socket: The socket instance (or null if disconnected) +- isConnected: Boolean connection status +- pendingChanges: List of changes waiting to be processed +``` + +## Lifecycle Integration + +### On App Start +1. Check if user is authenticated +2. If yes, connect WebSocket +3. Register event listeners + +### On App Foreground +1. Reconnect if disconnected +2. Clear stale pending changes + +### On App Background +1. Keep connection for brief period +2. Disconnect after timeout +3. Background service takes over + +### On Logout +1. Disconnect WebSocket +2. Clear socket instance +3. Clear pending changes + +## Error Handling + +### Connection Errors +- Log error message +- Set state to disconnected +- Auto-reconnection handles recovery + +### Event Processing Errors +- Log error with stack trace +- Continue processing other events +- Don't crash the app + +## Switching Event Listeners + +The app can switch between different event listener sets: + +**Stop Old Events:** +``` +- on_upload_success +- on_asset_delete +- on_asset_trash +- on_asset_restore +- on_asset_update +- on_asset_stack_update +- on_asset_hidden +``` + +**Start Beta Events:** +``` +- AssetUploadReadyV1 +- AssetEditReadyV1 +``` + +This allows smooth transition between different sync implementations. + +--- + +[Previous: Background Services](background-services.md) | [Next: Data Models](data-models.md)