button to run IGC manually

pull/1183/head
ggurdin 1 year ago
parent c0c0a9c6a8
commit a077cc4f6a

@ -3948,5 +3948,10 @@
"studentAnalyticsNotAvailable": "Student data not currently available",
"roomDataMissing": "Some data may be missing from rooms in which you are not a member.",
"updatePhoneOS": "You may need to update your device's OS version.",
"wordsPerMinute": "Words per minute"
"wordsPerMinute": "Words per minute",
"autoIGCToolName": "Run Language Assistance Automatically",
"autoIGCToolDescription": "Automatically run language assistance after typing messages",
"runGrammarCorrection": "Run grammar correction",
"grammarCorrectionFailed": "Grammar correction failed",
"grammarCorrectionComplete": "Grammar correction complete"
}

@ -9,6 +9,7 @@ import 'package:fluffychat/pages/chat/reactions_picker.dart';
import 'package:fluffychat/pages/chat/reply_display.dart';
import 'package:fluffychat/pangea/choreographer/widgets/has_error_button.dart';
import 'package:fluffychat/pangea/choreographer/widgets/language_permissions_warning_buttons.dart';
import 'package:fluffychat/pangea/choreographer/widgets/start_igc_button.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/pages/class_analytics/measure_able.dart';
import 'package:fluffychat/utils/account_config.dart';
@ -416,8 +417,8 @@ class ChatView extends StatelessWidget {
// #Pangea
// if (controller.dragging)
// Container(
// color: Theme.of(context)
// .scaffoldBackgroundColor
// color: Theme.of(context)
// .scaffoldBackgroundColor
// .withOpacity(0.9),
// alignment: Alignment.center,
// child: const Icon(
@ -425,6 +426,11 @@ class ChatView extends StatelessWidget {
// size: 100,
// ),
// ),
Positioned(
left: 20,
bottom: 75,
child: StartIGCButton(controller: controller),
),
// Pangea#
],
),

