Files
Timmy-time-dashboard/mobile-app/app.config.ts
Manus AI b4b508ff5a feat: add Timmy Chat mobile app (Expo/React Native)
- Single-screen chat interface with Timmy's sovereign AI personality
- Text messaging with real-time AI responses via server chat API
- Voice recording and playback with waveform visualization
- Image sharing (camera + photo library) with full-screen viewer
- File attachments via document picker
- Dark arcane theme matching the Timmy Time dashboard
- Custom app icon with glowing T circuit design
- Timmy system prompt ported from dashboard prompts.py
- Unit tests for chat utilities and message types
2026-02-26 21:55:41 -05:00

131 lines
3.7 KiB
TypeScript

// Load environment variables with proper priority (system > .env)
import "./scripts/load-env.js";
import type { ExpoConfig } from "expo/config";
// Bundle ID format: space.manus.<project_name_dots>.<timestamp>
// e.g., "my-app" created at 2024-01-15 10:30:45 -> "space.manus.my.app.t20240115103045"
// Bundle ID can only contain letters, numbers, and dots
// Android requires each dot-separated segment to start with a letter
const rawBundleId = "space.manus.timmy.chat.t20260226211148";
const bundleId =
rawBundleId
.replace(/[-_]/g, ".") // Replace hyphens/underscores with dots
.replace(/[^a-zA-Z0-9.]/g, "") // Remove invalid chars
.replace(/\.+/g, ".") // Collapse consecutive dots
.replace(/^\.+|\.+$/g, "") // Trim leading/trailing dots
.toLowerCase()
.split(".")
.map((segment) => {
// Android requires each segment to start with a letter
// Prefix with 'x' if segment starts with a digit
return /^[a-zA-Z]/.test(segment) ? segment : "x" + segment;
})
.join(".") || "space.manus.app";
// Extract timestamp from bundle ID and prefix with "manus" for deep link scheme
// e.g., "space.manus.my.app.t20240115103045" -> "manus20240115103045"
const timestamp = bundleId.split(".").pop()?.replace(/^t/, "") ?? "";
const schemeFromBundleId = `manus${timestamp}`;
const env = {
// App branding - update these values directly (do not use env vars)
appName: "Timmy Chat",
appSlug: "timmy-chat",
// S3 URL of the app logo - set this to the URL returned by generate_image when creating custom logo
// Leave empty to use the default icon from assets/images/icon.png
logoUrl: "https://files.manuscdn.com/user_upload_by_module/session_file/310519663286296482/kuSmtQpNVBtvECMG.png",
scheme: schemeFromBundleId,
iosBundleId: bundleId,
androidPackage: bundleId,
};
const config: ExpoConfig = {
name: env.appName,
slug: env.appSlug,
version: "1.0.0",
orientation: "portrait",
icon: "./assets/images/icon.png",
scheme: env.scheme,
userInterfaceStyle: "automatic",
newArchEnabled: true,
ios: {
supportsTablet: true,
bundleIdentifier: env.iosBundleId,
"infoPlist": {
"ITSAppUsesNonExemptEncryption": false
}
},
android: {
adaptiveIcon: {
backgroundColor: "#080412",
foregroundImage: "./assets/images/android-icon-foreground.png",
backgroundImage: "./assets/images/android-icon-background.png",
monochromeImage: "./assets/images/android-icon-monochrome.png",
},
edgeToEdgeEnabled: true,
predictiveBackGestureEnabled: false,
package: env.androidPackage,
permissions: ["POST_NOTIFICATIONS"],
intentFilters: [
{
action: "VIEW",
autoVerify: true,
data: [
{
scheme: env.scheme,
host: "*",
},
],
category: ["BROWSABLE", "DEFAULT"],
},
],
},
web: {
bundler: "metro",
output: "static",
favicon: "./assets/images/favicon.png",
},
plugins: [
"expo-router",
[
"expo-audio",
{
microphonePermission: "Allow $(PRODUCT_NAME) to access your microphone.",
},
],
[
"expo-video",
{
supportsBackgroundPlayback: true,
supportsPictureInPicture: true,
},
],
[
"expo-splash-screen",
{
image: "./assets/images/splash-icon.png",
imageWidth: 200,
resizeMode: "contain",
backgroundColor: "#080412",
dark: {
backgroundColor: "#080412",
},
},
],
[
"expo-build-properties",
{
android: {
buildArchs: ["armeabi-v7a", "arm64-v8a"],
minSdkVersion: 24,
},
},
],
],
experiments: {
typedRoutes: true,
reactCompiler: true,
},
};
export default config;