Merge pull request #453 from pangeachat/spans-from-matches
use match data to construct input underlines, without using tokens
This commit is contained in:
commit
f59372a5e2
3 changed files with 61 additions and 138 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<void> 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);
|
||||
|
|
|
|||
|
|
@ -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<TextSpan> constructTokenSpan({
|
||||
required BuildContext context,
|
||||
TextStyle? defaultStyle,
|
||||
|
|
@ -282,79 +293,58 @@ class IGCTextData {
|
|||
];
|
||||
}
|
||||
|
||||
final List<MatchToken> matchTokens = getMatchTokens();
|
||||
final List<List<int>> 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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue