Skip to content

Commit 4b5b490

Browse files
feat: implement core dashboard shell with navigation rail and updated overview screen layout
1 parent 2d38594 commit 4b5b490

13 files changed

Lines changed: 482 additions & 239 deletions

dashboard/lib/main.dart

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:flutter/material.dart';
22
import 'package:provider/provider.dart';
33
import 'package:sentracore_dashboard/providers/engine_provider.dart';
4+
import 'package:sentracore_dashboard/providers/settings_provider.dart';
45
import 'package:sentracore_dashboard/screens/dashboard_screen.dart';
56
import 'package:sentracore_dashboard/theme/app_theme.dart';
67

@@ -13,13 +14,22 @@ class SentraCoreApp extends StatelessWidget {
1314

1415
@override
1516
Widget build(BuildContext context) {
16-
return ChangeNotifierProvider(
17-
create: (_) => EngineProvider()..connect(),
18-
child: MaterialApp(
19-
title: 'SentraCore Dashboard',
20-
debugShowCheckedModeBanner: false,
21-
theme: AppTheme.darkTheme,
22-
home: const DashboardScreen(),
17+
return MultiProvider(
18+
providers: [
19+
ChangeNotifierProvider(create: (_) => EngineProvider()..connect()),
20+
ChangeNotifierProvider(create: (_) => SettingsProvider()),
21+
],
22+
child: Consumer<SettingsProvider>(
23+
builder: (context, settings, _) {
24+
return MaterialApp(
25+
title: 'SentraCore Intelligence',
26+
debugShowCheckedModeBanner: false,
27+
theme: AppTheme.lightTheme,
28+
darkTheme: AppTheme.darkTheme,
29+
themeMode: settings.themeMode,
30+
home: const DashboardScreen(),
31+
);
32+
},
2333
),
2434
);
2535
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import 'package:flutter/material.dart';
2+
3+
class SettingsProvider extends ChangeNotifier {
4+
ThemeMode _themeMode = ThemeMode.dark;
5+
ThemeMode get themeMode => _themeMode;
6+
7+
bool get isDarkMode => _themeMode == ThemeMode.dark;
8+
9+
void toggleTheme() {
10+
_themeMode =
11+
_themeMode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark;
12+
notifyListeners();
13+
}
14+
}

dashboard/lib/screens/dashboard_screen.dart

Lines changed: 83 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:sentracore_dashboard/screens/processes_screen.dart';
77
import 'package:sentracore_dashboard/screens/diagnostics_screen.dart';
88
import 'package:sentracore_dashboard/theme/app_theme.dart';
99
import 'package:sentracore_dashboard/widgets/connection_banner.dart';
10+
import 'package:sentracore_dashboard/providers/settings_provider.dart';
1011

1112
/// Root shell with persistent navigation rail and page switching.
1213
class DashboardScreen extends StatefulWidget {
@@ -45,10 +46,10 @@ class _DashboardScreenState extends State<DashboardScreen> {
4546
provider: provider,
4647
),
4748
// ── Vertical Divider ──
48-
const VerticalDivider(
49+
VerticalDivider(
4950
width: 1,
5051
thickness: 1,
51-
color: AppTheme.border,
52+
color: Theme.of(context).dividerColor,
5253
),
5354
// ── Page Content ──
5455
Expanded(child: _pages[_selectedIndex]),
@@ -82,77 +83,125 @@ class _SentraNavRail extends StatelessWidget {
8283

8384
return Container(
8485
width: 72,
85-
color: AppTheme.surface,
86+
decoration: BoxDecoration(
87+
color: Theme.of(context).colorScheme.surface,
88+
border: Border(
89+
right: BorderSide(
90+
color: Theme.of(context).dividerColor,
91+
width: 1,
92+
),
93+
),
94+
),
8695
child: Column(
8796
children: [
8897
const SizedBox(height: 12),
8998
// Logo / brand mark
9099
Container(
91-
width: 40,
92-
height: 40,
100+
width: 44,
101+
height: 44,
93102
decoration: BoxDecoration(
94-
color: AppTheme.primary.withValues(alpha: 0.15),
95-
borderRadius: BorderRadius.circular(10),
96-
border:
97-
Border.all(color: AppTheme.primary.withValues(alpha: 0.3)),
98-
image: const DecorationImage(
99-
image: AssetImage('assets/brandmark.jpeg'),
103+
gradient: LinearGradient(
104+
begin: Alignment.topLeft,
105+
end: Alignment.bottomRight,
106+
colors: [
107+
AppTheme.primary,
108+
AppTheme.primary.withValues(alpha: 0.6),
109+
],
110+
),
111+
borderRadius: BorderRadius.circular(12),
112+
boxShadow: [
113+
BoxShadow(
114+
color: AppTheme.primary.withValues(alpha: 0.3),
115+
blurRadius: 8,
116+
offset: const Offset(0, 4),
117+
),
118+
],
119+
),
120+
child: ClipRRect(
121+
borderRadius: BorderRadius.circular(12),
122+
child: Image.asset(
123+
'assets/brandmark.jpeg',
100124
fit: BoxFit.cover,
101125
),
102126
),
103127
),
104-
const SizedBox(height: 20),
128+
const SizedBox(height: 24),
105129
// Stability mini-score
106130
Container(
107-
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 4),
131+
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 6),
108132
decoration: BoxDecoration(
109133
color: stabilityColor.withValues(alpha: 0.1),
110-
borderRadius: BorderRadius.circular(8),
111-
border: Border.all(color: stabilityColor.withValues(alpha: 0.25)),
134+
borderRadius: BorderRadius.circular(12),
135+
border: Border.all(color: stabilityColor.withValues(alpha: 0.2)),
112136
),
113137
child: Column(
114138
children: [
115139
Text(
116140
stabilityScore,
117141
style: TextStyle(
118142
color: stabilityColor,
119-
fontSize: 14,
120-
fontWeight: FontWeight.w700,
143+
fontSize: 16,
144+
fontWeight: FontWeight.w800,
145+
fontFamily: 'Outfit',
121146
),
122147
),
123148
Text(
124-
'STA',
149+
'HEALTH',
125150
style: TextStyle(
126-
color: AppTheme.textMuted, fontSize: 8, letterSpacing: 1),
151+
color: stabilityColor.withValues(alpha: 0.7),
152+
fontSize: 8,
153+
fontWeight: FontWeight.w700,
154+
letterSpacing: 0.5,
155+
),
127156
),
128157
],
129158
),
130159
),
131-
const SizedBox(height: 16),
132-
const Divider(color: AppTheme.border, indent: 8, endIndent: 8),
160+
const SizedBox(height: 20),
161+
Padding(
162+
padding: const EdgeInsets.symmetric(horizontal: 12),
163+
child: Divider(color: Theme.of(context).dividerColor),
164+
),
165+
const SizedBox(height: 8),
133166
// Nav items
134-
_navItem(context, 0, Icons.dashboard_outlined, Icons.dashboard,
135-
'Overview'),
136-
_navItem(context, 1, Icons.show_chart_outlined, Icons.show_chart,
137-
'Performance'),
138-
_navItem(
139-
context, 2, Icons.memory_outlined, Icons.memory, 'Processes'),
140-
_navItem(context, 3, Icons.bug_report_outlined, Icons.bug_report,
141-
'Diagnostics'),
167+
_navItem(context, 0, Icons.grid_view_outlined,
168+
Icons.grid_view_rounded, 'Overview'),
169+
_navItem(context, 1, Icons.analytics_outlined,
170+
Icons.analytics_rounded, 'Performance'),
171+
_navItem(context, 2, Icons.layers_outlined, Icons.layers_rounded,
172+
'Processes'),
173+
_navItem(context, 3, Icons.troubleshoot_outlined,
174+
Icons.troubleshoot_rounded, 'Diagnostics'),
142175
const Spacer(),
176+
// Theme Toggle
177+
Consumer<SettingsProvider>(
178+
builder: (context, settings, _) => IconButton(
179+
onPressed: () => settings.toggleTheme(),
180+
icon: Icon(
181+
settings.isDarkMode
182+
? Icons.light_mode_outlined
183+
: Icons.dark_mode_outlined,
184+
color: Theme.of(context).iconTheme.color,
185+
size: 20,
186+
),
187+
),
188+
),
189+
const SizedBox(height: 8),
143190
// Connection status dot
144191
Container(
145192
width: 8,
146193
height: 8,
147-
margin: const EdgeInsets.only(bottom: 16),
194+
margin: const EdgeInsets.only(bottom: 20),
148195
decoration: BoxDecoration(
149-
color: provider.connected ? AppTheme.accent : AppTheme.error,
196+
color: provider.connected ? AppTheme.success : AppTheme.error,
150197
shape: BoxShape.circle,
151198
boxShadow: [
152199
BoxShadow(
153-
color: (provider.connected ? AppTheme.accent : AppTheme.error)
154-
.withValues(alpha: 0.5),
155-
blurRadius: 6,
200+
color:
201+
(provider.connected ? AppTheme.success : AppTheme.error)
202+
.withValues(alpha: 0.4),
203+
blurRadius: 8,
204+
spreadRadius: 1,
156205
)
157206
],
158207
),

dashboard/lib/screens/diagnostics_screen.dart

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,16 @@ class _DiagnosticsScreenState extends State<DiagnosticsScreen>
3939
// Header
4040
Container(
4141
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
42-
decoration: const BoxDecoration(
43-
color: AppTheme.surface,
44-
border: Border(bottom: BorderSide(color: AppTheme.border)),
42+
decoration: BoxDecoration(
43+
color: Theme.of(context).colorScheme.surface,
44+
border: Border(
45+
bottom: BorderSide(color: Theme.of(context).dividerColor)),
4546
),
4647
child: Row(children: [
4748
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
4849
Text('Diagnostics',
4950
style: TextStyle(
50-
color: AppTheme.textPrimary,
51+
color: Theme.of(context).textTheme.bodyLarge?.color,
5152
fontSize: 16,
5253
fontWeight: FontWeight.w600)),
5354
Text('Event log and alert history with root cause analysis',
@@ -271,8 +272,10 @@ class _EventRow extends StatelessWidget {
271272

272273
return Container(
273274
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
274-
decoration: const BoxDecoration(
275-
border: Border(bottom: BorderSide(color: AppTheme.border, width: 0.5)),
275+
decoration: BoxDecoration(
276+
border: Border(
277+
bottom:
278+
BorderSide(color: Theme.of(context).dividerColor, width: 0.5)),
276279
),
277280
child: Row(
278281
crossAxisAlignment: CrossAxisAlignment.start,
@@ -398,7 +401,7 @@ class _AlertSummaryCard extends StatelessWidget {
398401
fontSize: 14,
399402
fontWeight: FontWeight.w600)),
400403
]),
401-
const Divider(color: AppTheme.border, height: 20),
404+
Divider(color: Theme.of(context).dividerColor, height: 20),
402405
Row(
403406
mainAxisAlignment: MainAxisAlignment.spaceAround,
404407
children: [
@@ -471,7 +474,7 @@ class _RcaDetailCard extends StatelessWidget {
471474
fontWeight: FontWeight.w600)),
472475
),
473476
]),
474-
const Divider(color: AppTheme.border, height: 20),
477+
Divider(color: Theme.of(context).dividerColor, height: 20),
475478
// Alert message
476479
if (message.isNotEmpty) ...[
477480
Container(

0 commit comments

Comments
 (0)