This document describes the architecture of the Jules Mobile Client application.
┌─────────────────────────────────────────────────────────────────┐
│ App Entry Point │
│ app/_layout.tsx │
├─────────────────────────────────────────────────────────────────┤
│ Providers │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ ApiKeyProvider │ │ I18nProvider │ │ ThemeProvider │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Expo Router │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Stack Navigator │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │
│ │ │ (tabs) │ │create-session│ │ session/[id] │ │ │
│ │ │ Tab Nav │ │ Modal │ │ Screen │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Located in app/ directory, using Expo Router's file-based routing.
| Screen | Path | Description |
|---|---|---|
| Sessions List | /(tabs)/index.tsx |
Main session list with FAB |
| Settings | /(tabs)/settings.tsx |
API key and preferences |
| Session Detail | /session/[id].tsx |
Chat view with activities |
| Create Session | /create-session.tsx |
New task creation modal |
Specialized components for Jules functionality:
ActivityItem- Renders different activity types (messages, plans, artifacts)ActivityItemSkeleton- Chat-style shimmer skeleton for loading statesSessionCard- Session list item with i18n status badgeSessionCardSkeleton- Card shimmer skeleton for loading statesLoadingOverlay- Full-screen loading indicator (legacy)DataRenderer- Generic JSON/data rendererCodeBlock- Syntax highlighted code display
Components for GitHub integration features:
EnhancedRepositoryManager- Advanced repository browsing and managementGithubSessionCreator- Session creation wizard with GitHub contextGithubUrlHandler- URL parsing and deep linking for GitHub URLsNotificationsCenter- Centralized notification management interfaceOptimizedWorkflowDashboard- Performance-optimized workflow monitoringPullRequestAnalyzer- AI-powered pull request analysis and reviewRepositorySyncManager- Background synchronization and conflict resolutionWebhookManagement- Webhook configuration and event handlingWorkflowCard,WorkflowDashboard,WorkflowJobCard- Workflow visualization componentsWorkflowRunCard,WorkflowRunDetails,WorkflowLogsViewer- Workflow execution detailsWorkflowNotifications- Workflow status notification system
Generic, reusable UI components:
IconSymbol- Cross-platform icon component (SF Symbols / Material Icons)Collapsible- Expandable content containerOptimizedList- Performance-optimized list rendering
The main API hook that handles all Jules API communication:
const {
isLoading,
error,
sources,
fetchSessions,
fetchActivities,
createSession,
approvePlan,
} = useJulesApi({ apiKey, t });Features:
- Automatic error handling
- Loading state management
- Pagination support for sources
- Silent refresh option
Specialized hooks for GitHub functionality:
useGithubApi- Core GitHub API integration with OctokituseGithubDeepLinking- URL parsing and deep linking for GitHub URLsuseGithubService- GitHub service layer abstractionuseGithubSession- Session creation with GitHub repository contextuseGithubWebhooksNative- Native webhook event handlinguseGithubWebhooks- Webhook management and processinguseNotifications- Push notification system for repository eventsusePullRequestAnalysis- AI-powered PR analysis and reviewuseRepositoryManager- Repository browsing and managementuseRepositorySync- Background synchronization with conflict resolutionuseWorkflowUpdates- Real-time workflow status monitoring
Handles secure data persistence:
const {
saveApiKey,
getApiKey,
saveTheme,
getTheme,
saveLanguage,
getLanguage,
} = useSecureStorage();Strict TypeScript definitions for all API responses:
interface Session {
name: string;
title?: string;
state: "ACTIVE" | "COMPLETED" | "FAILED";
createTime: string;
updateTime: string;
}
interface Activity {
name: string;
originator: "agent" | "user";
agentMessaged?: { agentMessage: string };
userMessaged?: { userMessage: string };
planGenerated?: { plan: Plan };
// ...
}ApiKeyContext - Global API key state with secure persistence
<ApiKeyProvider>
{children}
</ApiKeyProvider>GithubContext - GitHub integration state and configuration
<GithubProvider>
{children}
</GithubProvider>I18nContext - Language state and translation function
const { language, setLanguage, t } = useI18n();Centralized service layer for GitHub API operations:
- Repository management (list, search, details)
- Webhook configuration and event handling
- Workflow monitoring and log retrieval
- Pull request analysis and review
- Authentication and token management
- Rate limiting and error handling
┌────────────┐ ┌──────────────┐ ┌────────────────┐
│ Screen │ ──▶ │ useJulesApi │ ──▶ │ Jules API │
│ │ │ Hook │ │ googleapis.com │
└────────────┘ └──────────────┘ └────────────────┘
│ │
│ ▼
│ ┌──────────────┐
│ │ State │
│ │ (useState) │
│ └──────────────┘
│ │
▼ ▼
┌────────────┐ ┌──────────────┐
│ Components │ ◀── │ Re-render │
└────────────┘ └──────────────┘
Used for component-specific state:
- Form inputs
- UI toggles
- Temporary data
Used for app-wide state:
- API Key
- Language preference
- Theme (via Appearance API)
Used for secure, persistent data:
- API Key
- User preferences
- StyleSheet.create() for static styles
- Conditional styles for dark mode:
[styles.base, isDark && styles.dark] - Inline styles only for dynamic values
// Light Theme
background: "#f8fafc";
card: "#ffffff";
text: "#0f172a";
accent: "#2563eb";
// Dark Theme
background: "#020617";
card: "#1e293b";
text: "#f8fafc";
accent: "#60a5fa";-
Memoized Components
const MemoizedSessionCard = memo(SessionCard);
-
FlatList Optimization
<FlatList removeClippedSubviews={true} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} getItemLayout={(_, index) => ({...})} />
-
Lazy Loading
- Sources loaded on dropdown open
- Pagination with infinite scroll
-
Polling Strategy
- 5-second interval for activity updates
- Silent refresh (no loading spinner)
try {
const data = await julesFetch("/sessions");
} catch (err) {
setError(err.message);
}- Errors displayed in dismissible banners
- API errors parsed from response
- Network errors handled gracefully
(To be implemented)
- Unit tests for hooks
- Component tests with React Native Testing Library
- E2E tests with Detox