Merge pull request #778 from pangeachat/bot-settings-design
initial work on updating bot settings UI
This commit is contained in:
commit
f87128af77
17 changed files with 457 additions and 745 deletions
|
|
@ -3904,7 +3904,6 @@
|
|||
"listen": "Listen",
|
||||
"addConversationBot": "Enable Conversation Bot",
|
||||
"addConversationBotDesc": "Add a bot to this chat",
|
||||
"convoBotSettingsTitle": "Conversation Bot Settings",
|
||||
"convoBotSettingsDescription": "Edit conversation topic and difficulty",
|
||||
"enterAConversationTopic": "Enter a conversation topic",
|
||||
"conversationTopic": "Conversation topic",
|
||||
|
|
@ -4009,7 +4008,7 @@
|
|||
"accuracy": "Accuracy",
|
||||
"points": "Points",
|
||||
"noPaymentInfo": "No payment info necessary!",
|
||||
"conversationBotModeSelectDescription": "Bot mode",
|
||||
"conversationBotModeSelectDescription": "Chat Activity",
|
||||
"conversationBotModeSelectOption_discussion": "Discussion",
|
||||
"conversationBotModeSelectOption_custom": "Custom",
|
||||
"conversationBotModeSelectOption_conversation": "Conversation",
|
||||
|
|
@ -4030,7 +4029,7 @@
|
|||
"conversationBotCustomZone_customSystemPromptPlaceholder": "Set custom system prompt",
|
||||
"conversationBotCustomZone_customSystemPromptEmptyError": "Missing custom system prompt",
|
||||
"conversationBotCustomZone_customTriggerReactionEnabledLabel": "Responds on ⏩ reaction",
|
||||
"botConfig": "Conversation Bot Settings",
|
||||
"botConfig": "Chat Settings",
|
||||
"addConversationBotDialogTitleInvite": "Confirm inviting conversation bot",
|
||||
"addConversationBotButtonInvite": "Invite",
|
||||
"addConversationBotDialogInviteConfirmation": "Invite",
|
||||
|
|
@ -4038,7 +4037,7 @@
|
|||
"addConversationBotButtonRemove": "Remove",
|
||||
"addConversationBotDialogRemoveConfirmation": "Remove",
|
||||
"conversationBotConfigConfirmChange": "Confirm",
|
||||
"conversationBotStatus": "Bot Status",
|
||||
"conversationBotStatus": "Invite bot",
|
||||
"conversationBotTextAdventureZone_title": "Text Adventure",
|
||||
"conversationBotTextAdventureZone_instructionLabel": "Game Master Instructions",
|
||||
"conversationBotTextAdventureZone_instructionPlaceholder": "Set game master instructions",
|
||||
|
|
@ -4360,5 +4359,10 @@
|
|||
"grammarCopyCase": "Case",
|
||||
"grammarCopyDefinite": "Definiteness",
|
||||
"grammarCopyNumForm": "Numeral Form",
|
||||
"grammarCopyUnknown": "Unknown"
|
||||
"grammarCopyUnknown": "Unknown",
|
||||
"enterPrompt": "Please enter a system prompt",
|
||||
"selectBotLanguage": "Select bot language",
|
||||
"chooseVoice": "Choose a voice",
|
||||
"enterLanguageLevel": "Please enter a language level",
|
||||
"enterDiscussionTopic": "Please enter a discussion topic"
|
||||
}
|
||||
|
|
@ -106,6 +106,20 @@ class NewGroupController extends State<NewGroup> {
|
|||
|
||||
// #Pangea
|
||||
// validate init bot options
|
||||
if (addConversationBotKey.currentState?.formKey.currentState != null) {
|
||||
final isValid = addConversationBotKey
|
||||
.currentState!.formKey.currentState!
|
||||
.validate();
|
||||
if (isValid == false) {
|
||||
setState(() {
|
||||
error = L10n.of(context)!
|
||||
.conversationBotCustomZone_customSystemPromptEmptyError;
|
||||
loading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
addConversationBotKey.currentState?.updateAllBotOptions();
|
||||
final addBot = addConversationBotKey.currentState?.addBot ?? false;
|
||||
if (addBot) {
|
||||
final botOptions = addConversationBotKey.currentState!.botOptions;
|
||||
|
|
|
|||
|
|
@ -121,6 +121,9 @@ class ModelKey {
|
|||
static const String textAdventureGameMasterInstructions =
|
||||
"text_adventure_game_master_instructions";
|
||||
|
||||
static const String targetLanguage = "target_language";
|
||||
static const String targetVoice = "target_voice";
|
||||
|
||||
static const String prevEventId = "prev_event_id";
|
||||
static const String prevLastUpdated = "prev_last_updated";
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ class BotOptionsModel {
|
|||
bool? customTriggerReactionEnabled;
|
||||
String? customTriggerReactionKey;
|
||||
String? textAdventureGameMasterInstructions;
|
||||
String? targetLanguage;
|
||||
String? targetVoice;
|
||||
|
||||
BotOptionsModel({
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -31,6 +33,8 @@ class BotOptionsModel {
|
|||
this.keywords = const [],
|
||||
this.safetyModeration = true,
|
||||
this.mode = BotMode.discussion,
|
||||
this.targetLanguage,
|
||||
this.targetVoice,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Discussion Mode Options
|
||||
|
|
@ -63,6 +67,8 @@ class BotOptionsModel {
|
|||
: null,
|
||||
safetyModeration: json[ModelKey.safetyModeration] ?? true,
|
||||
mode: json[ModelKey.mode] ?? BotMode.discussion,
|
||||
targetLanguage: json[ModelKey.targetLanguage],
|
||||
targetVoice: json[ModelKey.targetVoice],
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Discussion Mode Options
|
||||
|
|
@ -97,6 +103,8 @@ class BotOptionsModel {
|
|||
data[ModelKey.languageLevel] = languageLevel;
|
||||
data[ModelKey.safetyModeration] = safetyModeration;
|
||||
data[ModelKey.mode] = mode;
|
||||
data[ModelKey.targetLanguage] = targetLanguage;
|
||||
data[ModelKey.targetVoice] = targetVoice;
|
||||
data[ModelKey.discussionTopic] = discussionTopic;
|
||||
data[ModelKey.discussionKeywords] = discussionKeywords;
|
||||
data[ModelKey.discussionTriggerReactionEnabled] =
|
||||
|
|
@ -153,6 +161,12 @@ class BotOptionsModel {
|
|||
case ModelKey.textAdventureGameMasterInstructions:
|
||||
textAdventureGameMasterInstructions = value;
|
||||
break;
|
||||
case ModelKey.targetLanguage:
|
||||
targetLanguage = value;
|
||||
break;
|
||||
case ModelKey.targetVoice:
|
||||
targetVoice = value;
|
||||
break;
|
||||
default:
|
||||
throw Exception('Invalid key for bot options - $key');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,95 +0,0 @@
|
|||
import 'package:fluffychat/pangea/models/bot_options_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class ConversationBotCustomSystemPromptInput extends StatelessWidget {
|
||||
final BotOptionsModel initialBotOptions;
|
||||
// call this to update propagate changes to parents
|
||||
final void Function(BotOptionsModel) onChanged;
|
||||
|
||||
const ConversationBotCustomSystemPromptInput({
|
||||
super.key,
|
||||
required this.initialBotOptions,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String customSystemPrompt = initialBotOptions.customSystemPrompt ?? "";
|
||||
|
||||
final TextEditingController textFieldController =
|
||||
TextEditingController(text: customSystemPrompt);
|
||||
|
||||
final GlobalKey<FormState> customSystemPromptFormKey =
|
||||
GlobalKey<FormState>();
|
||||
|
||||
void setBotCustomSystemPromptAction() async {
|
||||
showDialog(
|
||||
context: context,
|
||||
useRootNavigator: false,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: Text(
|
||||
L10n.of(context)!.conversationBotCustomZone_customSystemPromptLabel,
|
||||
),
|
||||
content: Form(
|
||||
key: customSystemPromptFormKey,
|
||||
child: TextFormField(
|
||||
minLines: 1,
|
||||
maxLines: 10,
|
||||
maxLength: 1000,
|
||||
controller: textFieldController,
|
||||
onChanged: (value) {
|
||||
if (value.isNotEmpty) {
|
||||
customSystemPrompt = value;
|
||||
}
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'This field cannot be empty';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(L10n.of(context)!.cancel),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text(L10n.of(context)!.ok),
|
||||
onPressed: () {
|
||||
if (customSystemPromptFormKey.currentState!.validate()) {
|
||||
if (customSystemPrompt !=
|
||||
initialBotOptions.customSystemPrompt) {
|
||||
initialBotOptions.customSystemPrompt = customSystemPrompt;
|
||||
onChanged.call(initialBotOptions);
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
onTap: setBotCustomSystemPromptAction,
|
||||
title: Text(
|
||||
initialBotOptions.customSystemPrompt ??
|
||||
L10n.of(context)!
|
||||
.conversationBotCustomZone_customSystemPromptPlaceholder,
|
||||
),
|
||||
subtitle: customSystemPrompt.isEmpty
|
||||
? Text(
|
||||
L10n.of(context)!
|
||||
.conversationBotCustomZone_customSystemPromptEmptyError,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
import 'package:fluffychat/pangea/models/bot_options_model.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_custom_system_prompt_input.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class ConversationBotCustomZone extends StatelessWidget {
|
||||
final BotOptionsModel initialBotOptions;
|
||||
// call this to update propagate changes to parents
|
||||
final void Function(BotOptionsModel) onChanged;
|
||||
|
||||
const ConversationBotCustomZone({
|
||||
super.key,
|
||||
required this.initialBotOptions,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
ConversationBotDynamicZoneTitle(
|
||||
title: L10n.of(context)!.conversationBotCustomZone_title,
|
||||
),
|
||||
ConversationBotDynamicZoneLabel(
|
||||
label: L10n.of(context)!
|
||||
.conversationBotCustomZone_customSystemPromptLabel,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: ConversationBotCustomSystemPromptInput(
|
||||
initialBotOptions: initialBotOptions,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
CheckboxListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!
|
||||
.conversationBotCustomZone_customTriggerReactionEnabledLabel,
|
||||
),
|
||||
enabled: false,
|
||||
value: initialBotOptions.customTriggerReactionEnabled ?? true,
|
||||
onChanged: (value) {
|
||||
initialBotOptions.customTriggerReactionEnabled = value ?? true;
|
||||
initialBotOptions.customTriggerReactionKey =
|
||||
"⏩"; // hard code this for now
|
||||
onChanged.call(initialBotOptions);
|
||||
},
|
||||
// make this input disabled always
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
import 'package:fluffychat/pangea/models/bot_options_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class ConversationBotDiscussionKeywordsInput extends StatelessWidget {
|
||||
final BotOptionsModel initialBotOptions;
|
||||
// call this to update propagate changes to parents
|
||||
final void Function(BotOptionsModel) onChanged;
|
||||
|
||||
const ConversationBotDiscussionKeywordsInput({
|
||||
super.key,
|
||||
required this.initialBotOptions,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String discussionKeywords = initialBotOptions.discussionKeywords ?? "";
|
||||
|
||||
final TextEditingController textFieldController =
|
||||
TextEditingController(text: discussionKeywords);
|
||||
|
||||
void setBotDiscussionKeywordsAction() async {
|
||||
showDialog(
|
||||
context: context,
|
||||
useRootNavigator: false,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: Text(
|
||||
L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionKeywordsLabel,
|
||||
),
|
||||
content: TextField(
|
||||
minLines: 1,
|
||||
maxLines: 10,
|
||||
maxLength: 1000,
|
||||
controller: textFieldController,
|
||||
onChanged: (value) {
|
||||
discussionKeywords = value;
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(L10n.of(context)!.cancel),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text(L10n.of(context)!.ok),
|
||||
onPressed: () {
|
||||
if (discussionKeywords == "") return;
|
||||
if (discussionKeywords !=
|
||||
initialBotOptions.discussionKeywords) {
|
||||
initialBotOptions.discussionKeywords = discussionKeywords;
|
||||
onChanged.call(initialBotOptions);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
onTap: setBotDiscussionKeywordsAction,
|
||||
title: Text(
|
||||
initialBotOptions.discussionKeywords ??
|
||||
L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionKeywordsPlaceholder,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
import 'package:fluffychat/pangea/models/bot_options_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class ConversationBotDiscussionTopicInput extends StatelessWidget {
|
||||
final BotOptionsModel initialBotOptions;
|
||||
// call this to update propagate changes to parents
|
||||
final void Function(BotOptionsModel) onChanged;
|
||||
|
||||
const ConversationBotDiscussionTopicInput({
|
||||
super.key,
|
||||
required this.initialBotOptions,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String discussionTopic = initialBotOptions.discussionTopic ?? "";
|
||||
|
||||
final TextEditingController textFieldController =
|
||||
TextEditingController(text: discussionTopic);
|
||||
|
||||
void setBotDiscussionTopicAction() async {
|
||||
showDialog(
|
||||
context: context,
|
||||
useRootNavigator: false,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: Text(
|
||||
L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionTopicLabel,
|
||||
),
|
||||
content: TextField(
|
||||
minLines: 1,
|
||||
maxLines: 10,
|
||||
maxLength: 1000,
|
||||
controller: textFieldController,
|
||||
onChanged: (value) {
|
||||
discussionTopic = value;
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(L10n.of(context)!.cancel),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text(L10n.of(context)!.ok),
|
||||
onPressed: () {
|
||||
if (discussionTopic == "") return;
|
||||
if (discussionTopic != initialBotOptions.discussionTopic) {
|
||||
initialBotOptions.discussionTopic = discussionTopic;
|
||||
onChanged.call(initialBotOptions);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
onTap: setBotDiscussionTopicAction,
|
||||
title: Text(
|
||||
initialBotOptions.discussionTopic ??
|
||||
L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionTopicPlaceholder,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
import 'package:fluffychat/pangea/models/bot_options_model.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_discussion_keywords_input.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_discussion_topic_input.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class ConversationBotDiscussionZone extends StatelessWidget {
|
||||
final BotOptionsModel initialBotOptions;
|
||||
// call this to update propagate changes to parents
|
||||
final void Function(BotOptionsModel) onChanged;
|
||||
|
||||
const ConversationBotDiscussionZone({
|
||||
super.key,
|
||||
required this.initialBotOptions,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
ConversationBotDynamicZoneTitle(
|
||||
title: L10n.of(context)!.conversationBotDiscussionZone_title,
|
||||
),
|
||||
ConversationBotDynamicZoneLabel(
|
||||
label: L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionTopicLabel,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: ConversationBotDiscussionTopicInput(
|
||||
initialBotOptions: initialBotOptions,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
ConversationBotDynamicZoneLabel(
|
||||
label: L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionKeywordsLabel,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: ConversationBotDiscussionKeywordsInput(
|
||||
initialBotOptions: initialBotOptions,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
CheckboxListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel,
|
||||
),
|
||||
enabled: false,
|
||||
value: initialBotOptions.discussionTriggerReactionEnabled ?? true,
|
||||
onChanged: (value) {
|
||||
initialBotOptions.discussionTriggerReactionEnabled = value ?? true;
|
||||
initialBotOptions.discussionTriggerReactionKey =
|
||||
"⏩"; // hard code this for now
|
||||
onChanged.call(initialBotOptions);
|
||||
},
|
||||
// make this input disabled always
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ConversationBotDynamicZoneLabel extends StatelessWidget {
|
||||
final String label;
|
||||
|
||||
const ConversationBotDynamicZoneLabel({
|
||||
super.key,
|
||||
required this.label,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12, 0, 0, 0),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ConversationBotDynamicZoneTitle extends StatelessWidget {
|
||||
final String title;
|
||||
|
||||
const ConversationBotDynamicZoneTitle({
|
||||
super.key,
|
||||
required this.title,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
color: Colors.grey,
|
||||
thickness: 1,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +1,77 @@
|
|||
import 'package:fluffychat/pangea/constants/bot_mode.dart';
|
||||
import 'package:fluffychat/pangea/models/bot_options_model.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'conversation_bot_discussion_zone.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class ConversationBotModeDynamicZone extends StatelessWidget {
|
||||
final BotOptionsModel initialBotOptions;
|
||||
final void Function(BotOptionsModel) onChanged;
|
||||
final GlobalKey<FormState> formKey;
|
||||
|
||||
final TextEditingController discussionTopicController;
|
||||
final TextEditingController discussionKeywordsController;
|
||||
final TextEditingController customSystemPromptController;
|
||||
|
||||
const ConversationBotModeDynamicZone({
|
||||
super.key,
|
||||
required this.initialBotOptions,
|
||||
required this.onChanged,
|
||||
required this.formKey,
|
||||
required this.discussionTopicController,
|
||||
required this.discussionKeywordsController,
|
||||
required this.customSystemPromptController,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final zoneMap = {
|
||||
BotMode.discussion: ConversationBotDiscussionZone(
|
||||
initialBotOptions: initialBotOptions,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
BotMode.custom: ConversationBotCustomZone(
|
||||
initialBotOptions: initialBotOptions,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
};
|
||||
if (!zoneMap.containsKey(initialBotOptions.mode)) {
|
||||
return Container();
|
||||
}
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
width: 0.5,
|
||||
final discussionChildren = [
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
hintText: L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionTopicPlaceholder,
|
||||
),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||
controller: discussionTopicController,
|
||||
validator: (value) => value == null || value.isEmpty
|
||||
? L10n.of(context)!.enterDiscussionTopic
|
||||
: null,
|
||||
),
|
||||
child: zoneMap[initialBotOptions.mode],
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
hintText: L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionKeywordsPlaceholder,
|
||||
),
|
||||
controller: discussionKeywordsController,
|
||||
),
|
||||
];
|
||||
|
||||
final customChildren = [
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
hintText: L10n.of(context)!
|
||||
.conversationBotCustomZone_customSystemPromptPlaceholder,
|
||||
),
|
||||
validator: (value) => value == null || value.isEmpty
|
||||
? L10n.of(context)!.enterPrompt
|
||||
: null,
|
||||
controller: customSystemPromptController,
|
||||
),
|
||||
];
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
if (initialBotOptions.mode == BotMode.discussion) ...discussionChildren,
|
||||
if (initialBotOptions.mode == BotMode.custom) ...customChildren,
|
||||
const SizedBox(height: 12),
|
||||
CheckboxListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!
|
||||
.conversationBotCustomZone_customTriggerReactionEnabledLabel,
|
||||
),
|
||||
enabled: false,
|
||||
value: initialBotOptions.customTriggerReactionEnabled ?? true,
|
||||
onChanged: null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,56 +24,35 @@ class ConversationBotModeSelect extends StatelessWidget {
|
|||
// L10n.of(context)!.conversationBotModeSelectOption_storyGame,
|
||||
};
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
width: 0.5,
|
||||
),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||
),
|
||||
child: DropdownButton(
|
||||
// Initial Value
|
||||
hint: Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
String? mode = initialMode;
|
||||
if (!options.containsKey(initialMode)) {
|
||||
mode = null;
|
||||
}
|
||||
|
||||
return DropdownButtonFormField(
|
||||
// Initial Value
|
||||
hint: Text(
|
||||
options[mode ?? BotMode.discussion]!,
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
// ),
|
||||
isExpanded: true,
|
||||
// Down Arrow Icon
|
||||
icon: const Icon(Icons.keyboard_arrow_down),
|
||||
// Array list of items
|
||||
items: [
|
||||
for (final entry in options.entries)
|
||||
DropdownMenuItem(
|
||||
value: entry.key,
|
||||
child: Text(
|
||||
options[initialMode ?? BotMode.discussion]!,
|
||||
style: const TextStyle().copyWith(
|
||||
color: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
fontSize: 14,
|
||||
),
|
||||
entry.value,
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
isExpanded: true,
|
||||
underline: Container(),
|
||||
// Down Arrow Icon
|
||||
icon: const Icon(Icons.keyboard_arrow_down),
|
||||
// Array list of items
|
||||
items: [
|
||||
for (final entry in options.entries)
|
||||
DropdownMenuItem(
|
||||
value: entry.key,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Text(
|
||||
entry.value,
|
||||
style: const TextStyle().copyWith(
|
||||
color: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
fontSize: 14,
|
||||
),
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
onChanged: onChanged,
|
||||
),
|
||||
),
|
||||
],
|
||||
onChanged: onChanged,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,13 @@ class ConversationBotSettingsState extends State<ConversationBotSettings> {
|
|||
|
||||
ConversationBotSettingsState({Key? key});
|
||||
|
||||
final TextEditingController discussionTopicController =
|
||||
TextEditingController();
|
||||
final TextEditingController discussionKeywordsController =
|
||||
TextEditingController();
|
||||
final TextEditingController customSystemPromptController =
|
||||
TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
|
@ -55,6 +62,10 @@ class ConversationBotSettingsState extends State<ConversationBotSettings> {
|
|||
? Matrix.of(context).client.getRoomById(widget.activeSpaceId!)
|
||||
: null;
|
||||
isCreating = widget.room == null;
|
||||
|
||||
discussionKeywordsController.text = botOptions.discussionKeywords ?? "";
|
||||
discussionTopicController.text = botOptions.discussionTopic ?? "";
|
||||
customSystemPromptController.text = botOptions.customSystemPrompt ?? "";
|
||||
}
|
||||
|
||||
Future<void> setBotOption() async {
|
||||
|
|
@ -88,6 +99,109 @@ class ConversationBotSettingsState extends State<ConversationBotSettings> {
|
|||
);
|
||||
}
|
||||
|
||||
void updateAllBotOptions() {
|
||||
botOptions.discussionTopic = discussionTopicController.text;
|
||||
botOptions.discussionKeywords = discussionKeywordsController.text;
|
||||
botOptions.customSystemPrompt = customSystemPromptController.text;
|
||||
}
|
||||
|
||||
Future<void> showBotOptionsDialog() async {
|
||||
if (isCreating) return;
|
||||
final bool? confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) => Dialog(
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 450,
|
||||
maxHeight: 725,
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
child: ConversationBotSettingsDialog(
|
||||
addBot: addBot,
|
||||
botOptions: botOptions,
|
||||
formKey: formKey,
|
||||
updateAddBot: (bool value) =>
|
||||
setState(() => addBot = value),
|
||||
discussionKeywordsController: discussionKeywordsController,
|
||||
discussionTopicController: discussionTopicController,
|
||||
customSystemPromptController: customSystemPromptController,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (confirm == true) {
|
||||
updateAllBotOptions();
|
||||
updateBotOption(() => botOptions = botOptions);
|
||||
|
||||
final bool isBotRoomMember = await widget.room?.botIsInRoom ?? false;
|
||||
if (addBot && !isBotRoomMember) {
|
||||
await widget.room?.invite(BotName.byEnvironment);
|
||||
} else if (!addBot && isBotRoomMember) {
|
||||
await widget.room?.kick(BotName.byEnvironment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showNewRoomBotOptionsDialog() async {
|
||||
final bool? confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: addBot
|
||||
? Text(
|
||||
L10n.of(context)!.addConversationBotButtonTitleRemove,
|
||||
)
|
||||
: Text(
|
||||
L10n.of(context)!.addConversationBotDialogTitleInvite,
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
child: Text(L10n.of(context)!.cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(!addBot);
|
||||
},
|
||||
child: addBot
|
||||
? Text(
|
||||
L10n.of(context)!
|
||||
.addConversationBotDialogRemoveConfirmation,
|
||||
)
|
||||
: Text(
|
||||
L10n.of(context)!
|
||||
.addConversationBotDialogInviteConfirmation,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (confirm == true) {
|
||||
setState(() => addBot = true);
|
||||
widget.room?.invite(BotName.byEnvironment);
|
||||
} else {
|
||||
setState(() => addBot = false);
|
||||
widget.room?.kick(BotName.byEnvironment);
|
||||
}
|
||||
}
|
||||
|
||||
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedContainer(
|
||||
|
|
@ -119,162 +233,137 @@ class ConversationBotSettingsState extends State<ConversationBotSettings> {
|
|||
),
|
||||
trailing: isCreating
|
||||
? ElevatedButton(
|
||||
onPressed: () async {
|
||||
final bool? confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: addBot
|
||||
? Text(
|
||||
L10n.of(context)!
|
||||
.addConversationBotButtonTitleRemove,
|
||||
)
|
||||
: Text(
|
||||
L10n.of(context)!
|
||||
.addConversationBotDialogTitleInvite,
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
child: Text(L10n.of(context)!.cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(!addBot);
|
||||
},
|
||||
child: addBot
|
||||
? Text(
|
||||
L10n.of(context)!
|
||||
.addConversationBotDialogRemoveConfirmation,
|
||||
)
|
||||
: Text(
|
||||
L10n.of(context)!
|
||||
.addConversationBotDialogInviteConfirmation,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (confirm == true) {
|
||||
setState(() => addBot = true);
|
||||
widget.room?.invite(BotName.byEnvironment);
|
||||
} else {
|
||||
setState(() => addBot = false);
|
||||
widget.room?.kick(BotName.byEnvironment);
|
||||
}
|
||||
},
|
||||
child: addBot
|
||||
? Text(
|
||||
L10n.of(context)!.addConversationBotButtonRemove,
|
||||
)
|
||||
: Text(
|
||||
L10n.of(context)!.addConversationBotButtonInvite,
|
||||
),
|
||||
onPressed: showNewRoomBotOptionsDialog,
|
||||
child: Text(
|
||||
addBot
|
||||
? L10n.of(context)!.addConversationBotButtonRemove
|
||||
: L10n.of(context)!.addConversationBotButtonInvite,
|
||||
),
|
||||
)
|
||||
: const Icon(Icons.settings),
|
||||
onTap: isCreating
|
||||
? null
|
||||
: () async {
|
||||
final bool? confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) => AlertDialog(
|
||||
title: Text(
|
||||
L10n.of(context)!.botConfig,
|
||||
),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.fromLTRB(0, 0, 0, 12),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
L10n.of(context)!.conversationBotStatus,
|
||||
),
|
||||
Switch(
|
||||
value: addBot,
|
||||
onChanged: (value) {
|
||||
setState(
|
||||
() => addBot = value,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (addBot)
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
width: 0.5,
|
||||
),
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(10),
|
||||
),
|
||||
),
|
||||
child: ConversationBotSettingsForm(
|
||||
botOptions: botOptions,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
child: Text(L10n.of(context)!.cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
child: Text(
|
||||
L10n.of(context)!
|
||||
.conversationBotConfigConfirmChange,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
if (confirm == true) {
|
||||
updateBotOption(() {
|
||||
botOptions = botOptions;
|
||||
});
|
||||
final bool isBotRoomMember =
|
||||
await widget.room?.botIsInRoom ?? false;
|
||||
if (addBot && !isBotRoomMember) {
|
||||
await widget.room?.invite(BotName.byEnvironment);
|
||||
} else if (!addBot && isBotRoomMember) {
|
||||
await widget.room?.kick(BotName.byEnvironment);
|
||||
}
|
||||
}
|
||||
},
|
||||
onTap: showBotOptionsDialog,
|
||||
),
|
||||
if (isCreating && addBot)
|
||||
ConversationBotSettingsForm(
|
||||
botOptions: botOptions,
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Text(
|
||||
L10n.of(context)!.botConfig,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
),
|
||||
Form(
|
||||
key: formKey,
|
||||
child: ConversationBotSettingsForm(
|
||||
botOptions: botOptions,
|
||||
formKey: formKey,
|
||||
discussionKeywordsController:
|
||||
discussionKeywordsController,
|
||||
discussionTopicController: discussionTopicController,
|
||||
customSystemPromptController:
|
||||
customSystemPromptController,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ConversationBotSettingsDialog extends StatelessWidget {
|
||||
final bool addBot;
|
||||
final BotOptionsModel botOptions;
|
||||
final GlobalKey<FormState> formKey;
|
||||
|
||||
final void Function(bool) updateAddBot;
|
||||
|
||||
final TextEditingController discussionTopicController;
|
||||
final TextEditingController discussionKeywordsController;
|
||||
final TextEditingController customSystemPromptController;
|
||||
|
||||
const ConversationBotSettingsDialog({
|
||||
super.key,
|
||||
required this.addBot,
|
||||
required this.botOptions,
|
||||
required this.formKey,
|
||||
required this.updateAddBot,
|
||||
required this.discussionTopicController,
|
||||
required this.discussionKeywordsController,
|
||||
required this.customSystemPromptController,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 12,
|
||||
),
|
||||
child: Text(
|
||||
L10n.of(context)!.botConfig,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.conversationBotStatus,
|
||||
),
|
||||
value: addBot,
|
||||
onChanged: updateAddBot,
|
||||
contentPadding: const EdgeInsets.all(4),
|
||||
),
|
||||
if (addBot)
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
ConversationBotSettingsForm(
|
||||
botOptions: botOptions,
|
||||
formKey: formKey,
|
||||
discussionKeywordsController: discussionKeywordsController,
|
||||
discussionTopicController: discussionTopicController,
|
||||
customSystemPromptController: customSystemPromptController,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
child: Text(L10n.of(context)!.cancel),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
final isValid = formKey.currentState!.validate();
|
||||
if (!isValid) return;
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
child: Text(L10n.of(context)!.confirm),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,25 @@ import 'package:fluffychat/pangea/models/bot_options_model.dart';
|
|||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart';
|
||||
import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class ConversationBotSettingsForm extends StatefulWidget {
|
||||
final BotOptionsModel botOptions;
|
||||
final GlobalKey<FormState> formKey;
|
||||
|
||||
final TextEditingController discussionTopicController;
|
||||
final TextEditingController discussionKeywordsController;
|
||||
final TextEditingController customSystemPromptController;
|
||||
|
||||
const ConversationBotSettingsForm({
|
||||
super.key,
|
||||
required this.botOptions,
|
||||
required this.formKey,
|
||||
required this.discussionTopicController,
|
||||
required this.discussionKeywordsController,
|
||||
required this.customSystemPromptController,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -21,8 +31,6 @@ class ConversationBotSettingsForm extends StatefulWidget {
|
|||
|
||||
class ConversationBotSettingsFormState
|
||||
extends State<ConversationBotSettingsForm> {
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
late BotOptionsModel botOptions;
|
||||
|
||||
@override
|
||||
|
|
@ -35,17 +43,48 @@ class ConversationBotSettingsFormState
|
|||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Text(
|
||||
L10n.of(context)!.conversationLanguageLevel,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
DropdownButtonFormField(
|
||||
// Initial Value
|
||||
hint: Text(
|
||||
L10n.of(context)!.selectBotLanguage,
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
value: botOptions.targetLanguage,
|
||||
isExpanded: true,
|
||||
icon: const Icon(Icons.keyboard_arrow_down),
|
||||
items: MatrixState.pangeaController.pLanguageStore.targetOptions
|
||||
.map((language) {
|
||||
return DropdownMenuItem(
|
||||
value: language.langCode,
|
||||
child: Text(
|
||||
language.getDisplayName(context) ?? language.langCode,
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (String? newValue) => {
|
||||
setState(() => botOptions.targetLanguage = newValue!),
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
DropdownButtonFormField<String>(
|
||||
// Initial Value
|
||||
hint: Text(
|
||||
L10n.of(context)!.chooseVoice,
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
value: botOptions.targetVoice,
|
||||
isExpanded: true,
|
||||
icon: const Icon(Icons.keyboard_arrow_down),
|
||||
items: const [],
|
||||
onChanged: (String? newValue) => {
|
||||
setState(() => botOptions.targetVoice = newValue!),
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
LanguageLevelDropdown(
|
||||
initialLevel: botOptions.languageLevel,
|
||||
onChanged: (int? newValue) => {
|
||||
|
|
@ -53,13 +92,18 @@ class ConversationBotSettingsFormState
|
|||
botOptions.languageLevel = newValue!;
|
||||
}),
|
||||
},
|
||||
validator: (value) =>
|
||||
value == null ? L10n.of(context)!.enterLanguageLevel : null,
|
||||
),
|
||||
Text(
|
||||
L10n.of(context)!.conversationBotModeSelectDescription,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
const SizedBox(height: 12),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Text(
|
||||
L10n.of(context)!.conversationBotModeSelectDescription,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
),
|
||||
ConversationBotModeSelect(
|
||||
|
|
@ -70,18 +114,13 @@ class ConversationBotSettingsFormState
|
|||
}),
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: ConversationBotModeDynamicZone(
|
||||
initialBotOptions: botOptions,
|
||||
onChanged: (BotOptionsModel? newOptions) {
|
||||
if (newOptions != null) {
|
||||
setState(() {
|
||||
botOptions = newOptions;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
ConversationBotModeDynamicZone(
|
||||
initialBotOptions: botOptions,
|
||||
discussionTopicController: widget.discussionTopicController,
|
||||
discussionKeywordsController: widget.discussionKeywordsController,
|
||||
customSystemPromptController: widget.customSystemPromptController,
|
||||
formKey: widget.formKey,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import 'package:fluffychat/pangea/models/bot_options_model.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_text_adventure_game_master_instruction_input.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
// TODO check how this looks
|
||||
class ConversationBotTextAdventureZone extends StatelessWidget {
|
||||
final BotOptionsModel initialBotOptions;
|
||||
// call this to update propagate changes to parents
|
||||
|
|
@ -20,13 +18,6 @@ class ConversationBotTextAdventureZone extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
ConversationBotDynamicZoneTitle(
|
||||
title: L10n.of(context)!.conversationBotTextAdventureZone_title,
|
||||
),
|
||||
ConversationBotDynamicZoneLabel(
|
||||
label: L10n.of(context)!
|
||||
.conversationBotTextAdventureZone_instructionLabel,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: ConversationBotGameMasterInstructionsInput(
|
||||
|
|
|
|||
|
|
@ -6,71 +6,44 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||
class LanguageLevelDropdown extends StatelessWidget {
|
||||
final int? initialLevel;
|
||||
final void Function(int?)? onChanged;
|
||||
final String? Function(int?)? validator;
|
||||
|
||||
const LanguageLevelDropdown({
|
||||
super.key,
|
||||
this.initialLevel,
|
||||
this.onChanged,
|
||||
this.validator,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
width: 0.5,
|
||||
),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||
),
|
||||
child: DropdownButton(
|
||||
// Initial Value
|
||||
hint: Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Text(
|
||||
initialLevel == null
|
||||
? L10n.of(context)!.selectLanguageLevel
|
||||
: LanguageLevelTextPicker.languageLevelText(
|
||||
context,
|
||||
initialLevel!,
|
||||
),
|
||||
style: const TextStyle().copyWith(
|
||||
color: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
fontSize: 14,
|
||||
),
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
isExpanded: true,
|
||||
underline: Container(),
|
||||
// Down Arrow Icon
|
||||
icon: const Icon(Icons.keyboard_arrow_down),
|
||||
// Array list of items
|
||||
items: LanguageLevelType.allInts.map((int levelOption) {
|
||||
return DropdownMenuItem(
|
||||
value: levelOption,
|
||||
child: Text(
|
||||
LanguageLevelTextPicker.languageLevelText(
|
||||
context,
|
||||
levelOption,
|
||||
),
|
||||
style: const TextStyle().copyWith(
|
||||
color: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
fontSize: 14,
|
||||
),
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
// After selecting the desired option,it will
|
||||
// change button value to selected value
|
||||
onChanged: onChanged,
|
||||
),
|
||||
return DropdownButtonFormField(
|
||||
// Initial Value
|
||||
hint: Text(
|
||||
L10n.of(context)!.selectLanguageLevel,
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
value: initialLevel,
|
||||
isExpanded: true,
|
||||
// Down Arrow Icon
|
||||
icon: const Icon(Icons.keyboard_arrow_down),
|
||||
// Array list of items
|
||||
items: LanguageLevelType.allInts.map((int levelOption) {
|
||||
return DropdownMenuItem(
|
||||
value: levelOption,
|
||||
child: Text(
|
||||
LanguageLevelTextPicker.languageLevelText(
|
||||
context,
|
||||
levelOption,
|
||||
),
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: onChanged,
|
||||
validator: validator,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue