diff --git a/lib/pangea/choreographer/controllers/it_controller.dart b/lib/pangea/choreographer/controllers/it_controller.dart index 83d678e98..6d5f8e347 100644 --- a/lib/pangea/choreographer/controllers/it_controller.dart +++ b/lib/pangea/choreographer/controllers/it_controller.dart @@ -28,6 +28,7 @@ class ITController { String? sourceText; List completedITSteps = []; CurrentITStep? currentITStep; + CurrentITStep? nextITStep; GoldRouteTracker goldRouteTracker = GoldRouteTracker.defaultTracker; List payLoadIds = []; @@ -42,6 +43,7 @@ class ITController { sourceText = null; completedITSteps = []; currentITStep = null; + nextITStep = null; goldRouteTracker = GoldRouteTracker.defaultTracker; payLoadIds = []; @@ -130,36 +132,75 @@ class ITController { ); } - currentITStep = null; + if (nextITStep == null) { + currentITStep = null; - final ITResponseModel res = await _customInputTranslation(currentText); - // final ITResponseModel res = await (useCustomInput || - // currentText.isEmpty || - // translationId == null || - // completedITSteps.last.chosenContinuance?.indexSavedByServer == - // null - // ? _customInputTranslation(currentText) - // : _systemChoiceTranslation(translationId)); + final ITResponseModel res = await _customInputTranslation(currentText); + // final ITResponseModel res = await (useCustomInput || + // currentText.isEmpty || + // translationId == null || + // completedITSteps.last.chosenContinuance?.indexSavedByServer == + // null + // ? _customInputTranslation(currentText) + // : _systemChoiceTranslation(translationId)); - if (res.goldContinuances != null && res.goldContinuances!.isNotEmpty) { - goldRouteTracker = GoldRouteTracker( - res.goldContinuances!, - sourceText!, + if (res.goldContinuances != null && res.goldContinuances!.isNotEmpty) { + goldRouteTracker = GoldRouteTracker( + res.goldContinuances!, + sourceText!, + ); + } + + currentITStep = CurrentITStep( + sourceText: sourceText!, + currentText: currentText, + responseModel: res, + storedGoldContinuances: goldRouteTracker.continuances, ); + + _addPayloadId(res); + } else { + currentITStep = nextITStep; + nextITStep = null; } - currentITStep = CurrentITStep( - sourceText: sourceText!, - currentText: currentText, - responseModel: res, - storedGoldContinuances: goldRouteTracker.continuances, - ); - - _addPayloadId(res); - if (isTranslationDone) { choreographer.altTranslator.setTranslationFeedback(); choreographer.getLanguageHelp(true); + } else { + getNextTranslationData(); + } + } catch (e, s) { + debugger(when: kDebugMode); + if (e is! http.Response) { + ErrorHandler.logError(e: e, s: s); + } + choreographer.errorService.setErrorAndLock( + ChoreoError(type: ChoreoErrorType.unknown, raw: e), + ); + } finally { + choreographer.stopLoading(); + } + } + + FuturegetNextTranslationData() async { + try { + if (completedITSteps.length < goldRouteTracker.continuances.length) { + final String currentText = choreographer.currentText; + final String nextText = + goldRouteTracker.continuances[completedITSteps.length].text; + + final ITResponseModel res = + await _customInputTranslation(currentText + nextText); + + nextITStep = CurrentITStep( + sourceText: sourceText!, + currentText: nextText, + responseModel: res, + storedGoldContinuances: goldRouteTracker.continuances, + ); + } else { + nextITStep = null; } } catch (e, s) { debugger(when: kDebugMode); diff --git a/lib/pangea/choreographer/widgets/choice_array.dart b/lib/pangea/choreographer/widgets/choice_array.dart index ca3f3bf7d..7a2efe72b 100644 --- a/lib/pangea/choreographer/widgets/choice_array.dart +++ b/lib/pangea/choreographer/widgets/choice_array.dart @@ -1,4 +1,5 @@ import 'dart:developer'; +import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -86,45 +87,48 @@ class ChoiceItem extends StatelessWidget { waitDuration: onLongPress != null ? const Duration(milliseconds: 500) : const Duration(days: 1), - child: Container( - margin: const EdgeInsets.all(2), - padding: EdgeInsets.zero, - decoration: isSelected - ? BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(10)), - border: Border.all( - color: entry.value.color ?? theme.colorScheme.primary, - style: BorderStyle.solid, - width: 2.0, + child: SelectiveRotatingWidget( + selected: entry.value.color != null, + child: Container( + margin: const EdgeInsets.all(2), + padding: EdgeInsets.zero, + decoration: isSelected + ? BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(10)), + border: Border.all( + color: entry.value.color ?? theme.colorScheme.primary, + style: BorderStyle.solid, + width: 2.0, + ), + ) + : null, + child: TextButton( + style: ButtonStyle( + padding: MaterialStateProperty.all( + const EdgeInsets.symmetric(horizontal: 7), + ), + //if index is selected, then give the background a slight primary color + backgroundColor: MaterialStateProperty.all( + entry.value.color != null + ? entry.value.color!.withOpacity(0.2) + : theme.colorScheme.primary.withOpacity(0.1), + ), + textStyle: MaterialStateProperty.all( + BotStyle.text(context), + ), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), ), - ) - : null, - child: TextButton( - style: ButtonStyle( - padding: MaterialStateProperty.all( - const EdgeInsets.symmetric(horizontal: 7), - ), - //if index is selected, then give the background a slight primary color - backgroundColor: MaterialStateProperty.all( - entry.value.color != null - ? entry.value.color!.withOpacity(0.2) - : theme.colorScheme.primary.withOpacity(0.1), - ), - textStyle: MaterialStateProperty.all( - BotStyle.text(context), - ), - shape: MaterialStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), ), ), - ), - onLongPress: - onLongPress != null ? () => onLongPress!(entry.key) : null, - onPressed: () => onPressed(entry.key), - child: Text( - entry.value.text, - style: BotStyle.text(context), + onLongPress: + onLongPress != null ? () => onLongPress!(entry.key) : null, + onPressed: () => onPressed(entry.key), + child: Text( + entry.value.text, + style: BotStyle.text(context), + ), ), ), ), @@ -135,3 +139,80 @@ class ChoiceItem extends StatelessWidget { } } } + +class SelectiveRotatingWidget extends StatefulWidget { + final Widget child; + final bool selected; + + const SelectiveRotatingWidget({super.key, required this.child, required this.selected}); + + @override + SelectiveRotatingWidgetState createState() => SelectiveRotatingWidgetState(); +} + +class SelectiveRotatingWidgetState extends State with SingleTickerProviderStateMixin { + late final AnimationController _controller; + late final Animation _animation; + + @override + void initState() { + super.initState(); + + _controller = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); + + _animation = TweenSequence([ + TweenSequenceItem( + tween: Tween(begin: 0, end: -8 * pi / 180), + weight: 1.0, + ), + TweenSequenceItem( + tween: Tween(begin: -8 * pi / 180, end: 16 * pi / 180), + weight: 2.0, + ), + TweenSequenceItem( + tween: Tween(begin: 16 * pi / 180, end: 0), + weight: 1.0, + ), + ]).animate(_controller); + + if (widget.selected) { + _controller.repeat(reverse: true); + } + } + + @override + void didUpdateWidget(SelectiveRotatingWidget oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.selected != oldWidget.selected) { + if (widget.selected) { + _controller.repeat(reverse: true); + } else { + _controller.stop(); + _controller.reset(); + } + } + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _animation, + builder: (context, child) { + return Transform.rotate( + angle: _animation.value, + child: child, + ); + }, + child: widget.child, + ); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } +}