fix: multitriggerautocomplete + extendedtextfield

This commit is contained in:
DenserMeerkat
2024-07-11 21:58:12 +05:30
parent b2404e5cd7
commit 0e87fc90fe
15 changed files with 270 additions and 403 deletions

View File

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'package:extended_text_field/extended_text_field.dart';
import 'package:apidash/consts.dart';
import 'envvar_span.dart';
class EnvRegExpSpanBuilder extends RegExpSpecialTextSpanBuilder {
@override
List<RegExpSpecialText> get regExps => <RegExpSpecialText>[
RegExpEnvText(),
];
}
class RegExpEnvText extends RegExpSpecialText {
@override
RegExp get regExp => kEnvVarRegEx;
@override
InlineSpan finishText(int start, Match match,
{TextStyle? textStyle, SpecialTextGestureTapCallback? onTap}) {
final String value = '${match[0]}';
return ExtendedWidgetSpan(
actualText: value,
start: start,
alignment: PlaceholderAlignment.middle,
child: EnvVarSpan(variableKey: value.substring(2, value.length - 2)),
);
}
}

View File

@ -0,0 +1,110 @@
import 'package:flutter/material.dart';
import 'package:multi_trigger_autocomplete/multi_trigger_autocomplete.dart';
import 'package:extended_text_field/extended_text_field.dart';
import 'env_regexp_span_builder.dart';
import 'env_trigger_options.dart';
class EnvironmentTriggerField extends StatefulWidget {
const EnvironmentTriggerField({
super.key,
required this.keyId,
this.initialValue,
this.onChanged,
this.onFieldSubmitted,
this.style,
this.decoration,
});
final String keyId;
final String? initialValue;
final void Function(String)? onChanged;
final void Function(String)? onFieldSubmitted;
final TextStyle? style;
final InputDecoration? decoration;
@override
State<EnvironmentTriggerField> createState() =>
_EnvironmentTriggerFieldState();
}
class _EnvironmentTriggerFieldState extends State<EnvironmentTriggerField> {
final TextEditingController controller = TextEditingController();
final FocusNode focusNode = FocusNode();
@override
void initState() {
super.initState();
controller.text = widget.initialValue ?? '';
controller.selection =
TextSelection.collapsed(offset: controller.text.length);
}
@override
void dispose() {
controller.dispose();
focusNode.dispose();
super.dispose();
}
@override
void didUpdateWidget(EnvironmentTriggerField oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.initialValue != widget.initialValue) {
controller.text = widget.initialValue ?? "";
controller.selection =
TextSelection.collapsed(offset: controller.text.length);
}
}
@override
Widget build(BuildContext context) {
return MultiTriggerAutocomplete(
key: Key(widget.keyId),
textEditingController: controller,
focusNode: focusNode,
autocompleteTriggers: [
AutocompleteTrigger(
trigger: '{',
triggerEnd: "}}",
triggerOnlyAfterSpace: false,
optionsViewBuilder: (context, autocompleteQuery, controller) {
return EnvironmentAutocompleteOptions(
query: autocompleteQuery.query,
onSuggestionTap: (suggestion) {
final autocomplete = MultiTriggerAutocomplete.of(context);
autocomplete.acceptAutocompleteOption(
'{${suggestion.variable.key}',
);
widget.onChanged?.call(controller.text);
});
}),
AutocompleteTrigger(
trigger: '{{',
triggerEnd: "}}",
triggerOnlyAfterSpace: false,
optionsViewBuilder: (context, autocompleteQuery, controller) {
return EnvironmentAutocompleteOptions(
query: autocompleteQuery.query,
onSuggestionTap: (suggestion) {
final autocomplete = MultiTriggerAutocomplete.of(context);
autocomplete.acceptAutocompleteOption(
suggestion.variable.key,
);
widget.onChanged?.call(controller.text);
});
}),
],
fieldViewBuilder: (context, textEditingController, focusnode) {
return ExtendedTextField(
controller: textEditingController,
focusNode: focusnode,
decoration: widget.decoration,
style: widget.style,
onChanged: widget.onChanged,
onSubmitted: widget.onFieldSubmitted,
specialTextSpanBuilder: EnvRegExpSpanBuilder(),
);
},
);
}
}

