added send functionality to icon.

This commit is contained in:
Joshua
2024-07-10 13:44:16 -06:00
parent 097b99e0e6
commit 711991c7bf
13 changed files with 363 additions and 281 deletions
@@ -1,3 +1,4 @@
import 'package:app/theme.dart';
import 'package:flutter/material.dart';
import 'chat.dart';
@@ -26,9 +27,12 @@ class ChatBubbleWidget extends StatelessWidget{
bottomRight: c.role ? const Radius.circular(12.0) : const Radius
.circular(0.0),
),
color: c.role ? Colors.blue[200] : Colors.grey[200],
color: c.role ? AppTheme.darkest : AppTheme.dark,
),
child: Text(
c.content,
style: AppTheme.bodyMedium,
),
child: Text(c.content),
),
],
);
@@ -18,7 +18,7 @@ class Conversation with ChangeNotifier {
}
void loadChats() {
chats = Server.getChatsByConversationID(conversationID);
chats = Backend.getChatsByConversationID(conversationID);
}
void setLabel() {
@@ -20,7 +20,7 @@ class ConversationThreadModel extends FlutterFlowModel<ConversationThreadWidget>
@override
void initState(BuildContext context) {
conversation = Server.getLoadedConversation();
conversation = Backend.getLoadedConversation();
promptBoxModel = createModel(context, () => PromptBoxModel());
}
@@ -53,9 +53,7 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
return Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
color: AppTheme.primaryBackground,
),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -65,12 +63,12 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
listenable: _model.conversation,
builder: (BuildContext context, Widget? child) {
return ListView.builder(
itemCount: Server.getLoadedConversation().chats.length,
itemCount: Backend.getLoadedConversation().chats.length,
padding: const EdgeInsets.fromLTRB(0, 12, 0, 24,),
reverse: false,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return ChatBubbleWidget(c: Server.getLoadedConversation().chats[index]);
return ChatBubbleWidget(c: Backend.getLoadedConversation().chats[index]);
},
);
},
@@ -79,7 +77,7 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
Container(
width: double.infinity,
decoration: const BoxDecoration(
color: AppTheme.secondaryBackground,
color: AppTheme.medium,
boxShadow: [
BoxShadow(
blurRadius: 3,
@@ -95,74 +93,74 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(0, 12, 0, 0),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// FlutterFlowMediaDisplay(
// path: '',
// imageBuilder: (path) => ClipRRect(
// borderRadius: BorderRadius.circular(8),
// child: CachedNetworkImage(
// fadeInDuration: const Duration(milliseconds: 500),
// fadeOutDuration:
// const Duration(milliseconds: 500),
// imageUrl: path,
// width: 120,
// height: 100,
// fit: BoxFit.cover,
// ),
// ),
// TODO
// videoPlayerBuilder: (path) =>
// FlutterFlowVideoPlayer(
// path: path,
// width: 300,
// autoPlay: false,
// looping: true,
// showControls: true,
// allowFullScreen: true,
// allowPlaybackSpeedMenu: false,
// ),
// ),
Align(
alignment: const AlignmentDirectional(-1, -1),
// TODO: Make the delete button conditional upon media upload.
child: FlutterFlowIconButton(
borderColor:
AppTheme.error,
borderRadius: 20,
borderWidth: 2,
buttonSize: 40,
fillColor: AppTheme.primaryBackground,
icon: const Icon(
Icons.delete_outline_rounded,
color: AppTheme.error,
size: 24,
),
onPressed: () {
print('IconButton pressed ...');
},
),
),
]
.divide(const SizedBox(width: 8))
.addToStart(const SizedBox(width: 16))
.addToEnd(const SizedBox(width: 16)),
),
),
),
),
],
),
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Expanded(
// child: Padding(
// padding: const EdgeInsetsDirectional.fromSTEB(0, 12, 0, 0),
// child: SingleChildScrollView(
// scrollDirection: Axis.horizontal,
// child: Row(
// mainAxisSize: MainAxisSize.max,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// FlutterFlowMediaDisplay(
// path: '',
// imageBuilder: (path) => ClipRRect(
// borderRadius: BorderRadius.circular(8),
// child: CachedNetworkImage(
// fadeInDuration: const Duration(milliseconds: 500),
// fadeOutDuration:
// const Duration(milliseconds: 500),
// imageUrl: path,
// width: 120,
// height: 100,
// fit: BoxFit.cover,
// ),
// ),
// // TODO
// videoPlayerBuilder: (path) =>
// FlutterFlowVideoPlayer(
// path: path,
// width: 300,
// autoPlay: false,
// looping: true,
// showControls: true,
// allowFullScreen: true,
// allowPlaybackSpeedMenu: false,
// ),
// ),
// Align(
// alignment: const AlignmentDirectional(-1, -1),
// // TODO: Make the delete button conditional upon media upload.
// child: FlutterFlowIconButton(
// borderColor:
// AppTheme.error,
// borderRadius: 20,
// borderWidth: 2,
// buttonSize: 40,
// fillColor: AppTheme.primaryBackground,
// icon: const Icon(
// Icons.delete_outline_rounded,
// color: AppTheme.error,
// size: 24,
// ),
// onPressed: () {
// print('IconButton pressed ...');
// },
// ),
// ),
// ]
// .divide(const SizedBox(width: 8))
// .addToStart(const SizedBox(width: 16))
// .addToEnd(const SizedBox(width: 16)),
// ),
// ),
// ),
// ),
// ],
// ),
Form(
key: _model.formKey,
autovalidateMode: AutovalidateMode.disabled,
@@ -1,3 +1,4 @@
import 'package:app/components/conversation_thread/conversation.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
@@ -9,14 +10,18 @@ import 'model_item_model.dart';
export 'model_item_model.dart';
class ModelItemWidget extends StatefulWidget {
const ModelItemWidget({super.key});
final Conversation conversation;
const ModelItemWidget({super.key, required this.conversation});
@override
State<ModelItemWidget> createState() => _ModelItemWidgetState();
State<ModelItemWidget> createState() => _ModelItemWidgetState(conversation);
}
class _ModelItemWidgetState extends State<ModelItemWidget> {
late ModelItemModel _model;
late Conversation conversation;
_ModelItemWidgetState(this.conversation);
@override
void setState(VoidCallback callback) {
@@ -78,22 +83,22 @@ class _ModelItemWidgetState extends State<ModelItemWidget> {
),
),
),
const Expanded(
Expanded(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(12, 0, 8, 0),
padding: const EdgeInsetsDirectional.fromSTEB(12, 0, 8, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Randy Peterson',
Text( // Label
conversation.conversationLabel,
style: AppTheme.bodyMedium,
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 4, 0, 0),
child: Text(
'name@domainname.com',
padding: const EdgeInsetsDirectional.fromSTEB(0, 4, 0, 0),
child: Text( // Sub-label
conversation.conversationSubLabel,
style: AppTheme.bodySmall,
),
),
@@ -17,6 +17,7 @@ class PromptBoxWidget extends StatefulWidget {
class _PromptBoxWidgetState extends State<PromptBoxWidget> {
late PromptBoxModel _model;
late String entry_text;
@override
void setState(VoidCallback callback) {
@@ -69,7 +70,7 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
buttonSize: 40,
icon: const Icon(
Icons.file_upload_outlined,
color: AppTheme.secondaryText,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
@@ -88,7 +89,7 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
buttonSize: 40,
icon: const Icon(
Icons.photo_outlined,
color: AppTheme.secondaryText,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
@@ -105,13 +106,28 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
borderRadius: 30,
borderWidth: 1,
buttonSize: 40,
icon: const Icon(
Icons.mic_none,
color: AppTheme.secondaryText,
icon: // Backend.stt.speechToText.isListening ?
// const Icon(
// Icons.mic_none,
// color: AppTheme.error,
// size: 30,
// ) :
const Icon(
Icons.mic_off_outlined,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
print('IconButton pressed ...');
if(Backend.stt.isSpeechEnabled()) {
if(Backend.stt.speechToText.isListening) {
print('De-activating STT.');
Backend.stt.stopListening();
}
print('Activating STT.');
entry_text = Backend.stt.startListening() as String;
} else {
print('Microphone is unavailable for STT');
}
},
),
),
@@ -126,7 +142,7 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
buttonSize: 40,
icon: const Icon(
Icons.videocam_outlined,
color: AppTheme.secondaryText,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
@@ -145,7 +161,7 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
buttonSize: 40,
icon: const Icon(
Icons.camera_alt_outlined,
color: AppTheme.secondaryText,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
@@ -206,21 +222,28 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
),
filled: true,
fillColor: AppTheme.alternate,
suffixIcon: const Icon(
Icons.send,
color: AppTheme.primary,
size: 30,
suffixIcon: GestureDetector(
onTap: () {
// TODO: Connect with multimedia
entry_text = _model.textController.text;
Backend.respondWhenReady(entry_text);
_model.textController?.clear(); // Clear the text field
},
child: const Icon(
Icons.send,
color: AppTheme.primary,
size: 30,
),
),
),
style: AppTheme.bodyMedium,
style: AppTheme.displayMedium,
textAlign: TextAlign.start,
maxLines: 5,
minLines: 1,
validator: _model.textControllerValidator.asValidator(context),
textInputAction: TextInputAction.send, // "Send" on keyboard
onFieldSubmitted: (text) {
// TODO: Clear text box
Server.respondWhenReady(text); // TODO: Connect with multimedia
Backend.respondWhenReady(text); // TODO: Connect with multimedia
_model.textController?.clear(); // Clear the text field
},
),