diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index 66e11808b..24756f7a6 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -180,18 +180,9 @@ class Choreographer { return; } - if ([ - EditType.igc, - ].contains(_textController.editType)) { - // this may be unnecessary now that tokens are not used - // to allow click of words in the input field and we're getting this at the end - // TODO - turn it off and tested that this is fine - igc.justGetTokensAndAddThemToIGCTextData(); - - // we set editType to keyboard here because that is the default for it - // and we want to make sure that the next change is treated as a keyboard change - // unless the system explicity sets it to something else. this - textController.editType = EditType.keyboard; + if (_textController.editType == EditType.igc) { + _lastChecked = _textController.text; + _textController.editType = EditType.keyboard; return; } diff --git a/lib/pangea/choreographer/controllers/igc_controller.dart b/lib/pangea/choreographer/controllers/igc_controller.dart index 533b36c83..6295efa16 100644 --- a/lib/pangea/choreographer/controllers/igc_controller.dart +++ b/lib/pangea/choreographer/controllers/igc_controller.dart @@ -7,11 +7,9 @@ import 'package:fluffychat/pangea/choreographer/controllers/span_data_controller import 'package:fluffychat/pangea/models/igc_text_data_model.dart'; import 'package:fluffychat/pangea/models/pangea_match_model.dart'; import 'package:fluffychat/pangea/repo/igc_repo.dart'; -import 'package:fluffychat/pangea/repo/tokens_repo.dart'; import 'package:fluffychat/pangea/widgets/igc/span_card.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import '../../models/span_card_model.dart'; import '../../utils/error_handler.dart'; @@ -83,62 +81,6 @@ class IgcController { } } - Future justGetTokensAndAddThemToIGCTextData() async { - try { - if (igcTextData == null) { - debugger(when: kDebugMode); - choreographer.getLanguageHelp(); - return; - } - igcTextData!.loading = true; - choreographer.startLoading(); - if (igcTextData!.originalInput != choreographer.textController.text) { - debugger(when: kDebugMode); - ErrorHandler.logError( - m: "igcTextData fullText does not match current text", - s: StackTrace.current, - data: igcTextData!.toJson(), - ); - } - - if (choreographer.l1LangCode == null || - choreographer.l2LangCode == null) { - debugger(when: kDebugMode); - ErrorHandler.logError( - m: "l1LangCode and/or l2LangCode is null", - s: StackTrace.current, - data: { - "l1LangCode": choreographer.l1LangCode, - "l2LangCode": choreographer.l2LangCode, - }, - ); - return; - } - - final TokensResponseModel res = await TokensRepo.tokenize( - await choreographer.pangeaController.userController.accessToken, - TokensRequestModel( - fullText: igcTextData!.originalInput, - userL1: choreographer.l1LangCode!, - userL2: choreographer.l2LangCode!, - ), - ); - igcTextData?.tokens = res.tokens; - } catch (err, stack) { - debugger(when: kDebugMode); - choreographer.errorService.setError( - ChoreoError(type: ChoreoErrorType.unknown, raw: err), - ); - Sentry.addBreadcrumb( - Breadcrumb.fromJson({"igctextDdata": igcTextData?.toJson()}), - ); - ErrorHandler.logError(e: err, s: stack); - } finally { - igcTextData?.loading = false; - choreographer.stopLoading(); - } - } - void showFirstMatch(BuildContext context) { if (igcTextData == null || igcTextData!.matches.isEmpty) { debugger(when: kDebugMode); diff --git a/lib/pangea/models/igc_text_data_model.dart b/lib/pangea/models/igc_text_data_model.dart index 442bf4a60..fe052a5ec 100644 --- a/lib/pangea/models/igc_text_data_model.dart +++ b/lib/pangea/models/igc_text_data_model.dart @@ -1,14 +1,12 @@ import 'dart:developer'; +import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/controllers/language_detection_controller.dart'; import 'package:fluffychat/pangea/models/pangea_match_model.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/models/span_card_model.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; -import 'package:fluffychat/pangea/utils/overlay.dart'; -import 'package:fluffychat/pangea/widgets/igc/span_card.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; @@ -262,7 +260,20 @@ class IGCTextData { return matchTokens; } + TextSpan getSpanItem({ + required int start, + required int end, + TextStyle? style, + }) { + return TextSpan( + text: originalInput.characters.getRange(start, end).toString(), + style: style, + ); + } + //PTODO - handle multitoken spans + /// Returns a list of [TextSpan]s used to display the text in the input field + /// with the appropriate styling for each error match. List constructTokenSpan({ required BuildContext context, TextStyle? defaultStyle, @@ -282,79 +293,58 @@ class IGCTextData { ]; } - final List matchTokens = getMatchTokens(); + final List> matchRanges = matches + .map( + (match) => [ + match.match.offset, + match.match.length + match.match.offset, + ], + ) + .toList(); - for (int tokenIndex = 0; tokenIndex < matchTokens.length; tokenIndex++) { - final MatchToken matchToken = matchTokens[tokenIndex]; - final Widget? cardToShow = - matchToken.match != null && spanCardModel != null - ? SpanCard(scm: spanCardModel) - : null; - - int nextTokenIndex = matchTokens.indexWhere( - (e) => matchToken.match != null - ? e.match != matchToken.match - : e.match != null, - tokenIndex, + // create a pointer to the current index in the original input + // and iterate until the pointer has reached the end of the input + int currentIndex = 0; + while (currentIndex < originalInput.characters.length - 1) { + // check if the pointer is at a match, and if so, get the index of the match + final int matchIndex = matchRanges.indexWhere( + (range) => currentIndex >= range[0] && currentIndex < range[1], ); + final bool inMatch = matchIndex != -1; - if (nextTokenIndex < 0) { - nextTokenIndex = matchTokens.length; - } - - String matchText; - try { - final int start = matchTokens[tokenIndex].token.text.offset; - final int end = matchTokens[nextTokenIndex - 1].token.end; - matchText = originalInput.characters.getRange(start, end).toString(); - } catch (err) { - return [ - TextSpan( - text: originalInput, - style: defaultStyle, - ), - ]; - } - - items.add( - TextSpan( - text: matchText, - style: matchTokens[tokenIndex].match?.textStyle(defaultStyle) ?? - defaultStyle, - recognizer: handleClick && cardToShow != null - ? (TapGestureRecognizer() - ..onTapDown = (details) => OverlayUtil.showPositionedCard( - context: context, - cardToShow: cardToShow, - cardSize: - matchTokens[tokenIndex].match?.isITStart ?? false - ? const Size(350, 220) - : const Size(350, 400), - transformTargetId: transformTargetId, - )) - : null, - ), - ); - - final String beforeNextToken = originalInput.characters - .getRange( - matchTokens[nextTokenIndex - 1].token.end, - nextTokenIndex < matchTokens.length - ? matchTokens[nextTokenIndex].token.text.offset - : originalInput.length, - ) - .toString(); - - if (beforeNextToken.isNotEmpty) { + if (inMatch) { + // if the pointer is in a match, then add that match to items + // and then move the pointer to the end of the match range + final PangeaMatch match = matches[matchIndex]; items.add( - TextSpan( - text: beforeNextToken, + getSpanItem( + start: match.match.offset, + end: match.match.offset + match.match.length, + style: match.textStyle(defaultStyle), + ), + ); + + currentIndex = match.match.offset + match.match.length; + } else { + // otherwise, if the pointer is not at a match, then add all the text + // until the next match (or, if there is not next match, the end of the + // text) to items and move the pointer to the start of the next match + final int nextIndex = matchRanges + .firstWhereOrNull( + (range) => range[0] > currentIndex, + ) + ?.first ?? + originalInput.characters.length; + + items.add( + getSpanItem( + start: currentIndex, + end: nextIndex, style: defaultStyle, ), ); + currentIndex = nextIndex; } - - tokenIndex = nextTokenIndex - 1; } return items;