add docs part 2
This commit is contained in:
202
docs/activities.md
Normal file
202
docs/activities.md
Normal file
@@ -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)
|
||||||
607
docs/api-reference.md
Normal file
607
docs/api-reference.md
Normal file
@@ -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)
|
||||||
261
docs/background-services.md
Normal file
261
docs/background-services.md
Normal file
@@ -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)
|
||||||
308
docs/data-models.md
Normal file
308
docs/data-models.md
Normal file
@@ -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<String> | 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<Asset> | 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)
|
||||||
344
docs/error-handling.md
Normal file
344
docs/error-handling.md
Normal file
@@ -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<T>
|
||||||
|
- 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)
|
||||||
326
docs/local-storage.md
Normal file
326
docs/local-storage.md
Normal file
@@ -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)
|
||||||
326
docs/settings.md
Normal file
326
docs/settings.md
Normal file
@@ -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)
|
||||||
331
docs/theming.md
Normal file
331
docs/theming.md
Normal file
@@ -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)
|
||||||
444
docs/ui-components.md
Normal file
444
docs/ui-components.md
Normal file
@@ -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)
|
||||||
291
docs/websocket.md
Normal file
291
docs/websocket.md
Normal file
@@ -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)
|
||||||
Reference in New Issue
Block a user