@ -51,7 +51,7 @@ class Choreographer {
// last checked by IGC or translation
String? _lastChecked;
ChoreoMode choreoMode = ChoreoMode.igc;
final StreamController stateListener = StreamController();
final StreamController stateListener = StreamController.broadcast();
StreamSubscription? trialStream;
Choreographer(this.pangeaController, this.chatController) {
@ -205,14 +205,18 @@ class Choreographer {
textController.editType = EditType.keyboard;
}
Future<void> getLanguageHelp([bool tokensOnly = false]) async {
Future<void> getLanguageHelp([
bool tokensOnly = false,
bool manual = false,
]) async {
try {
if (errorService.isError) return;
final CanSendStatus canSendStatus =
pangeaController.subscriptionController.canSendStatus;
if (canSendStatus != CanSendStatus.subscribed ||
(!igcEnabled && !itEnabled)) {
(!igcEnabled && !itEnabled) ||
(!isAutoIGCEnabled && !manual && choreoMode != ChoreoMode.it)) {
return;
}
@ -535,4 +539,40 @@ class Choreographer {
pangeaController.permissionsController.isWritingAssistanceEnabled(
chatController.room,
);
bool get isAutoIGCEnabled =>
pangeaController.permissionsController.isToolEnabled(
ToolSetting.autoIGC,
chatController.room,
);
AssistanceState get assistanceState {
if (currentText.isEmpty && itController.sourceText == null) {
return AssistanceState.noMessage;
}
if (igc.igcTextData?.matches.isNotEmpty ?? false) {
return AssistanceState.fetched;
}
if (isFetching) {
return AssistanceState.fetching;
}
if (igc.igcTextData == null) {
return AssistanceState.notFetched;
}
return AssistanceState.complete;
}
}
// assistance state is, user has not typed a message, user has typed a message and IGC has not run,
// IGC is running, IGC has run and there are remaining steps (either IT or IGC), or all steps are done
enum AssistanceState {
noMessage,
notFetched,
fetching,
fetched,
complete,
}

@ -1,8 +1,7 @@
import 'package:fluffychat/pangea/constants/colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/pangea/constants/colors.dart';
import '../../../pages/chat/chat.dart';
class ChoreographerSendButton extends StatelessWidget {
@ -16,7 +15,8 @@ class ChoreographerSendButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
// commit for cicd
return controller.choreographer.isFetching
return controller.choreographer.isFetching &&
controller.choreographer.isAutoIGCEnabled
? Container(
height: 56,
width: 56,
@ -28,7 +28,8 @@ class ChoreographerSendButton extends StatelessWidget {
alignment: Alignment.center,
child: IconButton(
icon: const Icon(Icons.send_outlined),
color: controller.choreographer.igc.canSendMessage
color: controller.choreographer.igc.canSendMessage ||
!controller.choreographer.isAutoIGCEnabled
? null
: PangeaColors.igcError,
onPressed: () {

@ -0,0 +1,150 @@
import 'dart:async';
import 'dart:math' as math;
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
import 'package:fluffychat/pangea/constants/colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../../../pages/chat/chat.dart';
class StartIGCButton extends StatefulWidget {
const StartIGCButton({
super.key,
required this.controller,
});
final ChatController controller;
@override
State<StartIGCButton> createState() => StartIGCButtonState();
}
class StartIGCButtonState extends State<StartIGCButton>
with SingleTickerProviderStateMixin {
AssistanceState get assistanceState =>
widget.controller.choreographer.assistanceState;
AnimationController? _controller;
StreamSubscription? choreoListener;
AssistanceState? prevState;
@override
void initState() {
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
choreoListener = widget.controller.choreographer.stateListener.stream
.listen(updateSpinnerState);
super.initState();
}
void updateSpinnerState(_) {
if (prevState != AssistanceState.fetching &&
assistanceState == AssistanceState.fetching) {
_controller?.repeat();
} else if (prevState == AssistanceState.fetching &&
assistanceState != AssistanceState.fetching) {
_controller?.stop();
_controller?.reverse();
}
setState(() => prevState = assistanceState);
}
@override
Widget build(BuildContext context) {
if (widget.controller.choreographer.isAutoIGCEnabled) {
return const SizedBox.shrink();
}
final Widget icon = Icon(
Icons.autorenew_rounded,
size: 46,
color: assistanceState.stateColor,
);
return SizedBox(
height: 50,
width: 50,
child: FloatingActionButton(
tooltip: assistanceState.tooltip(
L10n.of(context)!,
),
backgroundColor: Colors.white,
disabledElevation: 0,
shape: const CircleBorder(),
onPressed: () {
if (assistanceState != AssistanceState.complete) {
widget.controller.choreographer.getLanguageHelp(
false,
true,
);
}
},
child: Stack(
alignment: Alignment.center,
children: [
_controller != null
? RotationTransition(
turns: Tween(begin: 0.0, end: math.pi * 2)
.animate(_controller!),
child: icon,
)
: icon,
Container(
width: 26,
height: 26,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
),
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: assistanceState.stateColor,
),
),
const Icon(
size: 16,
Icons.check,
color: Colors.white,
),
],
),
),
);
}
}
extension AssistanceStateExtension on AssistanceState {
Color get stateColor {
switch (this) {
case AssistanceState.noMessage:
case AssistanceState.notFetched:
case AssistanceState.fetching:
return AppConfig.primaryColor;
case AssistanceState.fetched:
return PangeaColors.igcError;
case AssistanceState.complete:
return AppConfig.success;
}
}
String tooltip(L10n l10n) {
switch (this) {
case AssistanceState.noMessage:
case AssistanceState.notFetched:
return l10n.runGrammarCorrection;
case AssistanceState.fetching:
return "";
case AssistanceState.fetched:
return l10n.grammarCorrectionFailed;
case AssistanceState.complete:
return l10n.grammarCorrectionComplete;
}
}
}

@ -1,13 +1,12 @@
import 'dart:developer';
import 'package:fluffychat/pangea/constants/model_keys.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/constants/model_keys.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import '../constants/class_default_values.dart';
import '../constants/language_keys.dart';
import '../constants/pangea_event_types.dart';
@ -124,6 +123,7 @@ class PangeaRoomRules {
int immersionMode;
int definitions;
int translations;
int autoIGC;
PangeaRoomRules({
this.isPublic = false,
@ -142,6 +142,7 @@ class PangeaRoomRules {
this.immersionMode = ClassDefaultValues.languageToolPermissions,
this.definitions = ClassDefaultValues.languageToolPermissions,
this.translations = ClassDefaultValues.languageToolPermissions,
this.autoIGC = ClassDefaultValues.languageToolPermissions,
});
updatePermission(String key, bool value) {
@ -201,6 +202,9 @@ class PangeaRoomRules {
case ToolSetting.translations:
translations = value;
break;
case ToolSetting.autoIGC:
autoIGC = value;
break;
default:
throw Exception('Invalid key for setting permissions - $setting');
}
@ -235,6 +239,7 @@ class PangeaRoomRules {
json['definitions'] ?? ClassDefaultValues.languageToolPermissions,
translations:
json['translations'] ?? ClassDefaultValues.languageToolPermissions,
autoIGC: json['auto_igc'] ?? ClassDefaultValues.languageToolPermissions,
);
Map<String, dynamic> toJson() {
@ -256,6 +261,7 @@ class PangeaRoomRules {
data['immersion_mode'] = immersionMode;
data['definitions'] = definitions;
data['translations'] = translations;
data['auto_igc'] = autoIGC;
return data;
}
@ -271,6 +277,8 @@ class PangeaRoomRules {
return definitions;
case ToolSetting.translations:
return translations;
case ToolSetting.autoIGC:
return autoIGC;
default:
throw Exception('Invalid key for setting permissions - $setting');
}
@ -299,6 +307,7 @@ enum ToolSetting {
immersionMode,
definitions,
translations,
autoIGC,
}
extension SettingCopy on ToolSetting {
@ -314,6 +323,8 @@ extension SettingCopy on ToolSetting {
return L10n.of(context)!.definitionsToolName;
case ToolSetting.translations:
return L10n.of(context)!.messageTranslationsToolName;
case ToolSetting.autoIGC:
return L10n.of(context)!.autoIGCToolName;
}
}
@ -330,6 +341,8 @@ extension SettingCopy on ToolSetting {
return L10n.of(context)!.definitionsToolDescription;
case ToolSetting.translations:
return L10n.of(context)!.translationsToolDescrption;
case ToolSetting.autoIGC:
return L10n.of(context)!.autoIGCToolDescription;
}
}
}

@ -68,6 +68,7 @@ enum MatrixProfile {
sourceLanguage,
country,
publicProfile,
autoIGC,
}
extension MatrixProfileExtension on MatrixProfile {
@ -89,6 +90,8 @@ extension MatrixProfileExtension on MatrixProfile {
return ToolSetting.definitions.toString();
case MatrixProfile.translations:
return ToolSetting.translations.toString();
case MatrixProfile.autoIGC:
return ToolSetting.autoIGC.toString();
case MatrixProfile.showedItInstructions:
return InstructionsEnum.itInstructions.toString();
case MatrixProfile.showedClickMessage:

Loading…
Cancel
Save