@@ -11,11 +11,13 @@ import 'package:flutter/material.dart';
1111import 'package:flutter/services.dart' ;
1212import 'package:flutter_bloc/flutter_bloc.dart' ;
1313
14+ import '../../application/chat_entity.dart' ;
1415import '../layout_define.dart' ;
1516import 'ai_prompt_buttons.dart' ;
1617import 'chat_input_file.dart' ;
1718import 'chat_input_span.dart' ;
1819import 'chat_mention_page_menu.dart' ;
20+ import 'predefined_format_buttons.dart' ;
1921import 'select_sources_menu.dart' ;
2022
2123class DesktopAIPromptInput extends StatefulWidget {
@@ -46,6 +48,9 @@ class _DesktopAIPromptInputState extends State<DesktopAIPromptInput> {
4648 final focusNode = FocusNode ();
4749 final textController = TextEditingController ();
4850
51+ bool showPredefinedFormatSection = false ;
52+ PredefinedFormat predefinedFormat = PredefinedFormat .text;
53+ PredefinedTextFormat ? predefinedTextFormat = PredefinedTextFormat .auto;
4954 late SendButtonState sendButtonState;
5055
5156 @override
@@ -115,6 +120,7 @@ class _DesktopAIPromptInputState extends State<DesktopAIPromptInput> {
115120 ? Theme .of (context).colorScheme.primary
116121 : Theme .of (context).colorScheme.outline,
117122 width: focusNode.hasFocus ? 1.5 : 1.0 ,
123+ strokeAlign: BorderSide .strokeAlignOutside,
118124 ),
119125 borderRadius: DesktopAIPromptSizes .promptFrameRadius,
120126 ),
@@ -136,24 +142,60 @@ class _DesktopAIPromptInputState extends State<DesktopAIPromptInput> {
136142 ),
137143 ),
138144 ),
145+ const VSpace (4.0 ),
139146 Stack (
140147 children: [
141- ConstrainedBox (
142- constraints: BoxConstraints (
143- minHeight: DesktopAIPromptSizes .textFieldMinHeight +
144- DesktopAIPromptSizes .actionBarHeight +
145- DesktopAIPromptSizes .actionBarPadding.vertical,
146- maxHeight: 300 ,
147- ),
148+ Container (
149+ constraints: getTextFieldConstraints (),
148150 child: inputTextField (),
149151 ),
152+ if (showPredefinedFormatSection)
153+ Positioned .fill (
154+ bottom: null ,
155+ child: TextFieldTapRegion (
156+ child: Padding (
157+ padding:
158+ const EdgeInsetsDirectional .only (start: 8.0 ),
159+ child: ChangeFormatBar (
160+ predefinedFormat: predefinedFormat,
161+ predefinedTextFormat: predefinedTextFormat,
162+ spacing: DesktopAIPromptSizes
163+ .predefinedFormatBarButtonSpacing,
164+ iconSize: DesktopAIPromptSizes
165+ .predefinedFormatIconHeight,
166+ buttonSize: DesktopAIPromptSizes
167+ .predefinedFormatButtonHeight,
168+ onSelectPredefinedFormat: (p0, p1) {
169+ setState (() {
170+ predefinedFormat = p0;
171+ predefinedTextFormat = p1;
172+ });
173+ },
174+ ),
175+ ),
176+ ),
177+ ),
150178 Positioned .fill (
151179 top: null ,
152180 child: TextFieldTapRegion (
153181 child: _PromptBottomActions (
154182 textController: textController,
155183 overlayController: overlayController,
156184 focusNode: focusNode,
185+ showPredefinedFormats: showPredefinedFormatSection,
186+ predefinedFormat: predefinedFormat,
187+ predefinedTextFormat: predefinedTextFormat,
188+ onTogglePredefinedFormatSection: () {
189+ setState (() {
190+ showPredefinedFormatSection =
191+ ! showPredefinedFormatSection;
192+ if (! showPredefinedFormatSection) {
193+ predefinedFormat = PredefinedFormat .text;
194+ predefinedTextFormat =
195+ PredefinedTextFormat .auto;
196+ }
197+ });
198+ },
157199 sendButtonState: sendButtonState,
158200 onSendPressed: handleSendPressed,
159201 onStopStreaming: widget.onStopStreaming,
@@ -172,6 +214,18 @@ class _DesktopAIPromptInputState extends State<DesktopAIPromptInput> {
172214 );
173215 }
174216
217+ BoxConstraints getTextFieldConstraints () {
218+ double minHeight = DesktopAIPromptSizes .textFieldMinHeight +
219+ DesktopAIPromptSizes .actionBarHeight +
220+ DesktopAIPromptSizes .actionBarPadding.vertical;
221+ double maxHeight = 300 ;
222+ if (showPredefinedFormatSection) {
223+ minHeight += DesktopAIPromptSizes .predefinedFormatButtonHeight;
224+ maxHeight += DesktopAIPromptSizes .predefinedFormatButtonHeight;
225+ }
226+ return BoxConstraints (minHeight: minHeight, maxHeight: maxHeight);
227+ }
228+
175229 void cancelMentionPage () {
176230 if (overlayController.isShowing) {
177231 inputControlCubit.reset ();
@@ -202,7 +256,13 @@ class _DesktopAIPromptInputState extends State<DesktopAIPromptInput> {
202256 }
203257
204258 // get the attached files and mentioned pages
205- final metadata = context.read <AIPromptInputBloc >().consumeMetadata ();
259+ final metadata = {
260+ ...context.read <AIPromptInputBloc >().consumeMetadata (),
261+ if (showPredefinedFormatSection) ...{
262+ "format" : predefinedFormat,
263+ "textFormat" : predefinedTextFormat,
264+ },
265+ };
206266
207267 widget.onSubmitted (trimmedText, metadata);
208268 }
@@ -301,6 +361,7 @@ class _DesktopAIPromptInputState extends State<DesktopAIPromptInput> {
301361 cubit: inputControlCubit,
302362 textController: textController,
303363 textFieldFocusNode: focusNode,
364+ showPredefinedFormatSection: showPredefinedFormatSection,
304365 hintText: switch (state.aiType) {
305366 AIType .appflowyAI => LocaleKeys .chat_inputMessageHint.tr (),
306367 AIType .localAI => LocaleKeys .chat_inputLocalAIMessageHint.tr ()
@@ -366,15 +427,17 @@ class _PromptTextField extends StatefulWidget {
366427 required this .cubit,
367428 required this .textController,
368429 required this .textFieldFocusNode,
369- // required this.onStartMentioningPage ,
430+ this .showPredefinedFormatSection = false ,
370431 this .hintText = "" ,
432+ // this.onStartMentioningPage,
371433 });
372434
373435 final ChatInputControlCubit cubit;
374436 final TextEditingController textController;
375437 final FocusNode textFieldFocusNode;
376- // final void Function() onStartMentioningPage ;
438+ final bool showPredefinedFormatSection ;
377439 final String hintText;
440+ // final void Function()? onStartMentioningPage;
378441
379442 @override
380443 State <_PromptTextField > createState () => _PromptTextFieldState ();
@@ -408,11 +471,7 @@ class _PromptTextFieldState extends State<_PromptTextField> {
408471 border: InputBorder .none,
409472 enabledBorder: InputBorder .none,
410473 focusedBorder: InputBorder .none,
411- contentPadding: DesktopAIPromptSizes .textFieldContentPadding.add (
412- const EdgeInsets .only (
413- bottom: DesktopAIPromptSizes .actionBarHeight,
414- ),
415- ),
474+ contentPadding: calculateContentPadding (),
416475 hintText: widget.hintText,
417476 hintStyle: Theme .of (context)
418477 .textTheme
@@ -450,6 +509,16 @@ class _PromptTextFieldState extends State<_PromptTextField> {
450509 );
451510 }
452511
512+ EdgeInsetsGeometry calculateContentPadding () {
513+ final top = widget.showPredefinedFormatSection
514+ ? DesktopAIPromptSizes .predefinedFormatButtonHeight
515+ : 0.0 ;
516+ const bottom = DesktopAIPromptSizes .actionBarHeight;
517+
518+ return DesktopAIPromptSizes .textFieldContentPadding
519+ .add (EdgeInsets .only (top: top, bottom: bottom));
520+ }
521+
453522 Map <ShortcutActivator , Intent > buildShortcuts () {
454523 if (isComposing) {
455524 return const {};
@@ -486,6 +555,10 @@ class _PromptBottomActions extends StatelessWidget {
486555 required this .overlayController,
487556 required this .focusNode,
488557 required this .sendButtonState,
558+ required this .predefinedFormat,
559+ required this .predefinedTextFormat,
560+ required this .onTogglePredefinedFormatSection,
561+ required this .showPredefinedFormats,
489562 required this .onSendPressed,
490563 required this .onStopStreaming,
491564 required this .onUpdateSelectedSources,
@@ -494,6 +567,10 @@ class _PromptBottomActions extends StatelessWidget {
494567 final TextEditingController textController;
495568 final OverlayPortalController overlayController;
496569 final FocusNode focusNode;
570+ final bool showPredefinedFormats;
571+ final PredefinedFormat predefinedFormat;
572+ final PredefinedTextFormat ? predefinedTextFormat;
573+ final void Function () onTogglePredefinedFormatSection;
497574 final SendButtonState sendButtonState;
498575 final void Function () onSendPressed;
499576 final void Function () onStopStreaming;
@@ -514,7 +591,7 @@ class _PromptBottomActions extends StatelessWidget {
514591 }
515592 return Row (
516593 children: [
517- // predefinedFormatButton (),
594+ _predefinedFormatButton (),
518595 const Spacer (),
519596 if (state.aiType == AIType .appflowyAI) ...[
520597 _selectSourcesButton (context),
@@ -540,6 +617,15 @@ class _PromptBottomActions extends StatelessWidget {
540617 );
541618 }
542619
620+ Widget _predefinedFormatButton () {
621+ return PromptInputDesktopToggleFormatButton (
622+ showFormatBar: showPredefinedFormats,
623+ predefinedFormat: predefinedFormat,
624+ predefinedTextFormat: predefinedTextFormat,
625+ onTap: onTogglePredefinedFormatSection,
626+ );
627+ }
628+
543629 Widget _selectSourcesButton (BuildContext context) {
544630 return PromptInputDesktopSelectSourcesButton (
545631 onUpdateSelectedSources: onUpdateSelectedSources,
0 commit comments