diff --git a/firebase_ai_logic_showcase/lib/demos/live_api/live_api_demo.dart b/firebase_ai_logic_showcase/lib/demos/live_api/live_api_demo.dart index 2d80d41..3a27738 100644 --- a/firebase_ai_logic_showcase/lib/demos/live_api/live_api_demo.dart +++ b/firebase_ai_logic_showcase/lib/demos/live_api/live_api_demo.dart @@ -23,8 +23,7 @@ import 'utilities/utilities.dart'; import 'firebaseai_live_api_service.dart'; class LiveAPIDemo extends ConsumerStatefulWidget { - const LiveAPIDemo({super.key, this.isSelected = false}); - final bool isSelected; + const LiveAPIDemo({super.key}); @override ConsumerState createState() => _LiveAPIDemoState(); @@ -45,9 +44,7 @@ class _LiveAPIDemoState extends ConsumerState { late final VideoInput _videoInput = VideoInput(); // Initialization flags. - bool _audioIsInitialized = false; bool _videoIsInitialized = false; - static bool _hasBeenSelected = false; // UI State flags. bool _isConnecting = false; // True when setting up the Gemini session. @@ -66,24 +63,19 @@ class _LiveAPIDemoState extends ConsumerState { @override void didUpdateWidget(LiveAPIDemo oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.isSelected != oldWidget.isSelected) { - _checkAndInitializeIO(); - } + _checkAndInitializeIO(); } Future _checkAndInitializeIO() async { - if (widget.isSelected && !_hasBeenSelected) { - _hasBeenSelected = true; - await _initializeAudio(); - await _initializeVideo(); - _liveApiService = LiveApiService( - audioOutput: _audioOutput, - ref: ref, // Pass the ref to the service - onImageLoadingChange: _onImageLoadingChange, - onImageGenerated: _onImageGenerated, - onError: _showErrorSnackBar, - ); - } + await _initializeAudio(); + await _initializeVideo(); + _liveApiService = LiveApiService( + audioOutput: _audioOutput, + ref: ref, // Pass the ref to the service + onImageLoadingChange: _onImageLoadingChange, + onImageGenerated: _onImageGenerated, + onError: _showErrorSnackBar, + ); } @override diff --git a/firebase_ai_logic_showcase/lib/flutter_firebase_ai_demo.dart b/firebase_ai_logic_showcase/lib/flutter_firebase_ai_demo.dart index 29c4bc6..b14aa79 100644 --- a/firebase_ai_logic_showcase/lib/flutter_firebase_ai_demo.dart +++ b/firebase_ai_logic_showcase/lib/flutter_firebase_ai_demo.dart @@ -27,6 +27,27 @@ class DemoHomeScreen extends StatefulWidget { class _DemoHomeScreenState extends State { int _selectedIndex = 0; + final List<({Widget icon, String label, Widget? selectedIcon})> destinations = + [ + (icon: const Icon(Icons.chat), label: 'Chat', selectedIcon: null), + ( + icon: const Icon(Icons.video_chat), + label: 'Live API', + selectedIcon: null, + ), + ( + icon: const Icon(Icons.photo_library), + label: 'Multimodal', + selectedIcon: null, + ), + ( + icon: RichText( + text: const TextSpan(style: TextStyle(fontSize: 24.0), text: '🍌'), + ), + label: 'Nano Banana', + selectedIcon: null, + ), + ]; void _onItemTapped(int index) { setState(() { @@ -36,35 +57,12 @@ class _DemoHomeScreenState extends State { @override Widget build(BuildContext context) { - final List demoPages = [ - const ChatDemo(), - LiveAPIDemo(isSelected: _selectedIndex == 1), - const MultimodalDemo(), - ChatDemoNano(isSelected: _selectedIndex == 3), - ]; - - final List<({Widget icon, String label, Widget? selectedIcon})> destinations = [ - (icon: const Icon(Icons.chat), label: 'Chat', selectedIcon: null), - (icon: const Icon(Icons.video_chat), label: 'Live API', selectedIcon: null), - (icon: const Icon(Icons.photo_library), label: 'Multimodal', selectedIcon: null), - ( - icon: RichText( - text: const TextSpan( - style: TextStyle(fontSize: 24.0), - text: '🍌', - ), - ), - label: 'Nano Banana', - selectedIcon: null - ), - ]; - return LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth < 600) { // Use BottomNavigationBar for smaller screens return Scaffold( - body: IndexedStack(index: _selectedIndex, children: demoPages), + body: demoPages[_selectedIndex], bottomNavigationBar: BottomNavigationBar( type: BottomNavigationBarType.fixed, items: destinations @@ -94,20 +92,17 @@ class _DemoHomeScreenState extends State { (e) => NavigationRailDestination( padding: const EdgeInsets.symmetric(vertical: 8.0), icon: e.icon, - label: Text(e.label.replaceAll(' ', '\n'), - textAlign: TextAlign.center), + label: Text( + e.label.replaceAll(' ', '\n'), + textAlign: TextAlign.center, + ), selectedIcon: e.selectedIcon, ), ) .toList(), ), const VerticalDivider(thickness: 1, width: 1), - Expanded( - child: IndexedStack( - index: _selectedIndex, - children: demoPages, - ), - ), + Expanded(child: demoPages[_selectedIndex]), ], ), ); @@ -116,3 +111,10 @@ class _DemoHomeScreenState extends State { ); } } + +final List demoPages = [ + const ChatDemo(), + LiveAPIDemo(), + const MultimodalDemo(), + ChatDemoNano(), +];