Skip to content

Commit

Permalink
Merge pull request #429 from DenserMeerkat/resolve-issue-env-field
Browse files Browse the repository at this point in the history
fix: environment field issues
  • Loading branch information
ashitaprasad authored Jul 13, 2024
2 parents 2625bb8 + da9b2c3 commit aadfc01
Show file tree
Hide file tree
Showing 15 changed files with 280 additions and 405 deletions.
27 changes: 27 additions & 0 deletions lib/screens/common_widgets/env_regexp_span_builder.dart
Original file line number Diff line number Diff line change
@@ -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)),
);
}
}
113 changes: 113 additions & 0 deletions lib/screens/common_widgets/env_trigger_field.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
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,
this.optionsWidthFactor,
});

final String keyId;
final String? initialValue;
final void Function(String)? onChanged;
final void Function(String)? onFieldSubmitted;
final TextStyle? style;
final InputDecoration? decoration;
final double? optionsWidthFactor;

@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,
optionsWidthFactor: widget.optionsWidthFactor,
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(),
);
},
);
}
}
66 changes: 66 additions & 0 deletions lib/screens/common_widgets/env_trigger_options.dart
Original file line number Diff line number Diff line change
@@ -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),
);
},
),
),
),
),
);
}
}
4 changes: 2 additions & 2 deletions lib/screens/common_widgets/envfield_cell.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:apidash/consts.dart';
import 'environment_field.dart';
import 'env_trigger_field.dart';

class EnvCellField extends StatelessWidget {
const EnvCellField({
Expand All @@ -21,7 +21,7 @@ class EnvCellField extends StatelessWidget {
@override
Widget build(BuildContext context) {
var clrScheme = colorScheme ?? Theme.of(context).colorScheme;
return EnvironmentField(
return EnvironmentTriggerField(
keyId: keyId,
initialValue: initialValue,
style: kCodeStyle.copyWith(
Expand Down
5 changes: 3 additions & 2 deletions lib/screens/common_widgets/envfield_url.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:apidash/consts.dart';
import 'environment_field.dart';
import 'env_trigger_field.dart';

class EnvURLField extends StatelessWidget {
const EnvURLField({
Expand All @@ -18,7 +18,7 @@ class EnvURLField extends StatelessWidget {

@override
Widget build(BuildContext context) {
return EnvironmentField(
return EnvironmentTriggerField(
keyId: "url-$selectedId",
initialValue: initialValue,
style: kCodeStyle,
Expand All @@ -33,6 +33,7 @@ class EnvURLField extends StatelessWidget {
),
onChanged: onChanged,
onFieldSubmitted: onFieldSubmitted,
optionsWidthFactor: 1,
);
}
}
49 changes: 0 additions & 49 deletions lib/screens/common_widgets/environment_field.dart

This file was deleted.

18 changes: 8 additions & 10 deletions lib/screens/common_widgets/envvar_span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,37 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:apidash/consts.dart';
import 'package:apidash/models/models.dart';
import 'package:apidash/providers/providers.dart';
import 'package:apidash/utils/utils.dart';
import 'envvar_popover.dart';

class EnvVarSpan extends HookConsumerWidget {
const EnvVarSpan({
super.key,
required this.suggestion,
required this.variableKey,
});

final EnvironmentVariableSuggestion suggestion;
final String variableKey;

@override
Widget build(BuildContext context, WidgetRef ref) {
final environments = ref.watch(environmentsStateNotifierProvider);
final envMap = ref.watch(availableEnvironmentVariablesStateProvider);
final activeEnvironmentId = ref.watch(activeEnvironmentIdStateProvider);

final currentSuggestion =
getCurrentVariableStatus(suggestion, envMap, activeEnvironmentId);
final suggestion =
getVariableStatus(variableKey, envMap, activeEnvironmentId);

final showPopover = useState(false);

final isMissingVariable = currentSuggestion.isUnknown;
final isMissingVariable = suggestion.isUnknown;
final String scope = isMissingVariable
? 'unknown'
: getEnvironmentTitle(
environments?[currentSuggestion.environmentId]?.name);
: getEnvironmentTitle(environments?[suggestion.environmentId]?.name);
final colorScheme = Theme.of(context).colorScheme;

var text = Text(
'{{${currentSuggestion.variable.key}}}',
'{{${suggestion.variable.key}}}',
style: TextStyle(
color: isMissingVariable ? colorScheme.error : colorScheme.primary,
fontWeight: FontWeight.w600),
Expand All @@ -50,7 +48,7 @@ class EnvVarSpan extends HookConsumerWidget {
onExit: (_) {
showPopover.value = false;
},
child: EnvVarPopover(suggestion: currentSuggestion, scope: scope),
child: EnvVarPopover(suggestion: suggestion, scope: scope),
),
anchor: const Aligned(
follower: Alignment.bottomCenter,
Expand Down
Loading

0 comments on commit aadfc01

Please sign in to comment.