From 8956ed7885e9712e19dc4a293b4850b80b7ccc41 Mon Sep 17 00:00:00 2001 From: Joshua Date: Sun, 7 Jul 2024 16:44:08 -0600 Subject: [PATCH] implemented basic chat bubbles generated from a list. --- .../conversation_bubbles_model.dart | 3 -- .../conversation_bubbles_widget.dart | 3 -- .../components/conversation_thread/chat.dart | 9 +++++ .../chat_bubble_model.dart | 18 ++++++++++ .../chat_bubble_widget.dart | 33 +++++++++++++++++ .../conversation_thread/conversation.dart | 15 ++++++++ .../conversation_thread_model.dart | 28 ++++++++------- .../conversation_thread_widget.dart | 36 +++++++------------ mobile/app/lib/pages/conversation_model.dart | 5 +-- .../lib/pages/conversations_list_model.dart | 2 ++ mobile/app/lib/util/server.dart | 22 +++++++++++- 11 files changed, 126 insertions(+), 48 deletions(-) delete mode 100644 mobile/app/lib/components/conversation_bubbles/conversation_bubbles_model.dart delete mode 100644 mobile/app/lib/components/conversation_bubbles/conversation_bubbles_widget.dart create mode 100644 mobile/app/lib/components/conversation_thread/chat.dart create mode 100644 mobile/app/lib/components/conversation_thread/chat_bubble_model.dart create mode 100644 mobile/app/lib/components/conversation_thread/chat_bubble_widget.dart create mode 100644 mobile/app/lib/components/conversation_thread/conversation.dart diff --git a/mobile/app/lib/components/conversation_bubbles/conversation_bubbles_model.dart b/mobile/app/lib/components/conversation_bubbles/conversation_bubbles_model.dart deleted file mode 100644 index 6c42b17..0000000 --- a/mobile/app/lib/components/conversation_bubbles/conversation_bubbles_model.dart +++ /dev/null @@ -1,3 +0,0 @@ -class ConversationBubblesModel { - -} \ No newline at end of file diff --git a/mobile/app/lib/components/conversation_bubbles/conversation_bubbles_widget.dart b/mobile/app/lib/components/conversation_bubbles/conversation_bubbles_widget.dart deleted file mode 100644 index 11bd06d..0000000 --- a/mobile/app/lib/components/conversation_bubbles/conversation_bubbles_widget.dart +++ /dev/null @@ -1,3 +0,0 @@ -class ConversationBubblesWidget { - -} \ No newline at end of file diff --git a/mobile/app/lib/components/conversation_thread/chat.dart b/mobile/app/lib/components/conversation_thread/chat.dart new file mode 100644 index 0000000..0b9da7a --- /dev/null +++ b/mobile/app/lib/components/conversation_thread/chat.dart @@ -0,0 +1,9 @@ +class Chat { + late String message; + late bool isMe; + + // Most basic chat, text from server or from user. + Chat(this.message, this.isMe); + + // TODO: Overload constructors to allow for multimedia. +} \ No newline at end of file diff --git a/mobile/app/lib/components/conversation_thread/chat_bubble_model.dart b/mobile/app/lib/components/conversation_thread/chat_bubble_model.dart new file mode 100644 index 0000000..b6efc16 --- /dev/null +++ b/mobile/app/lib/components/conversation_thread/chat_bubble_model.dart @@ -0,0 +1,18 @@ +import 'chat_bubble_widget.dart'; +import 'chat.dart'; + +import 'package:flutter/material.dart'; +import 'package:flutterflow_ui/flutterflow_ui.dart'; + + +class ChatBubbleModel extends FlutterFlowModel{ + late final Chat c; + + ChatBubbleModel(this.c); + + @override + void dispose() {} // TODO: Need to implement for prompt/response deletion. + + @override + void initState(BuildContext context) {} // TODO: Need to implement for loading in media and editing. +} \ No newline at end of file diff --git a/mobile/app/lib/components/conversation_thread/chat_bubble_widget.dart b/mobile/app/lib/components/conversation_thread/chat_bubble_widget.dart new file mode 100644 index 0000000..d4610a7 --- /dev/null +++ b/mobile/app/lib/components/conversation_thread/chat_bubble_widget.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'chat.dart'; + +class ChatBubbleWidget extends StatelessWidget{ + late Chat c; + + ChatBubbleWidget({super.key, required this.c}); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: c.isMe ? MainAxisAlignment.end : MainAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.all(16.0), + margin: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: const Radius.circular(12.0), + topRight: const Radius.circular(12.0), + bottomLeft: c.isMe ? const Radius.circular(12.0) : const Radius + .circular(0.0), + bottomRight: c.isMe ? const Radius.circular(12.0) : const Radius + .circular(0.0), + ), + color: c.isMe ? Colors.blue[200] : Colors.grey[200], + ), + child: Text(c.message), + ), + ], + ); + } +} \ No newline at end of file diff --git a/mobile/app/lib/components/conversation_thread/conversation.dart b/mobile/app/lib/components/conversation_thread/conversation.dart new file mode 100644 index 0000000..5023210 --- /dev/null +++ b/mobile/app/lib/components/conversation_thread/conversation.dart @@ -0,0 +1,15 @@ +import 'package:app/util/server.dart'; +import 'chat.dart'; + +class Conversation { + int conversationID; + List chats = []; + + Conversation(this.conversationID) { + chats = Server().getConversationByID(conversationID); + } + + List getChats() { + return chats; + } +} \ No newline at end of file diff --git a/mobile/app/lib/components/conversation_thread/conversation_thread_model.dart b/mobile/app/lib/components/conversation_thread/conversation_thread_model.dart index 123bd4f..08eacc1 100644 --- a/mobile/app/lib/components/conversation_thread/conversation_thread_model.dart +++ b/mobile/app/lib/components/conversation_thread/conversation_thread_model.dart @@ -1,32 +1,34 @@ -import '../conversation_bubbles/conversation_bubbles_model.dart'; -import '/components/prompt_box/prompt_box_widget.dart'; +import 'package:app/components/conversation_thread/chat_bubble_model.dart'; +import 'package:app/components/conversation_thread/chat.dart'; +import 'package:app/components/conversation_thread/conversation.dart'; +import 'package:app/util/server.dart'; + +import 'package:app/components/prompt_box/prompt_box_widget.dart'; import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'conversation_thread_widget.dart' show ConversationThreadWidget; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; +import 'package:cached_network_image/cached_network_image.dart'; -class ConversationThreadModel - extends FlutterFlowModel { - /// State fields for stateful widgets in this component. - +class ConversationThreadModel extends FlutterFlowModel { final formKey = GlobalKey(); - // Model for ConversationBubbles component. - late ConversationBubblesModel conversationBubblesModel; - - // Model for PromptBox component. late PromptBoxModel promptBoxModel; + late int ?conversationID; + late Conversation conversation; + + // If there's a conversation ID, retrieve the conversation history. + // Otherwise, start a new conversation with user defaults. + ConversationThreadModel(this.conversationID); @override void initState(BuildContext context) { - //conversationBubblesModel = createModel(context, () => ConversationBubblesModel()); + conversation = Conversation(conversationID!); promptBoxModel = createModel(context, () => PromptBoxModel()); } @override void dispose() { - //conversationBubblesModel.dispose(); promptBoxModel.dispose(); } } diff --git a/mobile/app/lib/components/conversation_thread/conversation_thread_widget.dart b/mobile/app/lib/components/conversation_thread/conversation_thread_widget.dart index aca9e13..6668fd6 100644 --- a/mobile/app/lib/components/conversation_thread/conversation_thread_widget.dart +++ b/mobile/app/lib/components/conversation_thread/conversation_thread_widget.dart @@ -1,10 +1,11 @@ -import '/components/conversation_bubbles/conversation_bubbles_widget.dart'; +import 'package:app/components/conversation_thread/conversation.dart'; + +import '/components/conversation_thread/chat_bubble_widget.dart'; +import 'package:app/components/conversation_thread/conversation_thread_model.dart'; import '/components/prompt_box/prompt_box_widget.dart'; import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:provider/provider.dart'; import 'package:app/theme.dart'; @@ -31,7 +32,7 @@ class _ConversationThreadWidgetState extends State { @override void initState() { super.initState(); - _model = createModel(context, () => ConversationThreadModel()); + _model = createModel(context, () => ConversationThreadModel(0)); // TODO } @override @@ -43,6 +44,7 @@ class _ConversationThreadWidgetState extends State { @override Widget build(BuildContext context) { + Conversation c = _model.conversation; return Container( width: double.infinity, height: double.infinity, @@ -54,28 +56,14 @@ class _ConversationThreadWidgetState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: ListView( + child: ListView.builder( + itemCount: c.chats.length, padding: const EdgeInsets.fromLTRB(0, 12, 0, 24,), - reverse: true, + reverse: false, scrollDirection: Axis.vertical, - children: [ - Container( - decoration: const BoxDecoration(), - ), - Container( - height: MediaQuery.sizeOf(context).height * 1, - constraints: BoxConstraints( - minHeight: MediaQuery.sizeOf(context).height * 1, - ), - decoration: const BoxDecoration(), - //child: wrapWithModel( - //model: _model.conversationBubblesModel, - //updateCallback: () => setState(() {}), - //child: ConversationBubblesWidget(), - //child: const Text("test"), - //), - ), - ], + itemBuilder: (BuildContext context, int index) { + return ChatBubbleWidget(c: c.chats[index]); + }, ), ), Container( diff --git a/mobile/app/lib/pages/conversation_model.dart b/mobile/app/lib/pages/conversation_model.dart index 8273bd9..4566fad 100644 --- a/mobile/app/lib/pages/conversation_model.dart +++ b/mobile/app/lib/pages/conversation_model.dart @@ -1,11 +1,8 @@ -import '/components/conversation_details_overlay/conversation_details_overlay_widget.dart'; import '/components/conversation_thread/conversation_thread_widget.dart'; import '/components/model_item/model_item_widget.dart'; import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'conversation_widget.dart' show ConversationWidget; import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:provider/provider.dart'; class ConversationModel extends FlutterFlowModel { /// State fields for stateful widgets in this page. @@ -19,7 +16,7 @@ class ConversationModel extends FlutterFlowModel { @override void initState(BuildContext context) { conversationThreadModel = - createModel(context, () => ConversationThreadModel()); + createModel(context, () => ConversationThreadModel(0)); // TODO modelItemModel = createModel(context, () => ModelItemModel()); } diff --git a/mobile/app/lib/pages/conversations_list_model.dart b/mobile/app/lib/pages/conversations_list_model.dart index c4ad379..23245b2 100644 --- a/mobile/app/lib/pages/conversations_list_model.dart +++ b/mobile/app/lib/pages/conversations_list_model.dart @@ -1,6 +1,8 @@ import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'conversations_list_widget.dart' show ConversationsListWidget; import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:provider/provider.dart'; class ConversationsListModel extends FlutterFlowModel { diff --git a/mobile/app/lib/util/server.dart b/mobile/app/lib/util/server.dart index e1076a5..8e7e365 100644 --- a/mobile/app/lib/util/server.dart +++ b/mobile/app/lib/util/server.dart @@ -1,18 +1,26 @@ import 'dart:convert'; import 'package:http/http.dart' as http; +import 'package:app/components/conversation_thread/chat.dart'; + import 'package:app/util/speech_to_text.dart'; class Server { // TODO: One-time process to establish server connection is required for easy setup/maintenance. + // Server variables final url = "http://10.0.2.2:11434"; - final headers = {'Content-Type': 'application/json'}; + Map headers = {'Content-Type': 'application/json'}; + // Model variables final SpeechToText stt = SpeechToText(); + + // Status variables late bool _speechEnabled; + // Runtime variables String prompt = ""; String response = ""; + int conversationID = 0; Server() { // Speech-To-Text engine activation. @@ -22,6 +30,18 @@ class Server { // TODO: Handshake w/ server to validate identity } + List getConversationByID(conversationID) { + this.conversationID = conversationID; + + // TODO: Implement conversation IDs & retrieval from server + List chats = [ + (Chat("hello world!", true)), + (Chat("hello to you too!", false)), + ]; + + return chats; + } + // Using native on-device Speech-To-Text capability, get the server response when ready. Future sttGetResponseWhenReady() async { // TODO: In case on-device STT is unavailable, use server-side STT service.