diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart index ff5286cd..bf1cb00f 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart @@ -51,13 +51,16 @@ class EditRequestHeadersState extends ConsumerState { grow: 1, cellBuilder: (_, row) { int idx = row.index; - return CellField( + TextEditingController headerController = + TextEditingController(text: rows[idx].name); + return HeaderField( keyId: "$activeId-$idx-headers-k-$seed", - initialValue: rows[idx].name, + controller: headerController, hintText: "Add Header Name", onChanged: (value) { rows[idx] = rows[idx].copyWith(name: value); _onFieldChange(activeId!); + headerController.text = value; }, colorScheme: Theme.of(context).colorScheme, ); diff --git a/lib/utils/header_utils.dart b/lib/utils/header_utils.dart new file mode 100644 index 00000000..63a456ef --- /dev/null +++ b/lib/utils/header_utils.dart @@ -0,0 +1,72 @@ +Map headers = { + "Accept": "Specifies the media types that are acceptable for the response.", + "Accept-Encoding": + "Indicates the encoding methods the client can understand.", + "Access-Control-Request-Headers": + "Used in preflight requests during CORS to specify the headers that will be included in the actual request.", + "Authorization": + "Contains credentials for authenticating the client with the server.", + "Authorization Bearer Token": "Often used for token-based authentication.", + "Cache-Control": + "Provides directives for caching mechanisms in both requests and responses.", + "Content-Disposition": + "Specifies the presentation style (inline or attachment) of the response.", + "Content-Encoding": + "Indicates the encoding transformations that have been applied to the entity body of the response.", + "Content-Security-Policy": + "Controls the sources from which content can be loaded on a web page to mitigate various types of attacks.", + "Cookie": "Used to send previously stored cookies back to the server.", + "Cross-Origin-Embedder-Policy": + "Controls whether a document is allowed to be embedded in another document.", + "Cross-Origin-Opener-Policy": + "Controls which documents are allowed to open a new window or access the current window.", + "Cross-Origin-Resource-Policy": + "Controls how cross-origin requests for resources are handled.", + "DNT": + "Informs websites whether the user's preference is to opt out of online tracking.", + "Expect": "Indicates certain expectations that need to be met by the server.", + "Host": "Specifies the domain name of the server and the port number.", + "If-Match": + "Used for conditional requests, allows the server to respond based on certain conditions.", + "If-Modified-Since": + "Used for conditional requests, allows the server to respond based on certain conditions.", + "If-None-Match": + "Used for conditional requests, allows the server to respond based on certain conditions.", + "If-Range": + "Used in conjunction with the Range header to conditionally request a partial resource.", + "If-Unmodified-Since": + "Used for conditional requests, allows the server to respond based on certain conditions.", + "Origin": "Specifies the origin of a cross-origin request.", + "Range": + "Used to request only part of a resource, typically in the context of downloading large files.", + "Referer": + "Indicates the URL of the page that referred the client to the current URL.", + "Referrer-Policy": + "Specifies how much information the browser should include in the Referer header when navigating to other pages.", + "Retry-After": + "Informs the client how long it should wait before making another request after a server has responded with a rate-limiting status code.", + "Strict-Transport-Security": + "Instructs the browser to always use HTTPS for the given domain.", + "TE": "Specifies the transfer encodings that are acceptable to the client.", + "User-Agent": + "Identifies the client software and version making the request.", + "Via": + "Indicates intermediate proxies or gateways through which the request or response has passed.", + "X-Api-Key": "Used to authenticate requests to an API with an API key.", + "X-CSRF-Token": + "Used for protection against Cross-Site Request Forgery (CSRF) attacks.", + "X-Forwarded-For": + "Identifies the client's original IP address when behind a proxy or load balancer.", + "X-Requested-With": + "Indicates whether the request was made with JavaScript using XMLHttpRequest.", + "X-XSS-Protection": + "Enables or disables the browser's built-in cross-site scripting (XSS) filter.", +}; + +List getHeaderSuggestions(String pattern) { + return headers.keys + .where( + (element) => element.toLowerCase().contains(pattern.toLowerCase()), + ) + .toList(); +} diff --git a/lib/widgets/headerfield.dart b/lib/widgets/headerfield.dart new file mode 100644 index 00000000..102d348c --- /dev/null +++ b/lib/widgets/headerfield.dart @@ -0,0 +1,90 @@ +import 'package:apidash/utils/header_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:apidash/consts.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; + +class HeaderField extends StatefulWidget { + const HeaderField({ + super.key, + required this.keyId, + required this.controller, + this.hintText, + this.onChanged, + this.colorScheme, + }); + final TextEditingController controller; + final String keyId; + final String? hintText; + final void Function(String)? onChanged; + final ColorScheme? colorScheme; + + @override + State createState() => _HeaderFieldState(); +} + +class _HeaderFieldState extends State { + @override + Widget build(BuildContext context) { + var colorScheme = widget.colorScheme ?? Theme.of(context).colorScheme; + return TypeAheadFormField( + minCharsForSuggestions: 1, + hideOnEmpty: true, + key: Key(widget.keyId), + onSuggestionSelected: widget.onChanged!, + itemBuilder: (context, String suggestion) { + return ListTile( + dense: true, + title: Text(suggestion), + ); + }, + suggestionsCallback: getHeaderSuggestions, + suggestionsBoxDecoration: suggestionBoxDecorations(context), + textFieldConfiguration: TextFieldConfiguration( + onChanged: widget.onChanged!, + controller: widget.controller, + style: kCodeStyle.copyWith( + color: colorScheme.onSurface, + ), + decoration: InputDecoration( + hintStyle: kCodeStyle.copyWith( + color: colorScheme.outline.withOpacity( + kHintOpacity, + ), + ), + hintText: widget.hintText, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: colorScheme.primary.withOpacity( + kHintOpacity, + ), + ), + ), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: colorScheme.surfaceVariant, + ), + ), + ), + ), + ); + } + + SuggestionsBoxDecoration suggestionBoxDecorations(BuildContext context) { + return SuggestionsBoxDecoration( + elevation: 4, + constraints: const BoxConstraints(maxHeight: 400), + shape: RoundedRectangleBorder( + side: BorderSide( + color: Theme.of(context).dividerColor, + width: 1.2, + ), + borderRadius: const BorderRadius.vertical(bottom: Radius.circular(8)), + ), + clipBehavior: Clip.hardEdge, + ); + } + + Future> headerSuggestionCallback(String pattern) async { + return getHeaderSuggestions(pattern); + } +} diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index efdb1e25..34c15f8f 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -9,6 +9,7 @@ export 'dropdowns.dart'; export 'splitviews.dart'; export 'texts.dart'; export 'textfields.dart'; +export 'headerfield.dart'; export 'menus.dart'; export 'cards.dart'; export 'intro_message.dart'; diff --git a/pubspec.lock b/pubspec.lock index c78b1211..2401981c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -278,6 +278,54 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_keyboard_visibility: + dependency: transitive + description: + name: flutter_keyboard_visibility + sha256: "4983655c26ab5b959252ee204c2fffa4afeb4413cd030455194ec0caa3b8e7cb" + url: "https://pub.dev" + source: hosted + version: "5.4.1" + flutter_keyboard_visibility_linux: + dependency: transitive + description: + name: flutter_keyboard_visibility_linux + sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_macos: + dependency: transitive + description: + name: flutter_keyboard_visibility_macos + sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_platform_interface: + dependency: transitive + description: + name: flutter_keyboard_visibility_platform_interface + sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_web: + dependency: transitive + description: + name: flutter_keyboard_visibility_web + sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_windows: + dependency: transitive + description: + name: flutter_keyboard_visibility_windows + sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73 + url: "https://pub.dev" + source: hosted + version: "1.0.0" flutter_launcher_icons: dependency: "direct dev" description: @@ -315,6 +363,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_typeahead: + dependency: "direct main" + description: + name: flutter_typeahead + sha256: b9942bd5b7611a6ec3f0730c477146cffa4cd4b051077983ba67ddfc9e7ee818 + url: "https://pub.dev" + source: hosted + version: "4.8.0" flutter_web_plugins: dependency: transitive description: flutter @@ -728,6 +784,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.5" + pointer_interceptor: + dependency: transitive + description: + name: pointer_interceptor + sha256: "7626e034489820fd599380d2bb4d3f4a0a5e3529370b62bfce53ab736b91adb2" + url: "https://pub.dev" + source: hosted + version: "0.9.3+6" pointycastle: dependency: transitive description: @@ -1143,5 +1207,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 61cec3fb..14b5b410 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: json_annotation: ^4.8.1 printing: ^5.11.0 package_info_plus: ^4.1.0 + flutter_typeahead: ^4.8.0 dev_dependencies: flutter_test: