|
|
@@ -1,13 +1,16 @@
|
|
|
import 'package:electronic_assistant/base/base_page.dart';
|
|
|
+import 'package:electronic_assistant/data/bean/chat_item.dart';
|
|
|
import 'package:electronic_assistant/module/chat/controller.dart';
|
|
|
-import 'package:electronic_assistant/module/chat/start/view.dart';
|
|
|
import 'package:electronic_assistant/resource/colors.gen.dart';
|
|
|
import 'package:electronic_assistant/utils/expand.dart';
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
import 'package:flutter/material.dart';
|
|
|
import 'package:flutter/services.dart';
|
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
+import 'package:get/get.dart';
|
|
|
+import 'package:pull_to_refresh/pull_to_refresh.dart';
|
|
|
|
|
|
+import '../../data/bean/progressing_chat_item.dart';
|
|
|
import '../../resource/assets.gen.dart';
|
|
|
|
|
|
class ChatPage extends BasePage<ChatController> {
|
|
|
@@ -20,8 +23,6 @@ class ChatPage extends BasePage<ChatController> {
|
|
|
|
|
|
@override
|
|
|
Widget buildBody(BuildContext context) {
|
|
|
- var controller = this.controller;
|
|
|
-
|
|
|
// 第一次启动时弹出定制窗口
|
|
|
controller.showStartSheet(context);
|
|
|
|
|
|
@@ -71,12 +72,39 @@ class ChatPage extends BasePage<ChatController> {
|
|
|
return Column(
|
|
|
children: [
|
|
|
Expanded(
|
|
|
- child: Padding(
|
|
|
+ child: Container(
|
|
|
padding: EdgeInsets.symmetric(horizontal: 12.w),
|
|
|
- child: AnimatedList(
|
|
|
- itemBuilder: _chatItemBuilder,
|
|
|
- initialItemCount: 20,
|
|
|
- ),
|
|
|
+ child: Obx(() {
|
|
|
+ return SmartRefresher(
|
|
|
+ controller: controller.refreshController,
|
|
|
+ footer: CustomFooter(
|
|
|
+ loadStyle: LoadStyle.ShowWhenLoading,
|
|
|
+ builder: (context, mode) {
|
|
|
+ if (mode == LoadStatus.loading ||
|
|
|
+ mode == LoadStatus.canLoading) {
|
|
|
+ return const SizedBox(
|
|
|
+ height: 60.0,
|
|
|
+ child: SizedBox(
|
|
|
+ height: 20.0,
|
|
|
+ width: 20.0,
|
|
|
+ child: CupertinoActivityIndicator(),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ return Container();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ enablePullDown: false,
|
|
|
+ enablePullUp: true,
|
|
|
+ onLoading: controller.loadMoreHistory,
|
|
|
+ onRefresh: controller.loadMoreHistory,
|
|
|
+ child: ListView.builder(
|
|
|
+ reverse: true,
|
|
|
+ controller: controller.listScrollController,
|
|
|
+ itemBuilder: _chatItemBuilder,
|
|
|
+ itemCount: controller.chatItems.length));
|
|
|
+ }),
|
|
|
)),
|
|
|
Container(
|
|
|
margin: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h),
|
|
|
@@ -103,6 +131,7 @@ class ChatPage extends BasePage<ChatController> {
|
|
|
child: Container(
|
|
|
margin: EdgeInsets.only(right: 6.w),
|
|
|
child: CupertinoTextField(
|
|
|
+ controller: controller.inputController,
|
|
|
padding: EdgeInsets.symmetric(vertical: 3.w),
|
|
|
style: TextStyle(
|
|
|
fontSize: 14.w, color: ColorName.primaryTextColor),
|
|
|
@@ -124,10 +153,15 @@ class ChatPage extends BasePage<ChatController> {
|
|
|
height: 26.w),
|
|
|
Container(
|
|
|
margin: EdgeInsets.only(left: 16.w),
|
|
|
- child: Image(
|
|
|
- image: Assets.images.iconChatSend.provider(),
|
|
|
- width: 26.w,
|
|
|
- height: 26.w),
|
|
|
+ child: GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ controller.sendMessage();
|
|
|
+ },
|
|
|
+ child: Image(
|
|
|
+ image: Assets.images.iconChatSend.provider(),
|
|
|
+ width: 26.w,
|
|
|
+ height: 26.w),
|
|
|
+ ),
|
|
|
)
|
|
|
],
|
|
|
)
|
|
|
@@ -139,9 +173,106 @@ class ChatPage extends BasePage<ChatController> {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- Widget _chatItemBuilder(
|
|
|
- BuildContext context, int index, Animation<double> animation) {
|
|
|
- return Text('聊天内容 $index');
|
|
|
+ Widget _chatItemBuilder(BuildContext context, int index) {
|
|
|
+ ChatItem chatItem = controller.chatItems[index];
|
|
|
+ if (chatItem.role == 'user') {
|
|
|
+ return _buildUserChatItem(context, chatItem);
|
|
|
+ } else if (chatItem.role == 'assistant') {
|
|
|
+ return _buildAssistantChatItem(context, chatItem);
|
|
|
+ } else {
|
|
|
+ return Container();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildAssistantChatItem(BuildContext context, ChatItem chatItem) {
|
|
|
+ ProgressingChatItem? progressingChatItem;
|
|
|
+ if (chatItem is ProgressingChatItem) {
|
|
|
+ progressingChatItem = chatItem;
|
|
|
+ }
|
|
|
+ return Align(
|
|
|
+ alignment: Alignment.centerLeft,
|
|
|
+ child: IntrinsicWidth(
|
|
|
+ child: progressingChatItem == null
|
|
|
+ ? _buildAssistantChatItemContent(null, chatItem.content)
|
|
|
+ : Obx(() {
|
|
|
+ bool? isStreamStarted = progressingChatItem == null
|
|
|
+ ? null
|
|
|
+ : progressingChatItem.streamContent.isNotEmpty ||
|
|
|
+ progressingChatItem.isFinished.value ||
|
|
|
+ progressingChatItem.isFailed.value;
|
|
|
+ return _buildAssistantChatItemContent(
|
|
|
+ isStreamStarted,
|
|
|
+ progressingChatItem!.isFailed.value
|
|
|
+ ? progressingChatItem.error.value
|
|
|
+ : progressingChatItem.streamContent.value);
|
|
|
+ }),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Container _buildAssistantChatItemContent(
|
|
|
+ bool? isStreamStarted, String content) {
|
|
|
+ return Container(
|
|
|
+ padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
|
|
|
+ margin: EdgeInsets.symmetric(vertical: 10.h),
|
|
|
+ alignment: Alignment.centerLeft,
|
|
|
+ constraints: BoxConstraints(
|
|
|
+ maxWidth: 0.78.sw, // 65% of screen width
|
|
|
+ ),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ border: isStreamStarted == null || isStreamStarted == true
|
|
|
+ ? null
|
|
|
+ : Border.all(color: ColorName.colorPrimary, width: 1.w),
|
|
|
+ color: ColorName.white,
|
|
|
+ borderRadius: BorderRadius.only(
|
|
|
+ topRight: Radius.circular(20.w),
|
|
|
+ bottomRight: Radius.circular(20.w),
|
|
|
+ bottomLeft: Radius.circular(20.w))),
|
|
|
+ child: isStreamStarted != null && isStreamStarted == false
|
|
|
+ ? Row(
|
|
|
+ children: [
|
|
|
+ Image(
|
|
|
+ image: Assets.images.iconStreamChatProgressing.provider(),
|
|
|
+ width: 24.w,
|
|
|
+ height: 20.w),
|
|
|
+ Padding(
|
|
|
+ padding: EdgeInsets.only(left: 8.w, right: 8.w),
|
|
|
+ child: Text(
|
|
|
+ "正在生成中,请稍后...",
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 14.w, color: ColorName.tertiaryTextColor),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ : SelectableText(content,
|
|
|
+ style:
|
|
|
+ TextStyle(fontSize: 14.w, color: ColorName.primaryTextColor)),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildUserChatItem(BuildContext context, ChatItem chatItem) {
|
|
|
+ return Align(
|
|
|
+ alignment: Alignment.centerRight,
|
|
|
+ child: IntrinsicWidth(
|
|
|
+ child: Container(
|
|
|
+ padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
|
|
|
+ margin: EdgeInsets.symmetric(vertical: 10.h),
|
|
|
+ alignment: Alignment.centerRight,
|
|
|
+ constraints: BoxConstraints(
|
|
|
+ maxWidth: 0.78.sw, // 65% of screen width
|
|
|
+ ),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: ColorName.colorPrimary,
|
|
|
+ borderRadius: BorderRadius.only(
|
|
|
+ topLeft: Radius.circular(16.w),
|
|
|
+ bottomRight: Radius.circular(16.w),
|
|
|
+ bottomLeft: Radius.circular(16.w))),
|
|
|
+ child: Text(chatItem.content,
|
|
|
+ style: TextStyle(fontSize: 14.w, color: ColorName.white)),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
Widget buildTopGradient() {
|