import 'dart:ui'; import 'package:elysia/page/FollowListPage.dart'; import 'package:elysia/page/child/ChatPage.dart'; import 'package:elysia/plugin/MarkdownSelectableText.dart'; import 'package:elysia/plugin/RouteAnimation.dart'; import 'package:flutter/material.dart'; import 'package:oktoast/oktoast.dart'; import '../../plugin/C.dart'; import '../../plugin/CacheAavatar.dart'; import '../../plugin/CacheBackgroundImage.dart'; import '../../plugin/HTTP.dart'; import '../../plugin/LoadingOverlay.dart'; import '../ChatRoomPage.dart'; class RobotProfilePage extends StatelessWidget { final int robotId; final String name; final String avatar; final String systemPrompt; final String description; final String creatorUsername; final String template; final bool followList; const RobotProfilePage({ Key? key, required this.robotId, required this.name, required this.avatar, required this.systemPrompt, required this.description, required this.creatorUsername, required this.template, required this.followList, }) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("角色详情", style: const TextStyle(color: Colors.black)), centerTitle: true, backgroundColor: Colors.grey[200], leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () => Navigator.pop(context), ), elevation: 0, ), body: Stack( children: [ SizedBox.expand(child: CacheBackgroundImage(url: avatar)), Positioned.fill( child: ClipRect( child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50), child: Container(color: Colors.black.withOpacity(0)), ), ), ), Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ // 头像 + 名字 + 简介 Container( decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(5), ), child: Padding( padding: EdgeInsets.all(10), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ CacheAvatar(url: avatar), SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( name, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), SizedBox(height: 8), Text( description, style: TextStyle( fontSize: 14, color: Colors.grey[700], ), ), ], ), ), ], ), ), ), SizedBox(height: 15), Container( decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(5), ), child: Padding( padding: EdgeInsets.all(10), child: SizedBox( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ SizedBox( width: 80, child: Text( "创 建 者 :", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), Text(creatorUsername), ], ), SizedBox(height: 8), Row( children: [ SizedBox( width: 80, child: Text( "回复模板:", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), Text(template), ], ), ], ), ), ), ), SizedBox(height: 15), // 多行不可编辑文本框 Container( width: double.infinity, // 宽度撑满 height: followList ? 520 : 570, // 你可以根据需要调整高度,例如200 padding: EdgeInsets.all(12), decoration: BoxDecoration( border: Border.all(color: Colors.white), color: Colors.white, borderRadius: BorderRadius.circular(8), ), child: SingleChildScrollView( child: MarkdownSelectableText( systemPrompt, style: TextStyle(fontSize: 16), ), ), ), SizedBox(height: 24), // 底部主题色按钮 if (followList) Row( children: [ Expanded( flex: 8, child: SizedBox( height: 50, child: ElevatedButton( onPressed: () { createChat(context, robotId, avatar, name); }, style: ElevatedButton.styleFrom( elevation: 0, // 去掉按钮阴影 shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text( '创建聊天', style: TextStyle( fontSize: 18, color: Colors.white, ), ), ), ), ), SizedBox(width: 5), Expanded( flex: 2, child: SizedBox( height: 50, child: ElevatedButton( onPressed: () async { bool status = await unfollowRobot( context, robotId, ); if (status) { Navigator.pop(context); } }, style: ElevatedButton.styleFrom( backgroundColor: Colors.amber, elevation: 0, // 去掉按钮阴影 shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Icon( Icons.heart_broken, color: Colors.white, ), ), ), ), ], ), ], ), ), ], ), ); } void createChat( BuildContext context, int robotId, String avatar, String name, ) { showDialog( context: context, builder: (_) => ChatRoomDialog( options: [ {'key': '对话引擎', 'value': 'deepseek-chat'}, {'key': '深度思考', 'value': 'deepseek-reasoner'}, ], onConfirm: (roomName, value) async { LoadingOverlay.show(context: context, barrierColor: Colors.black54); try { dynamic result = await HTTP .create("${C.BASE_URL}/chat/create") .setHeader(C.TOKEN) .setRequestType(RequestType.POST) .setBody({ "engine": value, "roomName": roomName, "robotId": robotId, }) .execute(); LoadingOverlay.hide(); if (result["code"] == 200) { ChatRoomPage.flushData!(null); Navigator.pop(context); Navigator.push( context, RouteAnimation( ChatPage( roomId: result["data"], robotAvatar: avatar, robotName: roomName, ), Offset(1, 0), ), ); } else { showToast(result["message"], position: ToastPosition.bottom); } } catch (e) { LoadingOverlay.hide(); } }, ), ); } Future unfollowRobot(BuildContext context, int index) async { LoadingOverlay.show(context: context, barrierColor: Colors.black54); try { dynamic result = await HTTP .create("${C.BASE_URL}/robot/unfollow/$robotId") .setHeader(C.TOKEN) .setRequestType(RequestType.GET) .execute(); LoadingOverlay.hide(); if (result["code"] == 200) { FollowListPage.delete!(robotId); return true; } else { showToast(result["message"]); return false; } } catch (e) { LoadingOverlay.hide(); return false; } } }