Files
MosisService/MILESTONE-6.md

11 KiB

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)

<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

// 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)

<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

-- 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

// 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

// 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