Skip to content

Commit 69746d0

Browse files
authored
Make Nano banana default chat demo (#47)
2 parents 0fd1bdd + 968c783 commit 69746d0

File tree

4 files changed

+95
-36
lines changed

4 files changed

+95
-36
lines changed

firebase_ai_logic_showcase/lib/demos/chat/chat_demo.dart

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,18 @@ class _ChatDemoState extends ConsumerState<ChatDemo> {
4545
Uint8List? _attachment;
4646
final ScrollController _scrollController = ScrollController();
4747
bool _loading = false;
48+
OverlayPortalController opController = OverlayPortalController();
4849

4950
@override
5051
void initState() {
5152
super.initState();
5253
_chatService = ChatService(ref);
5354
_chatService.init();
5455
_userTextInputController.text = geminiModels.selectedModel.defaultPrompt;
56+
57+
WidgetsBinding.instance.addPostFrameCallback((_) {
58+
opController.show();
59+
});
5560
}
5661

5762
@override
@@ -158,6 +163,7 @@ class _ChatDemoState extends ConsumerState<ChatDemo> {
158163
}
159164

160165
void showModelPicker() {
166+
opController.hide();
161167
showDialog(
162168
context: context,
163169
builder: (context) {
@@ -183,9 +189,30 @@ class _ChatDemoState extends ConsumerState<ChatDemo> {
183189
backgroundColor: Colors.transparent,
184190
title: const Text('Chat Demo'),
185191
actions: [
186-
IconButton(
187-
onPressed: showModelPicker,
188-
icon: Icon(Icons.settings_outlined),
192+
OverlayPortal(
193+
controller: opController,
194+
child: IconButton(
195+
onPressed: showModelPicker,
196+
icon: Icon(Icons.settings_outlined),
197+
),
198+
overlayChildBuilder: (context) {
199+
return Positioned(
200+
right: 0,
201+
top: 40,
202+
child: Dialog(
203+
insetAnimationDuration: Duration(milliseconds: 2000),
204+
constraints: BoxConstraints(maxWidth: 500),
205+
insetPadding: EdgeInsets.all(8),
206+
child: Padding(
207+
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
208+
child: Row(
209+
mainAxisSize: MainAxisSize.min,
210+
children: [Text('Try another model!')],
211+
),
212+
),
213+
),
214+
);
215+
},
189216
),
190217
],
191218
),

firebase_ai_logic_showcase/lib/demos/chat/models/gemini_model.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class GeminiModel {
1818
}
1919

2020
class GeminiModels {
21-
String selectedModelName = 'gemini-2.5-flash';
21+
String selectedModelName = 'gemini-2.5-flash-image-preview';
2222
GeminiModel get selectedModel => models[selectedModelName]!;
2323

2424
/// A map of Gemini models that can be used in the Chat Demo.
@@ -52,7 +52,8 @@ class GeminiModels {
5252
),
5353
),
5454
defaultPrompt:
55-
'Hey Gemini! Can you create an image of Dash, the Flutter mascot, surfing in Waikiki Hawaii?',
55+
'Hot air balloons rising over the San Francisco Bay at golden hour '
56+
'with a view of the Golden Gate Bridge. Make it anime style.',
5657
),
5758
};
5859

firebase_ai_logic_showcase/lib/flutter_firebase_ai_demo.dart

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,17 @@ List<Demo> demos = [
4545
),
4646
Demo(
4747
name: 'Multimodal Prompt',
48-
description: 'Ask a Gemini model about an image, audio, video, or PDF file.',
48+
description:
49+
'Ask a Gemini model about an image, audio, video, or PDF file.',
4950
icon: Icon(size: 32, Icons.attach_file),
5051
page: MultimodalDemo(),
5152
),
5253
Demo(
53-
name: 'Chat with Gemini * ',
54+
name: 'Create & Edit Images with Nano Banana *',
5455
description:
5556
'Chat with a Gemini model, including a chat history, tool calling, and even image generation.',
56-
icon: Icon(size: 32, Icons.chat),
57-
page: ChatDemo(),
58-
),
59-
Demo(
60-
name: 'Generate Images with Nano Banana *',
61-
description: 'Generate an image using a text prompt.',
6257
icon: Text(style: TextStyle(fontSize: 28), '🍌'),
63-
page: ImageGenerationDemo(),
58+
page: ChatDemo(),
6459
),
6560
];
6661

@@ -83,30 +78,60 @@ class DemoHomeScreen extends StatelessWidget {
8378
),
8479
],
8580
),
86-
body: Column(
87-
crossAxisAlignment: CrossAxisAlignment.center,
88-
mainAxisAlignment: MainAxisAlignment.center,
89-
children: [
90-
Row(
81+
body: Center(
82+
child: ConstrainedBox(
83+
constraints: BoxConstraints(maxWidth: 400),
84+
child: Column(
85+
crossAxisAlignment: CrossAxisAlignment.center,
9186
mainAxisAlignment: MainAxisAlignment.center,
9287
children: [
93-
Text(textAlign: TextAlign.center, 'Please let us know!'),
88+
RichText(
89+
textAlign: TextAlign.center,
90+
text: TextSpan(
91+
style: Theme.of(context).textTheme.bodyMedium,
92+
text:
93+
'Have features you want to see in the app? Please file an issue for us at: ',
94+
children: [
95+
WidgetSpan(
96+
baseline: TextBaseline.ideographic,
97+
alignment: PlaceholderAlignment.top,
98+
child: Link(
99+
uri: Uri.parse(
100+
'https://github.com/flutter/demos/issues',
101+
),
102+
target: LinkTarget.blank,
103+
builder: (context, followLink) => GestureDetector(
104+
onTap: followLink,
105+
child: Text(
106+
style: Theme.of(context).textTheme.bodyMedium!
107+
.copyWith(
108+
fontWeight: FontWeight.bold,
109+
height: 1.15,
110+
decoration: TextDecoration.underline,
111+
color: Theme.of(
112+
context,
113+
).colorScheme.primary,
114+
),
115+
'github.com/flutter/demos/issues',
116+
),
117+
),
118+
),
119+
),
120+
TextSpan(text: '.'),
121+
],
122+
),
123+
),
124+
SizedBox.square(dimension: 32),
125+
Text(
126+
style: TextStyle(
127+
color: Theme.of(context).colorScheme.onSurfaceVariant,
128+
),
129+
textAlign: TextAlign.center,
130+
'This app was made with ❤️\nby the Flutter & Firebase AI Logic Teams',
131+
),
94132
],
95133
),
96-
SelectableText(
97-
textAlign: TextAlign.center,
98-
style: TextStyle(fontWeight: FontWeight.bold),
99-
'github.com/firebase/flutterfire/issues',
100-
),
101-
SizedBox.square(dimension: 32),
102-
Text(
103-
style: TextStyle(
104-
color: Theme.of(context).colorScheme.onSurfaceVariant,
105-
),
106-
textAlign: TextAlign.center,
107-
'Made with ❤️\nby the Flutter & Firebase AI Logic Teams',
108-
),
109-
],
134+
),
110135
),
111136
),
112137
),

firebase_ai_logic_showcase/lib/shared/ui/blaze_warning.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ class BlazeWarning extends StatelessWidget {
1111
child: Padding(
1212
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
1313
child: RichText(
14+
textAlign: TextAlign.center,
1415
text: TextSpan(
1516
style: Theme.of(context).textTheme.bodyMedium,
16-
text: 'This demo includes some features that require an upgrade to the pay-as-you-go Blaze pricing plan, which you can ',
17+
text:
18+
'This demo includes some features that require an upgrade to the pay-as-you-go Blaze pricing plan, which you can ',
1719
children: [
1820
WidgetSpan(
1921
baseline: TextBaseline.ideographic,
@@ -53,10 +55,14 @@ class BlazeFooter extends StatelessWidget {
5355
return Padding(
5456
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8.0),
5557
child: Text.rich(
58+
textAlign: TextAlign.center,
5659
TextSpan(
5760
style: Theme.of(context).textTheme.bodyMedium,
5861
children: [
59-
TextSpan(text: '* This demo includes some features that require an upgrade to the '),
62+
TextSpan(
63+
text:
64+
'* This demo includes some features that require an upgrade to the ',
65+
),
6066
WidgetSpan(
6167
baseline: TextBaseline.ideographic,
6268
alignment: PlaceholderAlignment.top,

0 commit comments

Comments
 (0)