move docs to docs/ folder, merge architecture files, update references
This commit is contained in:
500
docs/MILESTONE-6.md
Normal file
500
docs/MILESTONE-6.md
Normal file
@@ -0,0 +1,500 @@
|
||||
# Milestone 6: System Apps
|
||||
|
||||
**Status**: 75% Complete
|
||||
**Goal**: Core smartphone apps with full functionality.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
System apps provide the essential smartphone experience:
|
||||
- Home launcher
|
||||
- Phone/Dialer
|
||||
- Messages
|
||||
- Contacts
|
||||
- Settings
|
||||
- Browser
|
||||
- Store (TODO)
|
||||
- Camera (TODO)
|
||||
- Music (TODO)
|
||||
|
||||
---
|
||||
|
||||
## App Status
|
||||
|
||||
### Completed Apps
|
||||
|
||||
| App | Location | Features | Status |
|
||||
|-----|----------|----------|--------|
|
||||
| Home | `apps/home/` | App grid, dock, navigation | Complete |
|
||||
| Dialer | `apps/dialer/` | Keypad, call UI (mock) | Complete |
|
||||
| Messages | `apps/messages/` | Conversation list, chat | Complete |
|
||||
| Contacts | `apps/contacts/` | List, search, detail | Complete |
|
||||
| Settings | `apps/settings/` | Display, sound, about | Complete |
|
||||
| Browser | `apps/browser/` | URL bar, placeholder | Complete |
|
||||
|
||||
### Remaining Apps
|
||||
|
||||
| App | Priority | Description |
|
||||
|-----|----------|-------------|
|
||||
| Store | High | Browse and install apps |
|
||||
| Camera | Medium | Viewfinder, capture photos |
|
||||
| Music | Low | Audio playback |
|
||||
|
||||
---
|
||||
|
||||
## App: Store
|
||||
|
||||
**Location**: `src/main/assets/apps/store/`
|
||||
|
||||
### Features
|
||||
|
||||
1. **Browse Apps**
|
||||
- Featured apps carousel
|
||||
- Categories (Games, Utilities, Social)
|
||||
- Search functionality
|
||||
|
||||
2. **App Details**
|
||||
- Name, icon, description
|
||||
- Screenshots
|
||||
- Permissions list
|
||||
- Install/Update button
|
||||
|
||||
3. **My Apps**
|
||||
- Installed apps list
|
||||
- Update available indicator
|
||||
- Uninstall option
|
||||
|
||||
### UI Screens
|
||||
|
||||
```
|
||||
store/
|
||||
├── store.rml # Main store screen
|
||||
├── store.rcss # Store styles
|
||||
├── category.rml # Category listing
|
||||
├── detail.rml # App detail page
|
||||
└── scripts/
|
||||
└── store.lua # Store logic
|
||||
```
|
||||
|
||||
### Main Screen (`store.rml`)
|
||||
|
||||
```html
|
||||
<rml>
|
||||
<head>
|
||||
<link type="text/rcss" href="store.rcss"/>
|
||||
<link type="text/rcss" href="../../ui/theme.rcss"/>
|
||||
</head>
|
||||
<body class="store-screen">
|
||||
<div class="app-bar">
|
||||
<div class="app-bar-nav btn-icon" onclick="goBack()">
|
||||
<img src="../../icons/back.tga"/>
|
||||
</div>
|
||||
<span class="app-bar-title">Store</span>
|
||||
<div class="app-bar-action btn-icon" onclick="openSearch()">
|
||||
<img src="../../icons/search.tga"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="store-content">
|
||||
<!-- Featured carousel -->
|
||||
<div class="featured-section">
|
||||
<h2>Featured</h2>
|
||||
<div class="featured-carousel" data-for="app : featured_apps">
|
||||
<div class="featured-card" data-event-click="showDetail(app.id)">
|
||||
<img class="featured-banner" data-attr-src="app.banner"/>
|
||||
<span class="featured-name" data-text="app.name"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Categories -->
|
||||
<div class="category-section">
|
||||
<h2>Categories</h2>
|
||||
<div class="category-grid">
|
||||
<div class="category-item" onclick="showCategory('games')">
|
||||
<img src="../../icons/games.tga"/>
|
||||
<span>Games</span>
|
||||
</div>
|
||||
<div class="category-item" onclick="showCategory('utilities')">
|
||||
<img src="../../icons/tools.tga"/>
|
||||
<span>Utilities</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top Apps -->
|
||||
<div class="top-apps-section">
|
||||
<h2>Top Apps</h2>
|
||||
<div class="app-list" data-for="app : top_apps">
|
||||
<div class="app-list-item" data-event-click="showDetail(app.id)">
|
||||
<img class="app-icon" data-attr-src="app.icon"/>
|
||||
<div class="app-info">
|
||||
<span class="app-name" data-text="app.name"/>
|
||||
<span class="app-category" data-text="app.category"/>
|
||||
</div>
|
||||
<button class="install-btn" data-event-click="install(app.id)">
|
||||
Install
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</rml>
|
||||
```
|
||||
|
||||
### Data Model
|
||||
|
||||
```cpp
|
||||
// In data_models.cpp
|
||||
struct StoreApp {
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string icon;
|
||||
std::string banner;
|
||||
std::string category;
|
||||
std::string description;
|
||||
std::string version;
|
||||
std::vector<std::string> screenshots;
|
||||
std::vector<std::string> permissions;
|
||||
bool installed;
|
||||
};
|
||||
|
||||
void setupStoreDataModel(Rml::Context* context) {
|
||||
auto model = context->CreateDataModel("store");
|
||||
|
||||
model.Bind("featured_apps", &g_featured_apps);
|
||||
model.Bind("top_apps", &g_top_apps);
|
||||
model.Bind("categories", &g_categories);
|
||||
model.Bind("current_app", &g_current_app);
|
||||
|
||||
model.BindEventCallback("install", [](auto& event, auto& args) {
|
||||
// Install app
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## App: Camera
|
||||
|
||||
**Location**: `src/main/assets/apps/camera/`
|
||||
|
||||
### Features
|
||||
|
||||
1. **Viewfinder**
|
||||
- Live camera preview (from ICamera)
|
||||
- Capture button
|
||||
- Switch camera (front/back)
|
||||
- Flash toggle
|
||||
|
||||
2. **Capture**
|
||||
- Take photo
|
||||
- Save to gallery
|
||||
- Share option
|
||||
|
||||
3. **Gallery**
|
||||
- View captured photos
|
||||
- Delete photos
|
||||
- Share photos
|
||||
|
||||
### UI Screens
|
||||
|
||||
```
|
||||
camera/
|
||||
├── camera.rml # Viewfinder
|
||||
├── camera.rcss # Camera styles
|
||||
├── gallery.rml # Photo gallery
|
||||
└── scripts/
|
||||
└── camera.lua # Camera logic
|
||||
```
|
||||
|
||||
### Viewfinder (`camera.rml`)
|
||||
|
||||
```html
|
||||
<rml>
|
||||
<head>
|
||||
<link type="text/rcss" href="camera.rcss"/>
|
||||
</head>
|
||||
<body class="camera-screen">
|
||||
<!-- Camera preview (texture from ICamera) -->
|
||||
<div id="camera-preview">
|
||||
<img id="preview-frame" data-attr-src="camera_frame"/>
|
||||
</div>
|
||||
|
||||
<!-- Top controls -->
|
||||
<div class="camera-top-bar">
|
||||
<div class="btn-icon" onclick="goBack()">
|
||||
<img src="../../icons/close.tga"/>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="toggleFlash()">
|
||||
<img id="flash-icon" src="../../icons/flash_off.tga"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom controls -->
|
||||
<div class="camera-bottom-bar">
|
||||
<div class="btn-icon" onclick="openGallery()">
|
||||
<img id="last-photo" data-attr-src="last_photo_thumb"/>
|
||||
</div>
|
||||
|
||||
<div id="capture-btn" onclick="capture()">
|
||||
<div class="capture-ring"/>
|
||||
</div>
|
||||
|
||||
<div class="btn-icon" onclick="switchCamera()">
|
||||
<img src="../../icons/flip_camera.tga"/>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</rml>
|
||||
```
|
||||
|
||||
### Camera Lua Script
|
||||
|
||||
```lua
|
||||
-- camera.lua
|
||||
local camera = mosis.platform.getCamera()
|
||||
local capture = mosis.testing.VisualCapture(540, 960)
|
||||
|
||||
local is_front_camera = false
|
||||
local flash_on = false
|
||||
|
||||
function onAppCreate()
|
||||
if camera:isAvailable() then
|
||||
camera:startCapture(function(frame)
|
||||
-- Update preview texture
|
||||
document:GetElementById("preview-frame"):SetAttribute("src", frame.texture_url)
|
||||
end)
|
||||
else
|
||||
-- Show "no camera" message
|
||||
end
|
||||
end
|
||||
|
||||
function capture()
|
||||
local path = mosis.filesystem:getSharedMediaPath() .. "/photos/" .. os.time() .. ".png"
|
||||
capture:CaptureScreenshot(path)
|
||||
|
||||
-- Show capture animation
|
||||
playSound("shutter")
|
||||
flashScreen()
|
||||
|
||||
-- Update last photo thumbnail
|
||||
document:GetElementById("last-photo"):SetAttribute("src", path)
|
||||
end
|
||||
|
||||
function switchCamera()
|
||||
is_front_camera = not is_front_camera
|
||||
-- camera:setFacing(is_front_camera and "front" or "back")
|
||||
end
|
||||
|
||||
function toggleFlash()
|
||||
flash_on = not flash_on
|
||||
local icon = flash_on and "flash_on" or "flash_off"
|
||||
document:GetElementById("flash-icon"):SetAttribute("src", "../../icons/" .. icon .. ".tga")
|
||||
end
|
||||
|
||||
function openGallery()
|
||||
navigateTo("camera/gallery")
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## App: Music
|
||||
|
||||
**Location**: `src/main/assets/apps/music/`
|
||||
|
||||
### Features
|
||||
|
||||
1. **Library**
|
||||
- Songs list
|
||||
- Albums
|
||||
- Artists
|
||||
- Playlists
|
||||
|
||||
2. **Player**
|
||||
- Play/pause
|
||||
- Next/previous
|
||||
- Seek bar
|
||||
- Volume control
|
||||
- Shuffle/repeat
|
||||
|
||||
3. **Now Playing**
|
||||
- Album art
|
||||
- Song info
|
||||
- Progress bar
|
||||
|
||||
### UI Screens
|
||||
|
||||
```
|
||||
music/
|
||||
├── music.rml # Library view
|
||||
├── music.rcss # Music styles
|
||||
├── player.rml # Now playing
|
||||
├── playlist.rml # Playlist view
|
||||
└── scripts/
|
||||
└── music.lua # Player logic
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Persistence
|
||||
|
||||
### Storage Layer
|
||||
|
||||
Apps need persistent storage for:
|
||||
- Contacts
|
||||
- Messages
|
||||
- Settings
|
||||
- Photos
|
||||
|
||||
**Implementation Options**:
|
||||
|
||||
1. **JSON Files** (Simple)
|
||||
```
|
||||
/data/contacts.json
|
||||
/data/messages.json
|
||||
/data/settings.json
|
||||
```
|
||||
|
||||
2. **SQLite** (Robust)
|
||||
```
|
||||
/data/mosis.db
|
||||
- contacts table
|
||||
- messages table
|
||||
- settings table
|
||||
```
|
||||
|
||||
### Contact Storage
|
||||
|
||||
```cpp
|
||||
// contact_storage.h
|
||||
struct Contact {
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string phone;
|
||||
std::string email;
|
||||
std::string avatar;
|
||||
};
|
||||
|
||||
class ContactStorage {
|
||||
public:
|
||||
std::vector<Contact> GetAll();
|
||||
std::optional<Contact> GetById(const std::string& id);
|
||||
bool Save(const Contact& contact);
|
||||
bool Delete(const std::string& id);
|
||||
std::vector<Contact> Search(const std::string& query);
|
||||
};
|
||||
```
|
||||
|
||||
### Message Storage
|
||||
|
||||
```cpp
|
||||
// message_storage.h
|
||||
struct Message {
|
||||
std::string id;
|
||||
std::string conversation_id;
|
||||
std::string sender;
|
||||
std::string text;
|
||||
int64_t timestamp;
|
||||
bool read;
|
||||
};
|
||||
|
||||
struct Conversation {
|
||||
std::string id;
|
||||
std::string contact_id;
|
||||
std::string last_message;
|
||||
int64_t last_timestamp;
|
||||
int unread_count;
|
||||
};
|
||||
|
||||
class MessageStorage {
|
||||
public:
|
||||
std::vector<Conversation> GetConversations();
|
||||
std::vector<Message> GetMessages(const std::string& conversation_id);
|
||||
bool SaveMessage(const Message& message);
|
||||
bool MarkAsRead(const std::string& conversation_id);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Store App UI
|
||||
- [ ] Main store screen layout
|
||||
- [ ] Category browsing
|
||||
- [ ] App detail page
|
||||
- [ ] Mock data for testing
|
||||
|
||||
### Phase 2: Camera App
|
||||
- [ ] Viewfinder UI
|
||||
- [ ] Capture to file
|
||||
- [ ] Gallery view
|
||||
- [ ] Integration with ICamera
|
||||
|
||||
### Phase 3: Music App
|
||||
- [ ] Library UI
|
||||
- [ ] Player UI
|
||||
- [ ] Audio playback (stub)
|
||||
|
||||
### Phase 4: Data Persistence
|
||||
- [ ] JSON storage layer
|
||||
- [ ] Contact CRUD
|
||||
- [ ] Message storage
|
||||
- [ ] Settings persistence
|
||||
|
||||
### Phase 5: Real Functionality
|
||||
- [ ] Store: Install real .mpkg files
|
||||
- [ ] Camera: Real camera frames
|
||||
- [ ] Music: Audio playback
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Test IDs for Store
|
||||
|
||||
| ID | Element |
|
||||
|----|---------|
|
||||
| `store-search` | Search button |
|
||||
| `store-featured` | Featured carousel |
|
||||
| `store-categories` | Category grid |
|
||||
| `app-install-btn` | Install button on detail |
|
||||
|
||||
### Test IDs for Camera
|
||||
|
||||
| ID | Element |
|
||||
|----|---------|
|
||||
| `camera-preview` | Preview area |
|
||||
| `capture-btn` | Capture button |
|
||||
| `gallery-btn` | Gallery button |
|
||||
| `switch-camera-btn` | Switch camera |
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
### Store
|
||||
- [ ] Browse featured and top apps
|
||||
- [ ] View app details
|
||||
- [ ] See permission requirements
|
||||
- [ ] Install apps (mock or real)
|
||||
|
||||
### Camera
|
||||
- [ ] Display camera preview
|
||||
- [ ] Capture photos
|
||||
- [ ] View in gallery
|
||||
- [ ] Share photos
|
||||
|
||||
### Music
|
||||
- [ ] Display music library
|
||||
- [ ] Play/pause audio
|
||||
- [ ] Show now playing
|
||||
|
||||
### Persistence
|
||||
- [ ] Contacts persist across sessions
|
||||
- [ ] Messages persist across sessions
|
||||
- [ ] Settings persist across sessions
|
||||
Reference in New Issue
Block a user