View File

@ -0,0 +1,66 @@
import 'package:apidash/consts.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:apidash/models/models.dart';
import 'package:apidash/providers/providers.dart';
import 'package:apidash/utils/utils.dart';
import 'envvar_indicator.dart';
class EnvironmentAutocompleteOptions extends ConsumerWidget {
const EnvironmentAutocompleteOptions({
super.key,
required this.query,
required this.onSuggestionTap,
});
final String query;
final ValueSetter<EnvironmentVariableSuggestion> onSuggestionTap;
@override
Widget build(BuildContext context, WidgetRef ref) {
final envMap = ref.watch(availableEnvironmentVariablesStateProvider);
final activeEnvironmentId = ref.watch(activeEnvironmentIdStateProvider);
final suggestions =
getEnvironmentTriggerSuggestions(query, envMap, activeEnvironmentId);
return suggestions == null || suggestions.isEmpty
? const SizedBox.shrink()
: ClipRRect(
borderRadius: kBorderRadius8,
child: Material(
type: MaterialType.card,
elevation: 8,
child: ConstrainedBox(
constraints:
const BoxConstraints(maxHeight: kSuggestionsMenuMaxHeight),
child: Ink(
width: kSuggestionsMenuWidth,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: kBorderRadius8,
border: Border.all(
color: Theme.of(context).colorScheme.outlineVariant,
),
),
child: ListView.separated(
shrinkWrap: true,
itemCount: suggestions.length,
separatorBuilder: (context, index) =>
const Divider(height: 2),
itemBuilder: (context, index) {
final suggestion = suggestions[index];
return ListTile(
dense: true,
leading: EnvVarIndicator(suggestion: suggestion),
title: Text(suggestion.variable.key),
subtitle: Text(suggestion.variable.value),
onTap: () => onSuggestionTap(suggestion),
);
},
),
),
),
),
);
}
}

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:apidash/consts.dart'; import 'package:apidash/consts.dart';
import 'environment_field.dart'; import 'env_trigger_field.dart';
class EnvCellField extends StatelessWidget { class EnvCellField extends StatelessWidget {
const EnvCellField({ const EnvCellField({
@ -21,7 +21,7 @@ class EnvCellField extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var clrScheme = colorScheme ?? Theme.of(context).colorScheme; var clrScheme = colorScheme ?? Theme.of(context).colorScheme;
return EnvironmentField( return EnvironmentTriggerField(
keyId: keyId, keyId: keyId,
initialValue: initialValue, initialValue: initialValue,
style: kCodeStyle.copyWith( style: kCodeStyle.copyWith(

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:apidash/consts.dart'; import 'package:apidash/consts.dart';
import 'environment_field.dart'; import 'env_trigger_field.dart';
class EnvURLField extends StatelessWidget { class EnvURLField extends StatelessWidget {
const EnvURLField({ const EnvURLField({
@ -18,7 +18,7 @@ class EnvURLField extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return EnvironmentField( return EnvironmentTriggerField(
keyId: "url-$selectedId", keyId: "url-$selectedId",
initialValue: initialValue, initialValue: initialValue,
style: kCodeStyle, style: kCodeStyle,

View File

@ -1,49 +0,0 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:apidash/providers/providers.dart';
import 'package:apidash/utils/envvar_utils.dart';
import 'package:apidash/widgets/widgets.dart';
class EnvironmentField extends HookConsumerWidget {
const EnvironmentField({
super.key,
required this.keyId,
this.initialValue,
this.onChanged,
this.onFieldSubmitted,
this.style,
this.decoration,
});
final String keyId;
final String? initialValue;
final void Function(String)? onChanged;
final void Function(String)? onFieldSubmitted;
final TextStyle? style;
final InputDecoration? decoration;
@override
Widget build(BuildContext context, WidgetRef ref) {
final mentionValue = ref.watch(environmentFieldEditStateProvider);
final envMap = ref.watch(availableEnvironmentVariablesStateProvider);
final activeEnvironmentId = ref.watch(activeEnvironmentIdStateProvider);
final initialMentions =
getMentions(initialValue, envMap, activeEnvironmentId);
final suggestions = getEnvironmentVariableSuggestions(
mentionValue, envMap, activeEnvironmentId);
return EnvironmentFieldBase(
key: Key(keyId),
mentionValue: mentionValue,
onMentionValueChanged: (value) {
ref.read(environmentFieldEditStateProvider.notifier).state = value;
},
initialValue: initialValue,
initialMentions: initialMentions,
suggestions: suggestions,
onChanged: onChanged,
onFieldSubmitted: onFieldSubmitted,
style: style,
decoration: decoration,
);
}
}

View File

@ -3,7 +3,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_portal/flutter_portal.dart'; import 'package:flutter_portal/flutter_portal.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:apidash/consts.dart'; import 'package:apidash/consts.dart';
import 'package:apidash/models/models.dart';
import 'package:apidash/providers/providers.dart'; import 'package:apidash/providers/providers.dart';
import 'package:apidash/utils/utils.dart'; import 'package:apidash/utils/utils.dart';
import 'envvar_popover.dart'; import 'envvar_popover.dart';
@ -11,10 +10,10 @@ import 'envvar_popover.dart';
class EnvVarSpan extends HookConsumerWidget { class EnvVarSpan extends HookConsumerWidget {
const EnvVarSpan({ const EnvVarSpan({
super.key, super.key,
required this.suggestion, required this.variableKey,
}); });
final EnvironmentVariableSuggestion suggestion; final String variableKey;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -22,20 +21,19 @@ class EnvVarSpan extends HookConsumerWidget {
final envMap = ref.watch(availableEnvironmentVariablesStateProvider); final envMap = ref.watch(availableEnvironmentVariablesStateProvider);
final activeEnvironmentId = ref.watch(activeEnvironmentIdStateProvider); final activeEnvironmentId = ref.watch(activeEnvironmentIdStateProvider);
final currentSuggestion = final suggestion =
getCurrentVariableStatus(suggestion, envMap, activeEnvironmentId); getVariableStatus(variableKey, envMap, activeEnvironmentId);
final showPopover = useState(false); final showPopover = useState(false);
final isMissingVariable = currentSuggestion.isUnknown; final isMissingVariable = suggestion.isUnknown;
final String scope = isMissingVariable final String scope = isMissingVariable
? 'unknown' ? 'unknown'
: getEnvironmentTitle( : getEnvironmentTitle(environments?[suggestion.environmentId]?.name);
environments?[currentSuggestion.environmentId]?.name);
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
var text = Text( var text = Text(
'{{${currentSuggestion.variable.key}}}', '{{${suggestion.variable.key}}}',
style: TextStyle( style: TextStyle(
color: isMissingVariable ? colorScheme.error : colorScheme.primary, color: isMissingVariable ? colorScheme.error : colorScheme.primary,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600),
@ -50,7 +48,7 @@ class EnvVarSpan extends HookConsumerWidget {
onExit: (_) { onExit: (_) {
showPopover.value = false; showPopover.value = false;
}, },
child: EnvVarPopover(suggestion: currentSuggestion, scope: scope), child: EnvVarPopover(suggestion: suggestion, scope: scope),
), ),
anchor: const Aligned( anchor: const Aligned(
follower: Alignment.bottomCenter, follower: Alignment.bottomCenter,

View File

@ -1,8 +1,6 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:apidash/consts.dart'; import 'package:apidash/consts.dart';
import 'package:apidash/models/models.dart'; import 'package:apidash/models/models.dart';
import '../screens/common_widgets/common_widgets.dart';
String getEnvironmentTitle(String? name) { String getEnvironmentTitle(String? name) {
if (name == null || name.trim() == "") { if (name == null || name.trim() == "") {
@ -92,92 +90,16 @@ HttpRequestModel substituteHttpRequestModel(
return newRequestModel; return newRequestModel;
} }
List<(String, Object?, Widget?)> getMentions( List<EnvironmentVariableSuggestion>? getEnvironmentTriggerSuggestions(
String? text,
Map<String, List<EnvironmentVariableModel>> envMap,
String? activeEnvironmentId) {
if (text == null) {
return [];
}
final mentions = <(String, Object?, Widget?)>[];
final matches = kEnvVarRegEx.allMatches(text);
for (final match in matches) {
final variableName = match.group(1);
EnvironmentVariableModel? variable;
String? environmentId;
for (final entry in envMap.entries) {
variable = entry.value.firstWhereOrNull((v) => v.key == variableName);
if (variable != null) {
environmentId = entry.key;
break;
}
}
final suggestion = EnvironmentVariableSuggestion(
environmentId: variable == null ? "unknown" : environmentId!,
variable: variable ??
kEnvironmentVariableEmptyModel.copyWith(
key: variableName ?? "",
),
isUnknown: variable == null);
mentions.add((
'{{${variable?.key ?? variableName}}}',
suggestion,
EnvVarSpan(suggestion: suggestion)
));
}
return mentions;
}
EnvironmentVariableSuggestion getCurrentVariableStatus(
EnvironmentVariableSuggestion currentSuggestion,
Map<String, List<EnvironmentVariableModel>> envMap,
String? activeEnvironmentId) {
if (activeEnvironmentId != null) {
final variable = envMap[activeEnvironmentId]!
.firstWhereOrNull((v) => v.key == currentSuggestion.variable.key);
if (variable != null) {
return currentSuggestion.copyWith(
environmentId: activeEnvironmentId,
variable: variable,
isUnknown: false,
);
}
}
final globalVariable = envMap[kGlobalEnvironmentId]
?.firstWhereOrNull((v) => v.key == currentSuggestion.variable.key);
if (globalVariable != null) {
return currentSuggestion.copyWith(
environmentId: kGlobalEnvironmentId,
variable: globalVariable,
isUnknown: false,
);
}
return currentSuggestion.copyWith(
isUnknown: true,
variable: currentSuggestion.variable.copyWith(value: "unknown"));
}
List<EnvironmentVariableSuggestion>? getEnvironmentVariableSuggestions(
String? query, String? query,
Map<String, List<EnvironmentVariableModel>> envMap, Map<String, List<EnvironmentVariableModel>> envMap,
String? activeEnvironmentId) { String? activeEnvironmentId) {
if (query == null || kEnvVarRegEx.hasMatch(query)) return null;
query = query.substring(1);
final suggestions = <EnvironmentVariableSuggestion>[]; final suggestions = <EnvironmentVariableSuggestion>[];
final Set<String> addedVariableKeys = {}; final Set<String> addedVariableKeys = {};
if (activeEnvironmentId != null && envMap[activeEnvironmentId] != null) { if (activeEnvironmentId != null && envMap[activeEnvironmentId] != null) {
for (final variable in envMap[activeEnvironmentId]!) { for (final variable in envMap[activeEnvironmentId]!) {
if ((query.isEmpty || variable.key.contains(query)) && if ((query!.isEmpty || variable.key.contains(query)) &&
!addedVariableKeys.contains(variable.key)) { !addedVariableKeys.contains(variable.key)) {
suggestions.add(EnvironmentVariableSuggestion( suggestions.add(EnvironmentVariableSuggestion(
environmentId: activeEnvironmentId, variable: variable)); environmentId: activeEnvironmentId, variable: variable));
@ -197,3 +119,36 @@ List<EnvironmentVariableSuggestion>? getEnvironmentVariableSuggestions(
return suggestions; return suggestions;
} }
EnvironmentVariableSuggestion getVariableStatus(
String key,
Map<String, List<EnvironmentVariableModel>> envMap,
String? activeEnvironmentId) {
if (activeEnvironmentId != null) {
final variable =
envMap[activeEnvironmentId]!.firstWhereOrNull((v) => v.key == key);
if (variable != null) {
return EnvironmentVariableSuggestion(
environmentId: activeEnvironmentId,
variable: variable,
isUnknown: false,
);
}
}
final globalVariable =
envMap[kGlobalEnvironmentId]?.firstWhereOrNull((v) => v.key == key);
if (globalVariable != null) {
return EnvironmentVariableSuggestion(
environmentId: kGlobalEnvironmentId,
variable: globalVariable,
isUnknown: false,
);
}
return EnvironmentVariableSuggestion(
isUnknown: true,
environmentId: "unknown",
variable: EnvironmentVariableModel(
key: key, type: EnvironmentVariableType.variable, value: "unknown"));
}

View File

@ -1,104 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:mention_tag_text_field/mention_tag_text_field.dart';
import 'package:apidash/models/models.dart';
import 'package:apidash/widgets/field_mention.dart';
import '../screens/common_widgets/common_widgets.dart';
import 'suggestions_menu.dart';
class EnvironmentFieldBase extends StatefulHookWidget {
const EnvironmentFieldBase({
super.key,
this.initialValue,
this.onChanged,
this.onFieldSubmitted,
this.style,
this.decoration,
this.initialMentions,
this.suggestions,
this.mentionValue,
required this.onMentionValueChanged,
});
final String? initialValue;
final void Function(String)? onChanged;
final void Function(String)? onFieldSubmitted;
final TextStyle? style;
final InputDecoration? decoration;
final List<(String, Object?, Widget?)>? initialMentions;
final List<EnvironmentVariableSuggestion>? suggestions;
final String? mentionValue;
final void Function(String?) onMentionValueChanged;
@override
State<EnvironmentFieldBase> createState() =>
_EnvironmentAutocompleteFieldBaseState();
}
class _EnvironmentAutocompleteFieldBaseState
extends State<EnvironmentFieldBase> {
final MentionTagTextEditingController controller =
MentionTagTextEditingController();
final FocusNode focusNode = FocusNode();
@override
void initState() {
super.initState();
controller.text = widget.initialValue ?? "";
}
@override
Widget build(BuildContext context) {
final isSuggestionsVisible = useState(false);
return PortalTarget(
visible: isSuggestionsVisible.value && focusNode.hasFocus,
portalFollower: SuggestionsMenu(
mentionController: controller,
suggestions: widget.suggestions,
suggestionBuilder: (context, index) {
final suggestion = widget.suggestions![index];
return ListTile(
dense: true,
leading: EnvVarIndicator(suggestion: suggestion),
title: Text(suggestion.variable.key),
subtitle: Text(suggestion.variable.value),
onTap: () {
controller.addMention(
label: '{${suggestion.variable.key}}}',
data: suggestion,
stylingWidget: EnvVarSpan(suggestion: suggestion));
widget.onChanged?.call(controller.text);
widget.onMentionValueChanged.call(null);
isSuggestionsVisible.value = false;
},
);
},
),
anchor: const Aligned(
follower: Alignment.topLeft,
target: Alignment.bottomLeft,
backup: Aligned(
follower: Alignment.bottomLeft,
target: Alignment.topLeft,
),
),
child: MentionField(
focusNode: focusNode,
controller: controller,
initialMentions: widget.initialMentions ?? [],
mentionValue: widget.mentionValue,
onMentionValueChanged: widget.onMentionValueChanged,
isSuggestionsVisible: isSuggestionsVisible,
onChanged: widget.onChanged,
onFieldSubmitted: widget.onFieldSubmitted,
style: widget.style,
decoration: widget.decoration,
mentionStart: const ['{'],
maxWords: 1,
),
);
}
}

View File

@ -1,85 +0,0 @@
import 'package:flutter/material.dart';
import 'package:mention_tag_text_field/mention_tag_text_field.dart';
class MentionField extends StatelessWidget {
const MentionField({
super.key,
required this.focusNode,
required this.controller,
required this.initialMentions,
required this.mentionValue,
required this.onMentionValueChanged,
required this.isSuggestionsVisible,
this.onChanged,
this.onFieldSubmitted,
this.style,
this.decoration,
required this.mentionStart,
this.mentionBreak = "",
this.maxWords,
this.allowDecrement = false,
this.allowEmbedding = true,
this.showMentionStartSymbol = false,
});
final FocusNode focusNode;
final MentionTagTextEditingController controller;
final List<(String, Object?, Widget?)> initialMentions;
final String? mentionValue;
final void Function(String?) onMentionValueChanged;
final ValueNotifier<bool> isSuggestionsVisible;
final void Function(String)? onChanged;
final void Function(String)? onFieldSubmitted;
final TextStyle? style;
final InputDecoration? decoration;
final List<String> mentionStart;
final String mentionBreak;
final int? maxWords;
final bool allowDecrement;
final bool allowEmbedding;
final bool showMentionStartSymbol;
void onMention(String? value) {
onMentionValueChanged.call(value);
if (value != null) {
isSuggestionsVisible.value = true;
} else {
isSuggestionsVisible.value = false;
}
}
@override
Widget build(BuildContext context) {
return MentionTagTextField(
focusNode: focusNode,
onTap: () {
focusNode.requestFocus();
},
onTapOutside: (event) {
focusNode.unfocus();
isSuggestionsVisible.value = false;
},
controller: controller,
style: style,
initialMentions: initialMentions,
onMention: onMention,
onChanged: (value) {
onChanged?.call(controller.text);
},
onEditingComplete: () {
focusNode.unfocus();
onFieldSubmitted?.call(controller.text);
isSuggestionsVisible.value = false;
},
decoration: decoration,
mentionTagDecoration: MentionTagDecoration(
mentionStart: mentionStart,
mentionBreak: mentionBreak,
maxWords: maxWords,
allowDecrement: allowDecrement,
allowEmbedding: allowEmbedding,
showMentionStartSymbol: showMentionStartSymbol,
),
);
}
}

View File

@ -1,53 +0,0 @@
import 'package:flutter/material.dart';
import 'package:mention_tag_text_field/mention_tag_text_field.dart';
import 'package:apidash/consts.dart';
class SuggestionsMenu extends StatelessWidget {
const SuggestionsMenu({
super.key,
required this.mentionController,
required this.suggestions,
required this.suggestionBuilder,
this.menuWidth = kSuggestionsMenuWidth,
this.menuMaxHeight = kSuggestionsMenuMaxHeight,
});
final MentionTagTextEditingController mentionController;
final List? suggestions;
final double menuWidth;
final double menuMaxHeight;
final Widget? Function(BuildContext, int) suggestionBuilder;
@override
Widget build(BuildContext context) {
return suggestions == null || suggestions!.isEmpty
? const SizedBox.shrink()
: ClipRRect(
borderRadius: kBorderRadius8,
child: Material(
type: MaterialType.card,
elevation: 8,
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: menuMaxHeight),
child: Ink(
width: menuWidth,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: kBorderRadius8,
border: Border.all(
color: Theme.of(context).colorScheme.outlineVariant,
),
),
child: ListView.separated(
shrinkWrap: true,
itemCount: suggestions?.length ?? 0,
separatorBuilder: (context, index) =>
const Divider(height: 2),
itemBuilder: suggestionBuilder,
),
),
),
),
);
}
}

View File

@ -17,13 +17,11 @@ export 'dropdown_formdata.dart';
export 'dropdown_http_method.dart'; export 'dropdown_http_method.dart';
export 'editor_json.dart'; export 'editor_json.dart';
export 'editor.dart'; export 'editor.dart';
export 'environment_field_base.dart';
export 'error_message.dart'; export 'error_message.dart';
export 'field_cell_obscurable.dart'; export 'field_cell_obscurable.dart';
export 'field_cell.dart'; export 'field_cell.dart';
export 'field_header.dart'; export 'field_header.dart';
export 'field_json_search.dart'; export 'field_json_search.dart';
export 'field_mention.dart';
export 'field_raw.dart'; export 'field_raw.dart';
export 'field_url.dart'; export 'field_url.dart';
export 'intro_message.dart'; export 'intro_message.dart';
@ -41,7 +39,6 @@ export 'snackbars.dart';
export 'splitview_drawer.dart'; export 'splitview_drawer.dart';
export 'splitview_dashboard.dart'; export 'splitview_dashboard.dart';
export 'splitview_equal.dart'; export 'splitview_equal.dart';
export 'suggestions_menu.dart';
export 'tables.dart'; export 'tables.dart';
export 'tabs.dart'; export 'tabs.dart';
export 'texts.dart'; export 'texts.dart';

View File

@ -258,7 +258,7 @@ packages:
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
extended_text_field: extended_text_field:
dependency: transitive dependency: "direct main"
description: description:
name: extended_text_field name: extended_text_field
sha256: "954c7eea1e82728a742f7ddf09b9a51cef087d4f52b716ba88cb3eb78ccd7c6e" sha256: "954c7eea1e82728a742f7ddf09b9a51cef087d4f52b716ba88cb3eb78ccd7c6e"
@ -817,14 +817,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.0" version: "0.8.0"
mention_tag_text_field:
dependency: "direct main"
description:
name: mention_tag_text_field
sha256: "9768a0a6fe5771cb8eb98f94b26b4c595ca2487b0eb28b9d5624f8d71a2ac17a"
url: "https://pub.dev"
source: hosted
version: "0.0.5"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@ -865,6 +857,15 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.1" version: "3.2.1"
multi_trigger_autocomplete:
dependency: "direct main"
description:
path: "."
ref: master
resolved-ref: "7ca8778e47f80c913cee33a3a01447039acc6936"
url: "https://github.com/DenserMeerkat/multi_trigger_autocomplete.git"
source: git
version: "1.0.1"
nested: nested:
dependency: transitive dependency: transitive
description: description:

View File

@ -63,7 +63,11 @@ dependencies:
hooks_riverpod: ^2.5.1 hooks_riverpod: ^2.5.1
flutter_hooks: ^0.20.5 flutter_hooks: ^0.20.5
flutter_portal: ^1.1.4 flutter_portal: ^1.1.4
mention_tag_text_field: ^0.0.5 multi_trigger_autocomplete:
git:
url: https://github.com/DenserMeerkat/multi_trigger_autocomplete.git
ref: master
extended_text_field: ^15.0.0
dependency_overrides: dependency_overrides:
web: ^0.5.0 web: ^0.5.0

View File

@ -15,12 +15,12 @@ import 'package:apidash/screens/intro_page.dart';
import 'package:apidash/screens/settings_page.dart'; import 'package:apidash/screens/settings_page.dart';
import 'package:apidash/services/hive_services.dart'; import 'package:apidash/services/hive_services.dart';
import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/widgets/widgets.dart';
import 'package:extended_text_field/extended_text_field.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_portal/flutter_portal.dart'; import 'package:flutter_portal/flutter_portal.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mention_tag_text_field/mention_tag_text_field.dart';
import '../extensions/widget_tester_extensions.dart'; import '../extensions/widget_tester_extensions.dart';
import '../test_consts.dart'; import '../test_consts.dart';
@ -446,7 +446,7 @@ void main() {
// Add some data in URLTextField // Add some data in URLTextField
Finder field = find.descendant( Finder field = find.descendant(
of: find.byType(EnvURLField), of: find.byType(EnvURLField),
matching: find.byType(MentionTagTextField), matching: find.byType(ExtendedTextField),
); );
await tester.enterText(field, kTestUrl); await tester.enterText(field, kTestUrl);
await tester.pump(); await tester.pump();
@ -493,7 +493,7 @@ void main() {
// Add some data in URLTextField // Add some data in URLTextField
Finder field = find.descendant( Finder field = find.descendant(
of: find.byType(EnvURLField), of: find.byType(EnvURLField),
matching: find.byType(MentionTagTextField), matching: find.byType(ExtendedTextField),
); );
await tester.enterText(field, kTestUrl); await tester.enterText(field, kTestUrl);
await tester.pump(); await tester.pump();
@ -544,7 +544,7 @@ void main() {
// Add some data in URLTextField // Add some data in URLTextField
Finder field = find.descendant( Finder field = find.descendant(
of: find.byType(EnvURLField), of: find.byType(EnvURLField),
matching: find.byType(MentionTagTextField), matching: find.byType(ExtendedTextField),
); );
await tester.enterText(field, kTestUrl); await tester.enterText(field, kTestUrl);
await tester.pump(); await tester.pump();
@ -604,7 +604,7 @@ void main() {
// Add some data in URLTextField // Add some data in URLTextField
Finder field = find.descendant( Finder field = find.descendant(
of: find.byType(EnvURLField), of: find.byType(EnvURLField),
matching: find.byType(MentionTagTextField), matching: find.byType(ExtendedTextField),
); );
await tester.enterText(field, kTestUrl); await tester.enterText(field, kTestUrl);
await tester.pump(); await tester.pump();