diff --git a/Frontend/lib/mih_components/mih_package_components/mih_search_bar.dart b/Frontend/lib/mih_components/mih_package_components/mih_search_bar.dart index 0be979f2..ab47262f 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_search_bar.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_search_bar.dart @@ -124,6 +124,10 @@ class _MihSearchBarState extends State { child: TextField( controller: widget.controller, // Assign the controller focusNode: widget.searchFocusNode, + onSubmitted: (value) { + widget.onPrefixIconTap + ?.call(); // Call the prefix icon tap handler + }, style: TextStyle( color: widget.hintColor, fontWeight: FontWeight.w600, diff --git a/Frontend/lib/mih_objects/arguments.dart b/Frontend/lib/mih_objects/arguments.dart index 0f67f2c2..49cf9a18 100644 --- a/Frontend/lib/mih_objects/arguments.dart +++ b/Frontend/lib/mih_objects/arguments.dart @@ -207,3 +207,13 @@ class WalletArguments { this.index, ); } + +class MzansiAiArguments { + final AppUser signedInUser; + final String? startUpQuestion; + + MzansiAiArguments( + this.signedInUser, + this.startUpQuestion, + ); +} diff --git a/Frontend/lib/mih_packages/mih_home/mih_home_legacy.dart b/Frontend/lib/mih_packages/mih_home/mih_home_legacy.dart index 940aa5a4..1e3a417c 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_home_legacy.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_home_legacy.dart @@ -229,7 +229,10 @@ class _MIHHomeLegacyState extends State { onTap: () { Navigator.of(context).pushNamed( '/mzansi-ai', - arguments: widget.signedInUser, + arguments: MzansiAiArguments( + widget.signedInUser, + "", + ), ); }, tileName: "Mzansi AI", @@ -464,7 +467,10 @@ class _MIHHomeLegacyState extends State { onTap: () { Navigator.of(context).pushNamed( '/mzansi-ai', - arguments: widget.signedInUser, + arguments: MzansiAiArguments( + widget.signedInUser, + "", + ), ); }, tileName: "Mzansi AI", diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index 26cf0922..b91f9314 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -1,3 +1,4 @@ +import 'package:flutter/services.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; @@ -45,6 +46,7 @@ class _MihBusinessHomeState extends State late final AnimationController _marqueeController; late final ScrollController _scrollController; final FocusNode _searchFocusNode = FocusNode(); + final FocusNode _focusNode = FocusNode(); final String maintenanceMsg = "\tHeads up! We're doing maintenance on Thur, 15 May 2025 at 10 PM (CAT). MIH may be unavailable briefly."; @@ -202,52 +204,79 @@ class _MihBusinessHomeState extends State Widget getBody(double width, double height) { return MihSingleChildScroll( - child: Column( - children: [ - const SizedBox(height: 10), - Padding( - padding: EdgeInsets.symmetric(horizontal: width / 20), - child: MihSearchBar( - controller: searchController, - hintText: "Ask Mzansi", - prefixIcon: Icons.search, - prefixAltIcon: MihIcons.mzansiAi, - fillColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - onPrefixIconTap: () { - print("Search Text: ${searchController.text}"); - }, - searchFocusNode: _searchFocusNode, - ), - ), - const SizedBox(height: 10), - ValueListenableBuilder( - valueListenable: searchPackageName, - builder: (context, value, child) { - List filteredPackages = value - .where((package) => package.keys.first - .toLowerCase() - .contains(searchController.text.toLowerCase())) - .map((package) => package.values.first) - .toList(); - return GridView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: getPadding(width, height), - // shrinkWrap: true, - itemCount: filteredPackages.length, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: packageSize, - crossAxisSpacing: 5, - ), - itemBuilder: (context, index) { - return filteredPackages[index]; + child: KeyboardListener( + focusNode: _focusNode, + autofocus: true, + onKeyEvent: (event) async { + if (event is KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.enter) { + Navigator.of(context).pushNamed( + '/mzansi-ai', + arguments: MzansiAiArguments( + widget.signedInUser, + searchController.text.isEmpty ? null : searchController.text, + ), + ); + searchController.clear(); + } + }, + child: Column( + children: [ + const SizedBox(height: 10), + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: searchController, + hintText: "Ask Mzansi", + prefixIcon: Icons.search, + prefixAltIcon: MihIcons.mzansiAi, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + Navigator.of(context).pushNamed( + '/mzansi-ai', + arguments: MzansiAiArguments( + widget.signedInUser, + searchController.text.isEmpty + ? null + : searchController.text, + ), + ); + searchController.clear(); }, - ); - }, - ), - ], + searchFocusNode: _searchFocusNode, + ), + ), + const SizedBox(height: 10), + ValueListenableBuilder( + valueListenable: searchPackageName, + builder: (context, value, child) { + List filteredPackages = value + .where((package) => package.keys.first + .toLowerCase() + .contains(searchController.text.toLowerCase())) + .map((package) => package.values.first) + .toList(); + return GridView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: getPadding(width, height), + // shrinkWrap: true, + itemCount: filteredPackages.length, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: packageSize, + crossAxisSpacing: 5, + ), + itemBuilder: (context, index) { + return filteredPackages[index]; + }, + ); + }, + ), + ], + ), ), ); } diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index 8da7e898..86a9b2a6 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -1,3 +1,4 @@ +import 'package:flutter/services.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; @@ -53,6 +54,7 @@ class _MihPersonalHomeState extends State late final AnimationController _marqueeController; late final ScrollController _scrollController; final FocusNode _searchFocusNode = FocusNode(); + final FocusNode _focusNode = FocusNode(); final String maintenanceMsg = "\tHeads up! We're doing maintenance on Thur, 15 May 2025 at 10 PM (CAT). MIH may be unavailable briefly."; @@ -245,53 +247,80 @@ class _MihPersonalHomeState extends State Widget getBody(double width, double height) { return MihSingleChildScroll( - child: Column( - children: [ - const SizedBox(height: 10), - Padding( - padding: EdgeInsets.symmetric(horizontal: width / 20), - child: MihSearchBar( - controller: searchController, - hintText: "Ask Mzansi", - prefixIcon: Icons.search, - prefixAltIcon: MihIcons.mzansiAi, - fillColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - onPrefixIconTap: () { - print("Search Text: ${searchController.text}"); - }, - searchFocusNode: _searchFocusNode, - ), - ), - const SizedBox(height: 10), - ValueListenableBuilder( - valueListenable: searchPackageName, - builder: (context, value, child) { - List filteredPackages = value - .where((package) => package.keys.first - .toLowerCase() - .contains(searchController.text.toLowerCase())) - .map((package) => package.values.first) - .toList(); - return GridView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: getPadding(width, height), - // shrinkWrap: true, - itemCount: filteredPackages.length, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: packageSize, - crossAxisSpacing: 5, - ), - itemBuilder: (context, index) { - return filteredPackages[index]; - // return personalPackages[index]; + child: KeyboardListener( + focusNode: _focusNode, + autofocus: true, + onKeyEvent: (event) async { + if (event is KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.enter) { + Navigator.of(context).pushNamed( + '/mzansi-ai', + arguments: MzansiAiArguments( + widget.signedInUser, + searchController.text.isEmpty ? null : searchController.text, + ), + ); + searchController.clear(); + } + }, + child: Column( + children: [ + const SizedBox(height: 10), + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: searchController, + hintText: "Ask Mzansi", + prefixIcon: Icons.search, + prefixAltIcon: MihIcons.mzansiAi, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + Navigator.of(context).pushNamed( + '/mzansi-ai', + arguments: MzansiAiArguments( + widget.signedInUser, + searchController.text.isEmpty + ? null + : searchController.text, + ), + ); + searchController.clear(); }, - ); - }, - ), - ], + searchFocusNode: _searchFocusNode, + ), + ), + const SizedBox(height: 10), + ValueListenableBuilder( + valueListenable: searchPackageName, + builder: (context, value, child) { + List filteredPackages = value + .where((package) => package.keys.first + .toLowerCase() + .contains(searchController.text.toLowerCase())) + .map((package) => package.values.first) + .toList(); + return GridView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: getPadding(width, height), + // shrinkWrap: true, + itemCount: filteredPackages.length, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: packageSize, + crossAxisSpacing: 5, + ), + itemBuilder: (context, index) { + return filteredPackages[index]; + // return personalPackages[index]; + }, + ); + }, + ), + ], + ), ), ); } diff --git a/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart b/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart index a3b080cf..66778d83 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart @@ -1,15 +1,19 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_ai/package_tools/ai_chat.dart'; import 'package:flutter/material.dart'; class MzansiAi extends StatefulWidget { - final AppUser signedInUser; + // final AppUser signedInUser; + // final String? startUpQuestion; + final MzansiAiArguments arguments; const MzansiAi({ super.key, - required this.signedInUser, + required this.arguments, + // required this.signedInUser, + // this.startUpQuestion, }); @override @@ -46,7 +50,10 @@ class _MzansiAiState extends State { List getToolBody() { List toolBodies = [ - AiChat(signedInUser: widget.signedInUser), + AiChat( + signedInUser: widget.arguments.signedInUser, + startUpQuestion: widget.arguments.startUpQuestion, + ), ]; return toolBodies; } diff --git a/Frontend/lib/mih_packages/mzansi_ai/package_tiles/mzansi_ai_tile.dart b/Frontend/lib/mih_packages/mzansi_ai/package_tiles/mzansi_ai_tile.dart index 3bdba607..e45ba497 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/package_tiles/mzansi_ai_tile.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/package_tiles/mzansi_ai_tile.dart @@ -3,6 +3,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; class MzansiAiTile extends StatefulWidget { final AppUser signedInUser; @@ -25,7 +26,10 @@ class _MzansiAiTileState extends State { onTap: () { Navigator.of(context).pushNamed( '/mzansi-ai', - arguments: widget.signedInUser, + arguments: MzansiAiArguments( + widget.signedInUser, + "", + ), ); }, appName: "Mzansi AI", diff --git a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart index bb4b0cfc..96f7c2fe 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart @@ -21,9 +21,11 @@ import 'package:uuid/uuid.dart'; class AiChat extends StatefulWidget { final AppUser signedInUser; + final String? startUpQuestion; const AiChat({ super.key, required this.signedInUser, + this.startUpQuestion, }); @override @@ -593,6 +595,12 @@ class _AiChatState extends State { _loadMessages(); initTTS(); _ttsVoiceController.addListener(voiceSelected); + if (widget.startUpQuestion != null && widget.startUpQuestion!.isNotEmpty) { + final partialText = types.PartialText(text: widget.startUpQuestion!); + WidgetsBinding.instance.addPostFrameCallback((_) { + _handleSendPressed(partialText); + }); + } } @override diff --git a/Frontend/lib/mih_router/routeGenerator.dart b/Frontend/lib/mih_router/routeGenerator.dart index b95680d6..fb40437a 100644 --- a/Frontend/lib/mih_router/routeGenerator.dart +++ b/Frontend/lib/mih_router/routeGenerator.dart @@ -331,11 +331,11 @@ class RouteGenerator { //Mzansi AI case '/mzansi-ai': - if (args is AppUser) { + if (args is MzansiAiArguments) { return MaterialPageRoute( settings: settings, builder: (_) => MzansiAi( - signedInUser: args, + arguments: args, ), ); }