move logic for continuation of IT fully into IT controller, fix some issues with IT step request queue
This commit is contained in:
parent
978d70822f
commit
ef8292b46c
9 changed files with 352 additions and 346 deletions
|
|
@ -15,7 +15,7 @@ import 'package:fluffychat/pangea/choreographer/enums/choreo_mode.dart';
|
|||
import 'package:fluffychat/pangea/choreographer/enums/edit_type.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/enums/pangea_match_status.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/choreo_record.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/it_step.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/completed_it_step.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/pangea_match_state.dart';
|
||||
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
|
|
@ -91,7 +91,7 @@ class Choreographer extends ChangeNotifier {
|
|||
}
|
||||
|
||||
void clear() {
|
||||
_choreoMode = ChoreoMode.igc;
|
||||
setChoreoMode(ChoreoMode.igc);
|
||||
_lastChecked = null;
|
||||
_timesClicked = 0;
|
||||
_isFetching.value = false;
|
||||
|
|
@ -105,6 +105,7 @@ class Choreographer extends ChangeNotifier {
|
|||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
itController.dispose();
|
||||
errorService.dispose();
|
||||
textController.dispose();
|
||||
_languageStream?.cancel();
|
||||
|
|
@ -234,6 +235,10 @@ class Choreographer extends ChangeNotifier {
|
|||
|
||||
_lastChecked = textController.text;
|
||||
|
||||
if (textController.editType == EditType.it) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (textController.editType == EditType.igc ||
|
||||
textController.editType == EditType.itDismissed) {
|
||||
textController.editType = EditType.keyboard;
|
||||
|
|
@ -247,15 +252,10 @@ class Choreographer extends ChangeNotifier {
|
|||
igc.clear();
|
||||
_resetDebounceTimer();
|
||||
|
||||
if (textController.editType == EditType.it) {
|
||||
_getLanguageAssistance();
|
||||
} else {
|
||||
_sourceText.value = null;
|
||||
_debounceTimer ??= Timer(
|
||||
const Duration(milliseconds: ChoreoConstants.msBeforeIGCStart),
|
||||
() => _getLanguageAssistance(),
|
||||
);
|
||||
}
|
||||
_debounceTimer ??= Timer(
|
||||
const Duration(milliseconds: ChoreoConstants.msBeforeIGCStart),
|
||||
() => _getLanguageAssistance(),
|
||||
);
|
||||
|
||||
//Note: we don't set the keyboard type on each keyboard stroke so this is how we default to
|
||||
//a change being from the keyboard unless explicitly set to one of the other
|
||||
|
|
@ -286,7 +286,7 @@ class Choreographer extends ChangeNotifier {
|
|||
_initChoreoRecord();
|
||||
|
||||
_startLoading();
|
||||
await (isRunningIT ? itController.continueIT() : igc.getIGCTextData());
|
||||
await igc.getIGCTextData();
|
||||
_stopLoading();
|
||||
}
|
||||
|
||||
|
|
@ -398,7 +398,7 @@ class Choreographer extends ChangeNotifier {
|
|||
}
|
||||
|
||||
void onAcceptContinuance(int index) {
|
||||
final step = itController.getAcceptedITStep(index);
|
||||
final step = itController.onAcceptContinuance(index);
|
||||
textController.setSystemText(
|
||||
textController.text + step.continuances[step.chosen].text,
|
||||
EditType.it,
|
||||
|
|
|
|||
|
|
@ -1,26 +1,28 @@
|
|||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/error_service.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/enums/choreo_mode.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/enums/edit_type.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/gold_route_tracker.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/it_step.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/it_repo.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/it_response_model.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../models/it_step.dart';
|
||||
import '../models/completed_it_step.dart';
|
||||
import '../repo/it_request_model.dart';
|
||||
import '../repo/it_response_model.dart';
|
||||
import 'choreographer.dart';
|
||||
|
||||
class ITController {
|
||||
final Choreographer _choreographer;
|
||||
|
||||
ValueNotifier<ITStep?> _currentITStep = ValueNotifier(null);
|
||||
final List<Completer<ITStep>> _queue = [];
|
||||
final ValueNotifier<ITStep?> _currentITStep = ValueNotifier(null);
|
||||
final Queue<Completer<ITStep>> _queue = Queue();
|
||||
GoldRouteTracker? _goldRouteTracker;
|
||||
|
||||
final ValueNotifier<bool> _open = ValueNotifier(false);
|
||||
|
|
@ -52,8 +54,37 @@ class ITController {
|
|||
);
|
||||
}
|
||||
|
||||
Future<Result<ITResponseModel>> _safeRequest(String text) {
|
||||
return ITRepo.get(_request(text)).timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () => Result.error(
|
||||
TimeoutException("ITRepo.get timed out after 10 seconds"),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void clear({bool dismissed = false}) {
|
||||
MatrixState.pAnyState.closeOverlay("it_feedback_card");
|
||||
|
||||
_open.value = false;
|
||||
_editing.value = false;
|
||||
_dismissed = dismissed;
|
||||
_queue.clear();
|
||||
_currentITStep.value = null;
|
||||
_goldRouteTracker = null;
|
||||
|
||||
_choreographer.setChoreoMode(ChoreoMode.igc);
|
||||
_choreographer.setSourceText(null);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_currentITStep.dispose();
|
||||
_editing.dispose();
|
||||
}
|
||||
|
||||
void openIT() {
|
||||
_open.value = true;
|
||||
continueIT();
|
||||
}
|
||||
|
||||
void closeIT() {
|
||||
|
|
@ -68,20 +99,6 @@ class ITController {
|
|||
clear(dismissed: true);
|
||||
}
|
||||
|
||||
void clear({bool dismissed = false}) {
|
||||
MatrixState.pAnyState.closeOverlay("it_feedback_card");
|
||||
|
||||
_open.value = false;
|
||||
_editing.value = false;
|
||||
_dismissed = dismissed;
|
||||
_queue.clear();
|
||||
_currentITStep = ValueNotifier(null);
|
||||
_goldRouteTracker = null;
|
||||
|
||||
_choreographer.setChoreoMode(ChoreoMode.igc);
|
||||
_choreographer.setSourceText(null);
|
||||
}
|
||||
|
||||
void setEditing(bool value) {
|
||||
_editing.value = value;
|
||||
}
|
||||
|
|
@ -89,7 +106,7 @@ class ITController {
|
|||
void onSubmitEdits() {
|
||||
_editing.value = false;
|
||||
_queue.clear();
|
||||
_currentITStep = ValueNotifier(null);
|
||||
_currentITStep.value = null;
|
||||
_goldRouteTracker = null;
|
||||
continueIT();
|
||||
}
|
||||
|
|
@ -113,54 +130,49 @@ class ITController {
|
|||
return _currentITStep.value!.continuances[index];
|
||||
}
|
||||
|
||||
CompletedITStep getAcceptedITStep(int chosenIndex) {
|
||||
CompletedITStep onAcceptContinuance(int chosenIndex) {
|
||||
if (_currentITStep.value == null) {
|
||||
throw "getAcceptedITStep called when _currentITStep is null";
|
||||
throw "onAcceptContinuance called when _currentITStep is null";
|
||||
}
|
||||
|
||||
if (chosenIndex < 0 ||
|
||||
chosenIndex >= _currentITStep.value!.continuances.length) {
|
||||
throw "getAcceptedITStep called with invalid index $chosenIndex";
|
||||
throw "onAcceptContinuance called with invalid index $chosenIndex";
|
||||
}
|
||||
|
||||
return CompletedITStep(
|
||||
final completedStep = CompletedITStep(
|
||||
_currentITStep.value!.continuances,
|
||||
chosen: chosenIndex,
|
||||
);
|
||||
|
||||
continueIT();
|
||||
return completedStep;
|
||||
}
|
||||
|
||||
bool _continuing = false;
|
||||
Future<void> continueIT() async {
|
||||
if (_currentITStep.value == null) {
|
||||
await _initTranslationData();
|
||||
return;
|
||||
}
|
||||
if (_queue.isEmpty) {
|
||||
_choreographer.closeIT();
|
||||
} else {
|
||||
try {
|
||||
final nextStepCompleter = _queue.removeAt(0);
|
||||
if (_continuing) return;
|
||||
_continuing = true;
|
||||
|
||||
try {
|
||||
if (_currentITStep.value == null) {
|
||||
await _initTranslationData();
|
||||
} else if (_queue.isEmpty) {
|
||||
_choreographer.closeIT();
|
||||
} else {
|
||||
final nextStepCompleter = _queue.removeFirst();
|
||||
_currentITStep.value = await nextStepCompleter.future;
|
||||
} catch (e) {
|
||||
if (_open.value) {
|
||||
_choreographer.errorService.setErrorAndLock(
|
||||
ChoreoError(raw: e),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
_choreographer.errorService.setErrorAndLock(ChoreoError(raw: e));
|
||||
} finally {
|
||||
_continuing = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initTranslationData() async {
|
||||
final String currentText = _choreographer.currentText;
|
||||
final res = await ITRepo.get(_request(currentText)).timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () {
|
||||
return Result.error(
|
||||
TimeoutException("ITRepo.get timed out after 10 seconds"),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
final res = await _safeRequest(currentText);
|
||||
if (_sourceText.value == null || !_open.value) return;
|
||||
if (res.isError || res.result?.goldContinuances == null) {
|
||||
_choreographer.errorService.setErrorAndLock(
|
||||
|
|
@ -193,135 +205,25 @@ class ITController {
|
|||
|
||||
final sourceText = _sourceText.value!;
|
||||
final goldContinuances = _goldRouteTracker!.continuances;
|
||||
String currentText =
|
||||
_choreographer.currentText + _goldRouteTracker!.continuances[0].text;
|
||||
|
||||
for (int i = 1; i < _goldRouteTracker!.continuances.length; i++) {
|
||||
_queue.add(Completer<ITStep>());
|
||||
final res = await ITRepo.get(_request(currentText)).timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () {
|
||||
return Result.error(
|
||||
TimeoutException("ITRepo.get timed out after 10 seconds"),
|
||||
);
|
||||
},
|
||||
);
|
||||
if (_queue.isEmpty) break;
|
||||
|
||||
if (res.isError) {
|
||||
_queue.last.completeError(res.asError!);
|
||||
String currentText = goldContinuances[0].text;
|
||||
for (int i = 1; i < goldContinuances.length; i++) {
|
||||
final completer = Completer<ITStep>();
|
||||
_queue.add(completer);
|
||||
final resp = await _safeRequest(currentText);
|
||||
if (resp.isError) {
|
||||
completer.completeError(resp.asError!);
|
||||
break;
|
||||
} else {
|
||||
final step = ITStep.fromResponse(
|
||||
sourceText: sourceText,
|
||||
currentText: currentText,
|
||||
responseModel: res.result!,
|
||||
responseModel: resp.result!,
|
||||
storedGoldContinuances: goldContinuances,
|
||||
);
|
||||
_queue.last.complete(step);
|
||||
completer.complete(step);
|
||||
}
|
||||
|
||||
currentText += goldContinuances[i].text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GoldRouteTracker {
|
||||
final String _originalText;
|
||||
final List<Continuance> continuances;
|
||||
|
||||
const GoldRouteTracker(this.continuances, String originalText)
|
||||
: _originalText = originalText;
|
||||
|
||||
Continuance? currentContinuance({
|
||||
required String currentText,
|
||||
required String sourceText,
|
||||
}) {
|
||||
if (_originalText != sourceText) {
|
||||
debugPrint("$_originalText != $_originalText");
|
||||
return null;
|
||||
}
|
||||
|
||||
String stack = "";
|
||||
for (final cont in continuances) {
|
||||
if (stack == currentText) {
|
||||
return cont;
|
||||
}
|
||||
stack += cont.text;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
String? get fullTranslation {
|
||||
if (continuances.isEmpty) return null;
|
||||
String full = "";
|
||||
for (final cont in continuances) {
|
||||
full += cont.text;
|
||||
}
|
||||
return full;
|
||||
}
|
||||
}
|
||||
|
||||
class ITStep {
|
||||
late List<Continuance> continuances;
|
||||
late bool isFinal;
|
||||
|
||||
ITStep({this.continuances = const [], this.isFinal = false});
|
||||
|
||||
factory ITStep.fromResponse({
|
||||
required String sourceText,
|
||||
required String currentText,
|
||||
required ITResponseModel responseModel,
|
||||
required List<Continuance>? storedGoldContinuances,
|
||||
}) {
|
||||
final List<Continuance> gold =
|
||||
storedGoldContinuances ?? responseModel.goldContinuances ?? [];
|
||||
final goldTracker = GoldRouteTracker(gold, sourceText);
|
||||
|
||||
final isFinal = responseModel.isFinal;
|
||||
List<Continuance> continuances;
|
||||
if (responseModel.continuances.isEmpty) {
|
||||
continuances = [];
|
||||
} else {
|
||||
final Continuance? goldCont = goldTracker.currentContinuance(
|
||||
currentText: currentText,
|
||||
sourceText: sourceText,
|
||||
);
|
||||
if (goldCont != null) {
|
||||
continuances = [
|
||||
...responseModel.continuances
|
||||
.where((c) => c.text.toLowerCase() != goldCont.text.toLowerCase())
|
||||
.map((e) {
|
||||
//we only want one green choice and for that to be our gold
|
||||
if (e.level == ChoreoConstants.levelThresholdForGreen) {
|
||||
return e.copyWith(
|
||||
level: ChoreoConstants.levelThresholdForYellow,
|
||||
);
|
||||
}
|
||||
return e;
|
||||
}),
|
||||
goldCont,
|
||||
];
|
||||
continuances.shuffle();
|
||||
} else {
|
||||
continuances = List<Continuance>.from(responseModel.continuances);
|
||||
}
|
||||
}
|
||||
|
||||
return ITStep(
|
||||
continuances: continuances,
|
||||
isFinal: isFinal,
|
||||
);
|
||||
}
|
||||
|
||||
ITStep copyWith({
|
||||
List<Continuance>? continuances,
|
||||
bool? isFinal,
|
||||
}) {
|
||||
return ITStep(
|
||||
continuances: continuances ?? this.continuances,
|
||||
isFinal: isFinal ?? this.isFinal,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import 'package:fluffychat/pangea/choreographer/enums/pangea_match_status.dart';
|
|||
import 'package:fluffychat/pangea/choreographer/models/choreo_edit.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/span_data.dart';
|
||||
import 'it_step.dart';
|
||||
import 'completed_it_step.dart';
|
||||
|
||||
/// this class lives within a [PangeaIGCEvent]
|
||||
/// it always has a [RepresentationEvent] parent
|
||||
|
|
|
|||
171
lib/pangea/choreographer/models/completed_it_step.dart
Normal file
171
lib/pangea/choreographer/models/completed_it_step.dart
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import '../constants/choreo_constants.dart';
|
||||
|
||||
class CompletedITStep {
|
||||
final List<Continuance> continuances;
|
||||
final int chosen;
|
||||
|
||||
const CompletedITStep(
|
||||
this.continuances, {
|
||||
required this.chosen,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['continuances'] = continuances.map((e) => e.toJson(true)).toList();
|
||||
data['chosen'] = chosen;
|
||||
return data;
|
||||
}
|
||||
|
||||
factory CompletedITStep.fromJson(Map<String, dynamic> json) {
|
||||
final List<Continuance> continuances = <Continuance>[];
|
||||
for (final Map<String, dynamic> continuance in json['continuances']) {
|
||||
continuances.add(Continuance.fromJson(continuance));
|
||||
}
|
||||
return CompletedITStep(
|
||||
continuances,
|
||||
chosen: json['chosen'],
|
||||
);
|
||||
}
|
||||
|
||||
Continuance? get chosenContinuance {
|
||||
return continuances[chosen];
|
||||
}
|
||||
}
|
||||
|
||||
class Continuance {
|
||||
final double probability;
|
||||
final int level;
|
||||
final String text;
|
||||
|
||||
final String description;
|
||||
final int? indexSavedByServer;
|
||||
final bool wasClicked;
|
||||
final bool inDictionary;
|
||||
final bool hasInfo;
|
||||
final bool gold;
|
||||
|
||||
const Continuance({
|
||||
required this.probability,
|
||||
required this.level,
|
||||
required this.text,
|
||||
required this.description,
|
||||
required this.indexSavedByServer,
|
||||
required this.wasClicked,
|
||||
required this.inDictionary,
|
||||
required this.hasInfo,
|
||||
required this.gold,
|
||||
});
|
||||
|
||||
factory Continuance.fromJson(Map<String, dynamic> json) {
|
||||
return Continuance(
|
||||
probability: json['probability'].toDouble(),
|
||||
level: json['level'],
|
||||
text: json['text'],
|
||||
description: json['description'] ?? "",
|
||||
indexSavedByServer: json["index"],
|
||||
inDictionary: json['in_dictionary'] ?? true,
|
||||
wasClicked: json['clkd'] ?? false,
|
||||
hasInfo: json['has_info'] ?? false,
|
||||
gold: json['gold'] ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson([bool condensed = false]) {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['probability'] = probability;
|
||||
data['level'] = level;
|
||||
data['text'] = text;
|
||||
data['clkd'] = wasClicked;
|
||||
|
||||
if (!condensed) {
|
||||
data['description'] = description;
|
||||
data['in_dictionary'] = inDictionary;
|
||||
data['has_info'] = hasInfo;
|
||||
data["index"] = indexSavedByServer;
|
||||
data['gold'] = gold;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
Continuance copyWith({
|
||||
double? probability,
|
||||
int? level,
|
||||
String? text,
|
||||
String? description,
|
||||
int? indexSavedByServer,
|
||||
bool? wasClicked,
|
||||
bool? inDictionary,
|
||||
bool? hasInfo,
|
||||
bool? gold,
|
||||
}) {
|
||||
return Continuance(
|
||||
probability: probability ?? this.probability,
|
||||
level: level ?? this.level,
|
||||
text: text ?? this.text,
|
||||
description: description ?? this.description,
|
||||
indexSavedByServer: indexSavedByServer ?? this.indexSavedByServer,
|
||||
wasClicked: wasClicked ?? this.wasClicked,
|
||||
inDictionary: inDictionary ?? this.inDictionary,
|
||||
hasInfo: hasInfo ?? this.hasInfo,
|
||||
gold: gold ?? this.gold,
|
||||
);
|
||||
}
|
||||
|
||||
Color? get color {
|
||||
if (!wasClicked) return null;
|
||||
switch (level) {
|
||||
case ChoreoConstants.levelThresholdForGreen:
|
||||
return ChoreoConstants.green;
|
||||
case ChoreoConstants.levelThresholdForYellow:
|
||||
return ChoreoConstants.yellow;
|
||||
case ChoreoConstants.levelThresholdForRed:
|
||||
return ChoreoConstants.red;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? feedbackText(BuildContext context) {
|
||||
final L10n l10n = L10n.of(context);
|
||||
switch (level) {
|
||||
case ChoreoConstants.levelThresholdForGreen:
|
||||
return l10n.greenFeedback;
|
||||
case ChoreoConstants.levelThresholdForYellow:
|
||||
return l10n.yellowFeedback;
|
||||
case ChoreoConstants.levelThresholdForRed:
|
||||
return l10n.redFeedback;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is Continuance &&
|
||||
runtimeType == other.runtimeType &&
|
||||
probability == other.probability &&
|
||||
level == other.level &&
|
||||
text == other.text &&
|
||||
description == other.description &&
|
||||
indexSavedByServer == other.indexSavedByServer &&
|
||||
wasClicked == other.wasClicked &&
|
||||
inDictionary == other.inDictionary &&
|
||||
hasInfo == other.hasInfo &&
|
||||
gold == other.gold;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
probability.hashCode ^
|
||||
level.hashCode ^
|
||||
text.hashCode ^
|
||||
description.hashCode ^
|
||||
indexSavedByServer.hashCode ^
|
||||
wasClicked.hashCode ^
|
||||
inDictionary.hashCode ^
|
||||
hasInfo.hashCode ^
|
||||
gold.hashCode;
|
||||
}
|
||||
37
lib/pangea/choreographer/models/gold_route_tracker.dart
Normal file
37
lib/pangea/choreographer/models/gold_route_tracker.dart
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import 'package:fluffychat/pangea/choreographer/models/completed_it_step.dart';
|
||||
|
||||
class GoldRouteTracker {
|
||||
final String _originalText;
|
||||
final List<Continuance> continuances;
|
||||
|
||||
const GoldRouteTracker(this.continuances, String originalText)
|
||||
: _originalText = originalText;
|
||||
|
||||
Continuance? currentContinuance({
|
||||
required String currentText,
|
||||
required String sourceText,
|
||||
}) {
|
||||
if (_originalText != sourceText) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String stack = "";
|
||||
for (final cont in continuances) {
|
||||
if (stack == currentText) {
|
||||
return cont;
|
||||
}
|
||||
stack += cont.text;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
String? get fullTranslation {
|
||||
if (continuances.isEmpty) return null;
|
||||
String full = "";
|
||||
for (final cont in continuances) {
|
||||
full += cont.text;
|
||||
}
|
||||
return full;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,171 +1,67 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/completed_it_step.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/gold_route_tracker.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/it_response_model.dart';
|
||||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import '../constants/choreo_constants.dart';
|
||||
class ITStep {
|
||||
late List<Continuance> continuances;
|
||||
late bool isFinal;
|
||||
|
||||
class CompletedITStep {
|
||||
final List<Continuance> continuances;
|
||||
final int chosen;
|
||||
ITStep({this.continuances = const [], this.isFinal = false});
|
||||
|
||||
const CompletedITStep(
|
||||
this.continuances, {
|
||||
required this.chosen,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['continuances'] = continuances.map((e) => e.toJson(true)).toList();
|
||||
data['chosen'] = chosen;
|
||||
return data;
|
||||
}
|
||||
|
||||
factory CompletedITStep.fromJson(Map<String, dynamic> json) {
|
||||
final List<Continuance> continuances = <Continuance>[];
|
||||
for (final Map<String, dynamic> continuance in json['continuances']) {
|
||||
continuances.add(Continuance.fromJson(continuance));
|
||||
}
|
||||
return CompletedITStep(
|
||||
continuances,
|
||||
chosen: json['chosen'],
|
||||
);
|
||||
}
|
||||
|
||||
Continuance? get chosenContinuance {
|
||||
return continuances[chosen];
|
||||
}
|
||||
}
|
||||
|
||||
class Continuance {
|
||||
final double probability;
|
||||
final int level;
|
||||
final String text;
|
||||
|
||||
final String description;
|
||||
final int? indexSavedByServer;
|
||||
final bool wasClicked;
|
||||
final bool inDictionary;
|
||||
final bool hasInfo;
|
||||
final bool gold;
|
||||
|
||||
const Continuance({
|
||||
required this.probability,
|
||||
required this.level,
|
||||
required this.text,
|
||||
required this.description,
|
||||
required this.indexSavedByServer,
|
||||
required this.wasClicked,
|
||||
required this.inDictionary,
|
||||
required this.hasInfo,
|
||||
required this.gold,
|
||||
});
|
||||
|
||||
factory Continuance.fromJson(Map<String, dynamic> json) {
|
||||
return Continuance(
|
||||
probability: json['probability'].toDouble(),
|
||||
level: json['level'],
|
||||
text: json['text'],
|
||||
description: json['description'] ?? "",
|
||||
indexSavedByServer: json["index"],
|
||||
inDictionary: json['in_dictionary'] ?? true,
|
||||
wasClicked: json['clkd'] ?? false,
|
||||
hasInfo: json['has_info'] ?? false,
|
||||
gold: json['gold'] ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson([bool condensed = false]) {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['probability'] = probability;
|
||||
data['level'] = level;
|
||||
data['text'] = text;
|
||||
data['clkd'] = wasClicked;
|
||||
|
||||
if (!condensed) {
|
||||
data['description'] = description;
|
||||
data['in_dictionary'] = inDictionary;
|
||||
data['has_info'] = hasInfo;
|
||||
data["index"] = indexSavedByServer;
|
||||
data['gold'] = gold;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
Continuance copyWith({
|
||||
double? probability,
|
||||
int? level,
|
||||
String? text,
|
||||
String? description,
|
||||
int? indexSavedByServer,
|
||||
bool? wasClicked,
|
||||
bool? inDictionary,
|
||||
bool? hasInfo,
|
||||
bool? gold,
|
||||
factory ITStep.fromResponse({
|
||||
required String sourceText,
|
||||
required String currentText,
|
||||
required ITResponseModel responseModel,
|
||||
required List<Continuance>? storedGoldContinuances,
|
||||
}) {
|
||||
return Continuance(
|
||||
probability: probability ?? this.probability,
|
||||
level: level ?? this.level,
|
||||
text: text ?? this.text,
|
||||
description: description ?? this.description,
|
||||
indexSavedByServer: indexSavedByServer ?? this.indexSavedByServer,
|
||||
wasClicked: wasClicked ?? this.wasClicked,
|
||||
inDictionary: inDictionary ?? this.inDictionary,
|
||||
hasInfo: hasInfo ?? this.hasInfo,
|
||||
gold: gold ?? this.gold,
|
||||
final List<Continuance> gold =
|
||||
storedGoldContinuances ?? responseModel.goldContinuances ?? [];
|
||||
final goldTracker = GoldRouteTracker(gold, sourceText);
|
||||
|
||||
final isFinal = responseModel.isFinal;
|
||||
List<Continuance> continuances;
|
||||
if (responseModel.continuances.isEmpty) {
|
||||
continuances = [];
|
||||
} else {
|
||||
final Continuance? goldCont = goldTracker.currentContinuance(
|
||||
currentText: currentText,
|
||||
sourceText: sourceText,
|
||||
);
|
||||
if (goldCont != null) {
|
||||
continuances = [
|
||||
...responseModel.continuances
|
||||
.where((c) => c.text.toLowerCase() != goldCont.text.toLowerCase())
|
||||
.map((e) {
|
||||
//we only want one green choice and for that to be our gold
|
||||
if (e.level == ChoreoConstants.levelThresholdForGreen) {
|
||||
return e.copyWith(
|
||||
level: ChoreoConstants.levelThresholdForYellow,
|
||||
);
|
||||
}
|
||||
return e;
|
||||
}),
|
||||
goldCont,
|
||||
];
|
||||
continuances.shuffle();
|
||||
} else {
|
||||
continuances = List<Continuance>.from(responseModel.continuances);
|
||||
}
|
||||
}
|
||||
|
||||
return ITStep(
|
||||
continuances: continuances,
|
||||
isFinal: isFinal,
|
||||
);
|
||||
}
|
||||
|
||||
Color? get color {
|
||||
if (!wasClicked) return null;
|
||||
switch (level) {
|
||||
case ChoreoConstants.levelThresholdForGreen:
|
||||
return ChoreoConstants.green;
|
||||
case ChoreoConstants.levelThresholdForYellow:
|
||||
return ChoreoConstants.yellow;
|
||||
case ChoreoConstants.levelThresholdForRed:
|
||||
return ChoreoConstants.red;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
ITStep copyWith({
|
||||
List<Continuance>? continuances,
|
||||
bool? isFinal,
|
||||
}) {
|
||||
return ITStep(
|
||||
continuances: continuances ?? this.continuances,
|
||||
isFinal: isFinal ?? this.isFinal,
|
||||
);
|
||||
}
|
||||
|
||||
String? feedbackText(BuildContext context) {
|
||||
final L10n l10n = L10n.of(context);
|
||||
switch (level) {
|
||||
case ChoreoConstants.levelThresholdForGreen:
|
||||
return l10n.greenFeedback;
|
||||
case ChoreoConstants.levelThresholdForYellow:
|
||||
return l10n.yellowFeedback;
|
||||
case ChoreoConstants.levelThresholdForRed:
|
||||
return l10n.redFeedback;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is Continuance &&
|
||||
runtimeType == other.runtimeType &&
|
||||
probability == other.probability &&
|
||||
level == other.level &&
|
||||
text == other.text &&
|
||||
description == other.description &&
|
||||
indexSavedByServer == other.indexSavedByServer &&
|
||||
wasClicked == other.wasClicked &&
|
||||
inDictionary == other.inDictionary &&
|
||||
hasInfo == other.hasInfo &&
|
||||
gold == other.gold;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
probability.hashCode ^
|
||||
level.hashCode ^
|
||||
text.hashCode ^
|
||||
description.hashCode ^
|
||||
indexSavedByServer.hashCode ^
|
||||
wasClicked.hashCode ^
|
||||
inDictionary.hashCode ^
|
||||
hasInfo.hashCode ^
|
||||
gold.hashCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/choreographer/models/it_step.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/completed_it_step.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
|
||||
class ITRequestModel {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/it_step.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/completed_it_step.dart';
|
||||
|
||||
class ITResponseModel {
|
||||
final String fullTextTranslation;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart'
|
|||
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/extensions/choregrapher_user_settings_extension.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/extensions/choreographer_ui_extension.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/it_step.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/completed_it_step.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_request_model.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/igc/word_data_card.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/it_feedback_card.dart';
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue