Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions lib/providers/navigation/models/home_tab.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// Primary destinations for [HomeScreen] bottom navigation.
enum HomeTab {
dashboard,
calendar,
workspace,
chat,
profile;

static HomeTab fromIndex(int index) {
if (index < 0 || index >= HomeTab.values.length) {
return HomeTab.dashboard;
}
return HomeTab.values[index];
}
}
12 changes: 6 additions & 6 deletions lib/providers/navigation_provider.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';

/// Bottom navigation index for the home shell ([HomeScreen]).
///
/// 0: Dashboard, 1: Calendar, 2: Workspace, 3: Chat, 4: Profile.
///
/// Not wired to [HomeScreen] yet — foundation for future migration.
final homeTabIndexProvider = StateProvider<int>((ref) => 0);
import 'navigation/models/home_tab.dart';

/// Selected tab for [HomeScreen] bottom navigation.
final homeTabProvider = StateProvider<HomeTab>(
(ref) => HomeTab.dashboard,
);
191 changes: 43 additions & 148 deletions lib/screens/home/home_screen.dart
Original file line number Diff line number Diff line change
@@ -1,73 +1,32 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../widgets/custom_widgets.dart';
import '../../services/navigation_service.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../providers/navigation/models/home_tab.dart';
import '../../providers/navigation_provider.dart';
import '../workspace/workspace_screen.dart';
import '../calendar/calendar_screen.dart';
import '../profile/profile_screen.dart';
import '../chat/chat_screen.dart';
import 'dashboard_screen.dart';

class HomeScreen extends StatefulWidget {
class HomeScreen extends ConsumerStatefulWidget {
final Map<String, dynamic>? arguments;

const HomeScreen({super.key, this.arguments});

@override
State<HomeScreen> createState() => _HomeScreenState();
ConsumerState<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen>
with SingleTickerProviderStateMixin {
final TextEditingController _messageController = TextEditingController();
final ScrollController _scrollController = ScrollController();
final List<ChatMessage> _messages = [];
bool _isListening = false;
int _selectedIndex = 0;
bool _isFabExpanded = false;
late AnimationController _fabController;
late Animation<double> _fabAnimation;

class _HomeScreenState extends ConsumerState<HomeScreen> {
List<Widget> _screens = [];

@override
void initState() {
super.initState();
_fabController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_fabAnimation = CurvedAnimation(
parent: _fabController,
curve: Curves.easeOut,
reverseCurve: Curves.easeIn,
);

// Initialize screens
_initializeScreens();

// Handle initial arguments if provided
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.arguments != null) {
if (widget.arguments!.containsKey('screen') &&
widget.arguments!['screen'] is int) {
setState(() {
_selectedIndex = widget.arguments!['screen'];
});
}

// Handle initial message for chat screen
if (widget.arguments!.containsKey('initial_message') &&
widget.arguments!['initial_message'] is String &&
_selectedIndex == 3) {
// Update the chat screen with the initial message
setState(() {
_screens[3] = ChatScreen(arguments: {
'initial_message': widget.arguments!['initial_message']
});
});
}
}
_applyRouteArguments();
});
}

Expand All @@ -81,70 +40,43 @@ class _HomeScreenState extends State<HomeScreen>
];
}

@override
void dispose() {
_messageController.dispose();
_scrollController.dispose();
_fabController.dispose();
super.dispose();
void _applyRouteArguments() {
final args = widget.arguments;
if (args == null) return;

if (args.containsKey('screen') && args['screen'] is int) {
ref.read(homeTabProvider.notifier).state =
HomeTab.fromIndex(args['screen'] as int);
}

if (args.containsKey('initial_message') &&
args['initial_message'] is String &&
ref.read(homeTabProvider) == HomeTab.chat) {
setState(() {
_screens[HomeTab.chat.index] = ChatScreen(arguments: {
'initial_message': args['initial_message'],
});
});
}
}

void _sendMessage() {
if (_messageController.text.trim().isEmpty) return;

setState(() {
_messages.add(
ChatMessage(
text: _messageController.text,
isUser: true,
timestamp: DateTime.now(),
),
);
_messageController.clear();
});

_scrollToBottom();
// TODO: Implement AI response
}

void _scrollToBottom() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
});
}

void _toggleListening() {
setState(() {
_isListening = !_isListening;
});
// TODO: Implement voice recognition
}

void _toggleFab() {
setState(() {
_isFabExpanded = !_isFabExpanded;
if (_isFabExpanded) {
_fabController.forward();
} else {
_fabController.reverse();
}
});
void _selectTab(int index) {
ref.read(homeTabProvider.notifier).state = HomeTab.fromIndex(index);
}

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final selectedTab = ref.watch(homeTabProvider);

return Scaffold(
body: IndexedStack(index: _selectedIndex, children: _screens),
body: IndexedStack(
index: selectedTab.index,
children: _screens,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
currentIndex: selectedTab.index,
onTap: _selectTab,
type: BottomNavigationBarType.fixed,
selectedItemColor: theme.colorScheme.primary,
unselectedItemColor: theme.colorScheme.onSurfaceVariant,
Expand All @@ -157,57 +89,20 @@ class _HomeScreenState extends State<HomeScreen>
icon: Icon(Icons.calendar_today),
label: 'Calendar',
),
BottomNavigationBarItem(icon: Icon(Icons.work), label: 'Workspace'),
BottomNavigationBarItem(
icon: Icon(Icons.work),
label: 'Workspace',
),
BottomNavigationBarItem(
icon: Icon(Icons.chat_bubble_outline),
label: 'Chat',
),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
),
);
}
}

class _ChatBubble extends StatelessWidget {
final ChatMessage message;

const _ChatBubble({required this.message});

@override
Widget build(BuildContext context) {
return Align(
alignment: message.isUser ? Alignment.centerRight : Alignment.centerLeft,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 4),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: message.isUser
? Colors.green.shade400
: Theme.of(context).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(20),
),
child: Text(
message.text,
style: TextStyle(
color: message.isUser
? Colors.white
: Theme.of(context).colorScheme.onSurface,
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
),
),
],
),
);
}
}

class ChatMessage {
final String text;
final bool isUser;
final DateTime timestamp;

ChatMessage({
required this.text,
required this.isUser,
required this.timestamp,
});
}