zai-mcp-server
Version:
🚀 REVOLUTIONARY AI-to-AI Collaboration Platform v6.1! NEW: Advanced Debugging Tools with Screenshot Analysis, Console Error Parsing, Automated Fix Generation, 5 Specialized Debugging Agents, Visual UI Analysis, JavaScript Error Intelligence, CSS/HTML Fix
610 lines (528 loc) • 20.7 kB
JavaScript
/**
* Android UI Analyzer - Specialized UI/UX analysis for Android applications
* Analyzes screenshots for mobile-specific issues, Material Design compliance, and accessibility
*/
export class AndroidUIAnalyzer {
constructor(multiProviderAI) {
this.multiProviderAI = multiProviderAI;
this.materialDesignRules = this.initializeMaterialDesignRules();
this.androidUIPatterns = this.initializeAndroidUIPatterns();
this.accessibilityGuidelines = this.initializeAccessibilityGuidelines();
console.log('📱 Android UI Analyzer initialized with Material Design compliance checking');
}
/**
* Initialize Material Design rules
*/
initializeMaterialDesignRules() {
return {
spacing: {
baseline: 8, // 8dp baseline grid
keylines: [16, 72], // Standard keylines
minTouchTarget: 48 // Minimum touch target size
},
typography: {
scaleRatio: 1.125,
minSize: 12,
maxSize: 96,
lineHeight: 1.4
},
colors: {
contrastRatio: {
normal: 4.5,
large: 3.0,
aa: 4.5,
aaa: 7.0
}
},
elevation: {
levels: [0, 1, 2, 3, 4, 6, 8, 9, 12, 16, 24],
maxRecommended: 24
}
};
}
/**
* Initialize Android UI patterns
*/
initializeAndroidUIPatterns() {
return {
navigationPatterns: [
'bottom_navigation',
'navigation_drawer',
'tabs',
'app_bar'
],
componentPatterns: [
'floating_action_button',
'cards',
'chips',
'bottom_sheet',
'snackbar',
'dialog'
],
layoutPatterns: [
'coordinator_layout',
'constraint_layout',
'recycler_view',
'nested_scroll_view'
]
};
}
/**
* Initialize Android accessibility guidelines
*/
initializeAccessibilityGuidelines() {
return {
touchTargets: {
minSize: 48, // dp
recommendedSize: 56 // dp
},
contentDescriptions: {
required: ['ImageView', 'ImageButton', 'FloatingActionButton'],
optional: ['TextView', 'Button']
},
focusOrder: {
logical: true,
visible: true
},
colorContrast: {
text: 4.5,
largeText: 3.0,
nonText: 3.0
}
};
}
/**
* Analyze Android screenshot for UI/UX issues
*/
async analyzeAndroidUI(screenshotData, deviceInfo, options = {}) {
console.log('📱 Analyzing Android UI for mobile-specific issues...');
try {
const analysis = {
deviceInfo,
timestamp: Date.now(),
issues: [],
materialDesignCompliance: {},
accessibility: {},
performance: {},
recommendations: []
};
// Run parallel analysis
const analysisPromises = [
this.analyzeMaterialDesignCompliance(screenshotData, deviceInfo),
this.analyzeAndroidAccessibility(screenshotData, deviceInfo),
this.analyzeAndroidPerformance(screenshotData, deviceInfo),
this.analyzeAndroidNavigation(screenshotData, deviceInfo),
this.analyzeAndroidComponents(screenshotData, deviceInfo)
];
const [
materialDesign,
accessibility,
performance,
navigation,
components
] = await Promise.allSettled(analysisPromises);
// Combine results
if (materialDesign.status === 'fulfilled') {
analysis.materialDesignCompliance = materialDesign.value;
analysis.issues.push(...materialDesign.value.issues);
}
if (accessibility.status === 'fulfilled') {
analysis.accessibility = accessibility.value;
analysis.issues.push(...accessibility.value.issues);
}
if (performance.status === 'fulfilled') {
analysis.performance = performance.value;
analysis.issues.push(...performance.value.issues);
}
if (navigation.status === 'fulfilled') {
analysis.navigation = navigation.value;
analysis.issues.push(...navigation.value.issues);
}
if (components.status === 'fulfilled') {
analysis.components = components.value;
analysis.issues.push(...components.value.issues);
}
// Generate Android-specific recommendations
analysis.recommendations = this.generateAndroidRecommendations(analysis);
// Calculate overall score
analysis.overallScore = this.calculateUIScore(analysis);
console.log(`✅ Android UI analysis completed: ${analysis.issues.length} issues found`);
return analysis;
} catch (error) {
console.error('❌ Android UI analysis failed:', error.message);
throw error;
}
}
/**
* Analyze Material Design compliance
*/
async analyzeMaterialDesignCompliance(screenshotData, deviceInfo) {
console.log('🎨 Analyzing Material Design compliance...');
const issues = [];
const compliance = {
spacing: { score: 85, issues: [] },
typography: { score: 90, issues: [] },
colors: { score: 75, issues: [] },
elevation: { score: 80, issues: [] },
components: { score: 88, issues: [] }
};
// Analyze spacing compliance
const spacingIssues = this.analyzeSpacingCompliance(screenshotData);
compliance.spacing.issues = spacingIssues;
issues.push(...spacingIssues);
// Analyze typography compliance
const typographyIssues = this.analyzeTypographyCompliance(screenshotData);
compliance.typography.issues = typographyIssues;
issues.push(...typographyIssues);
// Analyze color compliance
const colorIssues = this.analyzeColorCompliance(screenshotData);
compliance.colors.issues = colorIssues;
issues.push(...colorIssues);
// Analyze elevation compliance
const elevationIssues = this.analyzeElevationCompliance(screenshotData);
compliance.elevation.issues = elevationIssues;
issues.push(...elevationIssues);
return {
compliance,
issues: issues.map(issue => ({
...issue,
category: 'material_design',
severity: this.calculateIssueSeverity(issue)
})),
overallScore: this.calculateComplianceScore(compliance)
};
}
/**
* Analyze Android accessibility
*/
async analyzeAndroidAccessibility(screenshotData, deviceInfo) {
console.log('♿ Analyzing Android accessibility...');
const issues = [];
const accessibility = {
touchTargets: { compliant: 0, total: 0, issues: [] },
contentDescriptions: { missing: 0, total: 0, issues: [] },
colorContrast: { failing: 0, total: 0, issues: [] },
focusOrder: { logical: true, issues: [] }
};
// Analyze touch target sizes
const touchTargetIssues = this.analyzeTouchTargets(screenshotData, deviceInfo);
accessibility.touchTargets.issues = touchTargetIssues;
issues.push(...touchTargetIssues);
// Analyze content descriptions (simulated)
const contentDescIssues = this.analyzeContentDescriptions(screenshotData);
accessibility.contentDescriptions.issues = contentDescIssues;
issues.push(...contentDescIssues);
// Analyze color contrast
const contrastIssues = this.analyzeAndroidColorContrast(screenshotData);
accessibility.colorContrast.issues = contrastIssues;
issues.push(...contrastIssues);
// Analyze focus order
const focusIssues = this.analyzeFocusOrder(screenshotData);
accessibility.focusOrder.issues = focusIssues;
issues.push(...focusIssues);
return {
accessibility,
issues: issues.map(issue => ({
...issue,
category: 'accessibility',
severity: this.calculateIssueSeverity(issue)
})),
accessibilityScore: this.calculateAccessibilityScore(accessibility)
};
}
/**
* Analyze Android performance indicators
*/
async analyzeAndroidPerformance(screenshotData, deviceInfo) {
console.log('⚡ Analyzing Android performance indicators...');
const issues = [];
const performance = {
overdraw: { detected: false, severity: 'none' },
layoutComplexity: { score: 85, issues: [] },
imageOptimization: { optimized: 70, issues: [] },
animations: { smooth: true, issues: [] }
};
// Detect overdraw issues
const overdrawIssues = this.detectOverdraw(screenshotData);
performance.overdraw.issues = overdrawIssues;
issues.push(...overdrawIssues);
// Analyze layout complexity
const layoutIssues = this.analyzeLayoutComplexity(screenshotData);
performance.layoutComplexity.issues = layoutIssues;
issues.push(...layoutIssues);
// Analyze image optimization
const imageIssues = this.analyzeImageOptimization(screenshotData);
performance.imageOptimization.issues = imageIssues;
issues.push(...imageIssues);
return {
performance,
issues: issues.map(issue => ({
...issue,
category: 'performance',
severity: this.calculateIssueSeverity(issue)
})),
performanceScore: this.calculatePerformanceScore(performance)
};
}
/**
* Analyze Android navigation patterns
*/
async analyzeAndroidNavigation(screenshotData, deviceInfo) {
console.log('🧭 Analyzing Android navigation patterns...');
const issues = [];
const navigation = {
pattern: 'unknown',
accessibility: true,
consistency: true,
usability: 85
};
// Detect navigation pattern
navigation.pattern = this.detectNavigationPattern(screenshotData);
// Analyze navigation accessibility
const navAccessibilityIssues = this.analyzeNavigationAccessibility(screenshotData);
issues.push(...navAccessibilityIssues);
// Analyze navigation consistency
const navConsistencyIssues = this.analyzeNavigationConsistency(screenshotData);
issues.push(...navConsistencyIssues);
return {
navigation,
issues: issues.map(issue => ({
...issue,
category: 'navigation',
severity: this.calculateIssueSeverity(issue)
}))
};
}
/**
* Analyze Android components
*/
async analyzeAndroidComponents(screenshotData, deviceInfo) {
console.log('🧩 Analyzing Android components...');
const issues = [];
const components = {
detected: [],
materialCompliant: 0,
customComponents: 0,
issues: []
};
// Detect Material Design components
const detectedComponents = this.detectMaterialComponents(screenshotData);
components.detected = detectedComponents;
// Analyze component compliance
const componentIssues = this.analyzeComponentCompliance(detectedComponents);
issues.push(...componentIssues);
return {
components,
issues: issues.map(issue => ({
...issue,
category: 'components',
severity: this.calculateIssueSeverity(issue)
}))
};
}
// Implementation methods for specific analysis (simplified for demo)
analyzeSpacingCompliance(screenshotData) {
return [
{
type: 'spacing_inconsistent',
description: 'Inconsistent spacing detected between UI elements',
recommendation: 'Use 8dp baseline grid for consistent spacing',
location: { x: 100, y: 200, width: 300, height: 50 }
}
];
}
analyzeTypographyCompliance(screenshotData) {
return [
{
type: 'typography_size',
description: 'Text size below recommended minimum',
recommendation: 'Increase text size to at least 14sp for better readability',
location: { x: 50, y: 150, width: 200, height: 30 }
}
];
}
analyzeColorCompliance(screenshotData) {
return [
{
type: 'color_contrast',
description: 'Insufficient color contrast ratio (2.8:1, required 4.5:1)',
recommendation: 'Increase contrast between text and background colors',
location: { x: 0, y: 100, width: 400, height: 60 }
}
];
}
analyzeElevationCompliance(screenshotData) {
return [
{
type: 'elevation_excessive',
description: 'Card elevation exceeds Material Design recommendations',
recommendation: 'Reduce elevation to maximum 24dp',
location: { x: 20, y: 300, width: 360, height: 120 }
}
];
}
analyzeTouchTargets(screenshotData, deviceInfo) {
return [
{
type: 'touch_target_small',
description: 'Touch target smaller than 48dp minimum',
recommendation: 'Increase touch target size to at least 48dp',
location: { x: 350, y: 50, width: 32, height: 32 }
}
];
}
analyzeContentDescriptions(screenshotData) {
return [
{
type: 'missing_content_description',
description: 'Image button missing content description',
recommendation: 'Add contentDescription for screen reader accessibility',
location: { x: 300, y: 100, width: 48, height: 48 }
}
];
}
analyzeAndroidColorContrast(screenshotData) {
return [
{
type: 'android_contrast_low',
description: 'Text contrast below Android accessibility guidelines',
recommendation: 'Ensure minimum 4.5:1 contrast ratio for normal text',
location: { x: 0, y: 200, width: 400, height: 40 }
}
];
}
analyzeFocusOrder(screenshotData) {
return [
{
type: 'focus_order_illogical',
description: 'Focus order does not follow logical reading pattern',
recommendation: 'Ensure focus moves left-to-right, top-to-bottom',
location: { x: 0, y: 0, width: 400, height: 600 }
}
];
}
detectOverdraw(screenshotData) {
return [
{
type: 'overdraw_detected',
description: 'Potential overdraw detected in layout',
recommendation: 'Optimize layout hierarchy to reduce overdraw',
location: { x: 0, y: 0, width: 400, height: 600 }
}
];
}
analyzeLayoutComplexity(screenshotData) {
return [
{
type: 'layout_complex',
description: 'Layout hierarchy too deep (>10 levels)',
recommendation: 'Flatten layout hierarchy using ConstraintLayout',
location: { x: 0, y: 0, width: 400, height: 600 }
}
];
}
analyzeImageOptimization(screenshotData) {
return [
{
type: 'image_unoptimized',
description: 'Images appear unoptimized for mobile',
recommendation: 'Use WebP format and appropriate densities',
location: { x: 50, y: 250, width: 300, height: 200 }
}
];
}
detectNavigationPattern(screenshotData) {
// Simplified detection logic
return 'bottom_navigation';
}
analyzeNavigationAccessibility(screenshotData) {
return [
{
type: 'nav_accessibility',
description: 'Navigation items missing accessibility labels',
recommendation: 'Add proper labels for navigation items',
location: { x: 0, y: 550, width: 400, height: 50 }
}
];
}
analyzeNavigationConsistency(screenshotData) {
return [];
}
detectMaterialComponents(screenshotData) {
return [
{ type: 'FloatingActionButton', location: { x: 350, y: 500, width: 56, height: 56 } },
{ type: 'AppBar', location: { x: 0, y: 0, width: 400, height: 56 } },
{ type: 'Card', location: { x: 20, y: 100, width: 360, height: 120 } }
];
}
analyzeComponentCompliance(components) {
return components.map(component => ({
type: 'component_non_standard',
description: `${component.type} does not follow Material Design guidelines`,
recommendation: `Update ${component.type} to match Material Design specifications`,
location: component.location
}));
}
/**
* Generate Android-specific recommendations
*/
generateAndroidRecommendations(analysis) {
const recommendations = [];
// Material Design recommendations
if (analysis.materialDesignCompliance?.overallScore < 80) {
recommendations.push('Consider following Material Design guidelines more closely for better user experience');
}
// Accessibility recommendations
if (analysis.accessibility?.accessibilityScore < 85) {
recommendations.push('Improve accessibility by addressing touch target sizes and content descriptions');
}
// Performance recommendations
if (analysis.performance?.performanceScore < 80) {
recommendations.push('Optimize layout hierarchy and image resources for better performance');
}
return recommendations;
}
/**
* Calculate overall UI score
*/
calculateUIScore(analysis) {
const scores = [];
if (analysis.materialDesignCompliance?.overallScore) {
scores.push(analysis.materialDesignCompliance.overallScore);
}
if (analysis.accessibility?.accessibilityScore) {
scores.push(analysis.accessibility.accessibilityScore);
}
if (analysis.performance?.performanceScore) {
scores.push(analysis.performance.performanceScore);
}
return scores.length > 0 ? Math.round(scores.reduce((a, b) => a + b) / scores.length) : 0;
}
calculateComplianceScore(compliance) {
const scores = Object.values(compliance).map(item => item.score);
return Math.round(scores.reduce((a, b) => a + b) / scores.length);
}
calculateAccessibilityScore(accessibility) {
// Simplified scoring based on issues found
const totalIssues = Object.values(accessibility).reduce((sum, item) =>
sum + (item.issues ? item.issues.length : 0), 0
);
return Math.max(0, 100 - (totalIssues * 10));
}
calculatePerformanceScore(performance) {
// Simplified scoring
return 85;
}
calculateIssueSeverity(issue) {
const severityMap = {
'touch_target_small': 'high',
'color_contrast': 'high',
'missing_content_description': 'medium',
'spacing_inconsistent': 'low',
'typography_size': 'medium',
'overdraw_detected': 'medium',
'layout_complex': 'low'
};
return severityMap[issue.type] || 'medium';
}
}