add simulator mode to desktop designer for testing apps
- Add --simulator flag to launch home screen showing discovered apps - Create app discovery system to scan test-apps/ directory - Build simulator home screen with dark phone-like UI - Add Lua API: simulator.launchApp, simulator.goHome, simulator.getApps - ESC key returns to home when inside an app - Apps displayed with icons in grid layout Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
91
designer/src/app_discovery.cpp
Normal file
91
designer/src/app_discovery.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// D:\Dev\Mosis\MosisService\designer\src\app_discovery.cpp
|
||||
#include "app_discovery.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace mosis {
|
||||
|
||||
std::vector<AppInfo> AppDiscovery::DiscoverApps(const std::string& apps_directory) {
|
||||
std::vector<AppInfo> apps;
|
||||
|
||||
if (!fs::exists(apps_directory) || !fs::is_directory(apps_directory)) {
|
||||
std::cerr << "AppDiscovery: Directory not found: " << apps_directory << std::endl;
|
||||
return apps;
|
||||
}
|
||||
|
||||
std::cout << "AppDiscovery: Scanning " << apps_directory << std::endl;
|
||||
|
||||
for (const auto& entry : fs::directory_iterator(apps_directory)) {
|
||||
if (!entry.is_directory()) continue;
|
||||
|
||||
std::string app_dir = entry.path().string();
|
||||
AppInfo info;
|
||||
|
||||
if (LoadAppManifest(app_dir, info)) {
|
||||
apps.push_back(std::move(info));
|
||||
std::cout << "AppDiscovery: Found app '" << apps.back().name
|
||||
<< "' (" << apps.back().id << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "AppDiscovery: Found " << apps.size() << " apps" << std::endl;
|
||||
return apps;
|
||||
}
|
||||
|
||||
bool AppDiscovery::LoadAppManifest(const std::string& app_directory, AppInfo& info) {
|
||||
fs::path manifest_path = fs::path(app_directory) / "manifest.json";
|
||||
|
||||
if (!fs::exists(manifest_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
std::ifstream file(manifest_path);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "AppDiscovery: Cannot open " << manifest_path << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
json j;
|
||||
file >> j;
|
||||
|
||||
// Required fields
|
||||
if (!j.contains("id") || !j.contains("name") || !j.contains("entry")) {
|
||||
std::cerr << "AppDiscovery: Missing required fields in " << manifest_path << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
info.id = j["id"].get<std::string>();
|
||||
info.name = j["name"].get<std::string>();
|
||||
info.entry = j["entry"].get<std::string>();
|
||||
|
||||
// Optional fields
|
||||
info.version = j.value("version", "1.0.0");
|
||||
info.icon = j.value("icon", "icon.tga");
|
||||
info.description = j.value("description", "");
|
||||
|
||||
// Normalize path separators
|
||||
info.app_path = app_directory;
|
||||
std::replace(info.app_path.begin(), info.app_path.end(), '\\', '/');
|
||||
|
||||
// Verify entry file exists
|
||||
fs::path entry_path = fs::path(app_directory) / info.entry;
|
||||
if (!fs::exists(entry_path)) {
|
||||
std::cerr << "AppDiscovery: Entry file not found: " << entry_path << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "AppDiscovery: Error parsing " << manifest_path << ": " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mosis
|
||||
32
designer/src/app_discovery.h
Normal file
32
designer/src/app_discovery.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// D:\Dev\Mosis\MosisService\designer\src\app_discovery.h
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace mosis {
|
||||
|
||||
struct AppInfo {
|
||||
std::string id; // e.g., "com.mosis.sandbox-test"
|
||||
std::string name; // Display name
|
||||
std::string version; // Version string
|
||||
std::string entry; // Entry point (e.g., "main.rml")
|
||||
std::string icon; // Icon filename (e.g., "icon.tga")
|
||||
std::string description; // App description
|
||||
std::string app_path; // Full path to app directory
|
||||
|
||||
// Computed paths
|
||||
std::string GetEntryPath() const { return app_path + "/" + entry; }
|
||||
std::string GetIconPath() const { return app_path + "/" + icon; }
|
||||
};
|
||||
|
||||
class AppDiscovery {
|
||||
public:
|
||||
// Scan a directory for apps (folders with manifest.json)
|
||||
static std::vector<AppInfo> DiscoverApps(const std::string& apps_directory);
|
||||
|
||||
// Load a single app's manifest
|
||||
static bool LoadAppManifest(const std::string& app_directory, AppInfo& info);
|
||||
};
|
||||
|
||||
} // namespace mosis
|
||||
Reference in New Issue
Block a user