Console/lib/console_landing_page.dart
jean-philippe 13c963575d Comprehensive codebase audit and cleanup
- Fixed broken test suite: replaced counter widget tests with Console UI tests
- Removed dead code: deleted unused MyHomePage widget and svrnty_components.dart library
- Updated project branding: renamed package from "my_app" to "console"
- Enhanced documentation: rewrote README with project features and setup instructions
- Added coding standards: strict typing rules forbidding 'any' type across all languages
- Implemented response protocol: structured answer format with context persistence
- Fixed backend button: corrected URL from https to http, added proper error handling
- Improved .gitignore: added Flutter plugins, CocoaPods, and design folder exclusions
- Fixed UI overflow: increased status card height to prevent RenderFlex overflow

These changes eliminate technical debt, establish code quality standards, and ensure all functionality works correctly across platforms.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-26 09:17:24 -04:00

585 lines
18 KiB
Dart

import 'package:flutter/material.dart';
import 'package:iconsax/iconsax.dart';
import 'package:animate_do/animate_do.dart';
import 'package:getwidget/getwidget.dart';
import 'package:url_launcher/url_launcher.dart';
import 'components/navigation_sidebar.dart';
import 'pages/architech_page.dart';
class ConsoleLandingPage extends StatefulWidget {
const ConsoleLandingPage({Key? key}) : super(key: key);
@override
State<ConsoleLandingPage> createState() => _ConsoleLandingPageState();
}
class _ConsoleLandingPageState extends State<ConsoleLandingPage> {
bool _isSidebarExpanded = true;
String _currentPage = 'dashboard';
void _toggleSidebar() {
setState(() {
_isSidebarExpanded = !_isSidebarExpanded;
});
}
void _navigateToPage(String pageId) {
setState(() {
_currentPage = pageId;
});
}
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Scaffold(
backgroundColor: colorScheme.surface,
body: Row(
children: [
// Navigation Sidebar
NavigationSidebar(
isExpanded: _isSidebarExpanded,
onNavigate: _navigateToPage,
currentPage: _currentPage,
),
// Main Content Area
Expanded(
child: Column(
children: [
// AppBar
_buildAppBar(colorScheme),
// Main Content
Expanded(
child: _buildMainContent(colorScheme),
),
],
),
),
],
),
);
}
Widget _buildAppBar(ColorScheme colorScheme) {
return Container(
height: 70,
decoration: BoxDecoration(
color: colorScheme.surfaceContainerLow,
border: Border(
bottom: BorderSide(
color: colorScheme.outline.withOpacity(0.2),
width: 1,
),
),
),
child: Row(
children: [
// Toggle Sidebar Button
IconButton(
icon: Icon(
_isSidebarExpanded ? Iconsax.arrow_left_2 : Iconsax.arrow_right_3,
color: colorScheme.onSurface,
),
onPressed: _toggleSidebar,
tooltip: _isSidebarExpanded ? 'Collapse sidebar' : 'Expand sidebar',
),
const SizedBox(width: 12),
// Page Title
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_getPageTitle(),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
),
),
Text(
'sovereign AI solutions',
style: TextStyle(
fontSize: 11,
color: colorScheme.onSurfaceVariant,
),
),
],
),
),
// Action Buttons
Container(
margin: const EdgeInsets.only(right: 8),
child: IconButton(
icon: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: colorScheme.primary.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(Iconsax.notification, color: colorScheme.primary),
),
onPressed: () {},
),
),
Container(
margin: const EdgeInsets.only(right: 12),
child: IconButton(
icon: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: colorScheme.secondary.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(Iconsax.setting_2, color: colorScheme.secondary),
),
onPressed: () {},
),
),
],
),
);
}
String _getPageTitle() {
switch (_currentPage) {
case 'dashboard':
return 'Dashboard';
case 'architech':
return 'The Architech';
case 'agents':
return 'AI Agents';
case 'analytics':
return 'Analytics';
case 'tools':
return 'Tools';
case 'settings':
return 'Settings';
default:
return 'Svrnty Console';
}
}
Widget _buildMainContent(ColorScheme colorScheme) {
// Switch between different pages
switch (_currentPage) {
case 'architech':
return const ArchitechPage();
case 'dashboard':
default:
return _buildDashboardContent(colorScheme);
}
}
Widget _buildDashboardContent(ColorScheme colorScheme) {
return LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
padding: EdgeInsets.all(_getPagePadding(constraints.maxWidth)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Status Cards Grid
_buildResponsiveGrid(
constraints.maxWidth,
[
_buildStatusCard(
'Backend',
'Access Swagger',
colorScheme.primary,
Icons.api,
'Active',
url: 'http://localhost:7108/swagger/',
),
_buildStatusCard(
'Frontend',
'UI Status',
colorScheme.primary,
Icons.web,
'Online',
),
_buildStatusCard(
'To-Do',
'Analytics Dashboard',
colorScheme.primary,
Icons.analytics_outlined,
'Running',
),
_buildStatusCard(
'Pull requests',
'Connection Pool',
colorScheme.secondary,
Icons.storage_outlined,
'Connected',
),
_buildStatusCard(
'Work Logs',
'View Recent Activity',
colorScheme.secondary,
Icons.receipt_long_outlined,
'Active',
),
_buildStatusCard(
'Mindbox',
'Metrics & Monitoring',
colorScheme.secondary,
Icons.speed_outlined,
'Normal',
),
],
),
const SizedBox(height: 32),
// Recent Activity Section
_buildSectionHeader('Recent Activity'),
const SizedBox(height: 16),
_buildActivityCard(
'PR request',
'Authentification_module.config is updated',
'2 minutes ago',
Icons.check_circle_outline,
colorScheme.primary,
),
const SizedBox(height: 12),
_buildActivityCard(
'Database Sync',
'Completed backup operation',
'3 hours 11 minutes ago',
Icons.cloud_done_outlined,
colorScheme.secondary,
),
const SizedBox(height: 12),
_buildActivityCard(
'The Archivist agent created',
'Modele configured and operational',
'3 days ago',
Icons.security_outlined,
colorScheme.secondary,
),
],
),
);
},
);
}
// Helper method: Get responsive padding based on screen width
double _getPagePadding(double width) {
if (width < 600) {
return 16.0; // Mobile
} else if (width < 1024) {
return 24.0; // Tablet
} else {
return 32.0; // Desktop
}
}
// Helper method: Build responsive grid
Widget _buildResponsiveGrid(double width, List<Widget> children) {
int crossAxisCount;
double spacing;
if (width < 600) {
// Mobile: 1 column
crossAxisCount = 1;
spacing = 12.0;
} else if (width < 900) {
// Tablet: 2 columns
crossAxisCount = 2;
spacing = 16.0;
} else if (width < 1200) {
// Small desktop: 3 columns
crossAxisCount = 3;
spacing = 20.0;
} else {
// Large desktop: 3 columns with more space
crossAxisCount = 3;
spacing = 24.0;
}
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
mainAxisExtent: 155,
crossAxisSpacing: spacing,
mainAxisSpacing: spacing,
),
itemCount: children.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => children[index],
);
}
// Helper method: Build GetWidget-powered status card
Widget _buildStatusCard(
String title,
String subtitle,
Color color,
IconData icon,
String status, {
String? url,
}) {
final colorScheme = Theme.of(context).colorScheme;
return FadeInUp(
duration: const Duration(milliseconds: 400),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
color.withOpacity(0.25),
color.withOpacity(0.12),
],
),
border: Border.all(
color: color.withOpacity(0.5),
width: 1.5,
),
),
child: Card(
elevation: 4,
color: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: InkWell(
onTap: () async {
if (url != null) {
try {
final uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
if (context.mounted) {
GFToast.showToast(
'Opening $title...',
context,
toastPosition: GFToastPosition.BOTTOM,
textStyle: const TextStyle(fontSize: 14, color: Colors.white),
backgroundColor: color.withOpacity(0.9),
toastDuration: 2,
);
}
} else {
if (context.mounted) {
GFToast.showToast(
'Cannot open $url',
context,
toastPosition: GFToastPosition.BOTTOM,
textStyle: const TextStyle(fontSize: 14, color: Colors.white),
backgroundColor: colorScheme.error.withOpacity(0.9),
toastDuration: 3,
);
}
}
} catch (e) {
if (context.mounted) {
GFToast.showToast(
'Error: ${e.toString()}',
context,
toastPosition: GFToastPosition.BOTTOM,
textStyle: const TextStyle(fontSize: 14, color: Colors.white),
backgroundColor: colorScheme.error.withOpacity(0.9),
toastDuration: 3,
);
}
}
} else {
GFToast.showToast(
'$title tapped',
context,
toastPosition: GFToastPosition.BOTTOM,
textStyle: const TextStyle(fontSize: 14, color: Colors.white),
backgroundColor: color.withOpacity(0.9),
toastDuration: 2,
);
}
},
borderRadius: BorderRadius.circular(16),
child: Container(
decoration: BoxDecoration(
border: Border(
left: BorderSide(
color: color,
width: 4,
),
),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GFAvatar(
backgroundColor: color.withOpacity(0.3),
child: Icon(icon, size: 24, color: color),
radius: 22,
shape: GFAvatarShape.standard,
),
Container(
constraints: const BoxConstraints(minWidth: 90),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(20),
),
child: Center(
child: Text(
status,
style: const TextStyle(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold,
letterSpacing: 0.5,
),
),
),
),
],
),
const SizedBox(height: 12),
Text(
title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
letterSpacing: 0.3,
),
),
const SizedBox(height: 4),
Text(
subtitle,
style: TextStyle(
fontSize: 13,
color: colorScheme.onSurfaceVariant,
),
),
],
),
),
),
),
),
),
);
}
// Helper method: Build section header
Widget _buildSectionHeader(String title) {
final colorScheme = Theme.of(context).colorScheme;
return Row(
children: [
Container(
width: 4,
height: 24,
decoration: BoxDecoration(
color: colorScheme.primary,
borderRadius: BorderRadius.circular(2),
),
),
const SizedBox(width: 12),
Text(
title,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
),
),
],
);
}
// Helper method: Build GetWidget-powered activity card
Widget _buildActivityCard(
String title,
String description,
String time,
IconData icon,
Color color,
) {
final colorScheme = Theme.of(context).colorScheme;
return FadeInLeft(
duration: const Duration(milliseconds: 400),
child: Container(
margin: const EdgeInsets.only(bottom: 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: color.withOpacity(0.4),
width: 1.5,
),
),
child: Card(
elevation: 2,
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
leading: GFAvatar(
backgroundColor: color.withOpacity(0.25),
child: Icon(icon, color: color, size: 22),
radius: 22,
shape: GFAvatarShape.circle,
),
title: Text(
title,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: colorScheme.onSurface,
letterSpacing: 0.2,
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
description,
style: TextStyle(
fontSize: 13,
color: colorScheme.onSurfaceVariant,
),
),
),
Container(
margin: const EdgeInsets.only(top: 8),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(8),
),
child: Text(
time,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w500,
color: colorScheme.onSurfaceVariant,
),
),
),
],
),
),
),
),
);
}
}