From 5995eef4d98cc08658c718307abc7c506e892b74 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Tue, 24 Dec 2024 10:27:58 +0530 Subject: [PATCH 01/30] stashing --- pubspec.lock | 88 ++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 31f020bf9..ea2ef9204 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,23 +5,23 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" url: "https://pub.dev" source: hosted - version: "72.0.0" + version: "76.0.0" _macros: dependency: transitive description: dart source: sdk - version: "0.3.2" + version: "0.3.3" analyzer: dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "6.11.0" ansi_styles: dependency: transitive description: @@ -72,10 +72,10 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" audio_session: dependency: transitive description: @@ -104,10 +104,10 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" build: dependency: transitive description: @@ -224,10 +224,10 @@ packages: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" code_builder: dependency: "direct main" description: @@ -240,10 +240,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" conventional_commit: dependency: transitive description: @@ -375,10 +375,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" ffi: dependency: transitive description: @@ -391,10 +391,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" file_selector: dependency: "direct main" description: @@ -876,18 +876,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -924,10 +924,10 @@ packages: dependency: transitive description: name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" url: "https://pub.dev" source: hosted - version: "0.1.2-main.4" + version: "0.1.3-main.0" markdown: dependency: "direct main" description: @@ -1069,10 +1069,10 @@ packages: dependency: "direct main" description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_parsing: dependency: transitive description: @@ -1157,10 +1157,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -1221,10 +1221,10 @@ packages: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "5.0.3" prompts: dependency: transitive description: @@ -1429,7 +1429,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_gen: dependency: transitive description: @@ -1490,10 +1490,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" state_notifier: dependency: transitive description: @@ -1522,10 +1522,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.0" sync_http: dependency: transitive description: @@ -1546,26 +1546,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" + sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" url: "https://pub.dev" source: hosted - version: "1.25.7" + version: "1.25.8" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" test_core: dependency: transitive description: name: test_core - sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" + sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" textwrap: dependency: transitive description: @@ -1762,10 +1762,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.1" watcher: dependency: transitive description: @@ -1794,10 +1794,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.4" webkit_inspection_protocol: dependency: transitive description: From 55428f451e571336efe65f1b37eb254f2083852c Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Thu, 16 Jan 2025 19:47:15 +0530 Subject: [PATCH 02/30] added model and service files --- .../lib/models/websocket_frame.dart | 49 ++++++++ .../lib/models/websocket_model.dart | 57 +++++++++ .../lib/services/websocket_service.dart | 115 ++++++++++++++++++ pubspec.lock | 2 +- pubspec.yaml | 1 + 5 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 packages/apidash_core/lib/models/websocket_frame.dart create mode 100644 packages/apidash_core/lib/models/websocket_model.dart create mode 100644 packages/apidash_core/lib/services/websocket_service.dart diff --git a/packages/apidash_core/lib/models/websocket_frame.dart b/packages/apidash_core/lib/models/websocket_frame.dart new file mode 100644 index 000000000..b6bdd2179 --- /dev/null +++ b/packages/apidash_core/lib/models/websocket_frame.dart @@ -0,0 +1,49 @@ +import 'dart:typed_data'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'websocket_frame_model.freezed.dart'; +part 'websocket_frame_model.g.dart'; + +/// WebSocket Frame Model +@freezed +class WebSocketFrameModel with _$WebSocketFrameModel { + const WebSocketFrameModel._(); + + @JsonSerializable(explicitToJson: true, anyMap: true) + const factory WebSocketFrameModel({ + @Default("") String frameType, // Type of frame (e.g., "text", "binary", "ping", "pong", "close") + @Default("") String message, // Text message (if frameType is "text") + Uint8List? binaryData, // Binary payload (if frameType is "binary") + Map? metadata, // Additional metadata for the frame + @Default(false) bool isFinalFrame, // Is this the final frame in a fragmented message? + DateTime? timestamp, // Timestamp of when the frame was sent/received + }) = _WebSocketFrameModel; + + /// Factory method to create a frame from JSON + factory WebSocketFrameModel.fromJson(Map json) => + _$WebSocketFrameModelFromJson(json); + + /// Utility method to check if the frame is text + bool get isTextFrame => frameType.toLowerCase() == "text"; + + /// Utility method to check if the frame is binary + bool get isBinaryFrame => frameType.toLowerCase() == "binary"; + + /// Utility to check if the frame is a control frame (e.g., "ping", "pong", "close") + bool get isControlFrame => + frameType.toLowerCase() == "ping" || + frameType.toLowerCase() == "pong" || + frameType.toLowerCase() == "close"; + + /// Serialize frame as a string for logging/debugging + @override + String toString() { + return 'WebSocketFrameModel(' + 'frameType: $frameType, ' + 'message: $message, ' + 'binaryData: ${binaryData?.length ?? 0} bytes, ' + 'metadata: $metadata, ' + 'isFinalFrame: $isFinalFrame, ' + 'timestamp: $timestamp)'; + } +} diff --git a/packages/apidash_core/lib/models/websocket_model.dart b/packages/apidash_core/lib/models/websocket_model.dart new file mode 100644 index 000000000..04788d1d9 --- /dev/null +++ b/packages/apidash_core/lib/models/websocket_model.dart @@ -0,0 +1,57 @@ +import 'dart:convert'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:seed/models/name_value_model.dart'; +import '../extensions/extensions.dart'; // Custom extensions for map/row handling +import '../utils/utils.dart' + show rowsToMap, getEnabledRows; // Utility functions for row handling + +part 'websocket_request_model.freezed.dart'; +part 'websocket_request_model.g.dart'; + +@freezed +class WebSocketRequestModel with _$WebSocketRequestModel { + const WebSocketRequestModel._(); + + @JsonSerializable( + explicitToJson: true, + anyMap: true, + ) + const factory WebSocketRequestModel({ + @Default("") String url, + bool? isConnected, + List? headers, + List? isHeaderEnabledList, // Enabled state for headers + List? params, // List of parameters + List? isParamEnabledList, // Enabled state for parameters + String? initialMessage, // Optional message to send on connection + List? receivedMessages, // Log of received messages + }) = _WebSocketRequestModel; + + factory WebSocketRequestModel.fromJson(Map json) => + _$WebSocketRequestModelFromJson(json); + + /// Headers Map + Map get headersMap => rowsToMap(headers) ?? {}; + List? get enabledHeaders => + getEnabledRows(headers, isHeaderEnabledList); + Map get enabledHeadersMap => rowsToMap(enabledHeaders) ?? {}; + bool get hasHeaders => enabledHeadersMap.isNotEmpty; + + + Map get paramsMap => rowsToMap(params) ?? {}; + List? get enabledParams => + getEnabledRows(params, isParamEnabledList); + Map get enabledParamsMap => rowsToMap(enabledParams) ?? {}; + bool get hasParams => enabledParamsMap.isNotEmpty; + + + bool get isValidUrl => url.startsWith("ws://") || url.startsWith("wss://"); + + + bool get hasReceivedMessages => receivedMessages?.isNotEmpty ?? false; + + /// Resets received messages + List resetReceivedMessages() { + return []; + } +} diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart new file mode 100644 index 000000000..4936ad5eb --- /dev/null +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -0,0 +1,115 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:web_socket_channel/web_socket_channel.dart'; +import 'package:web_socket_channel/status.dart' as status; + +class WebSocketClient { + final String url; + late WebSocketChannel _channel; + StreamSubscription? _subscription; + + WebSocketClient(this.url); + + + Future connect() async { + try { + _channel = WebSocketChannel.connect(Uri.parse(url)); + print('Connected to WebSocket server: $url'); + } catch (e) { + print('Failed to connect to WebSocket server: $e'); + rethrow; + } + } + + + void sendText(String message) { + if (_channel != null) { + _channel.sink.add(message); + print('Sent text message: $message'); + } else { + print('WebSocket connection is not open. Unable to send text message.'); + } + } + + + void sendBinary(Uint8List data) { + if (_channel != null) { + _channel.sink.add(data); + print('Sent binary message: $data'); + } else { + print('WebSocket connection is not open. Unable to send binary message.'); + } + } + + + void listen(void Function(dynamic message) onMessage, + {void Function(dynamic error)? onError, void Function()? onDone}) { + _subscription = _channel.stream.listen( + (message) { + print('Received message: $message'); + onMessage(message); + }, + onError: (error) { + print('Error: $error'); + if (onError != null) onError(error); + }, + onDone: () { + print('Connection closed.'); + if (onDone != null) onDone(); + }, + cancelOnError: true, + ); + } + + + void disconnect({int closeCode = status.normalClosure, String? reason}) { + _subscription?.cancel(); + _channel.sink.close(closeCode, reason); + print('Disconnected from WebSocket server'); + } +} + + +void main() async { + const wsUrl = 'ws://localhost:3000'; + + final wsClient = WebSocketClient(wsUrl); + + try { + await wsClient.connect(); + + wsClient.listen( + (message) { + // Handle incoming messages + if (message is String) { + print('Text message received: $message'); + } else if (message is List) { + print('Binary message received: $message'); + } + }, + onError: (error) { + print('Error occurred: $error'); + }, + onDone: () { + print('WebSocket connection closed.'); + }, + ); + + + wsClient.sendText('Hello, WebSocket!'); + + + final binaryData = Uint8List.fromList([0x68, 0x69]); // "hi" in binary + wsClient.sendBinary(binaryData); + + + await Future.delayed(Duration(seconds: 5)); + while(True){ + + } + wsClient.disconnect(reason: 'Closing connection after demo.'); + } catch (e) { + print('Error: $e'); + } +} diff --git a/pubspec.lock b/pubspec.lock index e6df63be7..a6d6952c9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1830,7 +1830,7 @@ packages: source: hosted version: "0.1.6" web_socket_channel: - dependency: transitive + dependency: "direct main" description: name: web_socket_channel sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" diff --git a/pubspec.yaml b/pubspec.yaml index e2d00bad2..25e2c51e1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -67,6 +67,7 @@ dependencies: git: url: https://github.com/google/flutter-desktop-embedding.git path: plugins/window_size + web_socket_channel: ^3.0.1 dependency_overrides: extended_text_field: ^16.0.0 From 261af51445282014e17a4e23c15c988e7e4ca1fd Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Thu, 16 Jan 2025 22:22:19 +0530 Subject: [PATCH 03/30] working on models --- lib/models/request_model.dart | 1 + .../home_page/editor_pane/url_card.dart | 2 + lib/widgets/texts.dart | 2 + packages/apidash_core/lib/consts.dart | 3 +- ..._frame.dart => websocket_frame_model.dart} | 28 +- ...odel.dart => websocket_request_model.dart} | 14 +- .../websocket_request_model.freezed.dart | 385 ++++++++++++++++++ .../lib/utils/http_request_utils.dart | 1 + packages/apidash_core/pubspec.yaml | 3 +- 9 files changed, 412 insertions(+), 27 deletions(-) rename packages/apidash_core/lib/models/{websocket_frame.dart => websocket_frame_model.dart} (50%) rename packages/apidash_core/lib/models/{websocket_model.dart => websocket_request_model.dart} (80%) create mode 100644 packages/apidash_core/lib/models/websocket_request_model.freezed.dart diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index bb9eefaef..40cc90cf9 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -17,6 +17,7 @@ class RequestModel with _$RequestModel { @Default("") String description, @JsonKey(includeToJson: false) @Default(0) requestTabIndex, HttpRequestModel? httpRequestModel, + WebSocketRequestModel webSocketRequestModel, int? responseStatus, String? message, HttpResponseModel? httpResponseModel, diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index 829bc5c97..cdb4e68b4 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -35,6 +35,7 @@ class EditorPaneRequestURLCard extends ConsumerWidget { switch (apiType) { APIType.rest => const DropdownButtonHTTPMethod(), APIType.graphql => kSizedBoxEmpty, + APIType.webSocket => kSizedBoxEmpty, null => kSizedBoxEmpty, }, switch (apiType) { @@ -51,6 +52,7 @@ class EditorPaneRequestURLCard extends ConsumerWidget { switch (apiType) { APIType.rest => const DropdownButtonHTTPMethod(), APIType.graphql => kSizedBoxEmpty, + APIType.webSocket => kSizedBoxEmpty, null => kSizedBoxEmpty, }, switch (apiType) { diff --git a/lib/widgets/texts.dart b/lib/widgets/texts.dart index cd43714ec..5a7321b51 100644 --- a/lib/widgets/texts.dart +++ b/lib/widgets/texts.dart @@ -20,6 +20,7 @@ class SidebarRequestCardTextBox extends StatelessWidget { switch (apiType) { APIType.rest => method.abbr, APIType.graphql => apiType.abbr, + APIType.webSocket => apiType.abbr, }, textAlign: TextAlign.center, style: TextStyle( @@ -31,6 +32,7 @@ class SidebarRequestCardTextBox extends StatelessWidget { brightness: Theme.of(context).brightness, ), APIType.graphql => kColorGQL, + APIType.webSocket => Colors.deepOrange, }, ), ), diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index c3ac388ca..ddbde7da6 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -2,7 +2,8 @@ import 'dart:convert'; enum APIType { rest("HTTP", "HTTP"), - graphql("GraphQL", "GQL"); + graphql("GraphQL", "GQL"), + webSocket("WebSocket", "WS"); const APIType(this.label, this.abbr); final String label; diff --git a/packages/apidash_core/lib/models/websocket_frame.dart b/packages/apidash_core/lib/models/websocket_frame_model.dart similarity index 50% rename from packages/apidash_core/lib/models/websocket_frame.dart rename to packages/apidash_core/lib/models/websocket_frame_model.dart index b6bdd2179..fc2553c84 100644 --- a/packages/apidash_core/lib/models/websocket_frame.dart +++ b/packages/apidash_core/lib/models/websocket_frame_model.dart @@ -1,6 +1,6 @@ import 'dart:typed_data'; import 'package:freezed_annotation/freezed_annotation.dart'; - +import 'package:intl/intl.dart'; part 'websocket_frame_model.freezed.dart'; part 'websocket_frame_model.g.dart'; @@ -11,31 +11,25 @@ class WebSocketFrameModel with _$WebSocketFrameModel { @JsonSerializable(explicitToJson: true, anyMap: true) const factory WebSocketFrameModel({ - @Default("") String frameType, // Type of frame (e.g., "text", "binary", "ping", "pong", "close") - @Default("") String message, // Text message (if frameType is "text") - Uint8List? binaryData, // Binary payload (if frameType is "binary") - Map? metadata, // Additional metadata for the frame - @Default(false) bool isFinalFrame, // Is this the final frame in a fragmented message? - DateTime? timestamp, // Timestamp of when the frame was sent/received + required String id, + @Default("") String frameType, + @Default("") String message, + Uint8List? binaryData, + Map? metadata, + @Default(false) bool isFinalFrame, + DateTime? timeStamp, }) = _WebSocketFrameModel; - /// Factory method to create a frame from JSON factory WebSocketFrameModel.fromJson(Map json) => _$WebSocketFrameModelFromJson(json); - /// Utility method to check if the frame is text + String formattedTime => DateFormat('HH:mm:ss').format(timeStamp ?? DateTime.now()); bool get isTextFrame => frameType.toLowerCase() == "text"; - /// Utility method to check if the frame is binary + bool get isBinaryFrame => frameType.toLowerCase() == "binary"; - /// Utility to check if the frame is a control frame (e.g., "ping", "pong", "close") - bool get isControlFrame => - frameType.toLowerCase() == "ping" || - frameType.toLowerCase() == "pong" || - frameType.toLowerCase() == "close"; - - /// Serialize frame as a string for logging/debugging + @override String toString() { return 'WebSocketFrameModel(' diff --git a/packages/apidash_core/lib/models/websocket_model.dart b/packages/apidash_core/lib/models/websocket_request_model.dart similarity index 80% rename from packages/apidash_core/lib/models/websocket_model.dart rename to packages/apidash_core/lib/models/websocket_request_model.dart index 04788d1d9..b2d89065b 100644 --- a/packages/apidash_core/lib/models/websocket_model.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'package:apidash_core/models/websocket_frame_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:seed/models/name_value_model.dart'; import '../extensions/extensions.dart'; // Custom extensions for map/row handling @@ -20,11 +21,11 @@ class WebSocketRequestModel with _$WebSocketRequestModel { @Default("") String url, bool? isConnected, List? headers, - List? isHeaderEnabledList, // Enabled state for headers - List? params, // List of parameters - List? isParamEnabledList, // Enabled state for parameters - String? initialMessage, // Optional message to send on connection - List? receivedMessages, // Log of received messages + List? isHeaderEnabledList, + List? params, + List? isParamEnabledList, + @Default([]) List frames, + List? receivedMessages, }) = _WebSocketRequestModel; factory WebSocketRequestModel.fromJson(Map json) => @@ -47,9 +48,6 @@ class WebSocketRequestModel with _$WebSocketRequestModel { bool get isValidUrl => url.startsWith("ws://") || url.startsWith("wss://"); - - bool get hasReceivedMessages => receivedMessages?.isNotEmpty ?? false; - /// Resets received messages List resetReceivedMessages() { return []; diff --git a/packages/apidash_core/lib/models/websocket_request_model.freezed.dart b/packages/apidash_core/lib/models/websocket_request_model.freezed.dart new file mode 100644 index 000000000..082e368e9 --- /dev/null +++ b/packages/apidash_core/lib/models/websocket_request_model.freezed.dart @@ -0,0 +1,385 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'websocket_request_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +WebSocketRequestModel _$WebSocketRequestModelFromJson( + Map json) { + return _WebSocketRequestModel.fromJson(json); +} + +/// @nodoc +mixin _$WebSocketRequestModel { + String get url => throw _privateConstructorUsedError; + bool? get isConnected => throw _privateConstructorUsedError; + List? get headers => throw _privateConstructorUsedError; + List? get isHeaderEnabledList => throw _privateConstructorUsedError; + List? get params => throw _privateConstructorUsedError; + List? get isParamEnabledList => throw _privateConstructorUsedError; + List get frames => throw _privateConstructorUsedError; + List? get receivedMessages => throw _privateConstructorUsedError; + + /// Serializes this WebSocketRequestModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of WebSocketRequestModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $WebSocketRequestModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WebSocketRequestModelCopyWith<$Res> { + factory $WebSocketRequestModelCopyWith(WebSocketRequestModel value, + $Res Function(WebSocketRequestModel) then) = + _$WebSocketRequestModelCopyWithImpl<$Res, WebSocketRequestModel>; + @useResult + $Res call( + {String url, + bool? isConnected, + List? headers, + List? isHeaderEnabledList, + List? params, + List? isParamEnabledList, + List frames, + List? receivedMessages}); +} + +/// @nodoc +class _$WebSocketRequestModelCopyWithImpl<$Res, + $Val extends WebSocketRequestModel> + implements $WebSocketRequestModelCopyWith<$Res> { + _$WebSocketRequestModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of WebSocketRequestModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? url = null, + Object? isConnected = freezed, + Object? headers = freezed, + Object? isHeaderEnabledList = freezed, + Object? params = freezed, + Object? isParamEnabledList = freezed, + Object? frames = null, + Object? receivedMessages = freezed, + }) { + return _then(_value.copyWith( + url: null == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String, + isConnected: freezed == isConnected + ? _value.isConnected + : isConnected // ignore: cast_nullable_to_non_nullable + as bool?, + headers: freezed == headers + ? _value.headers + : headers // ignore: cast_nullable_to_non_nullable + as List?, + isHeaderEnabledList: freezed == isHeaderEnabledList + ? _value.isHeaderEnabledList + : isHeaderEnabledList // ignore: cast_nullable_to_non_nullable + as List?, + params: freezed == params + ? _value.params + : params // ignore: cast_nullable_to_non_nullable + as List?, + isParamEnabledList: freezed == isParamEnabledList + ? _value.isParamEnabledList + : isParamEnabledList // ignore: cast_nullable_to_non_nullable + as List?, + frames: null == frames + ? _value.frames + : frames // ignore: cast_nullable_to_non_nullable + as List, + receivedMessages: freezed == receivedMessages + ? _value.receivedMessages + : receivedMessages // ignore: cast_nullable_to_non_nullable + as List?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$WebSocketRequestModelImplCopyWith<$Res> + implements $WebSocketRequestModelCopyWith<$Res> { + factory _$$WebSocketRequestModelImplCopyWith( + _$WebSocketRequestModelImpl value, + $Res Function(_$WebSocketRequestModelImpl) then) = + __$$WebSocketRequestModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String url, + bool? isConnected, + List? headers, + List? isHeaderEnabledList, + List? params, + List? isParamEnabledList, + List frames, + List? receivedMessages}); +} + +/// @nodoc +class __$$WebSocketRequestModelImplCopyWithImpl<$Res> + extends _$WebSocketRequestModelCopyWithImpl<$Res, + _$WebSocketRequestModelImpl> + implements _$$WebSocketRequestModelImplCopyWith<$Res> { + __$$WebSocketRequestModelImplCopyWithImpl(_$WebSocketRequestModelImpl _value, + $Res Function(_$WebSocketRequestModelImpl) _then) + : super(_value, _then); + + /// Create a copy of WebSocketRequestModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? url = null, + Object? isConnected = freezed, + Object? headers = freezed, + Object? isHeaderEnabledList = freezed, + Object? params = freezed, + Object? isParamEnabledList = freezed, + Object? frames = null, + Object? receivedMessages = freezed, + }) { + return _then(_$WebSocketRequestModelImpl( + url: null == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String, + isConnected: freezed == isConnected + ? _value.isConnected + : isConnected // ignore: cast_nullable_to_non_nullable + as bool?, + headers: freezed == headers + ? _value._headers + : headers // ignore: cast_nullable_to_non_nullable + as List?, + isHeaderEnabledList: freezed == isHeaderEnabledList + ? _value._isHeaderEnabledList + : isHeaderEnabledList // ignore: cast_nullable_to_non_nullable + as List?, + params: freezed == params + ? _value._params + : params // ignore: cast_nullable_to_non_nullable + as List?, + isParamEnabledList: freezed == isParamEnabledList + ? _value._isParamEnabledList + : isParamEnabledList // ignore: cast_nullable_to_non_nullable + as List?, + frames: null == frames + ? _value._frames + : frames // ignore: cast_nullable_to_non_nullable + as List, + receivedMessages: freezed == receivedMessages + ? _value._receivedMessages + : receivedMessages // ignore: cast_nullable_to_non_nullable + as List?, + )); + } +} + +/// @nodoc + +@JsonSerializable(explicitToJson: true, anyMap: true) +class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { + const _$WebSocketRequestModelImpl( + {this.url = "", + this.isConnected, + final List? headers, + final List? isHeaderEnabledList, + final List? params, + final List? isParamEnabledList, + final List frames = const [], + final List? receivedMessages}) + : _headers = headers, + _isHeaderEnabledList = isHeaderEnabledList, + _params = params, + _isParamEnabledList = isParamEnabledList, + _frames = frames, + _receivedMessages = receivedMessages, + super._(); + + factory _$WebSocketRequestModelImpl.fromJson(Map json) => + _$$WebSocketRequestModelImplFromJson(json); + + @override + @JsonKey() + final String url; + @override + final bool? isConnected; + final List? _headers; + @override + List? get headers { + final value = _headers; + if (value == null) return null; + if (_headers is EqualUnmodifiableListView) return _headers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _isHeaderEnabledList; + @override + List? get isHeaderEnabledList { + final value = _isHeaderEnabledList; + if (value == null) return null; + if (_isHeaderEnabledList is EqualUnmodifiableListView) + return _isHeaderEnabledList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _params; + @override + List? get params { + final value = _params; + if (value == null) return null; + if (_params is EqualUnmodifiableListView) return _params; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _isParamEnabledList; + @override + List? get isParamEnabledList { + final value = _isParamEnabledList; + if (value == null) return null; + if (_isParamEnabledList is EqualUnmodifiableListView) + return _isParamEnabledList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List _frames; + @override + @JsonKey() + List get frames { + if (_frames is EqualUnmodifiableListView) return _frames; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_frames); + } + + final List? _receivedMessages; + @override + List? get receivedMessages { + final value = _receivedMessages; + if (value == null) return null; + if (_receivedMessages is EqualUnmodifiableListView) + return _receivedMessages; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + String toString() { + return 'WebSocketRequestModel(url: $url, isConnected: $isConnected, headers: $headers, isHeaderEnabledList: $isHeaderEnabledList, params: $params, isParamEnabledList: $isParamEnabledList, frames: $frames, receivedMessages: $receivedMessages)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$WebSocketRequestModelImpl && + (identical(other.url, url) || other.url == url) && + (identical(other.isConnected, isConnected) || + other.isConnected == isConnected) && + const DeepCollectionEquality().equals(other._headers, _headers) && + const DeepCollectionEquality() + .equals(other._isHeaderEnabledList, _isHeaderEnabledList) && + const DeepCollectionEquality().equals(other._params, _params) && + const DeepCollectionEquality() + .equals(other._isParamEnabledList, _isParamEnabledList) && + const DeepCollectionEquality().equals(other._frames, _frames) && + const DeepCollectionEquality() + .equals(other._receivedMessages, _receivedMessages)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + url, + isConnected, + const DeepCollectionEquality().hash(_headers), + const DeepCollectionEquality().hash(_isHeaderEnabledList), + const DeepCollectionEquality().hash(_params), + const DeepCollectionEquality().hash(_isParamEnabledList), + const DeepCollectionEquality().hash(_frames), + const DeepCollectionEquality().hash(_receivedMessages)); + + /// Create a copy of WebSocketRequestModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$WebSocketRequestModelImplCopyWith<_$WebSocketRequestModelImpl> + get copyWith => __$$WebSocketRequestModelImplCopyWithImpl< + _$WebSocketRequestModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$WebSocketRequestModelImplToJson( + this, + ); + } +} + +abstract class _WebSocketRequestModel extends WebSocketRequestModel { + const factory _WebSocketRequestModel( + {final String url, + final bool? isConnected, + final List? headers, + final List? isHeaderEnabledList, + final List? params, + final List? isParamEnabledList, + final List frames, + final List? receivedMessages}) = _$WebSocketRequestModelImpl; + const _WebSocketRequestModel._() : super._(); + + factory _WebSocketRequestModel.fromJson(Map json) = + _$WebSocketRequestModelImpl.fromJson; + + @override + String get url; + @override + bool? get isConnected; + @override + List? get headers; + @override + List? get isHeaderEnabledList; + @override + List? get params; + @override + List? get isParamEnabledList; + @override + List get frames; + @override + List? get receivedMessages; + + /// Create a copy of WebSocketRequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$WebSocketRequestModelImplCopyWith<_$WebSocketRequestModelImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/utils/http_request_utils.dart b/packages/apidash_core/lib/utils/http_request_utils.dart index 7a912ac1b..c5af64415 100644 --- a/packages/apidash_core/lib/utils/http_request_utils.dart +++ b/packages/apidash_core/lib/utils/http_request_utils.dart @@ -99,5 +99,6 @@ String? getRequestBody(APIType type, HttpRequestModel httpRequestModel) { ? httpRequestModel.body : null, APIType.graphql => getGraphQLBody(httpRequestModel), + APIType.webSocket => null, }; } diff --git a/packages/apidash_core/pubspec.yaml b/packages/apidash_core/pubspec.yaml index f9c31cfd7..e76247498 100644 --- a/packages/apidash_core/pubspec.yaml +++ b/packages/apidash_core/pubspec.yaml @@ -21,6 +21,8 @@ dependencies: path: ../postman seed: ^0.0.3 xml: ^6.3.0 + intl: ^0.20.1 + json_serializable: ^6.9.0 dev_dependencies: flutter_test: @@ -28,5 +30,4 @@ dev_dependencies: build_runner: ^2.4.12 flutter_lints: ^4.0.0 freezed: ^2.5.7 - json_serializable: ^6.7.1 test: ^1.25.2 From c93ccc8e12690576d5f92f52f7ca020e13484c6f Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Thu, 16 Jan 2025 22:24:57 +0530 Subject: [PATCH 04/30] working on models --- packages/apidash_core/lib/models/websocket_frame_model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apidash_core/lib/models/websocket_frame_model.dart b/packages/apidash_core/lib/models/websocket_frame_model.dart index fc2553c84..aaa4fb4cf 100644 --- a/packages/apidash_core/lib/models/websocket_frame_model.dart +++ b/packages/apidash_core/lib/models/websocket_frame_model.dart @@ -23,7 +23,7 @@ class WebSocketFrameModel with _$WebSocketFrameModel { factory WebSocketFrameModel.fromJson(Map json) => _$WebSocketFrameModelFromJson(json); - String formattedTime => DateFormat('HH:mm:ss').format(timeStamp ?? DateTime.now()); + String formattedTime => DateFormat('HH:mm:ss').format(timeStamp); bool get isTextFrame => frameType.toLowerCase() == "text"; From fd0e7b6b1f9a467974beafda7aa535f9d3fa36ce Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Thu, 16 Jan 2025 22:40:01 +0530 Subject: [PATCH 05/30] working on clientWrapper --- .../lib/services/clientWrapper.dart | 28 +++++++++++++++++++ .../lib/services/http_client_manager.dart | 11 +++++++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 packages/apidash_core/lib/services/clientWrapper.dart diff --git a/packages/apidash_core/lib/services/clientWrapper.dart b/packages/apidash_core/lib/services/clientWrapper.dart new file mode 100644 index 000000000..037c4142d --- /dev/null +++ b/packages/apidash_core/lib/services/clientWrapper.dart @@ -0,0 +1,28 @@ +import 'package:apidash_core/services/clientWrapper.dart' as http; +import 'package:apidash_core/services/websocket_service.dart'; +import 'package:http/http.dart' as http; + +abstract class clientWrapper { + void close() {} +} + +class HttpClientWrapper extends clientWrapper { + final http.Client client; + HttpClientWrapper(this.client); + @override + void close() { + print("cancelling under rest"); + client.close(); + } +} + +class WebSocketClientWrapper extends clientWrapper { + final WebSocketClient client; + WebSocketClientWrapper(this.client); + @override + void close() { + print("cancelling under websocket"); + client.disconnect(); + } + +} diff --git a/packages/apidash_core/lib/services/http_client_manager.dart b/packages/apidash_core/lib/services/http_client_manager.dart index bec23214f..8bd9814c4 100644 --- a/packages/apidash_core/lib/services/http_client_manager.dart +++ b/packages/apidash_core/lib/services/http_client_manager.dart @@ -1,8 +1,11 @@ import 'dart:io'; import 'dart:collection'; +import 'package:apidash_core/consts.dart'; +import 'package:apidash_core/services/clientWrapper.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:http/io_client.dart'; +import '' http.Client createHttpClientWithNoSSL() { var ioClient = HttpClient() @@ -14,7 +17,7 @@ http.Client createHttpClientWithNoSSL() { class HttpClientManager { static final HttpClientManager _instance = HttpClientManager._internal(); static const int _maxCancelledRequests = 100; - final Map _clients = {}; + final Map _clients = {}; final Queue _cancelledRequests = Queue(); factory HttpClientManager() { @@ -27,6 +30,12 @@ class HttpClientManager { String requestId, { bool noSSL = false, }) { + switch(getRequestModel(requestId).apiType){ + case APIType.rest: + + case APIType.websocket: + + } final client = (noSSL && !kIsWeb) ? createHttpClientWithNoSSL() : http.Client(); _clients[requestId] = client; From 77fc705eab139f3d0d08871facfb5aa8faab2151 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Fri, 17 Jan 2025 22:47:50 +0530 Subject: [PATCH 06/30] some ui changes --- lib/models/history_meta_model.g.dart | 1 + lib/models/request_model.dart | 3 +- lib/models/request_model.freezed.dart | 43 ++- lib/models/request_model.g.dart | 6 + lib/providers/collection_providers.dart | 69 ++++ .../request_pane/request_body.dart | 28 ++ .../request_pane/request_pane.dart | 2 + .../request_pane/request_pane_websocket.dart | 54 +++ .../details_card/response_pane.dart | 16 + .../home_page/editor_pane/url_card.dart | 38 ++- lib/widgets/button_connection.dart | 44 +++ lib/widgets/websocket_frame.dart | 18 + .../lib/models/websocket_frame_model.dart | 7 +- .../models/websocket_frame_model.freezed.dart | 314 ++++++++++++++++++ .../lib/models/websocket_frame_model.g.dart | 35 ++ .../lib/models/websocket_request_model.dart | 1 + .../websocket_request_model.freezed.dart | 23 +- .../lib/models/websocket_request_model.g.dart | 50 +++ .../lib/services/clientWrapper.dart | 6 +- .../lib/services/http_client_manager.dart | 22 +- .../lib/services/websocket_service.dart | 131 ++++---- packages/apidash_core/pubspec.yaml | 2 +- 22 files changed, 829 insertions(+), 84 deletions(-) create mode 100644 lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart create mode 100644 lib/widgets/button_connection.dart create mode 100644 lib/widgets/websocket_frame.dart create mode 100644 packages/apidash_core/lib/models/websocket_frame_model.freezed.dart create mode 100644 packages/apidash_core/lib/models/websocket_frame_model.g.dart create mode 100644 packages/apidash_core/lib/models/websocket_request_model.g.dart diff --git a/lib/models/history_meta_model.g.dart b/lib/models/history_meta_model.g.dart index a2b2b7b1d..b8e14cedb 100644 --- a/lib/models/history_meta_model.g.dart +++ b/lib/models/history_meta_model.g.dart @@ -35,6 +35,7 @@ Map _$$HistoryMetaModelImplToJson( const _$APITypeEnumMap = { APIType.rest: 'rest', APIType.graphql: 'graphql', + APIType.webSocket: 'webSocket', }; const _$HTTPVerbEnumMap = { diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index 40cc90cf9..7e55d9c96 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -1,4 +1,5 @@ import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_core/models/websocket_request_model.dart'; part 'request_model.freezed.dart'; @@ -17,7 +18,7 @@ class RequestModel with _$RequestModel { @Default("") String description, @JsonKey(includeToJson: false) @Default(0) requestTabIndex, HttpRequestModel? httpRequestModel, - WebSocketRequestModel webSocketRequestModel, + WebSocketRequestModel? webSocketRequestModel, int? responseStatus, String? message, HttpResponseModel? httpResponseModel, diff --git a/lib/models/request_model.freezed.dart b/lib/models/request_model.freezed.dart index b237e3726..078d87266 100644 --- a/lib/models/request_model.freezed.dart +++ b/lib/models/request_model.freezed.dart @@ -27,6 +27,8 @@ mixin _$RequestModel { @JsonKey(includeToJson: false) dynamic get requestTabIndex => throw _privateConstructorUsedError; HttpRequestModel? get httpRequestModel => throw _privateConstructorUsedError; + WebSocketRequestModel? get webSocketRequestModel => + throw _privateConstructorUsedError; int? get responseStatus => throw _privateConstructorUsedError; String? get message => throw _privateConstructorUsedError; HttpResponseModel? get httpResponseModel => @@ -59,6 +61,7 @@ abstract class $RequestModelCopyWith<$Res> { String description, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, + WebSocketRequestModel? webSocketRequestModel, int? responseStatus, String? message, HttpResponseModel? httpResponseModel, @@ -66,6 +69,7 @@ abstract class $RequestModelCopyWith<$Res> { @JsonKey(includeToJson: false) DateTime? sendingTime}); $HttpRequestModelCopyWith<$Res>? get httpRequestModel; + $WebSocketRequestModelCopyWith<$Res>? get webSocketRequestModel; $HttpResponseModelCopyWith<$Res>? get httpResponseModel; } @@ -90,6 +94,7 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> Object? description = null, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, + Object? webSocketRequestModel = freezed, Object? responseStatus = freezed, Object? message = freezed, Object? httpResponseModel = freezed, @@ -121,6 +126,10 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ? _value.httpRequestModel : httpRequestModel // ignore: cast_nullable_to_non_nullable as HttpRequestModel?, + webSocketRequestModel: freezed == webSocketRequestModel + ? _value.webSocketRequestModel + : webSocketRequestModel // ignore: cast_nullable_to_non_nullable + as WebSocketRequestModel?, responseStatus: freezed == responseStatus ? _value.responseStatus : responseStatus // ignore: cast_nullable_to_non_nullable @@ -158,6 +167,21 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> }); } + /// Create a copy of RequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $WebSocketRequestModelCopyWith<$Res>? get webSocketRequestModel { + if (_value.webSocketRequestModel == null) { + return null; + } + + return $WebSocketRequestModelCopyWith<$Res>(_value.webSocketRequestModel!, + (value) { + return _then(_value.copyWith(webSocketRequestModel: value) as $Val); + }); + } + /// Create a copy of RequestModel /// with the given fields replaced by the non-null parameter values. @override @@ -188,6 +212,7 @@ abstract class _$$RequestModelImplCopyWith<$Res> String description, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, + WebSocketRequestModel? webSocketRequestModel, int? responseStatus, String? message, HttpResponseModel? httpResponseModel, @@ -197,6 +222,8 @@ abstract class _$$RequestModelImplCopyWith<$Res> @override $HttpRequestModelCopyWith<$Res>? get httpRequestModel; @override + $WebSocketRequestModelCopyWith<$Res>? get webSocketRequestModel; + @override $HttpResponseModelCopyWith<$Res>? get httpResponseModel; } @@ -219,6 +246,7 @@ class __$$RequestModelImplCopyWithImpl<$Res> Object? description = null, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, + Object? webSocketRequestModel = freezed, Object? responseStatus = freezed, Object? message = freezed, Object? httpResponseModel = freezed, @@ -249,6 +277,10 @@ class __$$RequestModelImplCopyWithImpl<$Res> ? _value.httpRequestModel : httpRequestModel // ignore: cast_nullable_to_non_nullable as HttpRequestModel?, + webSocketRequestModel: freezed == webSocketRequestModel + ? _value.webSocketRequestModel + : webSocketRequestModel // ignore: cast_nullable_to_non_nullable + as WebSocketRequestModel?, responseStatus: freezed == responseStatus ? _value.responseStatus : responseStatus // ignore: cast_nullable_to_non_nullable @@ -284,6 +316,7 @@ class _$RequestModelImpl implements _RequestModel { this.description = "", @JsonKey(includeToJson: false) this.requestTabIndex = 0, this.httpRequestModel, + this.webSocketRequestModel, this.responseStatus, this.message, this.httpResponseModel, @@ -310,6 +343,8 @@ class _$RequestModelImpl implements _RequestModel { @override final HttpRequestModel? httpRequestModel; @override + final WebSocketRequestModel? webSocketRequestModel; + @override final int? responseStatus; @override final String? message; @@ -324,7 +359,7 @@ class _$RequestModelImpl implements _RequestModel { @override String toString() { - return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, webSocketRequestModel: $webSocketRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; } @override @@ -341,6 +376,8 @@ class _$RequestModelImpl implements _RequestModel { .equals(other.requestTabIndex, requestTabIndex) && (identical(other.httpRequestModel, httpRequestModel) || other.httpRequestModel == httpRequestModel) && + (identical(other.webSocketRequestModel, webSocketRequestModel) || + other.webSocketRequestModel == webSocketRequestModel) && (identical(other.responseStatus, responseStatus) || other.responseStatus == responseStatus) && (identical(other.message, message) || other.message == message) && @@ -362,6 +399,7 @@ class _$RequestModelImpl implements _RequestModel { description, const DeepCollectionEquality().hash(requestTabIndex), httpRequestModel, + webSocketRequestModel, responseStatus, message, httpResponseModel, @@ -392,6 +430,7 @@ abstract class _RequestModel implements RequestModel { final String description, @JsonKey(includeToJson: false) final dynamic requestTabIndex, final HttpRequestModel? httpRequestModel, + final WebSocketRequestModel? webSocketRequestModel, final int? responseStatus, final String? message, final HttpResponseModel? httpResponseModel, @@ -416,6 +455,8 @@ abstract class _RequestModel implements RequestModel { @override HttpRequestModel? get httpRequestModel; @override + WebSocketRequestModel? get webSocketRequestModel; + @override int? get responseStatus; @override String? get message; diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index 68b563953..a2b4301db 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -17,6 +17,10 @@ _$RequestModelImpl _$$RequestModelImplFromJson(Map json) => _$RequestModelImpl( ? null : HttpRequestModel.fromJson( Map.from(json['httpRequestModel'] as Map)), + webSocketRequestModel: json['webSocketRequestModel'] == null + ? null + : WebSocketRequestModel.fromJson( + Map.from(json['webSocketRequestModel'] as Map)), responseStatus: (json['responseStatus'] as num?)?.toInt(), message: json['message'] as String?, httpResponseModel: json['httpResponseModel'] == null @@ -36,6 +40,7 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => 'name': instance.name, 'description': instance.description, 'httpRequestModel': instance.httpRequestModel?.toJson(), + 'webSocketRequestModel': instance.webSocketRequestModel?.toJson(), 'responseStatus': instance.responseStatus, 'message': instance.message, 'httpResponseModel': instance.httpResponseModel?.toJson(), @@ -44,4 +49,5 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => const _$APITypeEnumMap = { APIType.rest: 'rest', APIType.graphql: 'graphql', + APIType.webSocket: 'webSocket', }; diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 2fb830775..5aebf6030 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -431,4 +433,71 @@ class CollectionStateNotifier activeEnvId, ); } + Future connect() async { + print("connect fired"); + final requestId = ref.read(selectedIdStateProvider); + ref.read(codePaneVisibleStateProvider.notifier).state = false; + if (requestId == null || state == null) { + print(requestId); + return; + } + + RequestModel? requestModel = state![requestId]; + + // if (requestModel?.webSocketRequestModel == null) { + // print("no web socket request model"); + // return; + // } + + final client = httpClientManager.createWebSocketClient(requestId); + client.connect(requestModel!.httpRequestModel!); + client.listen( + (message) async{ + // var map = {...state!}; + // map[requestId] = requestModel.copyWith( + // responseStatus: 200, + // message: message, + // isWorking: false, + // ); + // state = map; + }, + onError: (error) async{ + // var map = {...state!}; + // map[requestId] = requestModel.copyWith( + // responseStatus: -1, + // message: error.toString(), + // isWorking: false, + // ); + // state = map; + }, + onDone: () async{ + // var map = {...state!}; + // map[requestId] = requestModel.copyWith( + // responseStatus: 200, + // message: "Connection closed", + // isWorking: false, + // ); + // state = map; + }, + ); + + Future disconnect() async { + print("connect fired"); + final requestId = ref.read(selectedIdStateProvider); + ref.read(codePaneVisibleStateProvider.notifier).state = false; + if (requestId == null || state == null) { + print(requestId); + return; + } + + RequestModel? requestModel = state![requestId]; + + // if (requestModel?.webSocketRequestModel == null) { + // print("no web socket request model"); + // return; + // } + + final client = httpClientManager.createWebSocketClient(requestId); + client.disconnect(); + } } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 26686e677..34c4a2fcd 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -110,6 +110,34 @@ class EditRequestBody extends ConsumerWidget { ), ), ), + APIType.webSocket => Expanded( + + child: Padding( + padding: kPt5o10, + child: Stack( + children: [ + TextFieldEditor( + key: Key("$selectedId-websocket-body"), + fieldKey: "$selectedId-websocket-body-editor", + // initialValue: requestModel?.websRequestModel?.body, + onChanged: (String value) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(body: value); + }, + hintText: kHintText, + ), + Positioned( + bottom: 0, + left: 0, + child: SendButton(isWorking: true, onTap: () { + + }), + ), + ], + ), + ), + ), _ => kSizedBoxEmpty, } ], diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart index 9c852c71b..017fea243 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart @@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; import 'request_pane_graphql.dart'; import 'request_pane_rest.dart'; +import 'request_pane_websocket.dart'; class EditRequestPane extends ConsumerWidget { const EditRequestPane({super.key}); @@ -17,6 +18,7 @@ class EditRequestPane extends ConsumerWidget { return switch (apiType) { APIType.rest => const EditRestRequestPane(), APIType.graphql => const EditGraphQLRequestPane(), + APIType.webSocket => const EditWebSocketRequestPane(), _ => kSizedBoxEmpty, }; } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart new file mode 100644 index 000000000..ff8d6044b --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart @@ -0,0 +1,54 @@ +import 'package:apidash/consts.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/widgets/widgets.dart'; +import 'request_headers.dart'; +import 'request_body.dart'; + +class EditWebSocketRequestPane extends ConsumerWidget { + const EditWebSocketRequestPane({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedId = ref.watch(selectedIdStateProvider); + var tabIndex = ref.watch( + selectedRequestModelProvider.select((value) => value?.requestTabIndex)); + final codePaneVisible = ref.watch(codePaneVisibleStateProvider); + final headerLength = ref.watch(selectedRequestModelProvider + .select((value) => value?.httpRequestModel?.headersMap.length)) ?? + 0; + final hasQuery = ref.watch(selectedRequestModelProvider + .select((value) => value?.httpRequestModel?.hasQuery)) ?? + false; + if (tabIndex >= 2) { + tabIndex = 0; + } + return RequestPane( + selectedId: selectedId, + codePaneVisible: codePaneVisible, + tabIndex: tabIndex, + onPressedCodeButton: () { + ref.read(codePaneVisibleStateProvider.notifier).state = + !codePaneVisible; + }, + onTapTabBar: (index) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(requestTabIndex: index); + }, + showIndicators: [ + headerLength > 0, + hasQuery, + ], + tabLabels: const [ + kLabelHeaders, + kLabelQuery, + ], + children: const [ + EditRequestHeaders(), + EditRequestBody(), + ], + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 50d5531a0..814e4566b 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -1,3 +1,4 @@ +import 'package:apidash/widgets/websocket_frame.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -117,3 +118,18 @@ class ResponseHeadersTab extends ConsumerWidget { ); } } + +// class WebsocketResponseView extends ConsumerWidget { +// const WebsocketResponseView({super.key}); + +// @override +// Widget build(BuildContext context, WidgetRef ref) { + +// return ListView.builder( +// itemCount:, +// itemBuilder: (context, index) { +// return WebsocketFrame(); +// }, +// ); +// } +// } \ No newline at end of file diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index cdb4e68b4..1a138b7e5 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -1,3 +1,4 @@ +import 'package:apidash/widgets/button_connection.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; @@ -63,10 +64,12 @@ class EditorPaneRequestURLCard extends ConsumerWidget { child: URLTextField(), ), kHSpacer20, - const SizedBox( - height: 36, - child: SendRequestButton(), - ) + switch (apiType) { + APIType.rest => const SendRequestButton(), + APIType.graphql =>const SendRequestButton(), + APIType.webSocket =>const ConnectionRequestButton(), + null => kSizedBoxEmpty, + }, ], ), ), @@ -144,3 +147,30 @@ class SendRequestButton extends ConsumerWidget { ); } } + + +class ConnectionRequestButton extends ConsumerWidget { + final Function()? onTap; + const ConnectionRequestButton({ + super.key, + this.onTap, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + ref.watch(selectedIdStateProvider); + final isWorking = ref.watch( + selectedRequestModelProvider.select((value) => value?.isWorking)); + + return ConnectionButton( + isWorking: isWorking ?? false, + onTap: () { + onTap?.call(); + ref.read(collectionStateNotifierProvider.notifier).connect(); + }, + onCancel: () { + ref.read(collectionStateNotifierProvider.notifier).connect(); + }, + ); + } +} \ No newline at end of file diff --git a/lib/widgets/button_connection.dart b/lib/widgets/button_connection.dart new file mode 100644 index 000000000..a9b291822 --- /dev/null +++ b/lib/widgets/button_connection.dart @@ -0,0 +1,44 @@ +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:apidash/consts.dart'; + +class ConnectionButton extends StatelessWidget { + const ConnectionButton({ + super.key, + required this.isWorking, + required this.onTap, + this.onCancel, + }); + + final bool isWorking; + final void Function() onTap; + final void Function()? onCancel; + + @override + Widget build(BuildContext context) { + return ADFilledButton( + onPressed: isWorking ? onCancel : onTap, + isTonal: isWorking ? true : false, + items: isWorking + ? const [ + kHSpacer8, + Text( + kLabelCancel, + style: kTextStyleButton, + ), + kHSpacer6, + ] + : const [ + Text( + kLabelSend, + style: kTextStyleButton, + ), + kHSpacer10, + Icon( + size: 16, + Icons.send, + ), + ], + ); + } +} diff --git a/lib/widgets/websocket_frame.dart b/lib/widgets/websocket_frame.dart new file mode 100644 index 000000000..1e2a46724 --- /dev/null +++ b/lib/widgets/websocket_frame.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; + +class WebsocketFrame extends StatefulWidget { + const WebsocketFrame({super.key}); + + @override + State createState() => _WebsocketFrameState(); +} + +class _WebsocketFrameState extends State { + @override + Widget build(BuildContext context) { + return ListTile( + + + ); + } +} \ No newline at end of file diff --git a/packages/apidash_core/lib/models/websocket_frame_model.dart b/packages/apidash_core/lib/models/websocket_frame_model.dart index aaa4fb4cf..c0c4b1326 100644 --- a/packages/apidash_core/lib/models/websocket_frame_model.dart +++ b/packages/apidash_core/lib/models/websocket_frame_model.dart @@ -1,4 +1,5 @@ import 'dart:typed_data'; +import 'package:apidash_core/models/http_response_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:intl/intl.dart'; part 'websocket_frame_model.freezed.dart'; @@ -14,7 +15,7 @@ class WebSocketFrameModel with _$WebSocketFrameModel { required String id, @Default("") String frameType, @Default("") String message, - Uint8List? binaryData, + @Uint8ListConverter() Uint8List? binaryData, Map? metadata, @Default(false) bool isFinalFrame, DateTime? timeStamp, @@ -23,7 +24,7 @@ class WebSocketFrameModel with _$WebSocketFrameModel { factory WebSocketFrameModel.fromJson(Map json) => _$WebSocketFrameModelFromJson(json); - String formattedTime => DateFormat('HH:mm:ss').format(timeStamp); + String get formattedTime => DateFormat('HH:mm:ss').format(timeStamp ?? DateTime.now()); bool get isTextFrame => frameType.toLowerCase() == "text"; @@ -38,6 +39,6 @@ class WebSocketFrameModel with _$WebSocketFrameModel { 'binaryData: ${binaryData?.length ?? 0} bytes, ' 'metadata: $metadata, ' 'isFinalFrame: $isFinalFrame, ' - 'timestamp: $timestamp)'; + 'timestamp: $timeStamp)'; } } diff --git a/packages/apidash_core/lib/models/websocket_frame_model.freezed.dart b/packages/apidash_core/lib/models/websocket_frame_model.freezed.dart new file mode 100644 index 000000000..40310c856 --- /dev/null +++ b/packages/apidash_core/lib/models/websocket_frame_model.freezed.dart @@ -0,0 +1,314 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'websocket_frame_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +WebSocketFrameModel _$WebSocketFrameModelFromJson(Map json) { + return _WebSocketFrameModel.fromJson(json); +} + +/// @nodoc +mixin _$WebSocketFrameModel { + String get id => throw _privateConstructorUsedError; + String get frameType => throw _privateConstructorUsedError; + String get message => throw _privateConstructorUsedError; + @Uint8ListConverter() + Uint8List? get binaryData => throw _privateConstructorUsedError; + Map? get metadata => throw _privateConstructorUsedError; + bool get isFinalFrame => throw _privateConstructorUsedError; + DateTime? get timeStamp => throw _privateConstructorUsedError; + + /// Serializes this WebSocketFrameModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of WebSocketFrameModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $WebSocketFrameModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WebSocketFrameModelCopyWith<$Res> { + factory $WebSocketFrameModelCopyWith( + WebSocketFrameModel value, $Res Function(WebSocketFrameModel) then) = + _$WebSocketFrameModelCopyWithImpl<$Res, WebSocketFrameModel>; + @useResult + $Res call( + {String id, + String frameType, + String message, + @Uint8ListConverter() Uint8List? binaryData, + Map? metadata, + bool isFinalFrame, + DateTime? timeStamp}); +} + +/// @nodoc +class _$WebSocketFrameModelCopyWithImpl<$Res, $Val extends WebSocketFrameModel> + implements $WebSocketFrameModelCopyWith<$Res> { + _$WebSocketFrameModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of WebSocketFrameModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? frameType = null, + Object? message = null, + Object? binaryData = freezed, + Object? metadata = freezed, + Object? isFinalFrame = null, + Object? timeStamp = freezed, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + frameType: null == frameType + ? _value.frameType + : frameType // ignore: cast_nullable_to_non_nullable + as String, + message: null == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String, + binaryData: freezed == binaryData + ? _value.binaryData + : binaryData // ignore: cast_nullable_to_non_nullable + as Uint8List?, + metadata: freezed == metadata + ? _value.metadata + : metadata // ignore: cast_nullable_to_non_nullable + as Map?, + isFinalFrame: null == isFinalFrame + ? _value.isFinalFrame + : isFinalFrame // ignore: cast_nullable_to_non_nullable + as bool, + timeStamp: freezed == timeStamp + ? _value.timeStamp + : timeStamp // ignore: cast_nullable_to_non_nullable + as DateTime?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$WebSocketFrameModelImplCopyWith<$Res> + implements $WebSocketFrameModelCopyWith<$Res> { + factory _$$WebSocketFrameModelImplCopyWith(_$WebSocketFrameModelImpl value, + $Res Function(_$WebSocketFrameModelImpl) then) = + __$$WebSocketFrameModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String id, + String frameType, + String message, + @Uint8ListConverter() Uint8List? binaryData, + Map? metadata, + bool isFinalFrame, + DateTime? timeStamp}); +} + +/// @nodoc +class __$$WebSocketFrameModelImplCopyWithImpl<$Res> + extends _$WebSocketFrameModelCopyWithImpl<$Res, _$WebSocketFrameModelImpl> + implements _$$WebSocketFrameModelImplCopyWith<$Res> { + __$$WebSocketFrameModelImplCopyWithImpl(_$WebSocketFrameModelImpl _value, + $Res Function(_$WebSocketFrameModelImpl) _then) + : super(_value, _then); + + /// Create a copy of WebSocketFrameModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? frameType = null, + Object? message = null, + Object? binaryData = freezed, + Object? metadata = freezed, + Object? isFinalFrame = null, + Object? timeStamp = freezed, + }) { + return _then(_$WebSocketFrameModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + frameType: null == frameType + ? _value.frameType + : frameType // ignore: cast_nullable_to_non_nullable + as String, + message: null == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String, + binaryData: freezed == binaryData + ? _value.binaryData + : binaryData // ignore: cast_nullable_to_non_nullable + as Uint8List?, + metadata: freezed == metadata + ? _value._metadata + : metadata // ignore: cast_nullable_to_non_nullable + as Map?, + isFinalFrame: null == isFinalFrame + ? _value.isFinalFrame + : isFinalFrame // ignore: cast_nullable_to_non_nullable + as bool, + timeStamp: freezed == timeStamp + ? _value.timeStamp + : timeStamp // ignore: cast_nullable_to_non_nullable + as DateTime?, + )); + } +} + +/// @nodoc + +@JsonSerializable(explicitToJson: true, anyMap: true) +class _$WebSocketFrameModelImpl extends _WebSocketFrameModel { + const _$WebSocketFrameModelImpl( + {required this.id, + this.frameType = "", + this.message = "", + @Uint8ListConverter() this.binaryData, + final Map? metadata, + this.isFinalFrame = false, + this.timeStamp}) + : _metadata = metadata, + super._(); + + factory _$WebSocketFrameModelImpl.fromJson(Map json) => + _$$WebSocketFrameModelImplFromJson(json); + + @override + final String id; + @override + @JsonKey() + final String frameType; + @override + @JsonKey() + final String message; + @override + @Uint8ListConverter() + final Uint8List? binaryData; + final Map? _metadata; + @override + Map? get metadata { + final value = _metadata; + if (value == null) return null; + if (_metadata is EqualUnmodifiableMapView) return _metadata; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(value); + } + + @override + @JsonKey() + final bool isFinalFrame; + @override + final DateTime? timeStamp; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$WebSocketFrameModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.frameType, frameType) || + other.frameType == frameType) && + (identical(other.message, message) || other.message == message) && + const DeepCollectionEquality() + .equals(other.binaryData, binaryData) && + const DeepCollectionEquality().equals(other._metadata, _metadata) && + (identical(other.isFinalFrame, isFinalFrame) || + other.isFinalFrame == isFinalFrame) && + (identical(other.timeStamp, timeStamp) || + other.timeStamp == timeStamp)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + id, + frameType, + message, + const DeepCollectionEquality().hash(binaryData), + const DeepCollectionEquality().hash(_metadata), + isFinalFrame, + timeStamp); + + /// Create a copy of WebSocketFrameModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$WebSocketFrameModelImplCopyWith<_$WebSocketFrameModelImpl> get copyWith => + __$$WebSocketFrameModelImplCopyWithImpl<_$WebSocketFrameModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$WebSocketFrameModelImplToJson( + this, + ); + } +} + +abstract class _WebSocketFrameModel extends WebSocketFrameModel { + const factory _WebSocketFrameModel( + {required final String id, + final String frameType, + final String message, + @Uint8ListConverter() final Uint8List? binaryData, + final Map? metadata, + final bool isFinalFrame, + final DateTime? timeStamp}) = _$WebSocketFrameModelImpl; + const _WebSocketFrameModel._() : super._(); + + factory _WebSocketFrameModel.fromJson(Map json) = + _$WebSocketFrameModelImpl.fromJson; + + @override + String get id; + @override + String get frameType; + @override + String get message; + @override + @Uint8ListConverter() + Uint8List? get binaryData; + @override + Map? get metadata; + @override + bool get isFinalFrame; + @override + DateTime? get timeStamp; + + /// Create a copy of WebSocketFrameModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$WebSocketFrameModelImplCopyWith<_$WebSocketFrameModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/models/websocket_frame_model.g.dart b/packages/apidash_core/lib/models/websocket_frame_model.g.dart new file mode 100644 index 000000000..a3299bc83 --- /dev/null +++ b/packages/apidash_core/lib/models/websocket_frame_model.g.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'websocket_frame_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$WebSocketFrameModelImpl _$$WebSocketFrameModelImplFromJson(Map json) => + _$WebSocketFrameModelImpl( + id: json['id'] as String, + frameType: json['frameType'] as String? ?? "", + message: json['message'] as String? ?? "", + binaryData: + const Uint8ListConverter().fromJson(json['binaryData'] as List?), + metadata: (json['metadata'] as Map?)?.map( + (k, e) => MapEntry(k as String, e as String), + ), + isFinalFrame: json['isFinalFrame'] as bool? ?? false, + timeStamp: json['timeStamp'] == null + ? null + : DateTime.parse(json['timeStamp'] as String), + ); + +Map _$$WebSocketFrameModelImplToJson( + _$WebSocketFrameModelImpl instance) => + { + 'id': instance.id, + 'frameType': instance.frameType, + 'message': instance.message, + 'binaryData': const Uint8ListConverter().toJson(instance.binaryData), + 'metadata': instance.metadata, + 'isFinalFrame': instance.isFinalFrame, + 'timeStamp': instance.timeStamp?.toIso8601String(), + }; diff --git a/packages/apidash_core/lib/models/websocket_request_model.dart b/packages/apidash_core/lib/models/websocket_request_model.dart index b2d89065b..9b6d77c28 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.dart @@ -24,6 +24,7 @@ class WebSocketRequestModel with _$WebSocketRequestModel { List? isHeaderEnabledList, List? params, List? isParamEnabledList, + String? message, @Default([]) List frames, List? receivedMessages, }) = _WebSocketRequestModel; diff --git a/packages/apidash_core/lib/models/websocket_request_model.freezed.dart b/packages/apidash_core/lib/models/websocket_request_model.freezed.dart index 082e368e9..81ff12b5d 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.freezed.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.freezed.dart @@ -27,6 +27,7 @@ mixin _$WebSocketRequestModel { List? get isHeaderEnabledList => throw _privateConstructorUsedError; List? get params => throw _privateConstructorUsedError; List? get isParamEnabledList => throw _privateConstructorUsedError; + String? get message => throw _privateConstructorUsedError; List get frames => throw _privateConstructorUsedError; List? get receivedMessages => throw _privateConstructorUsedError; @@ -53,6 +54,7 @@ abstract class $WebSocketRequestModelCopyWith<$Res> { List? isHeaderEnabledList, List? params, List? isParamEnabledList, + String? message, List frames, List? receivedMessages}); } @@ -79,6 +81,7 @@ class _$WebSocketRequestModelCopyWithImpl<$Res, Object? isHeaderEnabledList = freezed, Object? params = freezed, Object? isParamEnabledList = freezed, + Object? message = freezed, Object? frames = null, Object? receivedMessages = freezed, }) { @@ -107,6 +110,10 @@ class _$WebSocketRequestModelCopyWithImpl<$Res, ? _value.isParamEnabledList : isParamEnabledList // ignore: cast_nullable_to_non_nullable as List?, + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, frames: null == frames ? _value.frames : frames // ignore: cast_nullable_to_non_nullable @@ -135,6 +142,7 @@ abstract class _$$WebSocketRequestModelImplCopyWith<$Res> List? isHeaderEnabledList, List? params, List? isParamEnabledList, + String? message, List frames, List? receivedMessages}); } @@ -159,6 +167,7 @@ class __$$WebSocketRequestModelImplCopyWithImpl<$Res> Object? isHeaderEnabledList = freezed, Object? params = freezed, Object? isParamEnabledList = freezed, + Object? message = freezed, Object? frames = null, Object? receivedMessages = freezed, }) { @@ -187,6 +196,10 @@ class __$$WebSocketRequestModelImplCopyWithImpl<$Res> ? _value._isParamEnabledList : isParamEnabledList // ignore: cast_nullable_to_non_nullable as List?, + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, frames: null == frames ? _value._frames : frames // ignore: cast_nullable_to_non_nullable @@ -210,6 +223,7 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { final List? isHeaderEnabledList, final List? params, final List? isParamEnabledList, + this.message, final List frames = const [], final List? receivedMessages}) : _headers = headers, @@ -270,6 +284,8 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { return EqualUnmodifiableListView(value); } + @override + final String? message; final List _frames; @override @JsonKey() @@ -292,7 +308,7 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { @override String toString() { - return 'WebSocketRequestModel(url: $url, isConnected: $isConnected, headers: $headers, isHeaderEnabledList: $isHeaderEnabledList, params: $params, isParamEnabledList: $isParamEnabledList, frames: $frames, receivedMessages: $receivedMessages)'; + return 'WebSocketRequestModel(url: $url, isConnected: $isConnected, headers: $headers, isHeaderEnabledList: $isHeaderEnabledList, params: $params, isParamEnabledList: $isParamEnabledList, message: $message, frames: $frames, receivedMessages: $receivedMessages)'; } @override @@ -309,6 +325,7 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { const DeepCollectionEquality().equals(other._params, _params) && const DeepCollectionEquality() .equals(other._isParamEnabledList, _isParamEnabledList) && + (identical(other.message, message) || other.message == message) && const DeepCollectionEquality().equals(other._frames, _frames) && const DeepCollectionEquality() .equals(other._receivedMessages, _receivedMessages)); @@ -324,6 +341,7 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { const DeepCollectionEquality().hash(_isHeaderEnabledList), const DeepCollectionEquality().hash(_params), const DeepCollectionEquality().hash(_isParamEnabledList), + message, const DeepCollectionEquality().hash(_frames), const DeepCollectionEquality().hash(_receivedMessages)); @@ -352,6 +370,7 @@ abstract class _WebSocketRequestModel extends WebSocketRequestModel { final List? isHeaderEnabledList, final List? params, final List? isParamEnabledList, + final String? message, final List frames, final List? receivedMessages}) = _$WebSocketRequestModelImpl; const _WebSocketRequestModel._() : super._(); @@ -372,6 +391,8 @@ abstract class _WebSocketRequestModel extends WebSocketRequestModel { @override List? get isParamEnabledList; @override + String? get message; + @override List get frames; @override List? get receivedMessages; diff --git a/packages/apidash_core/lib/models/websocket_request_model.g.dart b/packages/apidash_core/lib/models/websocket_request_model.g.dart new file mode 100644 index 000000000..c6c4e9812 --- /dev/null +++ b/packages/apidash_core/lib/models/websocket_request_model.g.dart @@ -0,0 +1,50 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'websocket_request_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$WebSocketRequestModelImpl _$$WebSocketRequestModelImplFromJson(Map json) => + _$WebSocketRequestModelImpl( + url: json['url'] as String? ?? "", + isConnected: json['isConnected'] as bool?, + headers: (json['headers'] as List?) + ?.map((e) => + NameValueModel.fromJson(Map.from(e as Map))) + .toList(), + isHeaderEnabledList: (json['isHeaderEnabledList'] as List?) + ?.map((e) => e as bool) + .toList(), + params: (json['params'] as List?) + ?.map((e) => + NameValueModel.fromJson(Map.from(e as Map))) + .toList(), + isParamEnabledList: (json['isParamEnabledList'] as List?) + ?.map((e) => e as bool) + .toList(), + message: json['message'] as String?, + frames: (json['frames'] as List?) + ?.map((e) => WebSocketFrameModel.fromJson( + Map.from(e as Map))) + .toList() ?? + const [], + receivedMessages: (json['receivedMessages'] as List?) + ?.map((e) => e as String) + .toList(), + ); + +Map _$$WebSocketRequestModelImplToJson( + _$WebSocketRequestModelImpl instance) => + { + 'url': instance.url, + 'isConnected': instance.isConnected, + 'headers': instance.headers?.map((e) => e.toJson()).toList(), + 'isHeaderEnabledList': instance.isHeaderEnabledList, + 'params': instance.params?.map((e) => e.toJson()).toList(), + 'isParamEnabledList': instance.isParamEnabledList, + 'message': instance.message, + 'frames': instance.frames.map((e) => e.toJson()).toList(), + 'receivedMessages': instance.receivedMessages, + }; diff --git a/packages/apidash_core/lib/services/clientWrapper.dart b/packages/apidash_core/lib/services/clientWrapper.dart index 037c4142d..63f8efb0d 100644 --- a/packages/apidash_core/lib/services/clientWrapper.dart +++ b/packages/apidash_core/lib/services/clientWrapper.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:apidash_core/services/clientWrapper.dart' as http; import 'package:apidash_core/services/websocket_service.dart'; import 'package:http/http.dart' as http; @@ -11,7 +13,7 @@ class HttpClientWrapper extends clientWrapper { HttpClientWrapper(this.client); @override void close() { - print("cancelling under rest"); + log("cancelling under rest"); client.close(); } } @@ -21,7 +23,7 @@ class WebSocketClientWrapper extends clientWrapper { WebSocketClientWrapper(this.client); @override void close() { - print("cancelling under websocket"); + log("cancelling under websocket"); client.disconnect(); } diff --git a/packages/apidash_core/lib/services/http_client_manager.dart b/packages/apidash_core/lib/services/http_client_manager.dart index 8bd9814c4..330307ad4 100644 --- a/packages/apidash_core/lib/services/http_client_manager.dart +++ b/packages/apidash_core/lib/services/http_client_manager.dart @@ -2,10 +2,11 @@ import 'dart:io'; import 'dart:collection'; import 'package:apidash_core/consts.dart'; import 'package:apidash_core/services/clientWrapper.dart'; +import 'package:apidash_core/services/websocket_service.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:http/io_client.dart'; -import '' + http.Client createHttpClientWithNoSSL() { var ioClient = HttpClient() @@ -26,21 +27,26 @@ class HttpClientManager { HttpClientManager._internal(); + WebSocketClient createWebSocketClient( + String requestId, { + bool noSSL = false, + }) { + final client = WebSocketClient(); + _clients[requestId] = WebSocketClientWrapper(client); + return client; + } + http.Client createClient( String requestId, { bool noSSL = false, }) { - switch(getRequestModel(requestId).apiType){ - case APIType.rest: - - case APIType.websocket: - - } + final client = (noSSL && !kIsWeb) ? createHttpClientWithNoSSL() : http.Client(); - _clients[requestId] = client; + _clients[requestId] = HttpClientWrapper(client); return client; } + void cancelRequest(String? requestId) { if (requestId != null && _clients.containsKey(requestId)) { diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index 4936ad5eb..0fa07d7ed 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -1,61 +1,66 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'dart:typed_data'; +import 'package:apidash_core/models/models.dart'; +import 'package:apidash_core/models/websocket_request_model.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:web_socket_channel/status.dart' as status; class WebSocketClient { - final String url; late WebSocketChannel _channel; StreamSubscription? _subscription; - WebSocketClient(this.url); + WebSocketClient(); - Future connect() async { + Future<(String?,DateTime?)> connect(HttpRequestModel websocketRequestModel) async { + print("inside client connect"); try { - _channel = WebSocketChannel.connect(Uri.parse(url)); - print('Connected to WebSocket server: $url'); - } catch (e) { + _channel = WebSocketChannel.connect(Uri.parse("ws://localhost:3000")); + await _channel.ready; + print('Connected to WebSocket server: ${"ws://localhost:3000"}'); + return ("Connected",DateTime.now()); + } catch (e) { print('Failed to connect to WebSocket server: $e'); - rethrow; + return (e.toString(),DateTime.now()); } } - void sendText(String message) { - if (_channel != null) { - _channel.sink.add(message); - print('Sent text message: $message'); - } else { - print('WebSocket connection is not open. Unable to send text message.'); - } - } + // Future<(String?,DateTime?)> sendText(WebSocketRequestModel websocketRequestModel) { + // if (_channel != null) { + // _channel.sink.add(websocketRequestModel.message); + // log('Sent text message: ${websocketRequestModel.message}'); + // } else { + // log('WebSocket connection is not open. Unable to send text message.'); + // } + // } - void sendBinary(Uint8List data) { - if (_channel != null) { - _channel.sink.add(data); - print('Sent binary message: $data'); - } else { - print('WebSocket connection is not open. Unable to send binary message.'); - } - } + // Future<(String?,DateTime?)> sendBinary(Uint8List data) { + // if (_channel != null) { + // _channel.sink.add(data); + // log('Sent binary message: $data'); + // } else { + // log('WebSocket connection is not open. Unable to send binary message.'); + // } + // } - void listen(void Function(dynamic message) onMessage, - {void Function(dynamic error)? onError, void Function()? onDone}) { + Future listen(Future Function(dynamic message) onMessage, + {Future Function(dynamic error)? onError, Future Function()? onDone}) async{ _subscription = _channel.stream.listen( (message) { - print('Received message: $message'); + log('Received message: $message'); onMessage(message); }, onError: (error) { - print('Error: $error'); + log('Error: $error'); if (onError != null) onError(error); }, onDone: () { - print('Connection closed.'); + log('Connection closed.'); if (onDone != null) onDone(); }, cancelOnError: true, @@ -63,53 +68,53 @@ class WebSocketClient { } - void disconnect({int closeCode = status.normalClosure, String? reason}) { + Future disconnect({int closeCode = status.normalClosure, String? reason})async { _subscription?.cancel(); _channel.sink.close(closeCode, reason); - print('Disconnected from WebSocket server'); + log('Disconnected from WebSocket server'); } } -void main() async { - const wsUrl = 'ws://localhost:3000'; +// Future<(String?,DateTime?)> main() async { +// const wsUrl = '"ws://localhost:3000"'; - final wsClient = WebSocketClient(wsUrl); +// final wsClient = WebSocketClient(wsUrl); - try { - await wsClient.connect(); +// try { +// await wsClient.connect(); - wsClient.listen( - (message) { - // Handle incoming messages - if (message is String) { - print('Text message received: $message'); - } else if (message is List) { - print('Binary message received: $message'); - } - }, - onError: (error) { - print('Error occurred: $error'); - }, - onDone: () { - print('WebSocket connection closed.'); - }, - ); +// wsClient.listen( +// (message) { +// // Handle incoming messages +// if (message is String) { +// log('Text message received: $message'); +// } else if (message is List) { +// log('Binary message received: $message'); +// } +// }, +// onError: (error) { +// log('Error occurred: $error'); +// }, +// onDone: () { +// log('WebSocket connection closed.'); +// }, +// ); - wsClient.sendText('Hello, WebSocket!'); +// wsClient.sendText('Hello, WebSocket!'); - final binaryData = Uint8List.fromList([0x68, 0x69]); // "hi" in binary - wsClient.sendBinary(binaryData); +// final binaryData = Uint8List.fromList([0x68, 0x69]); // "hi" in binary +// wsClient.sendBinary(binaryData); - await Future.delayed(Duration(seconds: 5)); - while(True){ - - } - wsClient.disconnect(reason: 'Closing connection after demo.'); - } catch (e) { - print('Error: $e'); - } -} +// await Future.delayed(Duration(seconds: 5)); +// while(True){ + +// } +// wsClient.disconnect(reason: 'Closing connection after demo.'); +// } catch (e) { +// log('Error: $e'); +// } +// } diff --git a/packages/apidash_core/pubspec.yaml b/packages/apidash_core/pubspec.yaml index e76247498..11f3f7fb6 100644 --- a/packages/apidash_core/pubspec.yaml +++ b/packages/apidash_core/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: path: ../postman seed: ^0.0.3 xml: ^6.3.0 - intl: ^0.20.1 + intl: ^0.19.0 json_serializable: ^6.9.0 dev_dependencies: From 248010f5edb7fd831dadc7a67390dce790c63133 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Thu, 23 Jan 2025 23:10:08 +0530 Subject: [PATCH 07/30] working on sending frames --- lib/consts.dart | 4 + lib/models/history_request_model.dart | 3 + lib/models/history_request_model.freezed.dart | 92 +++++- lib/models/history_request_model.g.dart | 6 + lib/models/request_model.dart | 2 + lib/models/request_model.freezed.dart | 43 ++- lib/models/request_model.g.dart | 5 + lib/providers/collection_providers.dart | 207 ++++++++++---- .../request_pane/request_body.dart | 59 ++-- .../request_pane/request_pane_websocket.dart | 2 +- .../details_card/response_pane.dart | 85 ++++-- .../home_page/editor_pane/url_card.dart | 25 +- lib/screens/settings_page.dart | 14 + lib/widgets/button_connection.dart | 10 +- .../dropdown_websocket_content_type.dart | 24 ++ lib/widgets/websocket_frame.dart | 46 ++- packages/apidash_core/lib/consts.dart | 12 + packages/apidash_core/lib/models/models.dart | 3 + .../lib/models/websocket_request_model.dart | 10 +- .../websocket_request_model.freezed.dart | 54 ++-- .../lib/models/websocket_request_model.g.dart | 15 +- .../lib/models/websocket_response_model.dart | 28 ++ .../websocket_response_model.freezed.dart | 270 ++++++++++++++++++ .../models/websocket_response_model.g.dart | 32 +++ .../lib/services/clientWrapper.dart | 7 + .../lib/services/http_client_manager.dart | 4 + .../lib/services/websocket_service.dart | 40 ++- 27 files changed, 933 insertions(+), 169 deletions(-) create mode 100644 lib/widgets/dropdown_websocket_content_type.dart create mode 100644 packages/apidash_core/lib/models/websocket_response_model.dart create mode 100644 packages/apidash_core/lib/models/websocket_response_model.freezed.dart create mode 100644 packages/apidash_core/lib/models/websocket_response_model.g.dart diff --git a/lib/consts.dart b/lib/consts.dart index d03980f9e..7640e7b47 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -432,6 +432,8 @@ const kLabelContinue = "Continue"; const kLabelCancel = "Cancel"; const kLabelOk = "Ok"; const kUntitled = "untitled"; +const KLabelConnect = "Connect"; +const kLabelDisconnect = "Disconnect"; // Request Pane const kLabelRequest = "Request"; const kLabelHideCode = "Hide Code"; @@ -440,6 +442,7 @@ const kLabelURLParams = "URL Params"; const kLabelHeaders = "Headers"; const kLabelBody = "Body"; const kLabelQuery = "Query"; +const kLabelMessage = "Message"; const kNameCheckbox = "Checkbox"; const kNameURLParam = "URL Parameter"; const kNameHeader = "Header Name"; @@ -458,6 +461,7 @@ const kHintContent = "Enter content"; const kHintText = "Enter text"; const kHintJson = "Enter JSON"; const kHintQuery = "Enter Query"; +const kHintMessage = "Enter message"; // Response Pane const kLabelNotSent = "Not Sent"; const kLabelResponse = "Response"; diff --git a/lib/models/history_request_model.dart b/lib/models/history_request_model.dart index a895e945c..6623a5445 100644 --- a/lib/models/history_request_model.dart +++ b/lib/models/history_request_model.dart @@ -16,6 +16,9 @@ class HistoryRequestModel with _$HistoryRequestModel { required HistoryMetaModel metaData, required HttpRequestModel httpRequestModel, required HttpResponseModel httpResponseModel, + required WebSocketRequestModel webSocketRequestModel, + required WebSocketResponseModel webSocketResponseModel, + }) = _HistoryRequestModel; factory HistoryRequestModel.fromJson(Map json) => diff --git a/lib/models/history_request_model.freezed.dart b/lib/models/history_request_model.freezed.dart index bb7e94924..ddac2d4d0 100644 --- a/lib/models/history_request_model.freezed.dart +++ b/lib/models/history_request_model.freezed.dart @@ -24,6 +24,10 @@ mixin _$HistoryRequestModel { HistoryMetaModel get metaData => throw _privateConstructorUsedError; HttpRequestModel get httpRequestModel => throw _privateConstructorUsedError; HttpResponseModel get httpResponseModel => throw _privateConstructorUsedError; + WebSocketRequestModel get webSocketRequestModel => + throw _privateConstructorUsedError; + WebSocketResponseModel get webSocketResponseModel => + throw _privateConstructorUsedError; /// Serializes this HistoryRequestModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -45,11 +49,15 @@ abstract class $HistoryRequestModelCopyWith<$Res> { {String historyId, HistoryMetaModel metaData, HttpRequestModel httpRequestModel, - HttpResponseModel httpResponseModel}); + HttpResponseModel httpResponseModel, + WebSocketRequestModel webSocketRequestModel, + WebSocketResponseModel webSocketResponseModel}); $HistoryMetaModelCopyWith<$Res> get metaData; $HttpRequestModelCopyWith<$Res> get httpRequestModel; $HttpResponseModelCopyWith<$Res> get httpResponseModel; + $WebSocketRequestModelCopyWith<$Res> get webSocketRequestModel; + $WebSocketResponseModelCopyWith<$Res> get webSocketResponseModel; } /// @nodoc @@ -71,6 +79,8 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> Object? metaData = null, Object? httpRequestModel = null, Object? httpResponseModel = null, + Object? webSocketRequestModel = null, + Object? webSocketResponseModel = null, }) { return _then(_value.copyWith( historyId: null == historyId @@ -89,6 +99,14 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel, + webSocketRequestModel: null == webSocketRequestModel + ? _value.webSocketRequestModel + : webSocketRequestModel // ignore: cast_nullable_to_non_nullable + as WebSocketRequestModel, + webSocketResponseModel: null == webSocketResponseModel + ? _value.webSocketResponseModel + : webSocketResponseModel // ignore: cast_nullable_to_non_nullable + as WebSocketResponseModel, ) as $Val); } @@ -121,6 +139,28 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> return _then(_value.copyWith(httpResponseModel: value) as $Val); }); } + + /// Create a copy of HistoryRequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $WebSocketRequestModelCopyWith<$Res> get webSocketRequestModel { + return $WebSocketRequestModelCopyWith<$Res>(_value.webSocketRequestModel, + (value) { + return _then(_value.copyWith(webSocketRequestModel: value) as $Val); + }); + } + + /// Create a copy of HistoryRequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $WebSocketResponseModelCopyWith<$Res> get webSocketResponseModel { + return $WebSocketResponseModelCopyWith<$Res>(_value.webSocketResponseModel, + (value) { + return _then(_value.copyWith(webSocketResponseModel: value) as $Val); + }); + } } /// @nodoc @@ -135,7 +175,9 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res> {String historyId, HistoryMetaModel metaData, HttpRequestModel httpRequestModel, - HttpResponseModel httpResponseModel}); + HttpResponseModel httpResponseModel, + WebSocketRequestModel webSocketRequestModel, + WebSocketResponseModel webSocketResponseModel}); @override $HistoryMetaModelCopyWith<$Res> get metaData; @@ -143,6 +185,10 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res> $HttpRequestModelCopyWith<$Res> get httpRequestModel; @override $HttpResponseModelCopyWith<$Res> get httpResponseModel; + @override + $WebSocketRequestModelCopyWith<$Res> get webSocketRequestModel; + @override + $WebSocketResponseModelCopyWith<$Res> get webSocketResponseModel; } /// @nodoc @@ -162,6 +208,8 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> Object? metaData = null, Object? httpRequestModel = null, Object? httpResponseModel = null, + Object? webSocketRequestModel = null, + Object? webSocketResponseModel = null, }) { return _then(_$HistoryRequestModelImpl( historyId: null == historyId @@ -180,6 +228,14 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel, + webSocketRequestModel: null == webSocketRequestModel + ? _value.webSocketRequestModel + : webSocketRequestModel // ignore: cast_nullable_to_non_nullable + as WebSocketRequestModel, + webSocketResponseModel: null == webSocketResponseModel + ? _value.webSocketResponseModel + : webSocketResponseModel // ignore: cast_nullable_to_non_nullable + as WebSocketResponseModel, )); } } @@ -192,7 +248,9 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { {required this.historyId, required this.metaData, required this.httpRequestModel, - required this.httpResponseModel}); + required this.httpResponseModel, + required this.webSocketRequestModel, + required this.webSocketResponseModel}); factory _$HistoryRequestModelImpl.fromJson(Map json) => _$$HistoryRequestModelImplFromJson(json); @@ -205,10 +263,14 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { final HttpRequestModel httpRequestModel; @override final HttpResponseModel httpResponseModel; + @override + final WebSocketRequestModel webSocketRequestModel; + @override + final WebSocketResponseModel webSocketResponseModel; @override String toString() { - return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, httpResponseModel: $httpResponseModel)'; + return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, httpResponseModel: $httpResponseModel, webSocketRequestModel: $webSocketRequestModel, webSocketResponseModel: $webSocketResponseModel)'; } @override @@ -223,13 +285,23 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { (identical(other.httpRequestModel, httpRequestModel) || other.httpRequestModel == httpRequestModel) && (identical(other.httpResponseModel, httpResponseModel) || - other.httpResponseModel == httpResponseModel)); + other.httpResponseModel == httpResponseModel) && + (identical(other.webSocketRequestModel, webSocketRequestModel) || + other.webSocketRequestModel == webSocketRequestModel) && + (identical(other.webSocketResponseModel, webSocketResponseModel) || + other.webSocketResponseModel == webSocketResponseModel)); } @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( - runtimeType, historyId, metaData, httpRequestModel, httpResponseModel); + runtimeType, + historyId, + metaData, + httpRequestModel, + httpResponseModel, + webSocketRequestModel, + webSocketResponseModel); /// Create a copy of HistoryRequestModel /// with the given fields replaced by the non-null parameter values. @@ -253,7 +325,9 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { {required final String historyId, required final HistoryMetaModel metaData, required final HttpRequestModel httpRequestModel, - required final HttpResponseModel httpResponseModel}) = + required final HttpResponseModel httpResponseModel, + required final WebSocketRequestModel webSocketRequestModel, + required final WebSocketResponseModel webSocketResponseModel}) = _$HistoryRequestModelImpl; factory _HistoryRequestModel.fromJson(Map json) = @@ -267,6 +341,10 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { HttpRequestModel get httpRequestModel; @override HttpResponseModel get httpResponseModel; + @override + WebSocketRequestModel get webSocketRequestModel; + @override + WebSocketResponseModel get webSocketResponseModel; /// Create a copy of HistoryRequestModel /// with the given fields replaced by the non-null parameter values. diff --git a/lib/models/history_request_model.g.dart b/lib/models/history_request_model.g.dart index 830d7a4cf..611b5bf86 100644 --- a/lib/models/history_request_model.g.dart +++ b/lib/models/history_request_model.g.dart @@ -15,6 +15,10 @@ _$HistoryRequestModelImpl _$$HistoryRequestModelImplFromJson(Map json) => Map.from(json['httpRequestModel'] as Map)), httpResponseModel: HttpResponseModel.fromJson( Map.from(json['httpResponseModel'] as Map)), + webSocketRequestModel: WebSocketRequestModel.fromJson( + Map.from(json['webSocketRequestModel'] as Map)), + webSocketResponseModel: WebSocketResponseModel.fromJson( + Map.from(json['webSocketResponseModel'] as Map)), ); Map _$$HistoryRequestModelImplToJson( @@ -24,4 +28,6 @@ Map _$$HistoryRequestModelImplToJson( 'metaData': instance.metaData.toJson(), 'httpRequestModel': instance.httpRequestModel.toJson(), 'httpResponseModel': instance.httpResponseModel.toJson(), + 'webSocketRequestModel': instance.webSocketRequestModel.toJson(), + 'webSocketResponseModel': instance.webSocketResponseModel.toJson(), }; diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index 7e55d9c96..3083a54ec 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -1,5 +1,6 @@ import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_core/models/websocket_request_model.dart'; +import 'package:apidash_core/models/websocket_response_model.dart'; part 'request_model.freezed.dart'; @@ -22,6 +23,7 @@ class RequestModel with _$RequestModel { int? responseStatus, String? message, HttpResponseModel? httpResponseModel, + WebSocketResponseModel? webSocketResponseModel, @JsonKey(includeToJson: false) @Default(false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, }) = _RequestModel; diff --git a/lib/models/request_model.freezed.dart b/lib/models/request_model.freezed.dart index 078d87266..15da0e7b6 100644 --- a/lib/models/request_model.freezed.dart +++ b/lib/models/request_model.freezed.dart @@ -33,6 +33,8 @@ mixin _$RequestModel { String? get message => throw _privateConstructorUsedError; HttpResponseModel? get httpResponseModel => throw _privateConstructorUsedError; + WebSocketResponseModel? get webSocketResponseModel => + throw _privateConstructorUsedError; @JsonKey(includeToJson: false) bool get isWorking => throw _privateConstructorUsedError; @JsonKey(includeToJson: false) @@ -65,12 +67,14 @@ abstract class $RequestModelCopyWith<$Res> { int? responseStatus, String? message, HttpResponseModel? httpResponseModel, + WebSocketResponseModel? webSocketResponseModel, @JsonKey(includeToJson: false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime}); $HttpRequestModelCopyWith<$Res>? get httpRequestModel; $WebSocketRequestModelCopyWith<$Res>? get webSocketRequestModel; $HttpResponseModelCopyWith<$Res>? get httpResponseModel; + $WebSocketResponseModelCopyWith<$Res>? get webSocketResponseModel; } /// @nodoc @@ -98,6 +102,7 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> Object? responseStatus = freezed, Object? message = freezed, Object? httpResponseModel = freezed, + Object? webSocketResponseModel = freezed, Object? isWorking = null, Object? sendingTime = freezed, }) { @@ -142,6 +147,10 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel?, + webSocketResponseModel: freezed == webSocketResponseModel + ? _value.webSocketResponseModel + : webSocketResponseModel // ignore: cast_nullable_to_non_nullable + as WebSocketResponseModel?, isWorking: null == isWorking ? _value.isWorking : isWorking // ignore: cast_nullable_to_non_nullable @@ -195,6 +204,21 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> return _then(_value.copyWith(httpResponseModel: value) as $Val); }); } + + /// Create a copy of RequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $WebSocketResponseModelCopyWith<$Res>? get webSocketResponseModel { + if (_value.webSocketResponseModel == null) { + return null; + } + + return $WebSocketResponseModelCopyWith<$Res>(_value.webSocketResponseModel!, + (value) { + return _then(_value.copyWith(webSocketResponseModel: value) as $Val); + }); + } } /// @nodoc @@ -216,6 +240,7 @@ abstract class _$$RequestModelImplCopyWith<$Res> int? responseStatus, String? message, HttpResponseModel? httpResponseModel, + WebSocketResponseModel? webSocketResponseModel, @JsonKey(includeToJson: false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime}); @@ -225,6 +250,8 @@ abstract class _$$RequestModelImplCopyWith<$Res> $WebSocketRequestModelCopyWith<$Res>? get webSocketRequestModel; @override $HttpResponseModelCopyWith<$Res>? get httpResponseModel; + @override + $WebSocketResponseModelCopyWith<$Res>? get webSocketResponseModel; } /// @nodoc @@ -250,6 +277,7 @@ class __$$RequestModelImplCopyWithImpl<$Res> Object? responseStatus = freezed, Object? message = freezed, Object? httpResponseModel = freezed, + Object? webSocketResponseModel = freezed, Object? isWorking = null, Object? sendingTime = freezed, }) { @@ -293,6 +321,10 @@ class __$$RequestModelImplCopyWithImpl<$Res> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel?, + webSocketResponseModel: freezed == webSocketResponseModel + ? _value.webSocketResponseModel + : webSocketResponseModel // ignore: cast_nullable_to_non_nullable + as WebSocketResponseModel?, isWorking: null == isWorking ? _value.isWorking : isWorking // ignore: cast_nullable_to_non_nullable @@ -320,6 +352,7 @@ class _$RequestModelImpl implements _RequestModel { this.responseStatus, this.message, this.httpResponseModel, + this.webSocketResponseModel, @JsonKey(includeToJson: false) this.isWorking = false, @JsonKey(includeToJson: false) this.sendingTime}); @@ -351,6 +384,8 @@ class _$RequestModelImpl implements _RequestModel { @override final HttpResponseModel? httpResponseModel; @override + final WebSocketResponseModel? webSocketResponseModel; + @override @JsonKey(includeToJson: false) final bool isWorking; @override @@ -359,7 +394,7 @@ class _$RequestModelImpl implements _RequestModel { @override String toString() { - return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, webSocketRequestModel: $webSocketRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, webSocketRequestModel: $webSocketRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, webSocketResponseModel: $webSocketResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; } @override @@ -383,6 +418,8 @@ class _$RequestModelImpl implements _RequestModel { (identical(other.message, message) || other.message == message) && (identical(other.httpResponseModel, httpResponseModel) || other.httpResponseModel == httpResponseModel) && + (identical(other.webSocketResponseModel, webSocketResponseModel) || + other.webSocketResponseModel == webSocketResponseModel) && (identical(other.isWorking, isWorking) || other.isWorking == isWorking) && (identical(other.sendingTime, sendingTime) || @@ -403,6 +440,7 @@ class _$RequestModelImpl implements _RequestModel { responseStatus, message, httpResponseModel, + webSocketResponseModel, isWorking, sendingTime); @@ -434,6 +472,7 @@ abstract class _RequestModel implements RequestModel { final int? responseStatus, final String? message, final HttpResponseModel? httpResponseModel, + final WebSocketResponseModel? webSocketResponseModel, @JsonKey(includeToJson: false) final bool isWorking, @JsonKey(includeToJson: false) final DateTime? sendingTime}) = _$RequestModelImpl; @@ -463,6 +502,8 @@ abstract class _RequestModel implements RequestModel { @override HttpResponseModel? get httpResponseModel; @override + WebSocketResponseModel? get webSocketResponseModel; + @override @JsonKey(includeToJson: false) bool get isWorking; @override diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index a2b4301db..4fe406112 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -27,6 +27,10 @@ _$RequestModelImpl _$$RequestModelImplFromJson(Map json) => _$RequestModelImpl( ? null : HttpResponseModel.fromJson( Map.from(json['httpResponseModel'] as Map)), + webSocketResponseModel: json['webSocketResponseModel'] == null + ? null + : WebSocketResponseModel.fromJson( + Map.from(json['webSocketResponseModel'] as Map)), isWorking: json['isWorking'] as bool? ?? false, sendingTime: json['sendingTime'] == null ? null @@ -44,6 +48,7 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => 'responseStatus': instance.responseStatus, 'message': instance.message, 'httpResponseModel': instance.httpResponseModel?.toJson(), + 'webSocketResponseModel': instance.webSocketResponseModel?.toJson(), }; const _$APITypeEnumMap = { diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 5aebf6030..647e15d22 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -4,6 +4,7 @@ import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/consts.dart'; +import 'package:highlighter/languages/q.dart'; import 'providers.dart'; import '../models/models.dart'; import '../services/services.dart' show hiveHandler, HiveHandler; @@ -76,6 +77,7 @@ class CollectionStateNotifier final newRequestModel = RequestModel( id: id, httpRequestModel: const HttpRequestModel(), + webSocketRequestModel: const WebSocketRequestModel(), ); var map = {...state!}; map[id] = newRequestModel; @@ -229,46 +231,68 @@ class CollectionStateNotifier int? responseStatus, String? message, HttpResponseModel? httpResponseModel, - }) { +}) { final rId = id ?? ref.read(selectedIdStateProvider); if (rId == null) { - debugPrint("Unable to update as Request Id is null"); - return; + debugPrint("Unable to update as Request Id is null"); + return; } + var currentModel = state![rId]!; + var currentApiType = apiType ?? currentModel.apiType; var currentHttpRequestModel = currentModel.httpRequestModel; + final newHttpRequestModel = currentApiType == APIType.rest ? + currentHttpRequestModel?.copyWith( + method: method ?? currentHttpRequestModel.method, + url: url ?? currentHttpRequestModel.url, + headers: headers ?? currentHttpRequestModel.headers, + params: params ?? currentHttpRequestModel.params, + isHeaderEnabledList: isHeaderEnabledList ?? + currentHttpRequestModel.isHeaderEnabledList, + isParamEnabledList: + isParamEnabledList ?? currentHttpRequestModel.isParamEnabledList, + bodyContentType: + bodyContentType ?? currentHttpRequestModel.bodyContentType, + body: body ?? currentHttpRequestModel.body, + query: query ?? currentHttpRequestModel.query, + formData: formData ?? currentHttpRequestModel.formData, + ) : currentHttpRequestModel; + + var currentWebSocketRequestModel = currentModel.webSocketRequestModel; + final newWebSocketRequestModel = currentApiType == APIType.webSocket + ? currentWebSocketRequestModel?.copyWith( + url: url ?? currentWebSocketRequestModel.url, + headers: headers ?? currentWebSocketRequestModel.headers, + params: params ?? currentWebSocketRequestModel.params, + isHeaderEnabledList: isHeaderEnabledList ?? + currentWebSocketRequestModel.isHeaderEnabledList, + isParamEnabledList: + isParamEnabledList ?? currentWebSocketRequestModel.isParamEnabledList, + message: message ?? currentWebSocketRequestModel.message, + ) + : currentWebSocketRequestModel; + final newModel = currentModel.copyWith( - apiType: apiType ?? currentModel.apiType, - name: name ?? currentModel.name, - description: description ?? currentModel.description, - requestTabIndex: requestTabIndex ?? currentModel.requestTabIndex, - httpRequestModel: currentHttpRequestModel?.copyWith( - method: method ?? currentHttpRequestModel.method, - url: url ?? currentHttpRequestModel.url, - headers: headers ?? currentHttpRequestModel.headers, - params: params ?? currentHttpRequestModel.params, - isHeaderEnabledList: - isHeaderEnabledList ?? currentHttpRequestModel.isHeaderEnabledList, - isParamEnabledList: - isParamEnabledList ?? currentHttpRequestModel.isParamEnabledList, - bodyContentType: - bodyContentType ?? currentHttpRequestModel.bodyContentType, - body: body ?? currentHttpRequestModel.body, - query: query ?? currentHttpRequestModel.query, - formData: formData ?? currentHttpRequestModel.formData, - ), - responseStatus: responseStatus ?? currentModel.responseStatus, - message: message ?? currentModel.message, - httpResponseModel: httpResponseModel ?? currentModel.httpResponseModel, + apiType: apiType ?? currentModel.apiType, + name: name ?? currentModel.name, + description: description ?? currentModel.description, + requestTabIndex: requestTabIndex ?? currentModel.requestTabIndex, + httpRequestModel: newHttpRequestModel, + webSocketRequestModel: newWebSocketRequestModel, + responseStatus: responseStatus ?? currentModel.responseStatus, + message: message ?? currentModel.message, + httpResponseModel: httpResponseModel ?? currentModel.httpResponseModel, ); var map = {...state!}; map[rId] = newModel; state = map; unsave(); - } +} + Future sendRequest() async { + final requestId = ref.read(selectedIdStateProvider); ref.read(codePaneVisibleStateProvider.notifier).state = false; final defaultUriScheme = ref.read(settingsProvider).defaultUriScheme; @@ -283,6 +307,7 @@ class CollectionStateNotifier } APIType apiType = requestModel!.apiType; + HttpRequestModel substitutedHttpRequestModel = getSubstitutedHttpRequestModel(requestModel.httpRequestModel!); @@ -337,6 +362,9 @@ class CollectionStateNotifier ), httpRequestModel: substitutedHttpRequestModel, httpResponseModel: httpResponseModel, + webSocketRequestModel: WebSocketRequestModel(), // still not set up but an error was occuring here so had to fill it with something + webSocketResponseModel: WebSocketResponseModel() + ); ref.read(historyMetaStateNotifier.notifier).addHistoryRequest(model); } @@ -433,6 +461,51 @@ class CollectionStateNotifier activeEnvId, ); } + + Future sendFrames() async { + final requestId = ref.read(selectedIdStateProvider); + ref.read(codePaneVisibleStateProvider.notifier).state = false; + final defaultUriScheme = ref.read(settingsProvider).defaultUriScheme; + + if (requestId == null || state == null) { + return; + } + RequestModel? requestModel = state![requestId]; + + if (requestModel?.webSocketRequestModel== null) { + return; + } + + + + // substituted websocket needs to be added here + + // set current model's isWorking to true and update state + var map = {...state!}; + map[requestId] = requestModel!.copyWith( + isWorking: true, + ); + state = map; + + + + final client = httpClientManager.createWebSocketClient(requestId); + await client.sendText(requestModel.webSocketRequestModel!); + + + final newRequestModel = requestModel.copyWith( + webSocketRequestModel: requestModel.webSocketRequestModel, + isWorking: false, + ); + // update state with response data + map = {...state!}; + map[requestId] = newRequestModel; + state = map; + + unsave(); + } + + Future connect() async { print("connect fired"); final requestId = ref.read(selectedIdStateProvider); @@ -448,18 +521,41 @@ class CollectionStateNotifier // print("no web socket request model"); // return; // } + if (requestModel?.webSocketRequestModel == null) { + print("entered null"); + return; + } final client = httpClientManager.createWebSocketClient(requestId); - client.connect(requestModel!.httpRequestModel!); + final url = requestModel!.webSocketRequestModel!.url; + (String?,DateTime?) result = await client.connect(url); + + var map = {...state!}; + map[requestId] = requestModel.copyWith( + isWorking: result.$1 == "Connected", + sendingTime: result.$2, + webSocketResponseModel: WebSocketResponseModel(), + ); + state = map; + + client.listen( (message) async{ - // var map = {...state!}; - // map[requestId] = requestModel.copyWith( - // responseStatus: 200, - // message: message, - // isWorking: false, - // ); - // state = map; + var map = {...state!}; + RequestModel? requestModel = state![requestId]; + WebSocketResponseModel webSocketResponseModel = requestModel!.webSocketResponseModel!; + WebSocketResponseModel newWebSocketResponseModel = webSocketResponseModel.copyWith( + frames: [...webSocketResponseModel.frames, WebSocketFrameModel( + id: '1', + message: message, + timeStamp: DateTime.now(), + )] + ); + map[requestId] = requestModel.copyWith( + webSocketResponseModel: newWebSocketResponseModel, + ); + state = map; + print(message); }, onError: (error) async{ // var map = {...state!}; @@ -480,24 +576,35 @@ class CollectionStateNotifier // state = map; }, ); + } - Future disconnect() async { - print("connect fired"); - final requestId = ref.read(selectedIdStateProvider); - ref.read(codePaneVisibleStateProvider.notifier).state = false; - if (requestId == null || state == null) { - print(requestId); - return; - } - - RequestModel? requestModel = state![requestId]; - - // if (requestModel?.webSocketRequestModel == null) { - // print("no web socket request model"); + // ignore: unused_element + // Future disconnect() async { + // print("connect fired"); + // final requestId = ref.read(selectedIdStateProvider); + // ref.read(codePaneVisibleStateProvider.notifier).state = false; + // if (requestId == null || state == null) { + // print(requestId); // return; // } - final client = httpClientManager.createWebSocketClient(requestId); - client.disconnect(); - } + + + + // RequestModel? requestModel = state![requestId]; + + + // // if (requestModel?.webSocketRequestModel == null) { + // // print("no web socket request model"); + // // return; + // // } + + // final client = httpClientManager.(requestId); + + // var map = {...state!}; + // map[requestId] = requestModel!.copyWith( + // isWorking: false, + // ); + // state = map; + // } } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 34c4a2fcd..354bba1a0 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -1,3 +1,4 @@ +import 'package:apidash/widgets/dropdown_websocket_content_type.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; @@ -38,16 +39,28 @@ class EditRequestBody extends ConsumerWidget { return Column( children: [ - (apiType == APIType.rest) - ? const SizedBox( + (apiType == APIType.webSocket) //dont forget to make it switch and put for rest + ? SizedBox( height: kHeaderHeight, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const SizedBox( + height: kHeaderHeight, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( + Text( "Select Content Type:", ), - DropdownButtonBodyContentType(), + + DropdownButtonBodyContentWebSocketType(), + + ]),), + + SendButton(isWorking: false, onTap: (){ + ref.read(collectionStateNotifierProvider.notifier).sendFrames(); + }), ], ), ) @@ -100,11 +113,11 @@ class EditRequestBody extends ConsumerWidget { child: TextFieldEditor( key: Key("$selectedId-query"), fieldKey: "$selectedId-query-editor", - initialValue: requestModel?.httpRequestModel?.query, + initialValue: requestModel?.webSocketRequestModel?.message, onChanged: (String value) { ref .read(collectionStateNotifierProvider.notifier) - .update(query: value); + .update(message: value); }, hintText: kHintQuery, ), @@ -123,19 +136,14 @@ class EditRequestBody extends ConsumerWidget { onChanged: (String value) { ref .read(collectionStateNotifierProvider.notifier) - .update(body: value); + .update(message: value); }, - hintText: kHintText, - ), - Positioned( - bottom: 0, - left: 0, - child: SendButton(isWorking: true, onTap: () { - - }), + hintText: kHintMessage, ), + ], - ), + + ), ), ), _ => kSizedBoxEmpty, @@ -165,3 +173,22 @@ class DropdownButtonBodyContentType extends ConsumerWidget { ); } } + +class DropdownButtonBodyContentWebSocketType extends ConsumerWidget { + const DropdownButtonBodyContentWebSocketType({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + ref.watch(selectedIdStateProvider); + final requestBodyContentType = ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketRequestModel?.contentType)); + return DropdownButtonContentTypeWebSocket( + contentType: requestBodyContentType, + onChanged: (ContentTypeWebSocket? value) { + + }, + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart index ff8d6044b..ed097f2de 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart @@ -43,7 +43,7 @@ class EditWebSocketRequestPane extends ConsumerWidget { ], tabLabels: const [ kLabelHeaders, - kLabelQuery, + kLabelMessage, ], children: const [ EditRequestHeaders(), diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 814e4566b..e2a368abe 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -1,12 +1,13 @@ import 'package:apidash/widgets/websocket_frame.dart'; import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_core/models/websocket_frame_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/consts.dart'; -class ResponsePane extends ConsumerWidget { +class ResponsePane extends ConsumerWidget{ const ResponsePane({super.key}); @override @@ -20,11 +21,12 @@ class ResponsePane extends ConsumerWidget { selectedRequestModelProvider.select((value) => value?.responseStatus)); final message = ref .watch(selectedRequestModelProvider.select((value) => value?.message)); - + if (isWorking) { - return SendingWidget( - startSendingTime: startSendingTime, - ); + return const ResponseDetails(); + // return SendingWidget( + // startSendingTime: startSendingTime, + // ); } if (responseStatus == null) { return const NotSentWidget(); @@ -79,11 +81,19 @@ class ResponseTabs extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final selectedId = ref.watch(selectedIdStateProvider); + final apiType = ref + .watch(selectedRequestModelProvider.select((value) => value?.apiType)); return ResponseTabView( selectedId: selectedId, - children: const [ - ResponseBodyTab(), - ResponseHeadersTab(), + children: [ + if (apiType == APIType.rest) ...const [ + ResponseBodyTab(), + ResponseHeadersTab(), + ] else if (apiType == APIType.webSocket) ...const [ + WebsocketResponseView(), + ResponseHeadersTab(), + ], + ], ); } @@ -119,17 +129,50 @@ class ResponseHeadersTab extends ConsumerWidget { } } -// class WebsocketResponseView extends ConsumerWidget { -// const WebsocketResponseView({super.key}); -// @override -// Widget build(BuildContext context, WidgetRef ref) { - -// return ListView.builder( -// itemCount:, -// itemBuilder: (context, index) { -// return WebsocketFrame(); -// }, -// ); -// } -// } \ No newline at end of file + +class WebsocketResponseView extends ConsumerStatefulWidget { + const WebsocketResponseView({super.key}); + + @override + ConsumerState createState() => _WebsocketResponseViewState(); +} + +class _WebsocketResponseViewState extends ConsumerState { + final ScrollController _controller = ScrollController(); + + @override + void initState() { + super.initState(); + _controller.addListener(() { + if (_controller.position.atEdge && _controller.position.pixels != 0) { + setState(() { + _controller.jumpTo(_controller.position.maxScrollExtent); + }); + } + }); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final frames = ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketResponseModel?.frames)) ?? + []; + + return ListView.builder( + controller: _controller, + itemCount: frames.length, + itemBuilder: (context, index) { + return WebsocketFrame( + websocketFrame: frames[frames.length-index-1], + ); + }, + ); + } +} diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index 1a138b7e5..63adddcc6 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -65,8 +65,7 @@ class EditorPaneRequestURLCard extends ConsumerWidget { ), kHSpacer20, switch (apiType) { - APIType.rest => const SendRequestButton(), - APIType.graphql =>const SendRequestButton(), + APIType.rest || APIType.graphql => const SendRequestButton(), APIType.webSocket =>const ConnectionRequestButton(), null => kSizedBoxEmpty, }, @@ -105,14 +104,19 @@ class URLTextField extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final selectedId = ref.watch(selectedIdStateProvider); + final apiType = ref + .watch(selectedRequestModelProvider.select((value) => value?.apiType)); return EnvURLField( selectedId: selectedId!, - initialValue: ref - .read(collectionStateNotifierProvider.notifier) - .getRequestModel(selectedId) - ?.httpRequestModel - ?.url, + initialValue:switch (apiType) { + APIType.rest || APIType.graphql=> ref.watch(selectedRequestModelProvider + .select((value) => value?.httpRequestModel?.url)), + APIType.webSocket => ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketRequestModel?.url)), + null => '', + }, onChanged: (value) { + ref.read(collectionStateNotifierProvider.notifier).update(url: value); }, onFieldSubmitted: (value) { @@ -134,7 +138,6 @@ class SendRequestButton extends ConsumerWidget { ref.watch(selectedIdStateProvider); final isWorking = ref.watch( selectedRequestModelProvider.select((value) => value?.isWorking)); - return SendButton( isWorking: isWorking ?? false, onTap: () { @@ -168,8 +171,10 @@ class ConnectionRequestButton extends ConsumerWidget { onTap?.call(); ref.read(collectionStateNotifierProvider.notifier).connect(); }, - onCancel: () { - ref.read(collectionStateNotifierProvider.notifier).connect(); + onDisconnect: () { + onTap?.call(); + ref.read(collectionStateNotifierProvider.notifier).cancelRequest(); + }, ); } diff --git a/lib/screens/settings_page.dart b/lib/screens/settings_page.dart index eb4b60088..2567e1984 100644 --- a/lib/screens/settings_page.dart +++ b/lib/screens/settings_page.dart @@ -224,6 +224,20 @@ class SettingsPage extends ConsumerWidget { ), ), ), + ListTile( + hoverColor: kColorTransparent, + title: const Text('Maximum Reconnection Attempts'), + subtitle: Text( + 'Your request history will be retained${settings.historyRetentionPeriod == HistoryRetentionPeriod.forever ? "" : " for"} ${settings.historyRetentionPeriod.label}'), + trailing: HistoryRetentionPopupMenu( + value: settings.historyRetentionPeriod, + onChanged: (value) { + ref + .read(settingsProvider.notifier) + .update(historyRetentionPeriod: value); + }, + ), + ), ListTile( title: const Text('About'), subtitle: const Text( diff --git a/lib/widgets/button_connection.dart b/lib/widgets/button_connection.dart index a9b291822..d64ecad5c 100644 --- a/lib/widgets/button_connection.dart +++ b/lib/widgets/button_connection.dart @@ -7,30 +7,30 @@ class ConnectionButton extends StatelessWidget { super.key, required this.isWorking, required this.onTap, - this.onCancel, + this.onDisconnect, }); final bool isWorking; final void Function() onTap; - final void Function()? onCancel; + final void Function()? onDisconnect; @override Widget build(BuildContext context) { return ADFilledButton( - onPressed: isWorking ? onCancel : onTap, + onPressed: isWorking ? onDisconnect : onTap, isTonal: isWorking ? true : false, items: isWorking ? const [ kHSpacer8, Text( - kLabelCancel, + kLabelDisconnect, style: kTextStyleButton, ), kHSpacer6, ] : const [ Text( - kLabelSend, + KLabelConnect, style: kTextStyleButton, ), kHSpacer10, diff --git a/lib/widgets/dropdown_websocket_content_type.dart b/lib/widgets/dropdown_websocket_content_type.dart new file mode 100644 index 000000000..990471e6b --- /dev/null +++ b/lib/widgets/dropdown_websocket_content_type.dart @@ -0,0 +1,24 @@ +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; + +class DropdownButtonContentTypeWebSocket extends StatelessWidget { + const DropdownButtonContentTypeWebSocket({ + super.key, + this.contentType, + this.onChanged, + }); + + final ContentTypeWebSocket? contentType; + final void Function(ContentTypeWebSocket?)? onChanged; + + @override + Widget build(BuildContext context) { + return ADDropdownButton( + value: contentType, + values: ContentTypeWebSocket.values.map((e) => (e, e.name)), + onChanged: onChanged, + iconSize: 16, + ); + } +} diff --git a/lib/widgets/websocket_frame.dart b/lib/widgets/websocket_frame.dart index 1e2a46724..289f934fe 100644 --- a/lib/widgets/websocket_frame.dart +++ b/lib/widgets/websocket_frame.dart @@ -1,18 +1,56 @@ +import 'package:apidash_core/models/websocket_frame_model.dart'; import 'package:flutter/material.dart'; + class WebsocketFrame extends StatefulWidget { - const WebsocketFrame({super.key}); + final WebSocketFrameModel websocketFrame; + const WebsocketFrame({super.key, required this.websocketFrame}); @override State createState() => _WebsocketFrameState(); } class _WebsocketFrameState extends State { - @override - Widget build(BuildContext context) { - return ListTile( + bool _isExpanded = false; + void _toggleExpand() { + setState(() { + _isExpanded = !_isExpanded; + }); + } + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: _toggleExpand, + child: Container( + margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0), + decoration: BoxDecoration( + border: Border.all(color: Colors.white10), + borderRadius: BorderRadius.circular(8.0), + ), + child: ListTile( + contentPadding: EdgeInsets.symmetric(horizontal: 8.0), + leading: Icon( + Icons.arrow_upward, + ), + title: Text( + widget.websocketFrame.message + " " + widget.websocketFrame.formattedTime, + maxLines: _isExpanded ? null : 1, + overflow: _isExpanded ? TextOverflow.visible : TextOverflow.ellipsis, + ), + subtitle: Icon( + _isExpanded ? Icons.expand_less : Icons.expand_more, + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text(widget.websocketFrame.formattedTime), + IconButton(onPressed: () {}, icon: const Icon(Icons.delete)), + ], + ), + ), + ), ); } } \ No newline at end of file diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index ddbde7da6..47c6a2334 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -84,6 +84,16 @@ enum ContentType { final String header; } +enum ContentTypeWebSocket { + + text("$kTypeText/$kSubTypePlain"), + binary("$kTypeApplication/$kSubTypeOctetStream"); + + + const ContentTypeWebSocket(this.header); + final String header; +} + const JsonEncoder kJsonEncoder = JsonEncoder.withIndent(' '); const JsonDecoder kJsonDecoder = JsonDecoder(); const LineSplitter kSplitter = LineSplitter(); @@ -92,3 +102,5 @@ const kCodeCharsPerLineLimit = 200; const kHeaderContentType = "Content-Type"; const kMsgRequestCancelled = 'Request Cancelled'; +const kMsgConnected = 'Connected'; +const kMsgDisconnected = 'Disconnected'; diff --git a/packages/apidash_core/lib/models/models.dart b/packages/apidash_core/lib/models/models.dart index a33c6fddc..1fd7af033 100644 --- a/packages/apidash_core/lib/models/models.dart +++ b/packages/apidash_core/lib/models/models.dart @@ -1,2 +1,5 @@ export 'http_request_model.dart'; export 'http_response_model.dart'; +export 'websocket_request_model.dart'; +export 'websocket_response_model.dart'; +export 'websocket_frame_model.dart'; diff --git a/packages/apidash_core/lib/models/websocket_request_model.dart b/packages/apidash_core/lib/models/websocket_request_model.dart index 9b6d77c28..69cc0bef5 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.dart @@ -1,11 +1,9 @@ -import 'dart:convert'; +import 'package:apidash_core/consts.dart'; import 'package:apidash_core/models/websocket_frame_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:seed/models/name_value_model.dart'; -import '../extensions/extensions.dart'; // Custom extensions for map/row handling import '../utils/utils.dart' - show rowsToMap, getEnabledRows; // Utility functions for row handling - + show rowsToMap, getEnabledRows; part 'websocket_request_model.freezed.dart'; part 'websocket_request_model.g.dart'; @@ -18,14 +16,14 @@ class WebSocketRequestModel with _$WebSocketRequestModel { anyMap: true, ) const factory WebSocketRequestModel({ - @Default("") String url, + @Default("") String url, + @Default(ContentTypeWebSocket.text) ContentTypeWebSocket contentType, bool? isConnected, List? headers, List? isHeaderEnabledList, List? params, List? isParamEnabledList, String? message, - @Default([]) List frames, List? receivedMessages, }) = _WebSocketRequestModel; diff --git a/packages/apidash_core/lib/models/websocket_request_model.freezed.dart b/packages/apidash_core/lib/models/websocket_request_model.freezed.dart index 81ff12b5d..058a99844 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.freezed.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.freezed.dart @@ -22,13 +22,13 @@ WebSocketRequestModel _$WebSocketRequestModelFromJson( /// @nodoc mixin _$WebSocketRequestModel { String get url => throw _privateConstructorUsedError; + ContentTypeWebSocket get contentType => throw _privateConstructorUsedError; bool? get isConnected => throw _privateConstructorUsedError; List? get headers => throw _privateConstructorUsedError; List? get isHeaderEnabledList => throw _privateConstructorUsedError; List? get params => throw _privateConstructorUsedError; List? get isParamEnabledList => throw _privateConstructorUsedError; String? get message => throw _privateConstructorUsedError; - List get frames => throw _privateConstructorUsedError; List? get receivedMessages => throw _privateConstructorUsedError; /// Serializes this WebSocketRequestModel to a JSON map. @@ -49,13 +49,13 @@ abstract class $WebSocketRequestModelCopyWith<$Res> { @useResult $Res call( {String url, + ContentTypeWebSocket contentType, bool? isConnected, List? headers, List? isHeaderEnabledList, List? params, List? isParamEnabledList, String? message, - List frames, List? receivedMessages}); } @@ -76,13 +76,13 @@ class _$WebSocketRequestModelCopyWithImpl<$Res, @override $Res call({ Object? url = null, + Object? contentType = null, Object? isConnected = freezed, Object? headers = freezed, Object? isHeaderEnabledList = freezed, Object? params = freezed, Object? isParamEnabledList = freezed, Object? message = freezed, - Object? frames = null, Object? receivedMessages = freezed, }) { return _then(_value.copyWith( @@ -90,6 +90,10 @@ class _$WebSocketRequestModelCopyWithImpl<$Res, ? _value.url : url // ignore: cast_nullable_to_non_nullable as String, + contentType: null == contentType + ? _value.contentType + : contentType // ignore: cast_nullable_to_non_nullable + as ContentTypeWebSocket, isConnected: freezed == isConnected ? _value.isConnected : isConnected // ignore: cast_nullable_to_non_nullable @@ -114,10 +118,6 @@ class _$WebSocketRequestModelCopyWithImpl<$Res, ? _value.message : message // ignore: cast_nullable_to_non_nullable as String?, - frames: null == frames - ? _value.frames - : frames // ignore: cast_nullable_to_non_nullable - as List, receivedMessages: freezed == receivedMessages ? _value.receivedMessages : receivedMessages // ignore: cast_nullable_to_non_nullable @@ -137,13 +137,13 @@ abstract class _$$WebSocketRequestModelImplCopyWith<$Res> @useResult $Res call( {String url, + ContentTypeWebSocket contentType, bool? isConnected, List? headers, List? isHeaderEnabledList, List? params, List? isParamEnabledList, String? message, - List frames, List? receivedMessages}); } @@ -162,13 +162,13 @@ class __$$WebSocketRequestModelImplCopyWithImpl<$Res> @override $Res call({ Object? url = null, + Object? contentType = null, Object? isConnected = freezed, Object? headers = freezed, Object? isHeaderEnabledList = freezed, Object? params = freezed, Object? isParamEnabledList = freezed, Object? message = freezed, - Object? frames = null, Object? receivedMessages = freezed, }) { return _then(_$WebSocketRequestModelImpl( @@ -176,6 +176,10 @@ class __$$WebSocketRequestModelImplCopyWithImpl<$Res> ? _value.url : url // ignore: cast_nullable_to_non_nullable as String, + contentType: null == contentType + ? _value.contentType + : contentType // ignore: cast_nullable_to_non_nullable + as ContentTypeWebSocket, isConnected: freezed == isConnected ? _value.isConnected : isConnected // ignore: cast_nullable_to_non_nullable @@ -200,10 +204,6 @@ class __$$WebSocketRequestModelImplCopyWithImpl<$Res> ? _value.message : message // ignore: cast_nullable_to_non_nullable as String?, - frames: null == frames - ? _value._frames - : frames // ignore: cast_nullable_to_non_nullable - as List, receivedMessages: freezed == receivedMessages ? _value._receivedMessages : receivedMessages // ignore: cast_nullable_to_non_nullable @@ -218,19 +218,18 @@ class __$$WebSocketRequestModelImplCopyWithImpl<$Res> class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { const _$WebSocketRequestModelImpl( {this.url = "", + this.contentType = ContentTypeWebSocket.text, this.isConnected, final List? headers, final List? isHeaderEnabledList, final List? params, final List? isParamEnabledList, this.message, - final List frames = const [], final List? receivedMessages}) : _headers = headers, _isHeaderEnabledList = isHeaderEnabledList, _params = params, _isParamEnabledList = isParamEnabledList, - _frames = frames, _receivedMessages = receivedMessages, super._(); @@ -241,6 +240,9 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { @JsonKey() final String url; @override + @JsonKey() + final ContentTypeWebSocket contentType; + @override final bool? isConnected; final List? _headers; @override @@ -286,15 +288,6 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { @override final String? message; - final List _frames; - @override - @JsonKey() - List get frames { - if (_frames is EqualUnmodifiableListView) return _frames; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_frames); - } - final List? _receivedMessages; @override List? get receivedMessages { @@ -308,7 +301,7 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { @override String toString() { - return 'WebSocketRequestModel(url: $url, isConnected: $isConnected, headers: $headers, isHeaderEnabledList: $isHeaderEnabledList, params: $params, isParamEnabledList: $isParamEnabledList, message: $message, frames: $frames, receivedMessages: $receivedMessages)'; + return 'WebSocketRequestModel(url: $url, contentType: $contentType, isConnected: $isConnected, headers: $headers, isHeaderEnabledList: $isHeaderEnabledList, params: $params, isParamEnabledList: $isParamEnabledList, message: $message, receivedMessages: $receivedMessages)'; } @override @@ -317,6 +310,8 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { (other.runtimeType == runtimeType && other is _$WebSocketRequestModelImpl && (identical(other.url, url) || other.url == url) && + (identical(other.contentType, contentType) || + other.contentType == contentType) && (identical(other.isConnected, isConnected) || other.isConnected == isConnected) && const DeepCollectionEquality().equals(other._headers, _headers) && @@ -326,7 +321,6 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { const DeepCollectionEquality() .equals(other._isParamEnabledList, _isParamEnabledList) && (identical(other.message, message) || other.message == message) && - const DeepCollectionEquality().equals(other._frames, _frames) && const DeepCollectionEquality() .equals(other._receivedMessages, _receivedMessages)); } @@ -336,13 +330,13 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { int get hashCode => Object.hash( runtimeType, url, + contentType, isConnected, const DeepCollectionEquality().hash(_headers), const DeepCollectionEquality().hash(_isHeaderEnabledList), const DeepCollectionEquality().hash(_params), const DeepCollectionEquality().hash(_isParamEnabledList), message, - const DeepCollectionEquality().hash(_frames), const DeepCollectionEquality().hash(_receivedMessages)); /// Create a copy of WebSocketRequestModel @@ -365,13 +359,13 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { abstract class _WebSocketRequestModel extends WebSocketRequestModel { const factory _WebSocketRequestModel( {final String url, + final ContentTypeWebSocket contentType, final bool? isConnected, final List? headers, final List? isHeaderEnabledList, final List? params, final List? isParamEnabledList, final String? message, - final List frames, final List? receivedMessages}) = _$WebSocketRequestModelImpl; const _WebSocketRequestModel._() : super._(); @@ -381,6 +375,8 @@ abstract class _WebSocketRequestModel extends WebSocketRequestModel { @override String get url; @override + ContentTypeWebSocket get contentType; + @override bool? get isConnected; @override List? get headers; @@ -393,8 +389,6 @@ abstract class _WebSocketRequestModel extends WebSocketRequestModel { @override String? get message; @override - List get frames; - @override List? get receivedMessages; /// Create a copy of WebSocketRequestModel diff --git a/packages/apidash_core/lib/models/websocket_request_model.g.dart b/packages/apidash_core/lib/models/websocket_request_model.g.dart index c6c4e9812..d95d1d1c4 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.g.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.g.dart @@ -9,6 +9,9 @@ part of 'websocket_request_model.dart'; _$WebSocketRequestModelImpl _$$WebSocketRequestModelImplFromJson(Map json) => _$WebSocketRequestModelImpl( url: json['url'] as String? ?? "", + contentType: $enumDecodeNullable( + _$ContentTypeWebSocketEnumMap, json['contentType']) ?? + ContentTypeWebSocket.text, isConnected: json['isConnected'] as bool?, headers: (json['headers'] as List?) ?.map((e) => @@ -25,11 +28,6 @@ _$WebSocketRequestModelImpl _$$WebSocketRequestModelImplFromJson(Map json) => ?.map((e) => e as bool) .toList(), message: json['message'] as String?, - frames: (json['frames'] as List?) - ?.map((e) => WebSocketFrameModel.fromJson( - Map.from(e as Map))) - .toList() ?? - const [], receivedMessages: (json['receivedMessages'] as List?) ?.map((e) => e as String) .toList(), @@ -39,12 +37,17 @@ Map _$$WebSocketRequestModelImplToJson( _$WebSocketRequestModelImpl instance) => { 'url': instance.url, + 'contentType': _$ContentTypeWebSocketEnumMap[instance.contentType]!, 'isConnected': instance.isConnected, 'headers': instance.headers?.map((e) => e.toJson()).toList(), 'isHeaderEnabledList': instance.isHeaderEnabledList, 'params': instance.params?.map((e) => e.toJson()).toList(), 'isParamEnabledList': instance.isParamEnabledList, 'message': instance.message, - 'frames': instance.frames.map((e) => e.toJson()).toList(), 'receivedMessages': instance.receivedMessages, }; + +const _$ContentTypeWebSocketEnumMap = { + ContentTypeWebSocket.text: 'text', + ContentTypeWebSocket.binary: 'binary', +}; diff --git a/packages/apidash_core/lib/models/websocket_response_model.dart b/packages/apidash_core/lib/models/websocket_response_model.dart new file mode 100644 index 000000000..e6e8a0438 --- /dev/null +++ b/packages/apidash_core/lib/models/websocket_response_model.dart @@ -0,0 +1,28 @@ +import 'package:apidash_core/models/websocket_frame_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + + +part 'websocket_response_model.freezed.dart'; +part 'websocket_response_model.g.dart'; + + +@freezed +class WebSocketResponseModel with _$WebSocketResponseModel { + const WebSocketResponseModel._(); + + @JsonSerializable( + explicitToJson: true, + anyMap: true, + ) + const factory WebSocketResponseModel({ + int? statusCode, + @Default([]) List frames, + Map? headers, + Map? requestHeaders, + + }) = _WebSocketResponseModel; + + factory WebSocketResponseModel.fromJson(Map json) => + _$WebSocketResponseModelFromJson(json); + +} diff --git a/packages/apidash_core/lib/models/websocket_response_model.freezed.dart b/packages/apidash_core/lib/models/websocket_response_model.freezed.dart new file mode 100644 index 000000000..3478b7aa2 --- /dev/null +++ b/packages/apidash_core/lib/models/websocket_response_model.freezed.dart @@ -0,0 +1,270 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'websocket_response_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +WebSocketResponseModel _$WebSocketResponseModelFromJson( + Map json) { + return _WebSocketResponseModel.fromJson(json); +} + +/// @nodoc +mixin _$WebSocketResponseModel { + int? get statusCode => throw _privateConstructorUsedError; + List get frames => throw _privateConstructorUsedError; + Map? get headers => throw _privateConstructorUsedError; + Map? get requestHeaders => throw _privateConstructorUsedError; + + /// Serializes this WebSocketResponseModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of WebSocketResponseModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $WebSocketResponseModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WebSocketResponseModelCopyWith<$Res> { + factory $WebSocketResponseModelCopyWith(WebSocketResponseModel value, + $Res Function(WebSocketResponseModel) then) = + _$WebSocketResponseModelCopyWithImpl<$Res, WebSocketResponseModel>; + @useResult + $Res call( + {int? statusCode, + List frames, + Map? headers, + Map? requestHeaders}); +} + +/// @nodoc +class _$WebSocketResponseModelCopyWithImpl<$Res, + $Val extends WebSocketResponseModel> + implements $WebSocketResponseModelCopyWith<$Res> { + _$WebSocketResponseModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of WebSocketResponseModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? statusCode = freezed, + Object? frames = null, + Object? headers = freezed, + Object? requestHeaders = freezed, + }) { + return _then(_value.copyWith( + statusCode: freezed == statusCode + ? _value.statusCode + : statusCode // ignore: cast_nullable_to_non_nullable + as int?, + frames: null == frames + ? _value.frames + : frames // ignore: cast_nullable_to_non_nullable + as List, + headers: freezed == headers + ? _value.headers + : headers // ignore: cast_nullable_to_non_nullable + as Map?, + requestHeaders: freezed == requestHeaders + ? _value.requestHeaders + : requestHeaders // ignore: cast_nullable_to_non_nullable + as Map?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$WebSocketResponseModelImplCopyWith<$Res> + implements $WebSocketResponseModelCopyWith<$Res> { + factory _$$WebSocketResponseModelImplCopyWith( + _$WebSocketResponseModelImpl value, + $Res Function(_$WebSocketResponseModelImpl) then) = + __$$WebSocketResponseModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int? statusCode, + List frames, + Map? headers, + Map? requestHeaders}); +} + +/// @nodoc +class __$$WebSocketResponseModelImplCopyWithImpl<$Res> + extends _$WebSocketResponseModelCopyWithImpl<$Res, + _$WebSocketResponseModelImpl> + implements _$$WebSocketResponseModelImplCopyWith<$Res> { + __$$WebSocketResponseModelImplCopyWithImpl( + _$WebSocketResponseModelImpl _value, + $Res Function(_$WebSocketResponseModelImpl) _then) + : super(_value, _then); + + /// Create a copy of WebSocketResponseModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? statusCode = freezed, + Object? frames = null, + Object? headers = freezed, + Object? requestHeaders = freezed, + }) { + return _then(_$WebSocketResponseModelImpl( + statusCode: freezed == statusCode + ? _value.statusCode + : statusCode // ignore: cast_nullable_to_non_nullable + as int?, + frames: null == frames + ? _value._frames + : frames // ignore: cast_nullable_to_non_nullable + as List, + headers: freezed == headers + ? _value._headers + : headers // ignore: cast_nullable_to_non_nullable + as Map?, + requestHeaders: freezed == requestHeaders + ? _value._requestHeaders + : requestHeaders // ignore: cast_nullable_to_non_nullable + as Map?, + )); + } +} + +/// @nodoc + +@JsonSerializable(explicitToJson: true, anyMap: true) +class _$WebSocketResponseModelImpl extends _WebSocketResponseModel { + const _$WebSocketResponseModelImpl( + {this.statusCode, + final List frames = const [], + final Map? headers, + final Map? requestHeaders}) + : _frames = frames, + _headers = headers, + _requestHeaders = requestHeaders, + super._(); + + factory _$WebSocketResponseModelImpl.fromJson(Map json) => + _$$WebSocketResponseModelImplFromJson(json); + + @override + final int? statusCode; + final List _frames; + @override + @JsonKey() + List get frames { + if (_frames is EqualUnmodifiableListView) return _frames; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_frames); + } + + final Map? _headers; + @override + Map? get headers { + final value = _headers; + if (value == null) return null; + if (_headers is EqualUnmodifiableMapView) return _headers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(value); + } + + final Map? _requestHeaders; + @override + Map? get requestHeaders { + final value = _requestHeaders; + if (value == null) return null; + if (_requestHeaders is EqualUnmodifiableMapView) return _requestHeaders; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(value); + } + + @override + String toString() { + return 'WebSocketResponseModel(statusCode: $statusCode, frames: $frames, headers: $headers, requestHeaders: $requestHeaders)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$WebSocketResponseModelImpl && + (identical(other.statusCode, statusCode) || + other.statusCode == statusCode) && + const DeepCollectionEquality().equals(other._frames, _frames) && + const DeepCollectionEquality().equals(other._headers, _headers) && + const DeepCollectionEquality() + .equals(other._requestHeaders, _requestHeaders)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + statusCode, + const DeepCollectionEquality().hash(_frames), + const DeepCollectionEquality().hash(_headers), + const DeepCollectionEquality().hash(_requestHeaders)); + + /// Create a copy of WebSocketResponseModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$WebSocketResponseModelImplCopyWith<_$WebSocketResponseModelImpl> + get copyWith => __$$WebSocketResponseModelImplCopyWithImpl< + _$WebSocketResponseModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$WebSocketResponseModelImplToJson( + this, + ); + } +} + +abstract class _WebSocketResponseModel extends WebSocketResponseModel { + const factory _WebSocketResponseModel( + {final int? statusCode, + final List frames, + final Map? headers, + final Map? requestHeaders}) = + _$WebSocketResponseModelImpl; + const _WebSocketResponseModel._() : super._(); + + factory _WebSocketResponseModel.fromJson(Map json) = + _$WebSocketResponseModelImpl.fromJson; + + @override + int? get statusCode; + @override + List get frames; + @override + Map? get headers; + @override + Map? get requestHeaders; + + /// Create a copy of WebSocketResponseModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$WebSocketResponseModelImplCopyWith<_$WebSocketResponseModelImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/models/websocket_response_model.g.dart b/packages/apidash_core/lib/models/websocket_response_model.g.dart new file mode 100644 index 000000000..7dccd6070 --- /dev/null +++ b/packages/apidash_core/lib/models/websocket_response_model.g.dart @@ -0,0 +1,32 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'websocket_response_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$WebSocketResponseModelImpl _$$WebSocketResponseModelImplFromJson(Map json) => + _$WebSocketResponseModelImpl( + statusCode: (json['statusCode'] as num?)?.toInt(), + frames: (json['frames'] as List?) + ?.map((e) => WebSocketFrameModel.fromJson( + Map.from(e as Map))) + .toList() ?? + const [], + headers: (json['headers'] as Map?)?.map( + (k, e) => MapEntry(k as String, e as String), + ), + requestHeaders: (json['requestHeaders'] as Map?)?.map( + (k, e) => MapEntry(k as String, e as String), + ), + ); + +Map _$$WebSocketResponseModelImplToJson( + _$WebSocketResponseModelImpl instance) => + { + 'statusCode': instance.statusCode, + 'frames': instance.frames.map((e) => e.toJson()).toList(), + 'headers': instance.headers, + 'requestHeaders': instance.requestHeaders, + }; diff --git a/packages/apidash_core/lib/services/clientWrapper.dart b/packages/apidash_core/lib/services/clientWrapper.dart index 63f8efb0d..a69aefb02 100644 --- a/packages/apidash_core/lib/services/clientWrapper.dart +++ b/packages/apidash_core/lib/services/clientWrapper.dart @@ -1,11 +1,15 @@ import 'dart:developer'; +import 'package:apidash_core/models/websocket_request_model.dart'; import 'package:apidash_core/services/clientWrapper.dart' as http; import 'package:apidash_core/services/websocket_service.dart'; import 'package:http/http.dart' as http; abstract class clientWrapper { void close() {} + Future sendText(WebSocketRequestModel websocketRequestModel )async{ + throw UnimplementedError('sendText is not implemented for this client type.'); + } } class HttpClientWrapper extends clientWrapper { @@ -26,5 +30,8 @@ class WebSocketClientWrapper extends clientWrapper { log("cancelling under websocket"); client.disconnect(); } + Future sendText(WebSocketRequestModel websocketRequestModel) async{ + client.sendText(websocketRequestModel); + } } diff --git a/packages/apidash_core/lib/services/http_client_manager.dart b/packages/apidash_core/lib/services/http_client_manager.dart index 330307ad4..81462ffd2 100644 --- a/packages/apidash_core/lib/services/http_client_manager.dart +++ b/packages/apidash_core/lib/services/http_client_manager.dart @@ -74,4 +74,8 @@ class HttpClientManager { bool hasActiveClient(String requestId) { return _clients.containsKey(requestId); } + + clientWrapper? getClient(String requestId) { + return _clients[requestId]; + } } diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index 0fa07d7ed..b3bfa013d 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -1,23 +1,33 @@ import 'dart:async'; -import 'dart:convert'; import 'dart:developer'; -import 'dart:typed_data'; import 'package:apidash_core/models/models.dart'; +import 'dart:io'; import 'package:apidash_core/models/websocket_request_model.dart'; +import 'package:flutter/foundation.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:web_socket_channel/status.dart' as status; +import 'package:web_socket_channel/io.dart'; class WebSocketClient { late WebSocketChannel _channel; StreamSubscription? _subscription; + Duration? _pingDuration; + WebSocketClient(); - Future<(String?,DateTime?)> connect(HttpRequestModel websocketRequestModel) async { + Future<(String?,DateTime?)> connect(String url) async { print("inside client connect"); try { - _channel = WebSocketChannel.connect(Uri.parse("ws://localhost:3000")); + if(!kIsWeb){ + final WebSocket ioWebSocket = await WebSocket.connect(url); + _channel = IOWebSocketChannel(ioWebSocket); + ioWebSocket.pingInterval = _pingDuration; + + }else{ + _channel = WebSocketChannel.connect(Uri.parse(url)); + } await _channel.ready; print('Connected to WebSocket server: ${"ws://localhost:3000"}'); return ("Connected",DateTime.now()); @@ -28,14 +38,19 @@ class WebSocketClient { } - // Future<(String?,DateTime?)> sendText(WebSocketRequestModel websocketRequestModel) { - // if (_channel != null) { - // _channel.sink.add(websocketRequestModel.message); - // log('Sent text message: ${websocketRequestModel.message}'); - // } else { - // log('WebSocket connection is not open. Unable to send text message.'); - // } - // } + Future sendText(WebSocketRequestModel websocketRequestModel)async { + if (_channel != null) { + _channel.sink.add(websocketRequestModel.message); + // websocketRequestModel.frames.add(WebSocketFrameModel( + // id: '1', + // message: websocketRequestModel.message!, + // timeStamp: DateTime.now(), + // )); + log('Sent text message: ${websocketRequestModel.message}'); + } else { + log('WebSocket connection is not open. Unable to send text message.'); + } + } // Future<(String?,DateTime?)> sendBinary(Uint8List data) { @@ -75,6 +90,7 @@ class WebSocketClient { } } + // Future<(String?,DateTime?)> main() async { // const wsUrl = '"ws://localhost:3000"'; From 7331771fb4bef401b8d917d622e80775db6a830f Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sun, 26 Jan 2025 12:21:58 +0530 Subject: [PATCH 08/30] added ping and websocket manager --- lib/providers/collection_providers.dart | 176 ++++++++++++++---- .../details_card/response_pane.dart | 16 +- .../home_page/editor_pane/url_card.dart | 3 +- lib/screens/settings_page.dart | 23 ++- lib/widgets/websocket_frame.dart | 102 +++++++++- .../lib/models/websocket_frame_model.dart | 13 +- .../models/websocket_frame_model.freezed.dart | 40 ++-- .../lib/models/websocket_frame_model.g.dart | 4 +- .../lib/models/websocket_request_model.dart | 1 - .../websocket_request_model.freezed.dart | 45 +---- .../lib/models/websocket_request_model.g.dart | 4 - .../lib/services/clientWrapper.dart | 18 +- .../lib/services/http_client_manager.dart | 3 +- .../apidash_core/lib/services/services.dart | 2 + .../lib/services/web_socket_manager.dart | 58 ++++++ .../lib/services/websocket_service.dart | 99 +++++----- 16 files changed, 416 insertions(+), 191 deletions(-) create mode 100644 packages/apidash_core/lib/services/web_socket_manager.dart diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 647e15d22..f313e5acc 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -1,4 +1,5 @@ import 'dart:developer'; +import 'dart:io'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; @@ -29,6 +30,7 @@ final requestSequenceProvider = StateProvider>((ref) { }); final httpClientManager = HttpClientManager(); +final WebSocketManager webSocketManager = WebSocketManager(); final StateNotifierProvider?> collectionStateNotifierProvider = @@ -36,7 +38,8 @@ final StateNotifierProvider?> ref, hiveHandler, httpClientManager, - )); + webSocketManager + )); class CollectionStateNotifier extends StateNotifier?> { @@ -44,6 +47,7 @@ class CollectionStateNotifier this.ref, this.hiveHandler, this.httpClientManager, + this.webSocketManager ) : super(null) { var status = loadData(); Future.microtask(() { @@ -61,6 +65,8 @@ class CollectionStateNotifier final HiveHandler hiveHandler; final baseHttpResponseModel = const HttpResponseModel(); final HttpClientManager httpClientManager; + final WebSocketManager webSocketManager; + bool hasId(String id) => state?.keys.contains(id) ?? false; @@ -471,8 +477,8 @@ class CollectionStateNotifier return; } RequestModel? requestModel = state![requestId]; - - if (requestModel?.webSocketRequestModel== null) { + var currentWebSocketRequestModel = requestModel!.webSocketRequestModel; + if (currentWebSocketRequestModel == null) { return; } @@ -482,20 +488,51 @@ class CollectionStateNotifier // set current model's isWorking to true and update state var map = {...state!}; - map[requestId] = requestModel!.copyWith( + map[requestId] = requestModel.copyWith( isWorking: true, ); state = map; - final client = httpClientManager.createWebSocketClient(requestId); - await client.sendText(requestModel.webSocketRequestModel!); + String message = currentWebSocketRequestModel.message ?? ''; + (String?,DateTime?,String?) frame = await webSocketManager.sendText(requestId,message); + + var newWebSocketResponseModel; + if(frame.$1 != null){ + newWebSocketResponseModel = requestModel.webSocketResponseModel!.copyWith( + frames: [ + ...?requestModel.webSocketResponseModel?.frames, + WebSocketFrameModel( + id: getNewUuid(), + message:frame.$1!, + timeStamp: frame.$2, + isSend: true + ), + ], + ); + + }else if(frame.$3 != null){ + newWebSocketResponseModel = requestModel.webSocketResponseModel!.copyWith( + frames: [ + ...?requestModel.webSocketResponseModel?.frames, + WebSocketFrameModel( + id: getNewUuid(), + message:frame.$3!, + timeStamp: null, + isSend: true + ), + ], + ); + + + } + + final newRequestModel = requestModel.copyWith( - webSocketRequestModel: requestModel.webSocketRequestModel, - isWorking: false, + webSocketResponseModel: newWebSocketResponseModel, ); // update state with response data map = {...state!}; @@ -517,6 +554,7 @@ class CollectionStateNotifier RequestModel? requestModel = state![requestId]; + // if (requestModel?.webSocketRequestModel == null) { // print("no web socket request model"); // return; @@ -525,39 +563,48 @@ class CollectionStateNotifier print("entered null"); return; } - - final client = httpClientManager.createWebSocketClient(requestId); + webSocketManager.createWebSocketClient(requestId); + // webSocketClient.pingDuration = Duration(seconds: 5); final url = requestModel!.webSocketRequestModel!.url; - (String?,DateTime?) result = await client.connect(url); + (String?,DateTime?) result = await webSocketManager.connect(requestId,url); var map = {...state!}; map[requestId] = requestModel.copyWith( isWorking: result.$1 == "Connected", sendingTime: result.$2, - webSocketResponseModel: WebSocketResponseModel(), + webSocketResponseModel: const WebSocketResponseModel(), ); + state = map; - client.listen( + webSocketManager.listen( + requestId, (message) async{ var map = {...state!}; RequestModel? requestModel = state![requestId]; WebSocketResponseModel webSocketResponseModel = requestModel!.webSocketResponseModel!; WebSocketResponseModel newWebSocketResponseModel = webSocketResponseModel.copyWith( frames: [...webSocketResponseModel.frames, WebSocketFrameModel( - id: '1', + id: getNewUuid(), message: message, timeStamp: DateTime.now(), + isSend: false )] ); - map[requestId] = requestModel.copyWith( + var newRequestModel = requestModel.copyWith( webSocketResponseModel: newWebSocketResponseModel, ); - state = map; + + + map = {...state!}; + map[requestId] = newRequestModel; + state = map; print(message); }, onError: (error) async{ + print("error found"); + // var map = {...state!}; // map[requestId] = requestModel.copyWith( // responseStatus: -1, @@ -565,8 +612,12 @@ class CollectionStateNotifier // isWorking: false, // ); // state = map; + }, onDone: () async{ + print("Connection done"); + + // var map = {...state!}; // map[requestId] = requestModel.copyWith( // responseStatus: 200, @@ -575,36 +626,85 @@ class CollectionStateNotifier // ); // state = map; }, + cancelOnError: false, ); } + Future disconnect() async { + final requestId = ref.read(selectedIdStateProvider); + if (requestId == null || state == null) { + print(requestId); + return; + } - // ignore: unused_element - // Future disconnect() async { - // print("connect fired"); - // final requestId = ref.read(selectedIdStateProvider); - // ref.read(codePaneVisibleStateProvider.notifier).state = false; - // if (requestId == null || state == null) { - // print(requestId); - // return; - // } - + webSocketManager.disconnect(requestId); - // RequestModel? requestModel = state![requestId]; + RequestModel? requestModel = state![requestId]; + WebSocketRequestModel webSocketRequestModel = requestModel!.webSocketRequestModel!; + WebSocketRequestModel newWebSocketRequestModel = webSocketRequestModel.copyWith( + isConnected: false + ); + + var newRequestModel = requestModel.copyWith( + isWorking: false, + webSocketRequestModel: newWebSocketRequestModel, + + ); + + + var map = {...state!}; + map[requestId] = newRequestModel; + state = map; + } + + + void deleteAllFrames(){ + final requestId = ref.read(selectedIdStateProvider); + if (requestId == null || state == null) { + print(requestId); + return; + } + RequestModel? requestModel = state![requestId]; + WebSocketResponseModel webSocketResponseModel = requestModel!.webSocketResponseModel!; + WebSocketResponseModel newWebSocketResponseModel = webSocketResponseModel.copyWith( + frames: [], + ); - // // if (requestModel?.webSocketRequestModel == null) { - // // print("no web socket request model"); - // // return; - // // } + var newRequestModel = requestModel.copyWith( + webSocketResponseModel: newWebSocketResponseModel, + ); + var map = {...state!}; + map[requestId] = newRequestModel; + state = map; + } - // final client = httpClientManager.(requestId); + void deleteFrame(String id){ + final requestId = ref.read(selectedIdStateProvider); + if (requestId == null || state == null) { + print(requestId); + return; + } + RequestModel? requestModel = state![requestId]; + if (requestModel == null || state == null) { + print(requestId); + return; + } + WebSocketResponseModel webSocketResponseModel = requestModel!.webSocketResponseModel!; + List newFrames = requestModel!.webSocketResponseModel!.frames.where((element) => element.id != id).toList(); + WebSocketResponseModel newWebSocketResponseModel = webSocketResponseModel.copyWith( + frames: newFrames, + ); + + var newRequestModel = requestModel.copyWith( + webSocketResponseModel: newWebSocketResponseModel, + ); + var map = {...state!}; + map[requestId] = newRequestModel; + state = map; + + } - // var map = {...state!}; - // map[requestId] = requestModel!.copyWith( - // isWorking: false, - // ); - // state = map; - // } + } diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index e2a368abe..1601bdc92 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -21,9 +21,18 @@ class ResponsePane extends ConsumerWidget{ selectedRequestModelProvider.select((value) => value?.responseStatus)); final message = ref .watch(selectedRequestModelProvider.select((value) => value?.message)); + final apiType = ref + .watch(selectedRequestModelProvider.select((value) => value?.apiType)); if (isWorking) { - return const ResponseDetails(); + // if(apiType == APIType.webSocket ){ + // return const SendingWidget( + // startSendingTime: null, + // ); + // }else{ + + // } + return const ResponseDetails(); // return SendingWidget( // startSendingTime: startSendingTime, // ); @@ -149,6 +158,10 @@ class _WebsocketResponseViewState extends ConsumerState { setState(() { _controller.jumpTo(_controller.position.maxScrollExtent); }); + }else{ + setState(() { + _controller.jumpTo(_controller.offset); + }); } }); } @@ -171,6 +184,7 @@ class _WebsocketResponseViewState extends ConsumerState { itemBuilder: (context, index) { return WebsocketFrame( websocketFrame: frames[frames.length-index-1], + ref: ref, ); }, ); diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index 63adddcc6..86fc49970 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -173,7 +173,8 @@ class ConnectionRequestButton extends ConsumerWidget { }, onDisconnect: () { onTap?.call(); - ref.read(collectionStateNotifierProvider.notifier).cancelRequest(); + print("disconnected inside disconnect"); + ref.read(collectionStateNotifierProvider.notifier).disconnect(); }, ); diff --git a/lib/screens/settings_page.dart b/lib/screens/settings_page.dart index 2567e1984..2602bd602 100644 --- a/lib/screens/settings_page.dart +++ b/lib/screens/settings_page.dart @@ -224,20 +224,25 @@ class SettingsPage extends ConsumerWidget { ), ), ), - ListTile( + + ListTile( hoverColor: kColorTransparent, - title: const Text('Maximum Reconnection Attempts'), + title: const Text('Interval Between Ping Requests'), subtitle: Text( - 'Your request history will be retained${settings.historyRetentionPeriod == HistoryRetentionPeriod.forever ? "" : " for"} ${settings.historyRetentionPeriod.label}'), - trailing: HistoryRetentionPopupMenu( - value: settings.historyRetentionPeriod, + 'Current interval: seconds'), + trailing: SizedBox( + width: 120, + child: TextField( + controller: TextEditingController(text: "22"), + keyboardType: TextInputType.number, onChanged: (value) { - ref - .read(settingsProvider.notifier) - .update(historyRetentionPeriod: value); + // ref + // .read(settingsProvider.notifier) + // .update(pingInterval: int.parse(value)); }, + ), + ), ), - ), ListTile( title: const Text('About'), subtitle: const Text( diff --git a/lib/widgets/websocket_frame.dart b/lib/widgets/websocket_frame.dart index 289f934fe..7ddf6ef2f 100644 --- a/lib/widgets/websocket_frame.dart +++ b/lib/widgets/websocket_frame.dart @@ -1,10 +1,14 @@ +import 'package:apidash/providers/collection_providers.dart'; + import 'package:apidash_core/models/websocket_frame_model.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; class WebsocketFrame extends StatefulWidget { final WebSocketFrameModel websocketFrame; - const WebsocketFrame({super.key, required this.websocketFrame}); + final WidgetRef ref; + const WebsocketFrame({super.key, required this.websocketFrame,required this.ref}); @override State createState() => _WebsocketFrameState(); @@ -24,18 +28,18 @@ class _WebsocketFrameState extends State { return GestureDetector( onTap: _toggleExpand, child: Container( - margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0), + margin:const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0), decoration: BoxDecoration( border: Border.all(color: Colors.white10), borderRadius: BorderRadius.circular(8.0), ), child: ListTile( - contentPadding: EdgeInsets.symmetric(horizontal: 8.0), + contentPadding:const EdgeInsets.symmetric(horizontal: 8.0), leading: Icon( - Icons.arrow_upward, + widget.websocketFrame.isSend ? Icons.arrow_upward :Icons.arrow_downward, ), title: Text( - widget.websocketFrame.message + " " + widget.websocketFrame.formattedTime, + widget.websocketFrame.message, maxLines: _isExpanded ? null : 1, overflow: _isExpanded ? TextOverflow.visible : TextOverflow.ellipsis, ), @@ -46,11 +50,95 @@ class _WebsocketFrameState extends State { mainAxisSize: MainAxisSize.min, children: [ Text(widget.websocketFrame.formattedTime), - IconButton(onPressed: () {}, icon: const Icon(Icons.delete)), + IconButton(onPressed: () { + widget.ref.read(collectionStateNotifierProvider.notifier).deleteFrame(widget.websocketFrame.id); + }, icon: const Icon(Icons.delete)), ], ), ), ), ); } -} \ No newline at end of file +} + +// import 'package:apidash/providers/collection_providers.dart'; +// import 'package:apidash_core/models/websocket_frame_model.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_riverpod/flutter_riverpod.dart'; + +// class WebsocketFrame extends ConsumerWidget { +// final WebSocketFrameModel websocketFrame; + +// const WebsocketFrame({super.key, required this.websocketFrame}); + +// @override +// Widget build(BuildContext context, WidgetRef ref) { +// bool _isExpanded = false; + +// void _toggleExpand() { + +// _isExpanded = !_isExpanded; +// } + + +// return GestureDetector( +// onTap: _toggleExpand, +// child: AnimatedContainer( +// duration: const Duration(milliseconds: 300), +// margin: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0), +// padding: const EdgeInsets.all(8.0), +// decoration: BoxDecoration( +// color: _isExpanded ? Colors.grey.shade900 : Colors.grey.shade800, +// border: Border.all(color: Colors.white10), +// borderRadius: BorderRadius.circular(8.0), +// ), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// ListTile( +// contentPadding: const EdgeInsets.symmetric(horizontal: 8.0), +// leading: Icon( +// websocketFrame.isSend ? Icons.arrow_upward : Icons.arrow_downward, +// color: websocketFrame.isSend ? Colors.green : Colors.red, +// ), +// title: Text( +// websocketFrame.message, +// maxLines: _isExpanded ? null : 1, +// overflow: _isExpanded ? TextOverflow.visible : TextOverflow.ellipsis, +// style: const TextStyle(color: Colors.white), +// ), +// subtitle: Row( +// children: [ +// Icon( +// _isExpanded ? Icons.expand_less : Icons.expand_more, +// color: Colors.white70, +// ), +// const SizedBox(width: 4), +// Text( +// _isExpanded ? "Collapse" : "Expand", +// style: const TextStyle(color: Colors.white70, fontSize: 12), +// ), +// ], +// ), +// trailing: Row( +// mainAxisSize: MainAxisSize.min, +// children: [ +// Text( +// websocketFrame.formattedTime, +// style: const TextStyle(color: Colors.white54, fontSize: 12), +// ), +// IconButton( +// onPressed: () { +// ref.read(collectionStateNotifierProvider.notifier).deleteFrame(websocketFrame.id); +// }, +// icon: const Icon(Icons.delete, color: Colors.redAccent), +// ), +// ], +// ), +// ), +// ], +// ), +// ), +// ); +// } +// } diff --git a/packages/apidash_core/lib/models/websocket_frame_model.dart b/packages/apidash_core/lib/models/websocket_frame_model.dart index c0c4b1326..79b402223 100644 --- a/packages/apidash_core/lib/models/websocket_frame_model.dart +++ b/packages/apidash_core/lib/models/websocket_frame_model.dart @@ -17,7 +17,7 @@ class WebSocketFrameModel with _$WebSocketFrameModel { @Default("") String message, @Uint8ListConverter() Uint8List? binaryData, Map? metadata, - @Default(false) bool isFinalFrame, + @Default(false) bool isSend, DateTime? timeStamp, }) = _WebSocketFrameModel; @@ -30,15 +30,4 @@ class WebSocketFrameModel with _$WebSocketFrameModel { bool get isBinaryFrame => frameType.toLowerCase() == "binary"; - - @override - String toString() { - return 'WebSocketFrameModel(' - 'frameType: $frameType, ' - 'message: $message, ' - 'binaryData: ${binaryData?.length ?? 0} bytes, ' - 'metadata: $metadata, ' - 'isFinalFrame: $isFinalFrame, ' - 'timestamp: $timeStamp)'; - } } diff --git a/packages/apidash_core/lib/models/websocket_frame_model.freezed.dart b/packages/apidash_core/lib/models/websocket_frame_model.freezed.dart index 40310c856..2efd56a2d 100644 --- a/packages/apidash_core/lib/models/websocket_frame_model.freezed.dart +++ b/packages/apidash_core/lib/models/websocket_frame_model.freezed.dart @@ -26,7 +26,7 @@ mixin _$WebSocketFrameModel { @Uint8ListConverter() Uint8List? get binaryData => throw _privateConstructorUsedError; Map? get metadata => throw _privateConstructorUsedError; - bool get isFinalFrame => throw _privateConstructorUsedError; + bool get isSend => throw _privateConstructorUsedError; DateTime? get timeStamp => throw _privateConstructorUsedError; /// Serializes this WebSocketFrameModel to a JSON map. @@ -51,7 +51,7 @@ abstract class $WebSocketFrameModelCopyWith<$Res> { String message, @Uint8ListConverter() Uint8List? binaryData, Map? metadata, - bool isFinalFrame, + bool isSend, DateTime? timeStamp}); } @@ -75,7 +75,7 @@ class _$WebSocketFrameModelCopyWithImpl<$Res, $Val extends WebSocketFrameModel> Object? message = null, Object? binaryData = freezed, Object? metadata = freezed, - Object? isFinalFrame = null, + Object? isSend = null, Object? timeStamp = freezed, }) { return _then(_value.copyWith( @@ -99,9 +99,9 @@ class _$WebSocketFrameModelCopyWithImpl<$Res, $Val extends WebSocketFrameModel> ? _value.metadata : metadata // ignore: cast_nullable_to_non_nullable as Map?, - isFinalFrame: null == isFinalFrame - ? _value.isFinalFrame - : isFinalFrame // ignore: cast_nullable_to_non_nullable + isSend: null == isSend + ? _value.isSend + : isSend // ignore: cast_nullable_to_non_nullable as bool, timeStamp: freezed == timeStamp ? _value.timeStamp @@ -125,7 +125,7 @@ abstract class _$$WebSocketFrameModelImplCopyWith<$Res> String message, @Uint8ListConverter() Uint8List? binaryData, Map? metadata, - bool isFinalFrame, + bool isSend, DateTime? timeStamp}); } @@ -147,7 +147,7 @@ class __$$WebSocketFrameModelImplCopyWithImpl<$Res> Object? message = null, Object? binaryData = freezed, Object? metadata = freezed, - Object? isFinalFrame = null, + Object? isSend = null, Object? timeStamp = freezed, }) { return _then(_$WebSocketFrameModelImpl( @@ -171,9 +171,9 @@ class __$$WebSocketFrameModelImplCopyWithImpl<$Res> ? _value._metadata : metadata // ignore: cast_nullable_to_non_nullable as Map?, - isFinalFrame: null == isFinalFrame - ? _value.isFinalFrame - : isFinalFrame // ignore: cast_nullable_to_non_nullable + isSend: null == isSend + ? _value.isSend + : isSend // ignore: cast_nullable_to_non_nullable as bool, timeStamp: freezed == timeStamp ? _value.timeStamp @@ -193,7 +193,7 @@ class _$WebSocketFrameModelImpl extends _WebSocketFrameModel { this.message = "", @Uint8ListConverter() this.binaryData, final Map? metadata, - this.isFinalFrame = false, + this.isSend = false, this.timeStamp}) : _metadata = metadata, super._(); @@ -224,10 +224,15 @@ class _$WebSocketFrameModelImpl extends _WebSocketFrameModel { @override @JsonKey() - final bool isFinalFrame; + final bool isSend; @override final DateTime? timeStamp; + @override + String toString() { + return 'WebSocketFrameModel(id: $id, frameType: $frameType, message: $message, binaryData: $binaryData, metadata: $metadata, isSend: $isSend, timeStamp: $timeStamp)'; + } + @override bool operator ==(Object other) { return identical(this, other) || @@ -240,8 +245,7 @@ class _$WebSocketFrameModelImpl extends _WebSocketFrameModel { const DeepCollectionEquality() .equals(other.binaryData, binaryData) && const DeepCollectionEquality().equals(other._metadata, _metadata) && - (identical(other.isFinalFrame, isFinalFrame) || - other.isFinalFrame == isFinalFrame) && + (identical(other.isSend, isSend) || other.isSend == isSend) && (identical(other.timeStamp, timeStamp) || other.timeStamp == timeStamp)); } @@ -255,7 +259,7 @@ class _$WebSocketFrameModelImpl extends _WebSocketFrameModel { message, const DeepCollectionEquality().hash(binaryData), const DeepCollectionEquality().hash(_metadata), - isFinalFrame, + isSend, timeStamp); /// Create a copy of WebSocketFrameModel @@ -282,7 +286,7 @@ abstract class _WebSocketFrameModel extends WebSocketFrameModel { final String message, @Uint8ListConverter() final Uint8List? binaryData, final Map? metadata, - final bool isFinalFrame, + final bool isSend, final DateTime? timeStamp}) = _$WebSocketFrameModelImpl; const _WebSocketFrameModel._() : super._(); @@ -301,7 +305,7 @@ abstract class _WebSocketFrameModel extends WebSocketFrameModel { @override Map? get metadata; @override - bool get isFinalFrame; + bool get isSend; @override DateTime? get timeStamp; diff --git a/packages/apidash_core/lib/models/websocket_frame_model.g.dart b/packages/apidash_core/lib/models/websocket_frame_model.g.dart index a3299bc83..cbbfc8100 100644 --- a/packages/apidash_core/lib/models/websocket_frame_model.g.dart +++ b/packages/apidash_core/lib/models/websocket_frame_model.g.dart @@ -16,7 +16,7 @@ _$WebSocketFrameModelImpl _$$WebSocketFrameModelImplFromJson(Map json) => metadata: (json['metadata'] as Map?)?.map( (k, e) => MapEntry(k as String, e as String), ), - isFinalFrame: json['isFinalFrame'] as bool? ?? false, + isSend: json['isSend'] as bool? ?? false, timeStamp: json['timeStamp'] == null ? null : DateTime.parse(json['timeStamp'] as String), @@ -30,6 +30,6 @@ Map _$$WebSocketFrameModelImplToJson( 'message': instance.message, 'binaryData': const Uint8ListConverter().toJson(instance.binaryData), 'metadata': instance.metadata, - 'isFinalFrame': instance.isFinalFrame, + 'isSend': instance.isSend, 'timeStamp': instance.timeStamp?.toIso8601String(), }; diff --git a/packages/apidash_core/lib/models/websocket_request_model.dart b/packages/apidash_core/lib/models/websocket_request_model.dart index 69cc0bef5..cb49548b8 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.dart @@ -24,7 +24,6 @@ class WebSocketRequestModel with _$WebSocketRequestModel { List? params, List? isParamEnabledList, String? message, - List? receivedMessages, }) = _WebSocketRequestModel; factory WebSocketRequestModel.fromJson(Map json) => diff --git a/packages/apidash_core/lib/models/websocket_request_model.freezed.dart b/packages/apidash_core/lib/models/websocket_request_model.freezed.dart index 058a99844..26a23b27a 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.freezed.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.freezed.dart @@ -29,7 +29,6 @@ mixin _$WebSocketRequestModel { List? get params => throw _privateConstructorUsedError; List? get isParamEnabledList => throw _privateConstructorUsedError; String? get message => throw _privateConstructorUsedError; - List? get receivedMessages => throw _privateConstructorUsedError; /// Serializes this WebSocketRequestModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -55,8 +54,7 @@ abstract class $WebSocketRequestModelCopyWith<$Res> { List? isHeaderEnabledList, List? params, List? isParamEnabledList, - String? message, - List? receivedMessages}); + String? message}); } /// @nodoc @@ -83,7 +81,6 @@ class _$WebSocketRequestModelCopyWithImpl<$Res, Object? params = freezed, Object? isParamEnabledList = freezed, Object? message = freezed, - Object? receivedMessages = freezed, }) { return _then(_value.copyWith( url: null == url @@ -118,10 +115,6 @@ class _$WebSocketRequestModelCopyWithImpl<$Res, ? _value.message : message // ignore: cast_nullable_to_non_nullable as String?, - receivedMessages: freezed == receivedMessages - ? _value.receivedMessages - : receivedMessages // ignore: cast_nullable_to_non_nullable - as List?, ) as $Val); } } @@ -143,8 +136,7 @@ abstract class _$$WebSocketRequestModelImplCopyWith<$Res> List? isHeaderEnabledList, List? params, List? isParamEnabledList, - String? message, - List? receivedMessages}); + String? message}); } /// @nodoc @@ -169,7 +161,6 @@ class __$$WebSocketRequestModelImplCopyWithImpl<$Res> Object? params = freezed, Object? isParamEnabledList = freezed, Object? message = freezed, - Object? receivedMessages = freezed, }) { return _then(_$WebSocketRequestModelImpl( url: null == url @@ -204,10 +195,6 @@ class __$$WebSocketRequestModelImplCopyWithImpl<$Res> ? _value.message : message // ignore: cast_nullable_to_non_nullable as String?, - receivedMessages: freezed == receivedMessages - ? _value._receivedMessages - : receivedMessages // ignore: cast_nullable_to_non_nullable - as List?, )); } } @@ -224,13 +211,11 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { final List? isHeaderEnabledList, final List? params, final List? isParamEnabledList, - this.message, - final List? receivedMessages}) + this.message}) : _headers = headers, _isHeaderEnabledList = isHeaderEnabledList, _params = params, _isParamEnabledList = isParamEnabledList, - _receivedMessages = receivedMessages, super._(); factory _$WebSocketRequestModelImpl.fromJson(Map json) => @@ -288,20 +273,10 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { @override final String? message; - final List? _receivedMessages; - @override - List? get receivedMessages { - final value = _receivedMessages; - if (value == null) return null; - if (_receivedMessages is EqualUnmodifiableListView) - return _receivedMessages; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(value); - } @override String toString() { - return 'WebSocketRequestModel(url: $url, contentType: $contentType, isConnected: $isConnected, headers: $headers, isHeaderEnabledList: $isHeaderEnabledList, params: $params, isParamEnabledList: $isParamEnabledList, message: $message, receivedMessages: $receivedMessages)'; + return 'WebSocketRequestModel(url: $url, contentType: $contentType, isConnected: $isConnected, headers: $headers, isHeaderEnabledList: $isHeaderEnabledList, params: $params, isParamEnabledList: $isParamEnabledList, message: $message)'; } @override @@ -320,9 +295,7 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { const DeepCollectionEquality().equals(other._params, _params) && const DeepCollectionEquality() .equals(other._isParamEnabledList, _isParamEnabledList) && - (identical(other.message, message) || other.message == message) && - const DeepCollectionEquality() - .equals(other._receivedMessages, _receivedMessages)); + (identical(other.message, message) || other.message == message)); } @JsonKey(includeFromJson: false, includeToJson: false) @@ -336,8 +309,7 @@ class _$WebSocketRequestModelImpl extends _WebSocketRequestModel { const DeepCollectionEquality().hash(_isHeaderEnabledList), const DeepCollectionEquality().hash(_params), const DeepCollectionEquality().hash(_isParamEnabledList), - message, - const DeepCollectionEquality().hash(_receivedMessages)); + message); /// Create a copy of WebSocketRequestModel /// with the given fields replaced by the non-null parameter values. @@ -365,8 +337,7 @@ abstract class _WebSocketRequestModel extends WebSocketRequestModel { final List? isHeaderEnabledList, final List? params, final List? isParamEnabledList, - final String? message, - final List? receivedMessages}) = _$WebSocketRequestModelImpl; + final String? message}) = _$WebSocketRequestModelImpl; const _WebSocketRequestModel._() : super._(); factory _WebSocketRequestModel.fromJson(Map json) = @@ -388,8 +359,6 @@ abstract class _WebSocketRequestModel extends WebSocketRequestModel { List? get isParamEnabledList; @override String? get message; - @override - List? get receivedMessages; /// Create a copy of WebSocketRequestModel /// with the given fields replaced by the non-null parameter values. diff --git a/packages/apidash_core/lib/models/websocket_request_model.g.dart b/packages/apidash_core/lib/models/websocket_request_model.g.dart index d95d1d1c4..758e00992 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.g.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.g.dart @@ -28,9 +28,6 @@ _$WebSocketRequestModelImpl _$$WebSocketRequestModelImplFromJson(Map json) => ?.map((e) => e as bool) .toList(), message: json['message'] as String?, - receivedMessages: (json['receivedMessages'] as List?) - ?.map((e) => e as String) - .toList(), ); Map _$$WebSocketRequestModelImplToJson( @@ -44,7 +41,6 @@ Map _$$WebSocketRequestModelImplToJson( 'params': instance.params?.map((e) => e.toJson()).toList(), 'isParamEnabledList': instance.isParamEnabledList, 'message': instance.message, - 'receivedMessages': instance.receivedMessages, }; const _$ContentTypeWebSocketEnumMap = { diff --git a/packages/apidash_core/lib/services/clientWrapper.dart b/packages/apidash_core/lib/services/clientWrapper.dart index a69aefb02..3da383b1d 100644 --- a/packages/apidash_core/lib/services/clientWrapper.dart +++ b/packages/apidash_core/lib/services/clientWrapper.dart @@ -10,6 +10,11 @@ abstract class clientWrapper { Future sendText(WebSocketRequestModel websocketRequestModel )async{ throw UnimplementedError('sendText is not implemented for this client type.'); } + + Future<(String?, DateTime?)> connect(String url) { + throw UnimplementedError('sendText is not implemented for this client type.'); + + } } class HttpClientWrapper extends clientWrapper { @@ -30,8 +35,17 @@ class WebSocketClientWrapper extends clientWrapper { log("cancelling under websocket"); client.disconnect(); } - Future sendText(WebSocketRequestModel websocketRequestModel) async{ - client.sendText(websocketRequestModel); + @override + Future sendText(WebSocketRequestModel websocketRequestModel) async{ + client.sendText(""); } + + @override + Future<(String?, DateTime?)> connect(String url) { + return client.connect(url); + + } + + } diff --git a/packages/apidash_core/lib/services/http_client_manager.dart b/packages/apidash_core/lib/services/http_client_manager.dart index 81462ffd2..0d1141477 100644 --- a/packages/apidash_core/lib/services/http_client_manager.dart +++ b/packages/apidash_core/lib/services/http_client_manager.dart @@ -1,6 +1,5 @@ import 'dart:io'; import 'dart:collection'; -import 'package:apidash_core/consts.dart'; import 'package:apidash_core/services/clientWrapper.dart'; import 'package:apidash_core/services/websocket_service.dart'; import 'package:flutter/foundation.dart'; @@ -78,4 +77,6 @@ class HttpClientManager { clientWrapper? getClient(String requestId) { return _clients[requestId]; } + + } diff --git a/packages/apidash_core/lib/services/services.dart b/packages/apidash_core/lib/services/services.dart index d155e9c70..8849874f4 100644 --- a/packages/apidash_core/lib/services/services.dart +++ b/packages/apidash_core/lib/services/services.dart @@ -1,2 +1,4 @@ export 'http_client_manager.dart'; export 'http_service.dart'; +export 'websocket_service.dart'; +export 'web_socket_manager.dart'; diff --git a/packages/apidash_core/lib/services/web_socket_manager.dart b/packages/apidash_core/lib/services/web_socket_manager.dart new file mode 100644 index 000000000..3b950d08e --- /dev/null +++ b/packages/apidash_core/lib/services/web_socket_manager.dart @@ -0,0 +1,58 @@ +import 'dart:io'; +import 'dart:collection'; +import 'package:apidash_core/services/websocket_service.dart'; +import 'package:flutter/foundation.dart'; + +class WebSocketManager { + static final WebSocketManager _instance = WebSocketManager._internal(); + final Map _clients = {}; + + factory WebSocketManager() { + return _instance; + } + + WebSocketManager._internal(); + + WebSocketClient createWebSocketClient( + String requestId, { + bool noSSL = false, + }) { + final client = WebSocketClient(); + _clients[requestId] = client; + return client; + } + + WebSocketClient? getClient(String requestId) { + return _clients[requestId]; + } + + Future disconnect(String requestId) async{ + await _clients[requestId]?.disconnect(); + } + +Future<(String?,DateTime?)> connect(String requestId,String url) async { + if (_clients.containsKey(requestId)) { + return _clients[requestId]!.connect(url); + } + return (null,null); + + } + + Future<(String?,DateTime?,String?)> sendText(String requestId,String message) async { + if (_clients.containsKey(requestId)) { + return _clients[requestId]!.sendText(message); + } + return (null,null,null); + } + + Future listen(String requestId,Future Function(dynamic message) onMessage,{Future Function(dynamic error)? onError, Future Function()? onDone,bool? cancelOnError}) async { + if (_clients.containsKey(requestId)) { + return _clients[requestId]!.listen( + onMessage, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } + } +} diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index b3bfa013d..98c88ba3e 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -1,6 +1,6 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:developer'; -import 'package:apidash_core/models/models.dart'; import 'dart:io'; import 'package:apidash_core/models/websocket_request_model.dart'; import 'package:flutter/foundation.dart'; @@ -11,7 +11,7 @@ import 'package:web_socket_channel/io.dart'; class WebSocketClient { late WebSocketChannel _channel; StreamSubscription? _subscription; - Duration? _pingDuration; + Duration? pingDuration; WebSocketClient(); @@ -23,13 +23,13 @@ class WebSocketClient { if(!kIsWeb){ final WebSocket ioWebSocket = await WebSocket.connect(url); _channel = IOWebSocketChannel(ioWebSocket); - ioWebSocket.pingInterval = _pingDuration; + ioWebSocket.pingInterval = pingDuration; }else{ _channel = WebSocketChannel.connect(Uri.parse(url)); } await _channel.ready; - print('Connected to WebSocket server: ${"ws://localhost:3000"}'); + print('Connected to WebSocket server: ${url}'); return ("Connected",DateTime.now()); } catch (e) { print('Failed to connect to WebSocket server: $e'); @@ -38,18 +38,42 @@ class WebSocketClient { } - Future sendText(WebSocketRequestModel websocketRequestModel)async { - if (_channel != null) { - _channel.sink.add(websocketRequestModel.message); + Future<(String?,DateTime?,String?)> sendText(String message)async { + try{ + _channel.sink.add(message); // websocketRequestModel.frames.add(WebSocketFrameModel( // id: '1', // message: websocketRequestModel.message!, // timeStamp: DateTime.now(), // )); - log('Sent text message: ${websocketRequestModel.message}'); - } else { - log('WebSocket connection is not open. Unable to send text message.'); + log('Sent text message: $message}'); + return (message,DateTime.now(),null); + + }catch(e){ + return (null,DateTime.now(),e.toString()); + } + + } + + Future<(String?,DateTime?,String?)> sendBinary(String message)async { + try{ + Uint8List binary = Uint8List.fromList(utf8.encode(message)); + + _channel.sink.add(binary); + // websocketRequestModel.frames.add(WebSocketFrameModel( + // id: '1', + // message: websocketRequestModel.message!, + // timeStamp: DateTime.now(), + // )); + log('Sent text message: $message}'); + return (message,DateTime.now(),null); + + }catch(e){ + return (null,DateTime.now(),e.toString()); + + } + } @@ -64,7 +88,7 @@ class WebSocketClient { Future listen(Future Function(dynamic message) onMessage, - {Future Function(dynamic error)? onError, Future Function()? onDone}) async{ + {Future Function(dynamic error)? onError, Future Function()? onDone,bool? cancelOnError}) async{ _subscription = _channel.stream.listen( (message) { log('Received message: $message'); @@ -76,9 +100,15 @@ class WebSocketClient { }, onDone: () { log('Connection closed.'); + if (_channel.closeCode != null) { + print('Close code: ${_channel.closeCode}'); + } + if (_channel.closeReason != null) { + print('Close reason: ${_channel.closeReason}'); + } if (onDone != null) onDone(); }, - cancelOnError: true, + cancelOnError: cancelOnError ?? true, ); } @@ -89,48 +119,3 @@ class WebSocketClient { log('Disconnected from WebSocket server'); } } - - - -// Future<(String?,DateTime?)> main() async { -// const wsUrl = '"ws://localhost:3000"'; - -// final wsClient = WebSocketClient(wsUrl); - -// try { -// await wsClient.connect(); - -// wsClient.listen( -// (message) { -// // Handle incoming messages -// if (message is String) { -// log('Text message received: $message'); -// } else if (message is List) { -// log('Binary message received: $message'); -// } -// }, -// onError: (error) { -// log('Error occurred: $error'); -// }, -// onDone: () { -// log('WebSocket connection closed.'); -// }, -// ); - - -// wsClient.sendText('Hello, WebSocket!'); - - -// final binaryData = Uint8List.fromList([0x68, 0x69]); // "hi" in binary -// wsClient.sendBinary(binaryData); - - -// await Future.delayed(Duration(seconds: 5)); -// while(True){ - -// } -// wsClient.disconnect(reason: 'Closing connection after demo.'); -// } catch (e) { -// log('Error: $e'); -// } -// } From 5b377920158424ba590876bb0a1b1a6af2740f41 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sun, 26 Jan 2025 12:36:16 +0530 Subject: [PATCH 09/30] removed client wrapper --- .../lib/services/clientWrapper.dart | 51 ------------------- .../lib/services/http_client_manager.dart | 19 +------ .../lib/services/web_socket_manager.dart | 6 +-- 3 files changed, 4 insertions(+), 72 deletions(-) delete mode 100644 packages/apidash_core/lib/services/clientWrapper.dart diff --git a/packages/apidash_core/lib/services/clientWrapper.dart b/packages/apidash_core/lib/services/clientWrapper.dart deleted file mode 100644 index 3da383b1d..000000000 --- a/packages/apidash_core/lib/services/clientWrapper.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'dart:developer'; - -import 'package:apidash_core/models/websocket_request_model.dart'; -import 'package:apidash_core/services/clientWrapper.dart' as http; -import 'package:apidash_core/services/websocket_service.dart'; -import 'package:http/http.dart' as http; - -abstract class clientWrapper { - void close() {} - Future sendText(WebSocketRequestModel websocketRequestModel )async{ - throw UnimplementedError('sendText is not implemented for this client type.'); - } - - Future<(String?, DateTime?)> connect(String url) { - throw UnimplementedError('sendText is not implemented for this client type.'); - - } -} - -class HttpClientWrapper extends clientWrapper { - final http.Client client; - HttpClientWrapper(this.client); - @override - void close() { - log("cancelling under rest"); - client.close(); - } -} - -class WebSocketClientWrapper extends clientWrapper { - final WebSocketClient client; - WebSocketClientWrapper(this.client); - @override - void close() { - log("cancelling under websocket"); - client.disconnect(); - } - @override - Future sendText(WebSocketRequestModel websocketRequestModel) async{ - client.sendText(""); - } - - @override - Future<(String?, DateTime?)> connect(String url) { - return client.connect(url); - - } - - - -} diff --git a/packages/apidash_core/lib/services/http_client_manager.dart b/packages/apidash_core/lib/services/http_client_manager.dart index 0d1141477..ab2b79106 100644 --- a/packages/apidash_core/lib/services/http_client_manager.dart +++ b/packages/apidash_core/lib/services/http_client_manager.dart @@ -17,7 +17,7 @@ http.Client createHttpClientWithNoSSL() { class HttpClientManager { static final HttpClientManager _instance = HttpClientManager._internal(); static const int _maxCancelledRequests = 100; - final Map _clients = {}; + final Map _clients = {}; final Queue _cancelledRequests = Queue(); factory HttpClientManager() { @@ -25,15 +25,6 @@ class HttpClientManager { } HttpClientManager._internal(); - - WebSocketClient createWebSocketClient( - String requestId, { - bool noSSL = false, - }) { - final client = WebSocketClient(); - _clients[requestId] = WebSocketClientWrapper(client); - return client; - } http.Client createClient( String requestId, { @@ -42,7 +33,7 @@ class HttpClientManager { final client = (noSSL && !kIsWeb) ? createHttpClientWithNoSSL() : http.Client(); - _clients[requestId] = HttpClientWrapper(client); + _clients[requestId] = client; return client; } @@ -73,10 +64,4 @@ class HttpClientManager { bool hasActiveClient(String requestId) { return _clients.containsKey(requestId); } - - clientWrapper? getClient(String requestId) { - return _clients[requestId]; - } - - } diff --git a/packages/apidash_core/lib/services/web_socket_manager.dart b/packages/apidash_core/lib/services/web_socket_manager.dart index 3b950d08e..b25888e67 100644 --- a/packages/apidash_core/lib/services/web_socket_manager.dart +++ b/packages/apidash_core/lib/services/web_socket_manager.dart @@ -1,7 +1,5 @@ -import 'dart:io'; -import 'dart:collection'; -import 'package:apidash_core/services/websocket_service.dart'; -import 'package:flutter/foundation.dart'; + +import 'websocket_service.dart'; class WebSocketManager { static final WebSocketManager _instance = WebSocketManager._internal(); From 93668e846f8df8adaa7d8b57e6f411c2e6ffe021 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sun, 26 Jan 2025 20:07:07 +0530 Subject: [PATCH 10/30] SETTING HEADERS AND PARAMS --- lib/models/settings_model.dart | 22 +++++++- lib/providers/collection_providers.dart | 56 +++++++++---------- lib/providers/settings_providers.dart | 4 ++ .../request_pane/request_body.dart | 4 ++ .../request_pane/request_headers.dart | 24 +++++++- lib/screens/settings_page.dart | 28 ++++++++-- packages/apidash_core/lib/consts.dart | 6 +- .../lib/services/http_client_manager.dart | 2 - .../lib/services/web_socket_manager.dart | 13 +++++ .../lib/services/websocket_service.dart | 16 +----- packages/apidash_core/pubspec.yaml | 1 + pubspec.lock | 2 +- pubspec.yaml | 2 +- 13 files changed, 120 insertions(+), 60 deletions(-) diff --git a/lib/models/settings_model.dart b/lib/models/settings_model.dart index 74bc2ff9c..3ae484b8c 100644 --- a/lib/models/settings_model.dart +++ b/lib/models/settings_model.dart @@ -17,6 +17,8 @@ class SettingsModel { this.historyRetentionPeriod = HistoryRetentionPeriod.oneWeek, this.workspaceFolderPath, this.isSSLDisabled = false, + this.pingInterval = 100, + this.isPinging = false, }); final bool isDark; @@ -31,6 +33,8 @@ class SettingsModel { final HistoryRetentionPeriod historyRetentionPeriod; final String? workspaceFolderPath; final bool isSSLDisabled; + final int? pingInterval; + final bool isPinging; SettingsModel copyWith({ bool? isDark, @@ -45,6 +49,8 @@ class SettingsModel { HistoryRetentionPeriod? historyRetentionPeriod, String? workspaceFolderPath, bool? isSSLDisabled, + int? pingInterval, + bool? isPinging, }) { return SettingsModel( isDark: isDark ?? this.isDark, @@ -61,6 +67,8 @@ class SettingsModel { historyRetentionPeriod ?? this.historyRetentionPeriod, workspaceFolderPath: workspaceFolderPath ?? this.workspaceFolderPath, isSSLDisabled: isSSLDisabled ?? this.isSSLDisabled, + pingInterval: pingInterval ?? this.pingInterval, + isPinging: isPinging ?? this.isPinging, ); } @@ -80,6 +88,8 @@ class SettingsModel { historyRetentionPeriod: historyRetentionPeriod, workspaceFolderPath: workspaceFolderPath, isSSLDisabled: isSSLDisabled, + pingInterval: pingInterval, + isPinging: isPinging ); } @@ -134,6 +144,8 @@ class SettingsModel { } final workspaceFolderPath = data["workspaceFolderPath"] as String?; final isSSLDisabled = data["isSSLDisabled"] as bool?; + final pingInterval = data["pingInterval"] as int?; + final isPinging = data["isPinging"] as bool?; const sm = SettingsModel(); @@ -151,6 +163,8 @@ class SettingsModel { historyRetentionPeriod ?? HistoryRetentionPeriod.oneWeek, workspaceFolderPath: workspaceFolderPath, isSSLDisabled: isSSLDisabled, + pingInterval: pingInterval, + isPinging: isPinging ); } @@ -170,6 +184,8 @@ class SettingsModel { "historyRetentionPeriod": historyRetentionPeriod.name, "workspaceFolderPath": workspaceFolderPath, "isSSLDisabled": isSSLDisabled, + "pingInterval": pingInterval, + "isPinging": isPinging }; } @@ -194,7 +210,9 @@ class SettingsModel { other.activeEnvironmentId == activeEnvironmentId && other.historyRetentionPeriod == historyRetentionPeriod && other.workspaceFolderPath == workspaceFolderPath && - other.isSSLDisabled == isSSLDisabled; + other.isSSLDisabled == isSSLDisabled && + other.pingInterval == pingInterval && + other.isPinging == isPinging; } @override @@ -213,6 +231,8 @@ class SettingsModel { historyRetentionPeriod, workspaceFolderPath, isSSLDisabled, + pingInterval, + isPinging ); } } diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index f313e5acc..18b9f07f3 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -1,11 +1,7 @@ -import 'dart:developer'; -import 'dart:io'; - import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/consts.dart'; -import 'package:highlighter/languages/q.dart'; import 'providers.dart'; import '../models/models.dart'; import '../services/services.dart' show hiveHandler, HiveHandler; @@ -236,7 +232,9 @@ class CollectionStateNotifier List? formData, int? responseStatus, String? message, + ContentTypeWebSocket? contentType, HttpResponseModel? httpResponseModel, + WebSocketResponseModel? webSocketResponseModel, }) { final rId = id ?? ref.read(selectedIdStateProvider); if (rId == null) { @@ -264,10 +262,12 @@ class CollectionStateNotifier formData: formData ?? currentHttpRequestModel.formData, ) : currentHttpRequestModel; - var currentWebSocketRequestModel = currentModel.webSocketRequestModel; + var currentWebSocketRequestModel = currentModel.webSocketRequestModel ?? const WebSocketRequestModel(); + final newWebSocketRequestModel = currentApiType == APIType.webSocket ? currentWebSocketRequestModel?.copyWith( url: url ?? currentWebSocketRequestModel.url, + contentType: contentType ?? currentWebSocketRequestModel.contentType, headers: headers ?? currentWebSocketRequestModel.headers, params: params ?? currentWebSocketRequestModel.params, isHeaderEnabledList: isHeaderEnabledList ?? @@ -471,7 +471,7 @@ class CollectionStateNotifier Future sendFrames() async { final requestId = ref.read(selectedIdStateProvider); ref.read(codePaneVisibleStateProvider.notifier).state = false; - final defaultUriScheme = ref.read(settingsProvider).defaultUriScheme; + if (requestId == null || state == null) { return; @@ -484,9 +484,7 @@ class CollectionStateNotifier - // substituted websocket needs to be added here - - // set current model's isWorking to true and update state + var map = {...state!}; map[requestId] = requestModel.copyWith( isWorking: true, @@ -496,9 +494,14 @@ class CollectionStateNotifier String message = currentWebSocketRequestModel.message ?? ''; - (String?,DateTime?,String?) frame = await webSocketManager.sendText(requestId,message); + late (String?,DateTime?,String?) frame; + if(currentWebSocketRequestModel.contentType == ContentTypeWebSocket.text){ + frame = await webSocketManager.sendText(requestId,message); + }else if(currentWebSocketRequestModel.contentType == ContentTypeWebSocket.binary){ + frame = await webSocketManager.sendBinary(requestId,message); + } - var newWebSocketResponseModel; + late WebSocketResponseModel newWebSocketResponseModel; if(frame.$1 != null){ newWebSocketResponseModel = requestModel.webSocketResponseModel!.copyWith( frames: [ @@ -563,14 +566,23 @@ class CollectionStateNotifier print("entered null"); return; } + + bool isPinging = ref.read(settingsProvider).isPinging; + webSocketManager.createWebSocketClient(requestId); - // webSocketClient.pingDuration = Duration(seconds: 5); + if(isPinging){ + Duration durationPinging = Duration(milliseconds: ref.read(settingsProvider).pingInterval!); + webSocketManager.setPingInterval(requestId,durationPinging); + }else{ + webSocketManager.setPingInterval(requestId,null); + } + final url = requestModel!.webSocketRequestModel!.url; (String?,DateTime?) result = await webSocketManager.connect(requestId,url); var map = {...state!}; map[requestId] = requestModel.copyWith( - isWorking: result.$1 == "Connected", + isWorking: result.$1 == KLabelConnect, sendingTime: result.$2, webSocketResponseModel: const WebSocketResponseModel(), ); @@ -603,28 +615,10 @@ class CollectionStateNotifier print(message); }, onError: (error) async{ - print("error found"); - - // var map = {...state!}; - // map[requestId] = requestModel.copyWith( - // responseStatus: -1, - // message: error.toString(), - // isWorking: false, - // ); - // state = map; }, onDone: () async{ print("Connection done"); - - - // var map = {...state!}; - // map[requestId] = requestModel.copyWith( - // responseStatus: 200, - // message: "Connection closed", - // isWorking: false, - // ); - // state = map; }, cancelOnError: false, ); diff --git a/lib/providers/settings_providers.dart b/lib/providers/settings_providers.dart index 6b64343aa..0847ed41d 100644 --- a/lib/providers/settings_providers.dart +++ b/lib/providers/settings_providers.dart @@ -33,6 +33,8 @@ class ThemeStateNotifier extends StateNotifier { HistoryRetentionPeriod? historyRetentionPeriod, String? workspaceFolderPath, bool? isSSLDisabled, + int? pingInterval, + bool? isPinging }) async { state = state.copyWith( isDark: isDark, @@ -47,6 +49,8 @@ class ThemeStateNotifier extends StateNotifier { historyRetentionPeriod: historyRetentionPeriod, workspaceFolderPath: workspaceFolderPath, isSSLDisabled: isSSLDisabled, + pingInterval: pingInterval, + isPinging: isPinging, ); await setSettingsToSharedPrefs(state); } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 354bba1a0..0fd871611 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -187,6 +187,10 @@ class DropdownButtonBodyContentWebSocketType extends ConsumerWidget { return DropdownButtonContentTypeWebSocket( contentType: requestBodyContentType, onChanged: (ContentTypeWebSocket? value) { + + // ref.read(collectionStateNotifierProvider.notifier).update( + // contentType: value, + // ); }, ); 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 ecb3f6dab..f73ccafec 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 @@ -43,20 +43,40 @@ class EditRequestHeadersState extends ConsumerState { final selectedId = ref.watch(selectedIdStateProvider); ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.headers?.length)); - var rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; + var apiType = ref.read(selectedRequestModelProvider)?.apiType; + late List? rH; + if(apiType == APIType.webSocket){ + rH = ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.headers; + }else{ + rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; + } bool isHeadersEmpty = rH == null || rH.isEmpty; headerRows = isHeadersEmpty ? [ kNameValueEmptyModel, ] : rH + [kNameValueEmptyModel]; - isRowEnabledList = [ + + if(apiType == APIType.webSocket){ + isRowEnabledList = [ + ...(ref + .read(selectedRequestModelProvider) + ?.webSocketRequestModel + ?.isHeaderEnabledList ?? + List.filled(rH?.length ?? 0, true, growable: true)) + ]; + + }else{ + isRowEnabledList = [ ...(ref .read(selectedRequestModelProvider) ?.httpRequestModel ?.isHeaderEnabledList ?? List.filled(rH?.length ?? 0, true, growable: true)) ]; + + } + isRowEnabledList.add(false); isAddingRow = false; diff --git a/lib/screens/settings_page.dart b/lib/screens/settings_page.dart index 2602bd602..a8d9e2ad4 100644 --- a/lib/screens/settings_page.dart +++ b/lib/screens/settings_page.dart @@ -97,7 +97,7 @@ class SettingsPage extends ConsumerWidget { trailing: CodegenPopupMenu( value: settings.defaultCodeGenLang, onChanged: (value) { - ref + ref .read(settingsProvider.notifier) .update(defaultCodeGenLang: value); }, @@ -224,21 +224,37 @@ class SettingsPage extends ConsumerWidget { ), ), ), + !kIsWeb + ? SwitchListTile( + hoverColor: kColorTransparent, + title: const Text('Enable Pinging'), + subtitle: Text( + 'Current selection: ${settings.isPinging ? "Pinging Enabled" : "Pinging Disabled"}', + + ), + value: settings.isPinging, + onChanged: (bool value) { + ref + .read(settingsProvider.notifier) + .update(isPinging: value ); + }, + ) + : kSizedBoxEmpty, ListTile( hoverColor: kColorTransparent, title: const Text('Interval Between Ping Requests'), subtitle: Text( - 'Current interval: seconds'), + 'Current interval between consecutive pings are: ${settings.pingInterval} milliseconds'), trailing: SizedBox( width: 120, child: TextField( - controller: TextEditingController(text: "22"), + controller: TextEditingController(text: settings.pingInterval.toString()), keyboardType: TextInputType.number, onChanged: (value) { - // ref - // .read(settingsProvider.notifier) - // .update(pingInterval: int.parse(value)); + ref + .read(settingsProvider.notifier) + .update(pingInterval: int.parse(value)); }, ), ), diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index 47c6a2334..cd62fbe78 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -75,6 +75,8 @@ const kSubTypeFormData = "form-data"; const kSubTypeDefaultViewOptions = 'all'; +const kTypeBinary = 'binary'; + enum ContentType { json("$kTypeApplication/$kSubTypeJson"), text("$kTypeText/$kSubTypePlain"), @@ -86,8 +88,8 @@ enum ContentType { enum ContentTypeWebSocket { - text("$kTypeText/$kSubTypePlain"), - binary("$kTypeApplication/$kSubTypeOctetStream"); + text(kTypeText), + binary(kTypeBinary); const ContentTypeWebSocket(this.header); diff --git a/packages/apidash_core/lib/services/http_client_manager.dart b/packages/apidash_core/lib/services/http_client_manager.dart index ab2b79106..c98c16502 100644 --- a/packages/apidash_core/lib/services/http_client_manager.dart +++ b/packages/apidash_core/lib/services/http_client_manager.dart @@ -1,7 +1,5 @@ import 'dart:io'; import 'dart:collection'; -import 'package:apidash_core/services/clientWrapper.dart'; -import 'package:apidash_core/services/websocket_service.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:http/io_client.dart'; diff --git a/packages/apidash_core/lib/services/web_socket_manager.dart b/packages/apidash_core/lib/services/web_socket_manager.dart index b25888e67..a38db40e5 100644 --- a/packages/apidash_core/lib/services/web_socket_manager.dart +++ b/packages/apidash_core/lib/services/web_socket_manager.dart @@ -43,6 +43,14 @@ Future<(String?,DateTime?)> connect(String requestId,String url) async { return (null,null,null); } + Future<(String?,DateTime?,String?)> sendBinary(String requestId,String message) async { + if (_clients.containsKey(requestId)) { + return _clients[requestId]!.sendBinary(message); + } + return (null,null,null); + } + + Future listen(String requestId,Future Function(dynamic message) onMessage,{Future Function(dynamic error)? onError, Future Function()? onDone,bool? cancelOnError}) async { if (_clients.containsKey(requestId)) { return _clients[requestId]!.listen( @@ -53,4 +61,9 @@ Future<(String?,DateTime?)> connect(String requestId,String url) async { ); } } + Future setPingInterval(String requestId,Duration? interval) async { + if (_clients.containsKey(requestId)) { + _clients[requestId]!.pingInterval = interval; + } + } } diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index 98c88ba3e..999d8d44d 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io'; -import 'package:apidash_core/models/websocket_request_model.dart'; import 'package:flutter/foundation.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:web_socket_channel/status.dart' as status; @@ -11,7 +10,7 @@ import 'package:web_socket_channel/io.dart'; class WebSocketClient { late WebSocketChannel _channel; StreamSubscription? _subscription; - Duration? pingDuration; + Duration? pingInterval; WebSocketClient(); @@ -23,7 +22,7 @@ class WebSocketClient { if(!kIsWeb){ final WebSocket ioWebSocket = await WebSocket.connect(url); _channel = IOWebSocketChannel(ioWebSocket); - ioWebSocket.pingInterval = pingDuration; + ioWebSocket.pingInterval = pingInterval; }else{ _channel = WebSocketChannel.connect(Uri.parse(url)); @@ -75,17 +74,6 @@ class WebSocketClient { } } - - - // Future<(String?,DateTime?)> sendBinary(Uint8List data) { - // if (_channel != null) { - // _channel.sink.add(data); - // log('Sent binary message: $data'); - // } else { - // log('WebSocket connection is not open. Unable to send binary message.'); - // } - // } - Future listen(Future Function(dynamic message) onMessage, {Future Function(dynamic error)? onError, Future Function()? onDone,bool? cancelOnError}) async{ diff --git a/packages/apidash_core/pubspec.yaml b/packages/apidash_core/pubspec.yaml index 11f3f7fb6..6cf272b6d 100644 --- a/packages/apidash_core/pubspec.yaml +++ b/packages/apidash_core/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: xml: ^6.3.0 intl: ^0.19.0 json_serializable: ^6.9.0 + web_socket_channel: ^3.0.1 dev_dependencies: flutter_test: diff --git a/pubspec.lock b/pubspec.lock index a6d6952c9..e6df63be7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1830,7 +1830,7 @@ packages: source: hosted version: "0.1.6" web_socket_channel: - dependency: "direct main" + dependency: transitive description: name: web_socket_channel sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" diff --git a/pubspec.yaml b/pubspec.yaml index 25e2c51e1..fcd0aaecb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -67,7 +67,7 @@ dependencies: git: url: https://github.com/google/flutter-desktop-embedding.git path: plugins/window_size - web_socket_channel: ^3.0.1 + dependency_overrides: extended_text_field: ^16.0.0 From d29c51fb69badf587960c7497892d14d8f8cc2ee Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Mon, 27 Jan 2025 20:31:00 +0530 Subject: [PATCH 11/30] working on HEADERS AND PARAMS --- lib/consts.dart | 5 + lib/providers/collection_providers.dart | 41 +- .../request_pane/request_headers.dart | 525 +++++++++++++++++- .../request_pane/request_pane_websocket.dart | 19 +- .../details_card/response_pane.dart | 2 - lib/screens/settings_page.dart | 4 +- lib/widgets/widgets.dart | 2 + .../lib/services/websocket_service.dart | 5 +- 8 files changed, 562 insertions(+), 41 deletions(-) diff --git a/lib/consts.dart b/lib/consts.dart index 7640e7b47..b029ad0ec 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -294,6 +294,11 @@ const kResponseCodeReasons = { 508: 'Loop Detected', 510: 'Not Extended', 511: 'Network Authentication Required', + // 1000s - WebSocket Error + 1000: 'Normal Closure', + 1001: 'Going Away', + 1002: 'Protocol Error', + 1003: 'Unsupported Data', }; Map kHttpHeadersMap = { diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 18b9f07f3..e36b40c89 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -232,6 +232,7 @@ class CollectionStateNotifier List? formData, int? responseStatus, String? message, + String? webSocketMessage, ContentTypeWebSocket? contentType, HttpResponseModel? httpResponseModel, WebSocketResponseModel? webSocketResponseModel, @@ -274,7 +275,7 @@ class CollectionStateNotifier currentWebSocketRequestModel.isHeaderEnabledList, isParamEnabledList: isParamEnabledList ?? currentWebSocketRequestModel.isParamEnabledList, - message: message ?? currentWebSocketRequestModel.message, + message: webSocketMessage ?? currentWebSocketRequestModel.message, ) : currentWebSocketRequestModel; @@ -578,18 +579,31 @@ class CollectionStateNotifier } final url = requestModel!.webSocketRequestModel!.url; + var map = {...state!}; + + map[requestId] = requestModel.copyWith( + isWorking: true, + + webSocketResponseModel: const WebSocketResponseModel(), + ); + + state = map; (String?,DateTime?) result = await webSocketManager.connect(requestId,url); - var map = {...state!}; + map = {...state!}; + map[requestId] = requestModel.copyWith( - isWorking: result.$1 == KLabelConnect, + isWorking: true, + responseStatus: 101, + message: kResponseCodeReasons[101], sendingTime: result.$2, webSocketResponseModel: const WebSocketResponseModel(), ); state = map; - + if(result.$1 == kMsgConnected){ + map = {...state!}; webSocketManager.listen( requestId, (message) async{ @@ -609,12 +623,13 @@ class CollectionStateNotifier ); - map = {...state!}; - map[requestId] = newRequestModel; - state = map; + map = {...state!}; + map[requestId] = newRequestModel; + state = map; print(message); }, onError: (error) async{ + print(error.statusCode); }, onDone: () async{ @@ -622,6 +637,17 @@ class CollectionStateNotifier }, cancelOnError: false, ); + }else{ + map = {...state!}; + map[requestId] = requestModel.copyWith( + isWorking: false, + responseStatus: 1002, + message: result.$1, + sendingTime: result.$2, + ); + + state = map; + } } Future disconnect() async { final requestId = ref.read(selectedIdStateProvider); @@ -643,6 +669,7 @@ class CollectionStateNotifier var newRequestModel = requestModel.copyWith( isWorking: false, webSocketRequestModel: newWebSocketRequestModel, + ); 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 f73ccafec..fdde2924d 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 @@ -9,6 +9,505 @@ import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/consts.dart'; import 'package:apidash/screens/common_widgets/common_widgets.dart'; +// class EditRequestHeaders extends ConsumerStatefulWidget { +// const EditRequestHeaders({super.key}); + +// @override +// ConsumerState createState() => EditRequestHeadersState(); +// } + +// class EditRequestHeadersState extends ConsumerState { +// late int seed; +// final random = Random.secure(); +// late List headerRows; +// late List isRowEnabledList; +// bool isAddingRow = false; + +// @override +// void initState() { +// super.initState(); +// seed = random.nextInt(kRandMax); +// } + +// void _onFieldChange() { +// ref.read(collectionStateNotifierProvider.notifier).update( +// headers: headerRows.sublist(0, headerRows.length - 1), +// isHeaderEnabledList: +// isRowEnabledList.sublist(0, headerRows.length - 1), +// ); +// } + +// @override +// Widget build(BuildContext context) { +// dataTableShowLogs = false; +// final selectedId = ref.watch(selectedIdStateProvider); +// ref.watch(selectedRequestModelProvider +// .select((value) => value?.httpRequestModel?.headers?.length)); +// var apiType = ref.read(selectedRequestModelProvider)?.apiType; +// late List? rH; +// if(apiType == APIType.webSocket){ +// rH = ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.headers; +// }else{ +// rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; +// } +// bool isHeadersEmpty = rH == null || rH.isEmpty; +// headerRows = isHeadersEmpty +// ? [ +// kNameValueEmptyModel, +// ] +// : rH + [kNameValueEmptyModel]; + +// // if(apiType == APIType.webSocket){ +// // print("entered websocket"); +// // isRowEnabledList = [ +// // ...(ref +// // .read(selectedRequestModelProvider) +// // ?.webSocketRequestModel +// // ?.isHeaderEnabledList ?? +// // List.filled(rH?.length ?? 0, true, growable: true)) +// // ]; + +// // }else{ +// // isRowEnabledList = [ +// // ...(ref +// // .read(selectedRequestModelProvider) +// // ?.httpRequestModel +// // ?.isHeaderEnabledList ?? +// // List.filled(rH?.length ?? 0, true, growable: true)) + +// // ]; +// // } +// isRowEnabledList = [ +// ...(ref +// .read(selectedRequestModelProvider) +// ?.httpRequestModel +// ?.isHeaderEnabledList ?? +// List.filled(rH?.length ?? 0, true, growable: true)) + +// ]; +// isRowEnabledList.add(false); +// isAddingRow = false; + +// List columns = const [ +// DataColumn2( +// label: Text(kNameCheckbox), +// fixedWidth: 30, +// ), +// DataColumn2( +// label: Text(kNameHeader), +// ), +// DataColumn2( +// label: Text('='), +// fixedWidth: 30, +// ), +// DataColumn2( +// label: Text(kNameValue), +// ), +// DataColumn2( +// label: Text(''), +// fixedWidth: 32, +// ), +// ]; + +// List dataRows = List.generate( +// headerRows.length, +// (index) { +// bool isLast = index + 1 == headerRows.length; +// return DataRow( +// key: ValueKey("$selectedId-$index-headers-row-$seed"), +// cells: [ +// DataCell( +// ADCheckBox( +// keyId: "$selectedId-$index-headers-c-$seed", +// value: isRowEnabledList[index], +// onChanged: isLast +// ? null +// : (value) { +// setState(() { +// isRowEnabledList[index] = value!; +// }); +// _onFieldChange(); +// }, +// colorScheme: Theme.of(context).colorScheme, +// ), +// ), +// DataCell( +// HeaderField( +// keyId: "$selectedId-$index-headers-k-$seed", +// initialValue: headerRows[index].name, +// hintText: kHintAddName, +// onChanged: (value) { +// headerRows[index] = headerRows[index].copyWith(name: value); +// if (isLast && !isAddingRow) { +// isAddingRow = true; +// isRowEnabledList[index] = true; +// headerRows.add(kNameValueEmptyModel); +// isRowEnabledList.add(false); +// } +// _onFieldChange(); +// }, +// colorScheme: Theme.of(context).colorScheme, +// ), +// ), +// DataCell( +// Center( +// child: Text( +// "=", +// style: kCodeStyle, +// ), +// ), +// ), +// DataCell( +// EnvCellField( +// keyId: "$selectedId-$index-headers-v-$seed", +// initialValue: headerRows[index].value, +// hintText: kHintAddValue, +// onChanged: (value) { +// headerRows[index] = headerRows[index].copyWith(value: value); +// if (isLast && !isAddingRow) { +// isAddingRow = true; +// isRowEnabledList[index] = true; +// headerRows.add(kNameValueEmptyModel); +// isRowEnabledList.add(false); +// } +// _onFieldChange(); +// }, +// colorScheme: Theme.of(context).colorScheme, +// ), +// ), +// DataCell( +// InkWell( +// onTap: isLast +// ? null +// : () { + +// seed = random.nextInt(kRandMax); +// if (headerRows.length == 2) { +// setState(() { +// headerRows = [ +// kNameValueEmptyModel, +// ]; +// isRowEnabledList = [false]; +// }); +// } else { +// headerRows.removeAt(index); +// isRowEnabledList.removeAt(index); +// } +// _onFieldChange(); +// }, +// child: Theme.of(context).brightness == Brightness.dark +// ? kIconRemoveDark +// : kIconRemoveLight, +// ), +// ), +// ], +// ); +// }, +// ); + +// return Stack( +// children: [ +// Container( +// margin: kP10, +// child: Column( +// children: [ +// Expanded( +// child: Theme( +// data: Theme.of(context) +// .copyWith(scrollbarTheme: kDataTableScrollbarTheme), +// child: DataTable2( +// columnSpacing: 12, +// dividerThickness: 0, +// horizontalMargin: 0, +// headingRowHeight: 0, +// dataRowHeight: kDataTableRowHeight, +// bottomMargin: kDataTableBottomPadding, +// isVerticalScrollBarVisible: true, +// columns: columns, +// rows: dataRows, +// ), +// ), +// ), +// kVSpacer40, +// ], +// ), +// ), +// Align( +// alignment: Alignment.bottomCenter, +// child: Padding( +// padding: kPb15, +// child: ElevatedButton.icon( +// onPressed: () { +// print("added header"); //remove it +// headerRows.add(kNameValueEmptyModel); +// isRowEnabledList.add(false); +// _onFieldChange(); +// }, +// icon: const Icon(Icons.add), +// label: const Text( +// kLabelAddHeader, +// style: kTextStyleButton, +// ), +// ), +// ), +// ), +// ], +// ); +// } +// } + + +// class EditRequestHeaders extends ConsumerStatefulWidget { +// const EditRequestHeaders({super.key}); + +// @override +// ConsumerState createState() => EditRequestHeadersState(); +// } +// class EditRequestHeadersState extends ConsumerState { +// late int seed; +// final random = Random.secure(); +// late List headerRows; +// late List isRowEnabledList; +// bool isAddingRow = false; + +// @override +// void initState() { +// super.initState(); +// seed = random.nextInt(kRandMax); +// } + +// void _onFieldChange() { + +// // Update HTTP headers +// ref.read(collectionStateNotifierProvider.notifier).update( +// headers: headerRows.sublist(0, headerRows.length - 1), +// isHeaderEnabledList: +// isRowEnabledList.sublist(0, headerRows.length - 1), +// ); + +// } + +// @override +// Widget build(BuildContext context) { +// dataTableShowLogs = false; + +// final selectedId = ref.watch(selectedIdStateProvider); + +// // Watch header length to trigger rebuilds when headers change +// ref.watch(selectedRequestModelProvider +// .select((value) => value?.httpRequestModel?.headers?.length)); + +// final apiType = ref.read(selectedRequestModelProvider)?.apiType; + +// // Determine headers and `isHeaderEnabledList` based on `apiType` +// late List? rH; +// late List? rEnabledList; + +// if (apiType == APIType.webSocket) { +// rH = ref +// .read(selectedRequestModelProvider) +// ?.webSocketRequestModel +// ?.headers; +// rEnabledList = ref +// .read(selectedRequestModelProvider) +// ?.webSocketRequestModel +// ?.isHeaderEnabledList; +// } else { +// rH = ref +// .read(selectedRequestModelProvider) +// ?.httpRequestModel +// ?.headers; +// rEnabledList = ref +// .read(selectedRequestModelProvider) +// ?.httpRequestModel +// ?.isHeaderEnabledList; +// } + +// // Initialize `headerRows` +// final bool isHeadersEmpty = rH == null || rH.isEmpty; +// headerRows = isHeadersEmpty +// ? [kNameValueEmptyModel] +// : rH + [kNameValueEmptyModel]; + +// // Initialize `isRowEnabledList` +// isRowEnabledList = [ +// ...(rEnabledList ?? +// List.filled(rH?.length ?? 0, true, growable: true)), +// ]; +// isRowEnabledList.add(false); +// isAddingRow = false; + +// // Data table columns and rows +// List columns = const [ +// DataColumn2( +// label: Text(kNameCheckbox), +// fixedWidth: 30, +// ), +// DataColumn2( +// label: Text(kNameHeader), +// ), +// DataColumn2( +// label: Text('='), +// fixedWidth: 30, +// ), +// DataColumn2( +// label: Text(kNameValue), +// ), +// DataColumn2( +// label: Text(''), +// fixedWidth: 32, +// ), +// ]; + +// List dataRows = List.generate( +// headerRows.length, +// (index) { +// bool isLast = index + 1 == headerRows.length; +// return DataRow( +// key: ValueKey("$selectedId-$index-headers-row-$seed"), +// cells: [ +// DataCell( +// ADCheckBox( +// keyId: "$selectedId-$index-headers-c-$seed", +// value: isRowEnabledList[index], +// onChanged: isLast +// ? null +// : (value) { +// setState(() { +// isRowEnabledList[index] = value!; +// }); +// _onFieldChange(); +// }, +// colorScheme: Theme.of(context).colorScheme, +// ), +// ), +// DataCell( +// HeaderField( +// keyId: "$selectedId-$index-headers-k-$seed", +// initialValue: headerRows[index].name, +// hintText: kHintAddName, +// onChanged: (value) { +// headerRows[index] = headerRows[index].copyWith(name: value); +// if (isLast && !isAddingRow) { +// isAddingRow = true; +// isRowEnabledList[index] = true; +// headerRows.add(kNameValueEmptyModel); +// isRowEnabledList.add(false); +// } +// _onFieldChange(); +// }, +// colorScheme: Theme.of(context).colorScheme, +// ), +// ), +// DataCell( +// Center( +// child: Text( +// "=", +// style: kCodeStyle, +// ), +// ), +// ), +// DataCell( +// EnvCellField( +// keyId: "$selectedId-$index-headers-v-$seed", +// initialValue: headerRows[index].value, +// hintText: kHintAddValue, +// onChanged: (value) { +// headerRows[index] = +// headerRows[index].copyWith(value: value); +// if (isLast && !isAddingRow) { +// isAddingRow = true; +// isRowEnabledList[index] = true; +// headerRows.add(kNameValueEmptyModel); +// isRowEnabledList.add(false); +// } +// _onFieldChange(); +// }, +// colorScheme: Theme.of(context).colorScheme, +// ), +// ), +// DataCell( +// InkWell( +// onTap: isLast +// ? null +// : () { +// seed = random.nextInt(kRandMax); +// if (headerRows.length == 2) { +// setState(() { +// headerRows = [kNameValueEmptyModel]; +// isRowEnabledList = [false]; +// }); +// } else { +// headerRows.removeAt(index); +// isRowEnabledList.removeAt(index); +// } +// _onFieldChange(); +// }, +// child: Theme.of(context).brightness == Brightness.dark +// ? kIconRemoveDark +// : kIconRemoveLight, +// ), +// ), +// ], +// ); +// }, +// ); + +// return Stack( +// children: [ +// Container( +// margin: kP10, +// child: Column( +// children: [ +// Expanded( +// child: Theme( +// data: Theme.of(context) +// .copyWith(scrollbarTheme: kDataTableScrollbarTheme), +// child: DataTable2( +// columnSpacing: 12, +// dividerThickness: 0, +// horizontalMargin: 0, +// headingRowHeight: 0, +// dataRowHeight: kDataTableRowHeight, +// bottomMargin: kDataTableBottomPadding, +// isVerticalScrollBarVisible: true, +// columns: columns, +// rows: dataRows, +// ), +// ), +// ), +// kVSpacer40, +// ], +// ), +// ), +// Align( +// alignment: Alignment.bottomCenter, +// child: Padding( +// padding: kPb15, +// child: ElevatedButton.icon( +// onPressed: () { +// headerRows.add(kNameValueEmptyModel); +// isRowEnabledList.add(false); +// _onFieldChange(); +// }, +// icon: const Icon(Icons.add), +// label: const Text( +// kLabelAddHeader, +// style: kTextStyleButton, +// ), +// ), +// ), +// ), +// ], +// ); +// } +// } + + + +//DIRECT FROM GITHUB + + class EditRequestHeaders extends ConsumerStatefulWidget { const EditRequestHeaders({super.key}); @@ -43,40 +542,20 @@ class EditRequestHeadersState extends ConsumerState { final selectedId = ref.watch(selectedIdStateProvider); ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.headers?.length)); - var apiType = ref.read(selectedRequestModelProvider)?.apiType; - late List? rH; - if(apiType == APIType.webSocket){ - rH = ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.headers; - }else{ - rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; - } + var rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; bool isHeadersEmpty = rH == null || rH.isEmpty; headerRows = isHeadersEmpty ? [ kNameValueEmptyModel, ] : rH + [kNameValueEmptyModel]; - - if(apiType == APIType.webSocket){ - isRowEnabledList = [ - ...(ref - .read(selectedRequestModelProvider) - ?.webSocketRequestModel - ?.isHeaderEnabledList ?? - List.filled(rH?.length ?? 0, true, growable: true)) - ]; - - }else{ - isRowEnabledList = [ + isRowEnabledList = [ ...(ref .read(selectedRequestModelProvider) ?.httpRequestModel ?.isHeaderEnabledList ?? List.filled(rH?.length ?? 0, true, growable: true)) ]; - - } - isRowEnabledList.add(false); isAddingRow = false; @@ -244,4 +723,4 @@ class EditRequestHeadersState extends ConsumerState { ], ); } -} +} \ No newline at end of file diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart index ed097f2de..64066081c 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart @@ -5,6 +5,7 @@ import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import 'request_headers.dart'; import 'request_body.dart'; +import 'request_params.dart'; class EditWebSocketRequestPane extends ConsumerWidget { const EditWebSocketRequestPane({super.key}); @@ -16,14 +17,15 @@ class EditWebSocketRequestPane extends ConsumerWidget { selectedRequestModelProvider.select((value) => value?.requestTabIndex)); final codePaneVisible = ref.watch(codePaneVisibleStateProvider); final headerLength = ref.watch(selectedRequestModelProvider - .select((value) => value?.httpRequestModel?.headersMap.length)) ?? + .select((value) => value?.webSocketRequestModel?.headersMap.length)) ?? 0; + final paramLength = ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketRequestModel?.paramsMap.length)) ?? + 0; final hasQuery = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.hasQuery)) ?? false; - if (tabIndex >= 2) { - tabIndex = 0; - } + return RequestPane( selectedId: selectedId, codePaneVisible: codePaneVisible, @@ -38,15 +40,18 @@ class EditWebSocketRequestPane extends ConsumerWidget { .update(requestTabIndex: index); }, showIndicators: [ - headerLength > 0, + // paramLength > 0, + // headerLength > 0, hasQuery, ], tabLabels: const [ - kLabelHeaders, + // kLabelURLParams, + // kLabelHeaders, kLabelMessage, ], children: const [ - EditRequestHeaders(), + // EditRequestURLParams(), + // EditRequestHeaders(), EditRequestBody(), ], ); diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 1601bdc92..250dec28b 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -1,6 +1,4 @@ -import 'package:apidash/widgets/websocket_frame.dart'; import 'package:apidash_core/apidash_core.dart'; -import 'package:apidash_core/models/websocket_frame_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; diff --git a/lib/screens/settings_page.dart b/lib/screens/settings_page.dart index a8d9e2ad4..5e3d46ce1 100644 --- a/lib/screens/settings_page.dart +++ b/lib/screens/settings_page.dart @@ -249,7 +249,9 @@ class SettingsPage extends ConsumerWidget { trailing: SizedBox( width: 120, child: TextField( - controller: TextEditingController(text: settings.pingInterval.toString()), + decoration: InputDecoration( + hintText: settings.pingInterval.toString() + ), keyboardType: TextInputType.number, onChanged: (value) { ref diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index 59b61f54b..9c0c7e22a 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -60,3 +60,5 @@ export 'texts.dart'; export 'uint8_audio_player.dart'; export 'window_caption.dart'; export 'workspace_selector.dart'; +export 'button_connection.dart'; +export 'websocket_frame.dart'; \ No newline at end of file diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index 999d8d44d..d2c043aa6 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io'; +import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/foundation.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:web_socket_channel/status.dart' as status; @@ -22,6 +23,7 @@ class WebSocketClient { if(!kIsWeb){ final WebSocket ioWebSocket = await WebSocket.connect(url); _channel = IOWebSocketChannel(ioWebSocket); + ioWebSocket.pingInterval = pingInterval; }else{ @@ -29,7 +31,7 @@ class WebSocketClient { } await _channel.ready; print('Connected to WebSocket server: ${url}'); - return ("Connected",DateTime.now()); + return (kMsgConnected,DateTime.now()); } catch (e) { print('Failed to connect to WebSocket server: $e'); return (e.toString(),DateTime.now()); @@ -107,3 +109,4 @@ class WebSocketClient { log('Disconnected from WebSocket server'); } } + From f1521d674a6bd10b9b5d41ed4b6171d7ee7bef99 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Mon, 27 Jan 2025 22:09:43 +0530 Subject: [PATCH 12/30] working on HEADERS AND PARAMS --- .../request_pane/request_pane_graphql.dart | 7 +++++++ .../request_pane/request_pane_websocket.dart | 19 +++++++++---------- .../details_card/response_pane.dart | 2 +- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index beae2b6c5..2d3b0b3cf 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -5,6 +5,7 @@ import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import 'request_headers.dart'; import 'request_body.dart'; +import 'request_params.dart'; class EditGraphQLRequestPane extends ConsumerWidget { const EditGraphQLRequestPane({super.key}); @@ -18,6 +19,9 @@ class EditGraphQLRequestPane extends ConsumerWidget { final headerLength = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.headersMap.length)) ?? 0; + final paramLength = ref.watch(selectedRequestModelProvider + .select((value) => value?.httpRequestModel?.paramsMap.length)) ?? + 0; final hasQuery = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.hasQuery)) ?? false; @@ -39,14 +43,17 @@ class EditGraphQLRequestPane extends ConsumerWidget { }, showIndicators: [ headerLength > 0, + paramLength > 0, hasQuery, ], tabLabels: const [ kLabelHeaders, + kLabelURLParams, kLabelQuery, ], children: const [ EditRequestHeaders(), + EditRequestURLParams(), EditRequestBody(), ], ); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart index 64066081c..17302a13d 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart @@ -22,9 +22,8 @@ class EditWebSocketRequestPane extends ConsumerWidget { final paramLength = ref.watch(selectedRequestModelProvider .select((value) => value?.webSocketRequestModel?.paramsMap.length)) ?? 0; - final hasQuery = ref.watch(selectedRequestModelProvider - .select((value) => value?.httpRequestModel?.hasQuery)) ?? - false; + + return RequestPane( selectedId: selectedId, @@ -40,18 +39,18 @@ class EditWebSocketRequestPane extends ConsumerWidget { .update(requestTabIndex: index); }, showIndicators: [ - // paramLength > 0, - // headerLength > 0, - hasQuery, + paramLength > 0, + headerLength > 0, + true, ], tabLabels: const [ - // kLabelURLParams, - // kLabelHeaders, + kLabelURLParams, + kLabelHeaders, kLabelMessage, ], children: const [ - // EditRequestURLParams(), - // EditRequestHeaders(), + EditRequestURLParams(), + EditRequestHeaders(), EditRequestBody(), ], ); diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 250dec28b..7bc41120b 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -93,7 +93,7 @@ class ResponseTabs extends ConsumerWidget { return ResponseTabView( selectedId: selectedId, children: [ - if (apiType == APIType.rest) ...const [ + if (apiType == APIType.rest || apiType == APIType.webSocket) ...const [ ResponseBodyTab(), ResponseHeadersTab(), ] else if (apiType == APIType.webSocket) ...const [ From 2c926eec2050292efb0e24b26814cecbcc32895c Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Wed, 29 Jan 2025 00:59:56 +0530 Subject: [PATCH 13/30] fixed headers and params --- lib/providers/collection_providers.dart | 2 +- .../request_pane/request_headers.dart | 541 ++---------------- .../request_pane/request_pane_graphql.dart | 7 +- .../request_pane/request_pane_websocket.dart | 1 + .../request_pane/request_params.dart | 37 +- .../request_websocket_headers.dart | 227 ++++++++ lib/widgets/request_pane.dart | 3 + packages/apidash_core/lib/consts.dart | 2 +- .../lib/services/websocket_service.dart | 4 +- .../apidash_core/lib/utils/uri_utils.dart | 2 + 10 files changed, 306 insertions(+), 520 deletions(-) create mode 100644 lib/screens/home_page/editor_pane/details_card/request_pane/request_websocket_headers.dart diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index e36b40c89..5277a0798 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -246,7 +246,7 @@ class CollectionStateNotifier var currentModel = state![rId]!; var currentApiType = apiType ?? currentModel.apiType; var currentHttpRequestModel = currentModel.httpRequestModel; - final newHttpRequestModel = currentApiType == APIType.rest ? + final newHttpRequestModel = currentApiType == APIType.rest || currentApiType ==APIType.graphql ? currentHttpRequestModel?.copyWith( method: method ?? currentHttpRequestModel.method, url: url ?? currentHttpRequestModel.url, 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 fdde2924d..cdb145d33 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 @@ -9,505 +9,6 @@ import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/consts.dart'; import 'package:apidash/screens/common_widgets/common_widgets.dart'; -// class EditRequestHeaders extends ConsumerStatefulWidget { -// const EditRequestHeaders({super.key}); - -// @override -// ConsumerState createState() => EditRequestHeadersState(); -// } - -// class EditRequestHeadersState extends ConsumerState { -// late int seed; -// final random = Random.secure(); -// late List headerRows; -// late List isRowEnabledList; -// bool isAddingRow = false; - -// @override -// void initState() { -// super.initState(); -// seed = random.nextInt(kRandMax); -// } - -// void _onFieldChange() { -// ref.read(collectionStateNotifierProvider.notifier).update( -// headers: headerRows.sublist(0, headerRows.length - 1), -// isHeaderEnabledList: -// isRowEnabledList.sublist(0, headerRows.length - 1), -// ); -// } - -// @override -// Widget build(BuildContext context) { -// dataTableShowLogs = false; -// final selectedId = ref.watch(selectedIdStateProvider); -// ref.watch(selectedRequestModelProvider -// .select((value) => value?.httpRequestModel?.headers?.length)); -// var apiType = ref.read(selectedRequestModelProvider)?.apiType; -// late List? rH; -// if(apiType == APIType.webSocket){ -// rH = ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.headers; -// }else{ -// rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; -// } -// bool isHeadersEmpty = rH == null || rH.isEmpty; -// headerRows = isHeadersEmpty -// ? [ -// kNameValueEmptyModel, -// ] -// : rH + [kNameValueEmptyModel]; - -// // if(apiType == APIType.webSocket){ -// // print("entered websocket"); -// // isRowEnabledList = [ -// // ...(ref -// // .read(selectedRequestModelProvider) -// // ?.webSocketRequestModel -// // ?.isHeaderEnabledList ?? -// // List.filled(rH?.length ?? 0, true, growable: true)) -// // ]; - -// // }else{ -// // isRowEnabledList = [ -// // ...(ref -// // .read(selectedRequestModelProvider) -// // ?.httpRequestModel -// // ?.isHeaderEnabledList ?? -// // List.filled(rH?.length ?? 0, true, growable: true)) - -// // ]; -// // } -// isRowEnabledList = [ -// ...(ref -// .read(selectedRequestModelProvider) -// ?.httpRequestModel -// ?.isHeaderEnabledList ?? -// List.filled(rH?.length ?? 0, true, growable: true)) - -// ]; -// isRowEnabledList.add(false); -// isAddingRow = false; - -// List columns = const [ -// DataColumn2( -// label: Text(kNameCheckbox), -// fixedWidth: 30, -// ), -// DataColumn2( -// label: Text(kNameHeader), -// ), -// DataColumn2( -// label: Text('='), -// fixedWidth: 30, -// ), -// DataColumn2( -// label: Text(kNameValue), -// ), -// DataColumn2( -// label: Text(''), -// fixedWidth: 32, -// ), -// ]; - -// List dataRows = List.generate( -// headerRows.length, -// (index) { -// bool isLast = index + 1 == headerRows.length; -// return DataRow( -// key: ValueKey("$selectedId-$index-headers-row-$seed"), -// cells: [ -// DataCell( -// ADCheckBox( -// keyId: "$selectedId-$index-headers-c-$seed", -// value: isRowEnabledList[index], -// onChanged: isLast -// ? null -// : (value) { -// setState(() { -// isRowEnabledList[index] = value!; -// }); -// _onFieldChange(); -// }, -// colorScheme: Theme.of(context).colorScheme, -// ), -// ), -// DataCell( -// HeaderField( -// keyId: "$selectedId-$index-headers-k-$seed", -// initialValue: headerRows[index].name, -// hintText: kHintAddName, -// onChanged: (value) { -// headerRows[index] = headerRows[index].copyWith(name: value); -// if (isLast && !isAddingRow) { -// isAddingRow = true; -// isRowEnabledList[index] = true; -// headerRows.add(kNameValueEmptyModel); -// isRowEnabledList.add(false); -// } -// _onFieldChange(); -// }, -// colorScheme: Theme.of(context).colorScheme, -// ), -// ), -// DataCell( -// Center( -// child: Text( -// "=", -// style: kCodeStyle, -// ), -// ), -// ), -// DataCell( -// EnvCellField( -// keyId: "$selectedId-$index-headers-v-$seed", -// initialValue: headerRows[index].value, -// hintText: kHintAddValue, -// onChanged: (value) { -// headerRows[index] = headerRows[index].copyWith(value: value); -// if (isLast && !isAddingRow) { -// isAddingRow = true; -// isRowEnabledList[index] = true; -// headerRows.add(kNameValueEmptyModel); -// isRowEnabledList.add(false); -// } -// _onFieldChange(); -// }, -// colorScheme: Theme.of(context).colorScheme, -// ), -// ), -// DataCell( -// InkWell( -// onTap: isLast -// ? null -// : () { - -// seed = random.nextInt(kRandMax); -// if (headerRows.length == 2) { -// setState(() { -// headerRows = [ -// kNameValueEmptyModel, -// ]; -// isRowEnabledList = [false]; -// }); -// } else { -// headerRows.removeAt(index); -// isRowEnabledList.removeAt(index); -// } -// _onFieldChange(); -// }, -// child: Theme.of(context).brightness == Brightness.dark -// ? kIconRemoveDark -// : kIconRemoveLight, -// ), -// ), -// ], -// ); -// }, -// ); - -// return Stack( -// children: [ -// Container( -// margin: kP10, -// child: Column( -// children: [ -// Expanded( -// child: Theme( -// data: Theme.of(context) -// .copyWith(scrollbarTheme: kDataTableScrollbarTheme), -// child: DataTable2( -// columnSpacing: 12, -// dividerThickness: 0, -// horizontalMargin: 0, -// headingRowHeight: 0, -// dataRowHeight: kDataTableRowHeight, -// bottomMargin: kDataTableBottomPadding, -// isVerticalScrollBarVisible: true, -// columns: columns, -// rows: dataRows, -// ), -// ), -// ), -// kVSpacer40, -// ], -// ), -// ), -// Align( -// alignment: Alignment.bottomCenter, -// child: Padding( -// padding: kPb15, -// child: ElevatedButton.icon( -// onPressed: () { -// print("added header"); //remove it -// headerRows.add(kNameValueEmptyModel); -// isRowEnabledList.add(false); -// _onFieldChange(); -// }, -// icon: const Icon(Icons.add), -// label: const Text( -// kLabelAddHeader, -// style: kTextStyleButton, -// ), -// ), -// ), -// ), -// ], -// ); -// } -// } - - -// class EditRequestHeaders extends ConsumerStatefulWidget { -// const EditRequestHeaders({super.key}); - -// @override -// ConsumerState createState() => EditRequestHeadersState(); -// } -// class EditRequestHeadersState extends ConsumerState { -// late int seed; -// final random = Random.secure(); -// late List headerRows; -// late List isRowEnabledList; -// bool isAddingRow = false; - -// @override -// void initState() { -// super.initState(); -// seed = random.nextInt(kRandMax); -// } - -// void _onFieldChange() { - -// // Update HTTP headers -// ref.read(collectionStateNotifierProvider.notifier).update( -// headers: headerRows.sublist(0, headerRows.length - 1), -// isHeaderEnabledList: -// isRowEnabledList.sublist(0, headerRows.length - 1), -// ); - -// } - -// @override -// Widget build(BuildContext context) { -// dataTableShowLogs = false; - -// final selectedId = ref.watch(selectedIdStateProvider); - -// // Watch header length to trigger rebuilds when headers change -// ref.watch(selectedRequestModelProvider -// .select((value) => value?.httpRequestModel?.headers?.length)); - -// final apiType = ref.read(selectedRequestModelProvider)?.apiType; - -// // Determine headers and `isHeaderEnabledList` based on `apiType` -// late List? rH; -// late List? rEnabledList; - -// if (apiType == APIType.webSocket) { -// rH = ref -// .read(selectedRequestModelProvider) -// ?.webSocketRequestModel -// ?.headers; -// rEnabledList = ref -// .read(selectedRequestModelProvider) -// ?.webSocketRequestModel -// ?.isHeaderEnabledList; -// } else { -// rH = ref -// .read(selectedRequestModelProvider) -// ?.httpRequestModel -// ?.headers; -// rEnabledList = ref -// .read(selectedRequestModelProvider) -// ?.httpRequestModel -// ?.isHeaderEnabledList; -// } - -// // Initialize `headerRows` -// final bool isHeadersEmpty = rH == null || rH.isEmpty; -// headerRows = isHeadersEmpty -// ? [kNameValueEmptyModel] -// : rH + [kNameValueEmptyModel]; - -// // Initialize `isRowEnabledList` -// isRowEnabledList = [ -// ...(rEnabledList ?? -// List.filled(rH?.length ?? 0, true, growable: true)), -// ]; -// isRowEnabledList.add(false); -// isAddingRow = false; - -// // Data table columns and rows -// List columns = const [ -// DataColumn2( -// label: Text(kNameCheckbox), -// fixedWidth: 30, -// ), -// DataColumn2( -// label: Text(kNameHeader), -// ), -// DataColumn2( -// label: Text('='), -// fixedWidth: 30, -// ), -// DataColumn2( -// label: Text(kNameValue), -// ), -// DataColumn2( -// label: Text(''), -// fixedWidth: 32, -// ), -// ]; - -// List dataRows = List.generate( -// headerRows.length, -// (index) { -// bool isLast = index + 1 == headerRows.length; -// return DataRow( -// key: ValueKey("$selectedId-$index-headers-row-$seed"), -// cells: [ -// DataCell( -// ADCheckBox( -// keyId: "$selectedId-$index-headers-c-$seed", -// value: isRowEnabledList[index], -// onChanged: isLast -// ? null -// : (value) { -// setState(() { -// isRowEnabledList[index] = value!; -// }); -// _onFieldChange(); -// }, -// colorScheme: Theme.of(context).colorScheme, -// ), -// ), -// DataCell( -// HeaderField( -// keyId: "$selectedId-$index-headers-k-$seed", -// initialValue: headerRows[index].name, -// hintText: kHintAddName, -// onChanged: (value) { -// headerRows[index] = headerRows[index].copyWith(name: value); -// if (isLast && !isAddingRow) { -// isAddingRow = true; -// isRowEnabledList[index] = true; -// headerRows.add(kNameValueEmptyModel); -// isRowEnabledList.add(false); -// } -// _onFieldChange(); -// }, -// colorScheme: Theme.of(context).colorScheme, -// ), -// ), -// DataCell( -// Center( -// child: Text( -// "=", -// style: kCodeStyle, -// ), -// ), -// ), -// DataCell( -// EnvCellField( -// keyId: "$selectedId-$index-headers-v-$seed", -// initialValue: headerRows[index].value, -// hintText: kHintAddValue, -// onChanged: (value) { -// headerRows[index] = -// headerRows[index].copyWith(value: value); -// if (isLast && !isAddingRow) { -// isAddingRow = true; -// isRowEnabledList[index] = true; -// headerRows.add(kNameValueEmptyModel); -// isRowEnabledList.add(false); -// } -// _onFieldChange(); -// }, -// colorScheme: Theme.of(context).colorScheme, -// ), -// ), -// DataCell( -// InkWell( -// onTap: isLast -// ? null -// : () { -// seed = random.nextInt(kRandMax); -// if (headerRows.length == 2) { -// setState(() { -// headerRows = [kNameValueEmptyModel]; -// isRowEnabledList = [false]; -// }); -// } else { -// headerRows.removeAt(index); -// isRowEnabledList.removeAt(index); -// } -// _onFieldChange(); -// }, -// child: Theme.of(context).brightness == Brightness.dark -// ? kIconRemoveDark -// : kIconRemoveLight, -// ), -// ), -// ], -// ); -// }, -// ); - -// return Stack( -// children: [ -// Container( -// margin: kP10, -// child: Column( -// children: [ -// Expanded( -// child: Theme( -// data: Theme.of(context) -// .copyWith(scrollbarTheme: kDataTableScrollbarTheme), -// child: DataTable2( -// columnSpacing: 12, -// dividerThickness: 0, -// horizontalMargin: 0, -// headingRowHeight: 0, -// dataRowHeight: kDataTableRowHeight, -// bottomMargin: kDataTableBottomPadding, -// isVerticalScrollBarVisible: true, -// columns: columns, -// rows: dataRows, -// ), -// ), -// ), -// kVSpacer40, -// ], -// ), -// ), -// Align( -// alignment: Alignment.bottomCenter, -// child: Padding( -// padding: kPb15, -// child: ElevatedButton.icon( -// onPressed: () { -// headerRows.add(kNameValueEmptyModel); -// isRowEnabledList.add(false); -// _onFieldChange(); -// }, -// icon: const Icon(Icons.add), -// label: const Text( -// kLabelAddHeader, -// style: kTextStyleButton, -// ), -// ), -// ), -// ), -// ], -// ); -// } -// } - - - -//DIRECT FROM GITHUB - - class EditRequestHeaders extends ConsumerStatefulWidget { const EditRequestHeaders({super.key}); @@ -529,6 +30,9 @@ class EditRequestHeadersState extends ConsumerState { } void _onFieldChange() { + print(headerRows.toList()); + print(isRowEnabledList.toList()); + print("entered field change"); ref.read(collectionStateNotifierProvider.notifier).update( headers: headerRows.sublist(0, headerRows.length - 1), isHeaderEnabledList: @@ -542,13 +46,39 @@ class EditRequestHeadersState extends ConsumerState { final selectedId = ref.watch(selectedIdStateProvider); ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.headers?.length)); - var rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; - bool isHeadersEmpty = rH == null || rH.isEmpty; + ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketRequestModel?.headers?.length)); + var apiType = ref.watch(selectedRequestModelProvider + .select((value) => value?.apiType)); + late List? rH; + late bool isHeadersEmpty; + if (apiType == APIType.webSocket) { + rH = ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.headers; + isHeadersEmpty = rH == null || rH.isEmpty; + isRowEnabledList = [ + ...(ref + .read(selectedRequestModelProvider) + ?.webSocketRequestModel + ?.isHeaderEnabledList ?? + List.filled(rH?.length ?? 0, true, growable: true)) + ]; + }else{ + rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; + isHeadersEmpty = rH == null || rH.isEmpty; + isRowEnabledList = [ + ...(ref + .read(selectedRequestModelProvider) + ?.httpRequestModel + ?.isHeaderEnabledList ?? + List.filled(rH?.length ?? 0, true, growable: true)) + ]; + + } headerRows = isHeadersEmpty ? [ kNameValueEmptyModel, ] - : rH + [kNameValueEmptyModel]; + : rH! + [kNameValueEmptyModel]; isRowEnabledList = [ ...(ref .read(selectedRequestModelProvider) @@ -583,7 +113,9 @@ class EditRequestHeadersState extends ConsumerState { List dataRows = List.generate( headerRows.length, (index) { + bool isLast = index + 1 == headerRows.length; + print(isLast); return DataRow( key: ValueKey("$selectedId-$index-headers-row-$seed"), cells: [ @@ -594,6 +126,7 @@ class EditRequestHeadersState extends ConsumerState { onChanged: isLast ? null : (value) { + print("entered isLast false"); setState(() { isRowEnabledList[index] = value!; }); @@ -708,9 +241,11 @@ class EditRequestHeadersState extends ConsumerState { padding: kPb15, child: ElevatedButton.icon( onPressed: () { + print("pressed header"); headerRows.add(kNameValueEmptyModel); isRowEnabledList.add(false); _onFieldChange(); + print("pressed header"); }, icon: const Icon(Icons.add), label: const Text( @@ -723,4 +258,4 @@ class EditRequestHeadersState extends ConsumerState { ], ); } -} \ No newline at end of file +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index 2d3b0b3cf..bc8b42845 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -6,6 +6,7 @@ import 'package:apidash/widgets/widgets.dart'; import 'request_headers.dart'; import 'request_body.dart'; import 'request_params.dart'; +import 'request_websocket_headers.dart'; class EditGraphQLRequestPane extends ConsumerWidget { const EditGraphQLRequestPane({super.key}); @@ -19,9 +20,6 @@ class EditGraphQLRequestPane extends ConsumerWidget { final headerLength = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.headersMap.length)) ?? 0; - final paramLength = ref.watch(selectedRequestModelProvider - .select((value) => value?.httpRequestModel?.paramsMap.length)) ?? - 0; final hasQuery = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.hasQuery)) ?? false; @@ -43,17 +41,14 @@ class EditGraphQLRequestPane extends ConsumerWidget { }, showIndicators: [ headerLength > 0, - paramLength > 0, hasQuery, ], tabLabels: const [ kLabelHeaders, - kLabelURLParams, kLabelQuery, ], children: const [ EditRequestHeaders(), - EditRequestURLParams(), EditRequestBody(), ], ); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart index 17302a13d..b730c5327 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart @@ -6,6 +6,7 @@ import 'package:apidash/widgets/widgets.dart'; import 'request_headers.dart'; import 'request_body.dart'; import 'request_params.dart'; +import 'request_websocket_headers.dart'; class EditWebSocketRequestPane extends ConsumerWidget { const EditWebSocketRequestPane({super.key}); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart index a583b1839..63c0b4a86 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart @@ -42,20 +42,41 @@ class EditRequestURLParamsState extends ConsumerState { final selectedId = ref.watch(selectedIdStateProvider); ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.params?.length)); - var rP = ref.read(selectedRequestModelProvider)?.httpRequestModel?.params; - bool isParamsEmpty = rP == null || rP.isEmpty; - paramRows = isParamsEmpty - ? [ - kNameValueEmptyModel, - ] - : rP + [kNameValueEmptyModel]; - isRowEnabledList = [ + ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketRequestModel?.params?.length)); + var apiType = ref.watch(selectedRequestModelProvider + .select((value) => value?.apiType)); + late List? rP; + + + if(apiType == APIType.webSocket){ + rP= ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.params; + isRowEnabledList = [ + ...(ref + .read(selectedRequestModelProvider) + ?.webSocketRequestModel + ?.isParamEnabledList ?? + List.filled(rP?.length ?? 0, true, growable: true)) + ]; + + }else{ + rP= ref.read(selectedRequestModelProvider)?.httpRequestModel?.params; + isRowEnabledList = [ ...(ref .read(selectedRequestModelProvider) ?.httpRequestModel ?.isParamEnabledList ?? List.filled(rP?.length ?? 0, true, growable: true)) ]; + } + bool isParamsEmpty = rP == null || rP.isEmpty; + paramRows = isParamsEmpty + ? [ + kNameValueEmptyModel, + ] + : rP + [kNameValueEmptyModel]; + + isRowEnabledList.add(false); isAddingRow = false; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_websocket_headers.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_websocket_headers.dart new file mode 100644 index 000000000..57f3c36be --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_websocket_headers.dart @@ -0,0 +1,227 @@ +import 'dart:math'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:data_table_2/data_table_2.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/widgets/widgets.dart'; +import 'package:apidash/consts.dart'; +import 'package:apidash/screens/common_widgets/common_widgets.dart'; + +class EditWebSocketRequestHeaders extends ConsumerStatefulWidget { + const EditWebSocketRequestHeaders({super.key}); + + @override + ConsumerState createState() => EditWebSocketRequestHeadersState(); +} + +class EditWebSocketRequestHeadersState extends ConsumerState { + late int seed; + final random = Random.secure(); + late List headerRows; + late List isRowEnabledList; + bool isAddingRow = false; + + @override + void initState() { + super.initState(); + seed = random.nextInt(kRandMax); + } + + void _onFieldChange() { + ref.read(collectionStateNotifierProvider.notifier).update( + headers: headerRows.sublist(0, headerRows.length - 1), + isHeaderEnabledList: + isRowEnabledList.sublist(0, headerRows.length - 1), + ); + } + + @override + Widget build(BuildContext context) { + dataTableShowLogs = false; + final selectedId = ref.watch(selectedIdStateProvider); + ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketRequestModel?.headers?.length)); + var rH = ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.headers; + bool isHeadersEmpty = rH == null || rH.isEmpty; + headerRows = isHeadersEmpty + ? [ + kNameValueEmptyModel, + ] + : rH + [kNameValueEmptyModel]; + isRowEnabledList = [ + ...(ref + .read(selectedRequestModelProvider) + ?.webSocketRequestModel + ?.isHeaderEnabledList ?? + List.filled(rH?.length ?? 0, true, growable: true)) + ]; + isRowEnabledList.add(false); + isAddingRow = false; + + List columns = const [ + DataColumn2( + label: Text(kNameCheckbox), + fixedWidth: 30, + ), + DataColumn2( + label: Text(kNameHeader), + ), + DataColumn2( + label: Text('='), + fixedWidth: 30, + ), + DataColumn2( + label: Text(kNameValue), + ), + DataColumn2( + label: Text(''), + fixedWidth: 32, + ), + ]; + + List dataRows = List.generate( + headerRows.length, + (index) { + bool isLast = index + 1 == headerRows.length; + return DataRow( + key: ValueKey("$selectedId-$index-headers-row-$seed"), + cells: [ + DataCell( + ADCheckBox( + keyId: "$selectedId-$index-headers-c-$seed", + value: isRowEnabledList[index], + onChanged: isLast + ? null + : (value) { + setState(() { + isRowEnabledList[index] = value!; + }); + _onFieldChange(); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + HeaderField( + keyId: "$selectedId-$index-headers-k-$seed", + initialValue: headerRows[index].name, + hintText: kHintAddName, + onChanged: (value) { + headerRows[index] = headerRows[index].copyWith(name: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + isRowEnabledList[index] = true; + headerRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + } + _onFieldChange(); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + Center( + child: Text( + "=", + style: kCodeStyle, + ), + ), + ), + DataCell( + EnvCellField( + keyId: "$selectedId-$index-headers-v-$seed", + initialValue: headerRows[index].value, + hintText: kHintAddValue, + onChanged: (value) { + headerRows[index] = headerRows[index].copyWith(value: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + isRowEnabledList[index] = true; + headerRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + } + _onFieldChange(); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + InkWell( + onTap: isLast + ? null + : () { + seed = random.nextInt(kRandMax); + if (headerRows.length == 2) { + setState(() { + headerRows = [ + kNameValueEmptyModel, + ]; + isRowEnabledList = [false]; + }); + } else { + headerRows.removeAt(index); + isRowEnabledList.removeAt(index); + } + _onFieldChange(); + }, + child: Theme.of(context).brightness == Brightness.dark + ? kIconRemoveDark + : kIconRemoveLight, + ), + ), + ], + ); + }, + ); + + return Stack( + children: [ + Container( + margin: kP10, + child: Column( + children: [ + Expanded( + child: Theme( + data: Theme.of(context) + .copyWith(scrollbarTheme: kDataTableScrollbarTheme), + child: DataTable2( + columnSpacing: 12, + dividerThickness: 0, + horizontalMargin: 0, + headingRowHeight: 0, + dataRowHeight: kDataTableRowHeight, + bottomMargin: kDataTableBottomPadding, + isVerticalScrollBarVisible: true, + columns: columns, + rows: dataRows, + ), + ), + ), + kVSpacer40, + ], + ), + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: kPb15, + child: ElevatedButton.icon( + onPressed: () { + headerRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + _onFieldChange(); + }, + icon: const Icon(Icons.add), + label: const Text( + kLabelAddHeader, + style: kTextStyleButton, + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/widgets/request_pane.dart b/lib/widgets/request_pane.dart index 95871d532..55684b039 100644 --- a/lib/widgets/request_pane.dart +++ b/lib/widgets/request_pane.dart @@ -34,8 +34,11 @@ class RequestPane extends StatefulHookWidget { class _RequestPaneState extends State with TickerProviderStateMixin { + @override Widget build(BuildContext context) { + print("Number of tabs (tabLabels): ${widget.tabLabels.length}"); + print("Number of children (TabBarView): ${widget.children.length}"); final TabController controller = useTabController( initialLength: widget.children.length, vsync: this, diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index cd62fbe78..e60df44dc 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -22,7 +22,7 @@ enum HTTPVerb { final String abbr; } -enum SupportedUriSchemes { https, http } +enum SupportedUriSchemes { https, http , ws, wss} final kSupportedUriSchemes = SupportedUriSchemes.values.map((i) => i.name).toList(); diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index d2c043aa6..ed17d0349 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -17,9 +17,11 @@ class WebSocketClient { WebSocketClient(); - Future<(String?,DateTime?)> connect(String url) async { + Future<(String?,DateTime?)> connect(Uri uri,List? headers,List? params) async { print("inside client connect"); try { + + String urlWithParams = getValidRequestUri(uri.urlWithParams, requestParams); if(!kIsWeb){ final WebSocket ioWebSocket = await WebSocket.connect(url); _channel = IOWebSocketChannel(ioWebSocket); diff --git a/packages/apidash_core/lib/utils/uri_utils.dart b/packages/apidash_core/lib/utils/uri_utils.dart index b111a2e08..2954a6796 100644 --- a/packages/apidash_core/lib/utils/uri_utils.dart +++ b/packages/apidash_core/lib/utils/uri_utils.dart @@ -62,3 +62,5 @@ String stripUrlParams(String url) { } return (uri, null); } + + From 2850897c0008bf2552ab1a8aca0e33ab032900f8 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Thu, 30 Jan 2025 21:34:42 +0530 Subject: [PATCH 14/30] added isConnect --- lib/consts.dart | 8 + lib/providers/collection_providers.dart | 90 ++++--- .../request_pane/request_body.dart | 38 +-- .../request_pane/request_headers.dart | 6 - .../request_pane/request_pane_graphql.dart | 3 +- .../request_pane/request_pane_websocket.dart | 2 +- .../request_websocket_headers.dart | 227 ------------------ .../details_card/response_pane.dart | 82 +++++-- .../home_page/editor_pane/url_card.dart | 5 +- lib/widgets/button_connection.dart | 10 +- .../lib/services/http_service.dart | 1 + .../lib/services/web_socket_manager.dart | 6 +- .../lib/services/websocket_service.dart | 10 +- .../apidash_core/lib/utils/uri_utils.dart | 8 +- 14 files changed, 171 insertions(+), 325 deletions(-) delete mode 100644 lib/screens/home_page/editor_pane/details_card/request_pane/request_websocket_headers.dart diff --git a/lib/consts.dart b/lib/consts.dart index b029ad0ec..9586a10c6 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -299,6 +299,14 @@ const kResponseCodeReasons = { 1001: 'Going Away', 1002: 'Protocol Error', 1003: 'Unsupported Data', + 1005: 'No Status Received', + 1006: 'Abnormal Closure', + 1007: 'Invalid Frame Payload Data', + 1008: 'Policy Violation', + 1009: 'Message Too Big', + 1010: 'Missing Mandatory Extension', + 1011: 'Internal Server Error (WebSocket)', + 1015: 'TLS Handshake Failed', }; Map kHttpHeadersMap = { diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 5277a0798..346cca0e6 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -486,11 +486,7 @@ class CollectionStateNotifier - var map = {...state!}; - map[requestId] = requestModel.copyWith( - isWorking: true, - ); - state = map; + @@ -539,7 +535,7 @@ class CollectionStateNotifier webSocketResponseModel: newWebSocketResponseModel, ); // update state with response data - map = {...state!}; + var map = {...state!}; map[requestId] = newRequestModel; state = map; @@ -578,55 +574,79 @@ class CollectionStateNotifier webSocketManager.setPingInterval(requestId,null); } - final url = requestModel!.webSocketRequestModel!.url; + + + final webSocketRequestModel = requestModel!.webSocketRequestModel!; + final url = webSocketRequestModel.url; + final headers = webSocketRequestModel.headers; + final params = webSocketRequestModel.params; var map = {...state!}; map[requestId] = requestModel.copyWith( - isWorking: true, - + isWorking: true, + sendingTime: DateTime.now(), webSocketResponseModel: const WebSocketResponseModel(), ); + + requestModel = map[requestId]; state = map; - (String?,DateTime?) result = await webSocketManager.connect(requestId,url); + (String?,DateTime?) result = await webSocketManager.connect(requestId,url,headers,params); - map = {...state!}; + + + if(result.$1 == kMsgConnected){ + map = {...state!}; - map[requestId] = requestModel.copyWith( - isWorking: true, + map[requestId] = requestModel!.copyWith( + isWorking: false, responseStatus: 101, message: kResponseCodeReasons[101], - sendingTime: result.$2, - webSocketResponseModel: const WebSocketResponseModel(), + webSocketRequestModel: webSocketRequestModel.copyWith( + isConnected:true + ), + ); + + requestModel = map[requestId]; state = map; - if(result.$1 == kMsgConnected){ - map = {...state!}; webSocketManager.listen( requestId, (message) async{ - var map = {...state!}; - RequestModel? requestModel = state![requestId]; + map = {...state!}; + requestModel = map[requestId]; + + if(requestModel == null){ + print("webSocketResponseModel is null"); + } + WebSocketResponseModel webSocketResponseModel = requestModel!.webSocketResponseModel!; + + if(webSocketResponseModel == null){ + print("webSocketResponseModel is null"); + } WebSocketResponseModel newWebSocketResponseModel = webSocketResponseModel.copyWith( frames: [...webSocketResponseModel.frames, WebSocketFrameModel( id: getNewUuid(), message: message, - timeStamp: DateTime.now(), + timeStamp:DateTime.now(), isSend: false )] ); - var newRequestModel = requestModel.copyWith( + var newRequestModel = requestModel!.copyWith( + isWorking: false, + responseStatus: 101, webSocketResponseModel: newWebSocketResponseModel, ); - map = {...state!}; + map[requestId] = newRequestModel; + state = map; - print(message); + }, onError: (error) async{ print(error.statusCode); @@ -639,11 +659,19 @@ class CollectionStateNotifier ); }else{ map = {...state!}; - map[requestId] = requestModel.copyWith( + WebSocketResponseModel newWebSocketResponseModel = requestModel!.webSocketResponseModel!.copyWith( + frames: [...requestModel.webSocketResponseModel!.frames, WebSocketFrameModel( + id: getNewUuid(), + message: result.$1!, + timeStamp:DateTime.now(), + isSend: false + )]); + map[requestId] = requestModel!.copyWith( isWorking: false, responseStatus: 1002, - message: result.$1, + message: kResponseCodeReasons[1002], sendingTime: result.$2, + webSocketResponseModel: newWebSocketResponseModel, ); state = map; @@ -667,24 +695,20 @@ class CollectionStateNotifier ); var newRequestModel = requestModel.copyWith( - isWorking: false, - webSocketRequestModel: newWebSocketRequestModel, - - - ); + webSocketRequestModel: newWebSocketRequestModel, + ); - var map = {...state!}; + var map = {...state!}; map[requestId] = newRequestModel; state = map; } - void deleteAllFrames(){ + void deleteAllFrames(){ final requestId = ref.read(selectedIdStateProvider); if (requestId == null || state == null) { - print(requestId); return; } RequestModel? requestModel = state![requestId]; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 0fd871611..3aae1d676 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -45,22 +45,28 @@ class EditRequestBody extends ConsumerWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const SizedBox( - height: kHeaderHeight, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Select Content Type:", - ), + const Padding( + padding:EdgeInsets.only(left:10), + child: const SizedBox( + height: kHeaderHeight, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Select Content Type:", + ), + DropdownButtonBodyContentWebSocketType(), + ]),), + ), - DropdownButtonBodyContentWebSocketType(), - ]),), - - SendButton(isWorking: false, onTap: (){ - ref.read(collectionStateNotifierProvider.notifier).sendFrames(); - }), + Padding( + padding:const EdgeInsets.only(right:10), + child: SendButton(isWorking: false, onTap: (){ + ref.read(collectionStateNotifierProvider.notifier).sendFrames(); + }), + + ), ], ), ) @@ -132,11 +138,11 @@ class EditRequestBody extends ConsumerWidget { TextFieldEditor( key: Key("$selectedId-websocket-body"), fieldKey: "$selectedId-websocket-body-editor", - // initialValue: requestModel?.websRequestModel?.body, + initialValue: requestModel?.webSocketRequestModel?.message, onChanged: (String value) { ref .read(collectionStateNotifierProvider.notifier) - .update(message: value); + .update(webSocketMessage: value); }, hintText: kHintMessage, ), 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 cdb145d33..e557f574d 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 @@ -30,9 +30,6 @@ class EditRequestHeadersState extends ConsumerState { } void _onFieldChange() { - print(headerRows.toList()); - print(isRowEnabledList.toList()); - print("entered field change"); ref.read(collectionStateNotifierProvider.notifier).update( headers: headerRows.sublist(0, headerRows.length - 1), isHeaderEnabledList: @@ -126,7 +123,6 @@ class EditRequestHeadersState extends ConsumerState { onChanged: isLast ? null : (value) { - print("entered isLast false"); setState(() { isRowEnabledList[index] = value!; }); @@ -241,11 +237,9 @@ class EditRequestHeadersState extends ConsumerState { padding: kPb15, child: ElevatedButton.icon( onPressed: () { - print("pressed header"); headerRows.add(kNameValueEmptyModel); isRowEnabledList.add(false); _onFieldChange(); - print("pressed header"); }, icon: const Icon(Icons.add), label: const Text( diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index bc8b42845..185f8885c 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -5,8 +5,7 @@ import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import 'request_headers.dart'; import 'request_body.dart'; -import 'request_params.dart'; -import 'request_websocket_headers.dart'; + class EditGraphQLRequestPane extends ConsumerWidget { const EditGraphQLRequestPane({super.key}); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart index b730c5327..ccc97cc31 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart @@ -6,7 +6,7 @@ import 'package:apidash/widgets/widgets.dart'; import 'request_headers.dart'; import 'request_body.dart'; import 'request_params.dart'; -import 'request_websocket_headers.dart'; + class EditWebSocketRequestPane extends ConsumerWidget { const EditWebSocketRequestPane({super.key}); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_websocket_headers.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_websocket_headers.dart deleted file mode 100644 index 57f3c36be..000000000 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_websocket_headers.dart +++ /dev/null @@ -1,227 +0,0 @@ -import 'dart:math'; -import 'package:apidash_core/apidash_core.dart'; -import 'package:apidash_design_system/apidash_design_system.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:data_table_2/data_table_2.dart'; -import 'package:apidash/providers/providers.dart'; -import 'package:apidash/widgets/widgets.dart'; -import 'package:apidash/consts.dart'; -import 'package:apidash/screens/common_widgets/common_widgets.dart'; - -class EditWebSocketRequestHeaders extends ConsumerStatefulWidget { - const EditWebSocketRequestHeaders({super.key}); - - @override - ConsumerState createState() => EditWebSocketRequestHeadersState(); -} - -class EditWebSocketRequestHeadersState extends ConsumerState { - late int seed; - final random = Random.secure(); - late List headerRows; - late List isRowEnabledList; - bool isAddingRow = false; - - @override - void initState() { - super.initState(); - seed = random.nextInt(kRandMax); - } - - void _onFieldChange() { - ref.read(collectionStateNotifierProvider.notifier).update( - headers: headerRows.sublist(0, headerRows.length - 1), - isHeaderEnabledList: - isRowEnabledList.sublist(0, headerRows.length - 1), - ); - } - - @override - Widget build(BuildContext context) { - dataTableShowLogs = false; - final selectedId = ref.watch(selectedIdStateProvider); - ref.watch(selectedRequestModelProvider - .select((value) => value?.webSocketRequestModel?.headers?.length)); - var rH = ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.headers; - bool isHeadersEmpty = rH == null || rH.isEmpty; - headerRows = isHeadersEmpty - ? [ - kNameValueEmptyModel, - ] - : rH + [kNameValueEmptyModel]; - isRowEnabledList = [ - ...(ref - .read(selectedRequestModelProvider) - ?.webSocketRequestModel - ?.isHeaderEnabledList ?? - List.filled(rH?.length ?? 0, true, growable: true)) - ]; - isRowEnabledList.add(false); - isAddingRow = false; - - List columns = const [ - DataColumn2( - label: Text(kNameCheckbox), - fixedWidth: 30, - ), - DataColumn2( - label: Text(kNameHeader), - ), - DataColumn2( - label: Text('='), - fixedWidth: 30, - ), - DataColumn2( - label: Text(kNameValue), - ), - DataColumn2( - label: Text(''), - fixedWidth: 32, - ), - ]; - - List dataRows = List.generate( - headerRows.length, - (index) { - bool isLast = index + 1 == headerRows.length; - return DataRow( - key: ValueKey("$selectedId-$index-headers-row-$seed"), - cells: [ - DataCell( - ADCheckBox( - keyId: "$selectedId-$index-headers-c-$seed", - value: isRowEnabledList[index], - onChanged: isLast - ? null - : (value) { - setState(() { - isRowEnabledList[index] = value!; - }); - _onFieldChange(); - }, - colorScheme: Theme.of(context).colorScheme, - ), - ), - DataCell( - HeaderField( - keyId: "$selectedId-$index-headers-k-$seed", - initialValue: headerRows[index].name, - hintText: kHintAddName, - onChanged: (value) { - headerRows[index] = headerRows[index].copyWith(name: value); - if (isLast && !isAddingRow) { - isAddingRow = true; - isRowEnabledList[index] = true; - headerRows.add(kNameValueEmptyModel); - isRowEnabledList.add(false); - } - _onFieldChange(); - }, - colorScheme: Theme.of(context).colorScheme, - ), - ), - DataCell( - Center( - child: Text( - "=", - style: kCodeStyle, - ), - ), - ), - DataCell( - EnvCellField( - keyId: "$selectedId-$index-headers-v-$seed", - initialValue: headerRows[index].value, - hintText: kHintAddValue, - onChanged: (value) { - headerRows[index] = headerRows[index].copyWith(value: value); - if (isLast && !isAddingRow) { - isAddingRow = true; - isRowEnabledList[index] = true; - headerRows.add(kNameValueEmptyModel); - isRowEnabledList.add(false); - } - _onFieldChange(); - }, - colorScheme: Theme.of(context).colorScheme, - ), - ), - DataCell( - InkWell( - onTap: isLast - ? null - : () { - seed = random.nextInt(kRandMax); - if (headerRows.length == 2) { - setState(() { - headerRows = [ - kNameValueEmptyModel, - ]; - isRowEnabledList = [false]; - }); - } else { - headerRows.removeAt(index); - isRowEnabledList.removeAt(index); - } - _onFieldChange(); - }, - child: Theme.of(context).brightness == Brightness.dark - ? kIconRemoveDark - : kIconRemoveLight, - ), - ), - ], - ); - }, - ); - - return Stack( - children: [ - Container( - margin: kP10, - child: Column( - children: [ - Expanded( - child: Theme( - data: Theme.of(context) - .copyWith(scrollbarTheme: kDataTableScrollbarTheme), - child: DataTable2( - columnSpacing: 12, - dividerThickness: 0, - horizontalMargin: 0, - headingRowHeight: 0, - dataRowHeight: kDataTableRowHeight, - bottomMargin: kDataTableBottomPadding, - isVerticalScrollBarVisible: true, - columns: columns, - rows: dataRows, - ), - ), - ), - kVSpacer40, - ], - ), - ), - Align( - alignment: Alignment.bottomCenter, - child: Padding( - padding: kPb15, - child: ElevatedButton.icon( - onPressed: () { - headerRows.add(kNameValueEmptyModel); - isRowEnabledList.add(false); - _onFieldChange(); - }, - icon: const Icon(Icons.add), - label: const Text( - kLabelAddHeader, - style: kTextStyleButton, - ), - ), - ), - ), - ], - ); - } -} diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 7bc41120b..1b65cba4f 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -23,18 +23,22 @@ class ResponsePane extends ConsumerWidget{ .watch(selectedRequestModelProvider.select((value) => value?.apiType)); if (isWorking) { - // if(apiType == APIType.webSocket ){ - // return const SendingWidget( - // startSendingTime: null, - // ); + // if(apiType == APIType.rest || apiType == APIType.graphql){ + // return SendingWidget( + // startSendingTime: startSendingTime, + // ); // }else{ + // return const ResponseDetails(); // } - return const ResponseDetails(); - // return SendingWidget( - // startSendingTime: startSendingTime, - // ); + return SendingWidget( + startSendingTime: startSendingTime, + ); + + + } + if (responseStatus == null) { return const NotSentWidget(); } @@ -90,10 +94,11 @@ class ResponseTabs extends ConsumerWidget { final selectedId = ref.watch(selectedIdStateProvider); final apiType = ref .watch(selectedRequestModelProvider.select((value) => value?.apiType)); + return ResponseTabView( selectedId: selectedId, children: [ - if (apiType == APIType.rest || apiType == APIType.webSocket) ...const [ + if (apiType == APIType.rest || apiType == APIType.graphql) ...const [ ResponseBodyTab(), ResponseHeadersTab(), ] else if (apiType == APIType.webSocket) ...const [ @@ -123,16 +128,33 @@ class ResponseHeadersTab extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final requestHeaders = ref.watch(selectedRequestModelProvider + final requestHttpHeaders = ref.watch(selectedRequestModelProvider .select((value) => value?.httpResponseModel?.requestHeaders)) ?? {}; - final responseHeaders = ref.watch(selectedRequestModelProvider + final responseHttpHeaders = ref.watch(selectedRequestModelProvider .select((value) => value?.httpResponseModel?.headers)) ?? {}; - return ResponseHeaders( - responseHeaders: responseHeaders, - requestHeaders: requestHeaders, - ); + final requestWebSocketHeaders = ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketResponseModel?.requestHeaders)) ?? + {}; + final responseWebSocketHeaders = ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketResponseModel?.headers)) ?? + {}; + final apiType = ref + .watch(selectedRequestModelProvider.select((value) => value?.apiType)); + switch (apiType!) { + case APIType.rest || APIType.graphql: + return ResponseHeaders( + responseHeaders: responseHttpHeaders, + requestHeaders: requestHttpHeaders, + ); + case APIType.webSocket: + return ResponseHeaders( + responseHeaders: responseWebSocketHeaders, + requestHeaders: requestWebSocketHeaders, + ); + } + } } @@ -151,17 +173,26 @@ class _WebsocketResponseViewState extends ConsumerState { @override void initState() { super.initState(); - _controller.addListener(() { - if (_controller.position.atEdge && _controller.position.pixels != 0) { - setState(() { - _controller.jumpTo(_controller.position.maxScrollExtent); - }); - }else{ - setState(() { - _controller.jumpTo(_controller.offset); - }); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (_controller.hasClients) { + _controller.animateTo( + _controller.position.minScrollExtent, + duration: const Duration(milliseconds: 500), // Adjust for speed + curve: Curves.easeOut, // Smooth effect + ); } }); + // _controller.addListener(() { + // if (_controller.position.atEdge && _controller.position.pixels != 0) { + // setState(() { + // _controller.jumpTo(_controller.position.maxScrollExtent); + // }); + // }else{ + // setState(() { + // _controller.jumpTo(_controller.offset); + // }); + // } + // }); } @override @@ -172,12 +203,13 @@ class _WebsocketResponseViewState extends ConsumerState { @override Widget build(BuildContext context) { + final frames = ref.watch(selectedRequestModelProvider .select((value) => value?.webSocketResponseModel?.frames)) ?? []; - return ListView.builder( controller: _controller, + //physics: const BouncingScrollPhysics(), itemCount: frames.length, itemBuilder: (context, index) { return WebsocketFrame( diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index 86fc49970..3facac30d 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -162,11 +162,12 @@ class ConnectionRequestButton extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { ref.watch(selectedIdStateProvider); + final isConnected = ref.watch( + selectedRequestModelProvider.select((value) => value?.webSocketRequestModel!.isConnected)); final isWorking = ref.watch( selectedRequestModelProvider.select((value) => value?.isWorking)); - return ConnectionButton( - isWorking: isWorking ?? false, + isConnected:isConnected?? false, onTap: () { onTap?.call(); ref.read(collectionStateNotifierProvider.notifier).connect(); diff --git a/lib/widgets/button_connection.dart b/lib/widgets/button_connection.dart index d64ecad5c..64ada9d10 100644 --- a/lib/widgets/button_connection.dart +++ b/lib/widgets/button_connection.dart @@ -5,21 +5,21 @@ import 'package:apidash/consts.dart'; class ConnectionButton extends StatelessWidget { const ConnectionButton({ super.key, - required this.isWorking, + required this.isConnected, required this.onTap, this.onDisconnect, }); - final bool isWorking; + final bool isConnected; final void Function() onTap; final void Function()? onDisconnect; @override Widget build(BuildContext context) { return ADFilledButton( - onPressed: isWorking ? onDisconnect : onTap, - isTonal: isWorking ? true : false, - items: isWorking + onPressed: isConnected ? onDisconnect : onTap, + isTonal: isConnected ? true : false, + items: isConnected ? const [ kHSpacer8, Text( diff --git a/packages/apidash_core/lib/services/http_service.dart b/packages/apidash_core/lib/services/http_service.dart index 0bbc05019..52b7bfb5f 100644 --- a/packages/apidash_core/lib/services/http_service.dart +++ b/packages/apidash_core/lib/services/http_service.dart @@ -121,6 +121,7 @@ Future<(HttpResponse?, Duration?, String?)> request( ); } stopwatch.stop(); + return (response, stopwatch.elapsed, null); } catch (e) { if (clientManager.wasRequestCancelled(requestId)) { diff --git a/packages/apidash_core/lib/services/web_socket_manager.dart b/packages/apidash_core/lib/services/web_socket_manager.dart index a38db40e5..c64521bd0 100644 --- a/packages/apidash_core/lib/services/web_socket_manager.dart +++ b/packages/apidash_core/lib/services/web_socket_manager.dart @@ -1,5 +1,5 @@ -import 'websocket_service.dart'; +import 'package:apidash_core/apidash_core.dart'; class WebSocketManager { static final WebSocketManager _instance = WebSocketManager._internal(); @@ -28,9 +28,9 @@ class WebSocketManager { await _clients[requestId]?.disconnect(); } -Future<(String?,DateTime?)> connect(String requestId,String url) async { +Future<(String?,DateTime?)> connect(String requestId,String url,List? headers,List? params) async { if (_clients.containsKey(requestId)) { - return _clients[requestId]!.connect(url); + return _clients[requestId]!.connect(url,headers,params); } return (null,null); diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index ed17d0349..a5726275b 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -17,19 +17,21 @@ class WebSocketClient { WebSocketClient(); - Future<(String?,DateTime?)> connect(Uri uri,List? headers,List? params) async { + Future<(String?,DateTime?)> connect(String url,List? headers,List? params) async { print("inside client connect"); try { - String urlWithParams = getValidRequestUri(uri.urlWithParams, requestParams); + String urlWithParams = getValidRequestUri(url,params,defaultUriScheme:SupportedUriSchemes.wss).$1.toString(); if(!kIsWeb){ - final WebSocket ioWebSocket = await WebSocket.connect(url); + final WebSocket ioWebSocket = await WebSocket.connect( + urlWithParams, + headers: headers != null ? rowsToMap(headers)! : null); _channel = IOWebSocketChannel(ioWebSocket); ioWebSocket.pingInterval = pingInterval; }else{ - _channel = WebSocketChannel.connect(Uri.parse(url)); + _channel = WebSocketChannel.connect(Uri.parse(urlWithParams)); } await _channel.ready; print('Connected to WebSocket server: ${url}'); diff --git a/packages/apidash_core/lib/utils/uri_utils.dart b/packages/apidash_core/lib/utils/uri_utils.dart index 2954a6796..400707f7e 100644 --- a/packages/apidash_core/lib/utils/uri_utils.dart +++ b/packages/apidash_core/lib/utils/uri_utils.dart @@ -31,7 +31,12 @@ String stripUrlParams(String url) { } if (kLocalhostRegex.hasMatch(url)) { - url = '${SupportedUriSchemes.http.name}://$url'; + if(defaultUriScheme == SupportedUriSchemes.https){ + url = '${SupportedUriSchemes.http.name}://$url'; + }else if(defaultUriScheme == SupportedUriSchemes.wss){ + url = '${SupportedUriSchemes.ws.name}://$url'; + } + } Uri? uri = Uri.tryParse(url); if (uri == null) { @@ -58,6 +63,7 @@ String stripUrlParams(String url) { Map urlQueryParams = uri.queryParameters; queryParams = mergeMaps(urlQueryParams, queryParams); } + uri = uri.replace(queryParameters: queryParams); } return (uri, null); From ab20f2563b6fd3771dc53eb3b75d3deaa45c3672 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Thu, 30 Jan 2025 23:54:27 +0530 Subject: [PATCH 15/30] removed print and make time accurate --- lib/providers/collection_providers.dart | 44 +++++++++++-------- .../request_pane/request_body.dart | 2 +- .../home_page/editor_pane/url_card.dart | 4 -- lib/widgets/request_pane.dart | 3 +- .../lib/models/websocket_frame_model.dart | 2 +- .../lib/services/websocket_service.dart | 9 ---- 6 files changed, 29 insertions(+), 35 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 346cca0e6..2c347875c 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -2,6 +2,7 @@ import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/consts.dart'; +import 'package:intl/intl.dart'; import 'providers.dart'; import '../models/models.dart'; import '../services/services.dart' show hiveHandler, HiveHandler; @@ -369,9 +370,8 @@ class CollectionStateNotifier ), httpRequestModel: substitutedHttpRequestModel, httpResponseModel: httpResponseModel, - webSocketRequestModel: WebSocketRequestModel(), // still not set up but an error was occuring here so had to fill it with something - webSocketResponseModel: WebSocketResponseModel() - + webSocketRequestModel: newRequestModel.webSocketRequestModel!, + webSocketResponseModel: newRequestModel.webSocketResponseModel! ); ref.read(historyMetaStateNotifier.notifier).addHistoryRequest(model); } @@ -544,7 +544,6 @@ class CollectionStateNotifier Future connect() async { - print("connect fired"); final requestId = ref.read(selectedIdStateProvider); ref.read(codePaneVisibleStateProvider.notifier).state = false; if (requestId == null || state == null) { @@ -554,13 +553,8 @@ class CollectionStateNotifier RequestModel? requestModel = state![requestId]; - - // if (requestModel?.webSocketRequestModel == null) { - // print("no web socket request model"); - // return; - // } if (requestModel?.webSocketRequestModel == null) { - print("entered null"); + return; } @@ -618,15 +612,9 @@ class CollectionStateNotifier map = {...state!}; requestModel = map[requestId]; - if(requestModel == null){ - print("webSocketResponseModel is null"); - } WebSocketResponseModel webSocketResponseModel = requestModel!.webSocketResponseModel!; - if(webSocketResponseModel == null){ - print("webSocketResponseModel is null"); - } WebSocketResponseModel newWebSocketResponseModel = webSocketResponseModel.copyWith( frames: [...webSocketResponseModel.frames, WebSocketFrameModel( id: getNewUuid(), @@ -649,11 +637,29 @@ class CollectionStateNotifier }, onError: (error) async{ - print(error.statusCode); + var statusCode = error.statusCode; + map = {...state!}; + requestModel = map[requestId]; + WebSocketResponseModel webSocketResponseModel = requestModel!.webSocketResponseModel!; + WebSocketResponseModel newWebSocketResponseModel = webSocketResponseModel.copyWith( + frames: [...webSocketResponseModel.frames, WebSocketFrameModel( + id: getNewUuid(), + message: error.toString(), + timeStamp:DateTime.now(), + isSend: true + )] + ); + var newRequestModel = requestModel!.copyWith( + responseStatus: statusCode, + message: kResponseCodeReasons[statusCode], + webSocketResponseModel: newWebSocketResponseModel, + ); + map[requestId] = newRequestModel; + state = map; }, onDone: () async{ - print("Connection done"); + }, cancelOnError: false, ); @@ -677,6 +683,8 @@ class CollectionStateNotifier state = map; } } + + Future disconnect() async { final requestId = ref.read(selectedIdStateProvider); if (requestId == null || state == null) { diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 3aae1d676..e0af94a16 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -47,7 +47,7 @@ class EditRequestBody extends ConsumerWidget { children: [ const Padding( padding:EdgeInsets.only(left:10), - child: const SizedBox( + child: SizedBox( height: kHeaderHeight, child: Row( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index 3facac30d..f5b33cee9 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -1,4 +1,3 @@ -import 'package:apidash/widgets/button_connection.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; @@ -164,8 +163,6 @@ class ConnectionRequestButton extends ConsumerWidget { ref.watch(selectedIdStateProvider); final isConnected = ref.watch( selectedRequestModelProvider.select((value) => value?.webSocketRequestModel!.isConnected)); - final isWorking = ref.watch( - selectedRequestModelProvider.select((value) => value?.isWorking)); return ConnectionButton( isConnected:isConnected?? false, onTap: () { @@ -174,7 +171,6 @@ class ConnectionRequestButton extends ConsumerWidget { }, onDisconnect: () { onTap?.call(); - print("disconnected inside disconnect"); ref.read(collectionStateNotifierProvider.notifier).disconnect(); }, diff --git a/lib/widgets/request_pane.dart b/lib/widgets/request_pane.dart index 55684b039..248291c1e 100644 --- a/lib/widgets/request_pane.dart +++ b/lib/widgets/request_pane.dart @@ -37,8 +37,7 @@ class _RequestPaneState extends State @override Widget build(BuildContext context) { - print("Number of tabs (tabLabels): ${widget.tabLabels.length}"); - print("Number of children (TabBarView): ${widget.children.length}"); + final TabController controller = useTabController( initialLength: widget.children.length, vsync: this, diff --git a/packages/apidash_core/lib/models/websocket_frame_model.dart b/packages/apidash_core/lib/models/websocket_frame_model.dart index 79b402223..38d356a74 100644 --- a/packages/apidash_core/lib/models/websocket_frame_model.dart +++ b/packages/apidash_core/lib/models/websocket_frame_model.dart @@ -24,7 +24,7 @@ class WebSocketFrameModel with _$WebSocketFrameModel { factory WebSocketFrameModel.fromJson(Map json) => _$WebSocketFrameModelFromJson(json); - String get formattedTime => DateFormat('HH:mm:ss').format(timeStamp ?? DateTime.now()); + String get formattedTime => DateFormat('HH:mm:ss.SSS').format(timeStamp ?? DateTime.now()); bool get isTextFrame => frameType.toLowerCase() == "text"; diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index a5726275b..934bb2a3a 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -85,21 +85,12 @@ class WebSocketClient { {Future Function(dynamic error)? onError, Future Function()? onDone,bool? cancelOnError}) async{ _subscription = _channel.stream.listen( (message) { - log('Received message: $message'); onMessage(message); }, onError: (error) { - log('Error: $error'); if (onError != null) onError(error); }, onDone: () { - log('Connection closed.'); - if (_channel.closeCode != null) { - print('Close code: ${_channel.closeCode}'); - } - if (_channel.closeReason != null) { - print('Close reason: ${_channel.closeReason}'); - } if (onDone != null) onDone(); }, cancelOnError: cancelOnError ?? true, From 8d64ecf30e243f0dbccd1acae1fa93c5cf77e78b Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sat, 1 Feb 2025 01:13:33 +0530 Subject: [PATCH 16/30] referred dart analyze and some edits --- lib/consts.dart | 2 +- lib/models/request_model.dart | 4 --- lib/providers/collection_providers.dart | 32 ++++++++++--------- .../request_pane/request_body.dart | 2 +- .../request_pane/request_headers.dart | 32 ++++++++++++------- .../details_card/response_pane.dart | 14 ++------ lib/widgets/button_connection.dart | 2 +- .../lib/models/websocket_request_model.dart | 1 - .../lib/services/web_socket_manager.dart | 5 ++- .../lib/services/websocket_service.dart | 16 ---------- test/models/history_models.dart | 2 +- 11 files changed, 45 insertions(+), 67 deletions(-) diff --git a/lib/consts.dart b/lib/consts.dart index 9586a10c6..33c630f9a 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -445,7 +445,7 @@ const kLabelContinue = "Continue"; const kLabelCancel = "Cancel"; const kLabelOk = "Ok"; const kUntitled = "untitled"; -const KLabelConnect = "Connect"; +const kLabelConnect = "Connect"; const kLabelDisconnect = "Disconnect"; // Request Pane const kLabelRequest = "Request"; diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index 3083a54ec..587a8d38e 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -1,9 +1,5 @@ import 'package:apidash_core/apidash_core.dart'; -import 'package:apidash_core/models/websocket_request_model.dart'; -import 'package:apidash_core/models/websocket_response_model.dart'; - part 'request_model.freezed.dart'; - part 'request_model.g.dart'; @freezed diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 2c347875c..eaa6faa95 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -2,7 +2,6 @@ import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/consts.dart'; -import 'package:intl/intl.dart'; import 'providers.dart'; import '../models/models.dart'; import '../services/services.dart' show hiveHandler, HiveHandler; @@ -267,7 +266,7 @@ class CollectionStateNotifier var currentWebSocketRequestModel = currentModel.webSocketRequestModel ?? const WebSocketRequestModel(); final newWebSocketRequestModel = currentApiType == APIType.webSocket - ? currentWebSocketRequestModel?.copyWith( + ? currentWebSocketRequestModel.copyWith( url: url ?? currentWebSocketRequestModel.url, contentType: contentType ?? currentWebSocketRequestModel.contentType, headers: headers ?? currentWebSocketRequestModel.headers, @@ -371,7 +370,7 @@ class CollectionStateNotifier httpRequestModel: substitutedHttpRequestModel, httpResponseModel: httpResponseModel, webSocketRequestModel: newRequestModel.webSocketRequestModel!, - webSocketResponseModel: newRequestModel.webSocketResponseModel! + webSocketResponseModel: newRequestModel.webSocketResponseModel ??const WebSocketResponseModel() //still working ); ref.read(historyMetaStateNotifier.notifier).addHistoryRequest(model); } @@ -484,12 +483,6 @@ class CollectionStateNotifier } - - - - - - String message = currentWebSocketRequestModel.message ?? ''; late (String?,DateTime?,String?) frame; if(currentWebSocketRequestModel.contentType == ContentTypeWebSocket.text){ @@ -534,7 +527,7 @@ class CollectionStateNotifier final newRequestModel = requestModel.copyWith( webSocketResponseModel: newWebSocketResponseModel, ); - // update state with response data + var map = {...state!}; map[requestId] = newRequestModel; state = map; @@ -547,14 +540,12 @@ class CollectionStateNotifier final requestId = ref.read(selectedIdStateProvider); ref.read(codePaneVisibleStateProvider.notifier).state = false; if (requestId == null || state == null) { - print(requestId); return; } RequestModel? requestModel = state![requestId]; if (requestModel?.webSocketRequestModel == null) { - return; } @@ -609,6 +600,7 @@ class CollectionStateNotifier webSocketManager.listen( requestId, (message) async{ + map = {...state!}; requestModel = map[requestId]; @@ -659,6 +651,18 @@ class CollectionStateNotifier }, onDone: () async{ + map = {...state!}; + requestModel = map[requestId]; + WebSocketRequestModel webSocketRequestModel = requestModel!.webSocketRequestModel!; + WebSocketRequestModel newWebSocketRequestModel = webSocketRequestModel.copyWith( + isConnected: false + ); + var newRequestModel = requestModel!.copyWith( + webSocketRequestModel: newWebSocketRequestModel, + ); + map[requestId] = newRequestModel; + state = map; + }, cancelOnError: false, @@ -672,7 +676,7 @@ class CollectionStateNotifier timeStamp:DateTime.now(), isSend: false )]); - map[requestId] = requestModel!.copyWith( + map[requestId] = requestModel.copyWith( isWorking: false, responseStatus: 1002, message: kResponseCodeReasons[1002], @@ -736,12 +740,10 @@ class CollectionStateNotifier void deleteFrame(String id){ final requestId = ref.read(selectedIdStateProvider); if (requestId == null || state == null) { - print(requestId); return; } RequestModel? requestModel = state![requestId]; if (requestModel == null || state == null) { - print(requestId); return; } WebSocketResponseModel webSocketResponseModel = requestModel!.webSocketResponseModel!; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index e0af94a16..8f833b659 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -123,7 +123,7 @@ class EditRequestBody extends ConsumerWidget { onChanged: (String value) { ref .read(collectionStateNotifierProvider.notifier) - .update(message: value); + .update(query: value); }, hintText: kHintQuery, ), 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 e557f574d..a32058cb3 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 @@ -50,6 +50,7 @@ class EditRequestHeadersState extends ConsumerState { late List? rH; late bool isHeadersEmpty; if (apiType == APIType.webSocket) { + print("inside header"); rH = ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.headers; isHeadersEmpty = rH == null || rH.isEmpty; isRowEnabledList = [ @@ -59,33 +60,40 @@ class EditRequestHeadersState extends ConsumerState { ?.isHeaderEnabledList ?? List.filled(rH?.length ?? 0, true, growable: true)) ]; - }else{ - rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; - isHeadersEmpty = rH == null || rH.isEmpty; - isRowEnabledList = [ + headerRows = isHeadersEmpty + ? [ + kNameValueEmptyModel, + ] + : rH + [kNameValueEmptyModel]; + isRowEnabledList = [ ...(ref .read(selectedRequestModelProvider) - ?.httpRequestModel + ?.webSocketRequestModel ?.isHeaderEnabledList ?? List.filled(rH?.length ?? 0, true, growable: true)) ]; - - } - headerRows = isHeadersEmpty + + }else{ + print("inside http"); + rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; + isHeadersEmpty = rH == null || rH.isEmpty; + headerRows = isHeadersEmpty ? [ kNameValueEmptyModel, ] - : rH! + [kNameValueEmptyModel]; - isRowEnabledList = [ + : rH + [kNameValueEmptyModel]; + isRowEnabledList = [ ...(ref .read(selectedRequestModelProvider) ?.httpRequestModel ?.isHeaderEnabledList ?? List.filled(rH?.length ?? 0, true, growable: true)) ]; + + } isRowEnabledList.add(false); isAddingRow = false; - + List columns = const [ DataColumn2( label: Text(kNameCheckbox), @@ -112,7 +120,7 @@ class EditRequestHeadersState extends ConsumerState { (index) { bool isLast = index + 1 == headerRows.length; - print(isLast); + return DataRow( key: ValueKey("$selectedId-$index-headers-row-$seed"), cells: [ diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 1b65cba4f..9c84cfd8a 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -19,24 +19,14 @@ class ResponsePane extends ConsumerWidget{ selectedRequestModelProvider.select((value) => value?.responseStatus)); final message = ref .watch(selectedRequestModelProvider.select((value) => value?.message)); - final apiType = ref - .watch(selectedRequestModelProvider.select((value) => value?.apiType)); + + if (isWorking) { - // if(apiType == APIType.rest || apiType == APIType.graphql){ - // return SendingWidget( - // startSendingTime: startSendingTime, - // ); - // }else{ - // return const ResponseDetails(); - - // } return SendingWidget( startSendingTime: startSendingTime, ); - - } if (responseStatus == null) { diff --git a/lib/widgets/button_connection.dart b/lib/widgets/button_connection.dart index 64ada9d10..6329abd97 100644 --- a/lib/widgets/button_connection.dart +++ b/lib/widgets/button_connection.dart @@ -30,7 +30,7 @@ class ConnectionButton extends StatelessWidget { ] : const [ Text( - KLabelConnect, + kLabelConnect, style: kTextStyleButton, ), kHSpacer10, diff --git a/packages/apidash_core/lib/models/websocket_request_model.dart b/packages/apidash_core/lib/models/websocket_request_model.dart index cb49548b8..9b8a59b8c 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.dart @@ -1,5 +1,4 @@ import 'package:apidash_core/consts.dart'; -import 'package:apidash_core/models/websocket_frame_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:seed/models/name_value_model.dart'; import '../utils/utils.dart' diff --git a/packages/apidash_core/lib/services/web_socket_manager.dart b/packages/apidash_core/lib/services/web_socket_manager.dart index c64521bd0..aff737b40 100644 --- a/packages/apidash_core/lib/services/web_socket_manager.dart +++ b/packages/apidash_core/lib/services/web_socket_manager.dart @@ -1,6 +1,5 @@ - -import 'package:apidash_core/apidash_core.dart'; - +import 'package:seed/seed.dart'; +import './websocket_service.dart'; class WebSocketManager { static final WebSocketManager _instance = WebSocketManager._internal(); final Map _clients = {}; diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index 934bb2a3a..ea57dedcf 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:developer'; import 'dart:io'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/foundation.dart'; @@ -34,10 +33,8 @@ class WebSocketClient { _channel = WebSocketChannel.connect(Uri.parse(urlWithParams)); } await _channel.ready; - print('Connected to WebSocket server: ${url}'); return (kMsgConnected,DateTime.now()); } catch (e) { - print('Failed to connect to WebSocket server: $e'); return (e.toString(),DateTime.now()); } } @@ -46,12 +43,6 @@ class WebSocketClient { Future<(String?,DateTime?,String?)> sendText(String message)async { try{ _channel.sink.add(message); - // websocketRequestModel.frames.add(WebSocketFrameModel( - // id: '1', - // message: websocketRequestModel.message!, - // timeStamp: DateTime.now(), - // )); - log('Sent text message: $message}'); return (message,DateTime.now(),null); }catch(e){ @@ -66,12 +57,6 @@ class WebSocketClient { Uint8List binary = Uint8List.fromList(utf8.encode(message)); _channel.sink.add(binary); - // websocketRequestModel.frames.add(WebSocketFrameModel( - // id: '1', - // message: websocketRequestModel.message!, - // timeStamp: DateTime.now(), - // )); - log('Sent text message: $message}'); return (message,DateTime.now(),null); }catch(e){ @@ -101,7 +86,6 @@ class WebSocketClient { Future disconnect({int closeCode = status.normalClosure, String? reason})async { _subscription?.cancel(); _channel.sink.close(closeCode, reason); - log('Disconnected from WebSocket server'); } } diff --git a/test/models/history_models.dart b/test/models/history_models.dart index e33c2f99d..46ccc615b 100644 --- a/test/models/history_models.dart +++ b/test/models/history_models.dart @@ -17,7 +17,7 @@ final historyMetaModel1 = HistoryMetaModel( ); /// Basic History Request model 1 -final historyRequestModel1 = HistoryRequestModel( +final historyRequestModel1 = HistoryRequestModel( historyId: 'historyId1', metaData: historyMetaModel1, httpRequestModel: httpRequestModelGet4, From 3ef1fe3faed2d2eabee45930a58925f71a270590 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sat, 1 Feb 2025 09:48:48 +0530 Subject: [PATCH 17/30] disable headers for web --- .../request_pane/request_pane_websocket.dart | 14 ++++++-------- lib/screens/settings_page.dart | 5 +++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart index ccc97cc31..9824ebc40 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart @@ -6,7 +6,7 @@ import 'package:apidash/widgets/widgets.dart'; import 'request_headers.dart'; import 'request_body.dart'; import 'request_params.dart'; - +import 'package:flutter/foundation.dart' show kIsWeb; class EditWebSocketRequestPane extends ConsumerWidget { const EditWebSocketRequestPane({super.key}); @@ -22,10 +22,8 @@ class EditWebSocketRequestPane extends ConsumerWidget { 0; final paramLength = ref.watch(selectedRequestModelProvider .select((value) => value?.webSocketRequestModel?.paramsMap.length)) ?? - 0; - - - + 0; + return RequestPane( selectedId: selectedId, codePaneVisible: codePaneVisible, @@ -41,17 +39,17 @@ class EditWebSocketRequestPane extends ConsumerWidget { }, showIndicators: [ paramLength > 0, - headerLength > 0, + !kIsWeb && headerLength > 0, true, ], tabLabels: const [ kLabelURLParams, - kLabelHeaders, + if(!kIsWeb) kLabelHeaders, kLabelMessage, ], children: const [ EditRequestURLParams(), - EditRequestHeaders(), + if (!kIsWeb) EditRequestHeaders(), EditRequestBody(), ], ); diff --git a/lib/screens/settings_page.dart b/lib/screens/settings_page.dart index 5e3d46ce1..ce956f053 100644 --- a/lib/screens/settings_page.dart +++ b/lib/screens/settings_page.dart @@ -240,7 +240,8 @@ class SettingsPage extends ConsumerWidget { }, ) : kSizedBoxEmpty, - + !kIsWeb + ? ListTile( hoverColor: kColorTransparent, title: const Text('Interval Between Ping Requests'), @@ -260,7 +261,7 @@ class SettingsPage extends ConsumerWidget { }, ), ), - ), + ) : kSizedBoxEmpty, ListTile( title: const Text('About'), subtitle: const Text( From 5d171bcc572b551fad05ed4e30341e21c676efa7 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sat, 1 Feb 2025 10:34:04 +0530 Subject: [PATCH 18/30] request pane corrected --- .../request_pane/request_body.dart | 23 +++++++++++++++---- .../request_pane/request_pane_websocket.dart | 5 +++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 8f833b659..0aef5d1c4 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -39,8 +39,21 @@ class EditRequestBody extends ConsumerWidget { return Column( children: [ - (apiType == APIType.webSocket) //dont forget to make it switch and put for rest - ? SizedBox( + switch(apiType){ + APIType.rest => const SizedBox( + height: kHeaderHeight, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Select Content Type:", + ), + DropdownButtonBodyContentType(), + ], + ), + ), + APIType.webSocket => //dont forget to make it switch and put for rest + SizedBox( height: kHeaderHeight, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -69,8 +82,10 @@ class EditRequestBody extends ConsumerWidget { ), ], ), - ) - : kSizedBoxEmpty, + ), + _=> kSizedBoxEmpty, + + }, switch (apiType) { APIType.rest => Expanded( child: switch (contentType) { diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart index 9824ebc40..adaae9d63 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_websocket.dart @@ -23,6 +23,9 @@ class EditWebSocketRequestPane extends ConsumerWidget { final paramLength = ref.watch(selectedRequestModelProvider .select((value) => value?.webSocketRequestModel?.paramsMap.length)) ?? 0; + final message = ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketRequestModel?.message)) ?? + ""; return RequestPane( selectedId: selectedId, @@ -40,7 +43,7 @@ class EditWebSocketRequestPane extends ConsumerWidget { showIndicators: [ paramLength > 0, !kIsWeb && headerLength > 0, - true, + message.isNotEmpty, ], tabLabels: const [ kLabelURLParams, From 783821b9d53df620e027f0806a8cbf63f93c2b65 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sat, 1 Feb 2025 11:14:37 +0530 Subject: [PATCH 19/30] final commit --- .../editor_pane/details_card/request_pane/request_body.dart | 2 +- .../editor_pane/details_card/request_pane/request_headers.dart | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 0aef5d1c4..4a85a3a30 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -134,7 +134,7 @@ class EditRequestBody extends ConsumerWidget { child: TextFieldEditor( key: Key("$selectedId-query"), fieldKey: "$selectedId-query-editor", - initialValue: requestModel?.webSocketRequestModel?.message, + initialValue: requestModel?.httpRequestModel?.query, onChanged: (String value) { ref .read(collectionStateNotifierProvider.notifier) 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 a32058cb3..3347fd6db 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 @@ -50,7 +50,6 @@ class EditRequestHeadersState extends ConsumerState { late List? rH; late bool isHeadersEmpty; if (apiType == APIType.webSocket) { - print("inside header"); rH = ref.read(selectedRequestModelProvider)?.webSocketRequestModel?.headers; isHeadersEmpty = rH == null || rH.isEmpty; isRowEnabledList = [ @@ -74,7 +73,6 @@ class EditRequestHeadersState extends ConsumerState { ]; }else{ - print("inside http"); rH = ref.read(selectedRequestModelProvider)?.httpRequestModel?.headers; isHeadersEmpty = rH == null || rH.isEmpty; headerRows = isHeadersEmpty From 46d35220b7bb08c4792722983fe3aa3d6f4a27d0 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Mon, 17 Feb 2025 20:00:28 +0530 Subject: [PATCH 20/30] resolved scrolling issue --- .../details_card/response_pane.dart | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 9c84cfd8a..384103839 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -159,6 +159,8 @@ class WebsocketResponseView extends ConsumerStatefulWidget { class _WebsocketResponseViewState extends ConsumerState { final ScrollController _controller = ScrollController(); + bool _isAtTop = true; + List _pausedFrames = []; @override void initState() { @@ -172,17 +174,13 @@ class _WebsocketResponseViewState extends ConsumerState { ); } }); - // _controller.addListener(() { - // if (_controller.position.atEdge && _controller.position.pixels != 0) { - // setState(() { - // _controller.jumpTo(_controller.position.maxScrollExtent); - // }); - // }else{ - // setState(() { - // _controller.jumpTo(_controller.offset); - // }); - // } - // }); + _controller.addListener(() { + if (_controller.hasClients) { + setState(() { + _isAtTop = _controller.position.atEdge == true; + }); + } + }); } @override @@ -197,13 +195,19 @@ class _WebsocketResponseViewState extends ConsumerState { final frames = ref.watch(selectedRequestModelProvider .select((value) => value?.webSocketResponseModel?.frames)) ?? []; + + if (_isAtTop) { + _pausedFrames = List.from(frames); + } + + final displayFrames = _isAtTop ? frames : _pausedFrames; return ListView.builder( controller: _controller, //physics: const BouncingScrollPhysics(), - itemCount: frames.length, + itemCount: displayFrames.length, itemBuilder: (context, index) { return WebsocketFrame( - websocketFrame: frames[frames.length-index-1], + websocketFrame: displayFrames[displayFrames.length-index-1], ref: ref, ); }, From cc5808b16c7ab6cef392af8f0cd0946622dab1d0 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sun, 23 Feb 2025 11:22:52 +0530 Subject: [PATCH 21/30] added debugging commit --- packages/apidash_core/lib/services/http_client_manager.dart | 2 ++ packages/apidash_core/lib/services/http_service.dart | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/packages/apidash_core/lib/services/http_client_manager.dart b/packages/apidash_core/lib/services/http_client_manager.dart index c98c16502..5e6503ac8 100644 --- a/packages/apidash_core/lib/services/http_client_manager.dart +++ b/packages/apidash_core/lib/services/http_client_manager.dart @@ -37,6 +37,7 @@ class HttpClientManager { void cancelRequest(String? requestId) { + print("inside cance request"); if (requestId != null && _clients.containsKey(requestId)) { _clients[requestId]?.close(); _clients.remove(requestId); @@ -53,6 +54,7 @@ class HttpClientManager { } void closeClient(String requestId) { + print("inside closeClient"); if (_clients.containsKey(requestId)) { _clients[requestId]?.close(); _clients.remove(requestId); diff --git a/packages/apidash_core/lib/services/http_service.dart b/packages/apidash_core/lib/services/http_service.dart index 1a70b25e5..85037cd39 100644 --- a/packages/apidash_core/lib/services/http_service.dart +++ b/packages/apidash_core/lib/services/http_service.dart @@ -86,8 +86,10 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( response = await client.head(requestUrl, headers: headers); break; case HTTPVerb.post: + print("entered into post"); response = await client.post(requestUrl, headers: headers, body: body); + print("Response ${response.toString()}"); break; case HTTPVerb.put: response = @@ -130,6 +132,7 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( } return (null, null, e.toString()); } finally { + print("etered into finally"); httpClientManager.closeClient(requestId); } } else { @@ -138,5 +141,6 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( } void cancelHttpRequest(String? requestId) { + print("inside cancelHttpRequest"); httpClientManager.cancelRequest(requestId); } From 6ed15521d9a7edcdfbf13ba37de8a049c0a71e0c Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sun, 23 Feb 2025 17:25:10 +0530 Subject: [PATCH 22/30] added debuging codes --- lib/providers/collection_providers.dart | 2 ++ .../home_page/editor_pane/details_card/response_pane.dart | 1 + .../apidash_core/lib/services/http_client_manager.dart | 7 +++++-- packages/apidash_core/lib/services/http_service.dart | 7 ++++++- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 448e8ac12..2585c5065 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -334,12 +334,14 @@ class CollectionStateNotifier late final RequestModel newRequestModel; if (responseRec.$1 == null) { + print("inside response null error"); newRequestModel = requestModel.copyWith( responseStatus: -1, message: responseRec.$3, isWorking: false, ); } else { + print("inside some response"); final httpResponseModel = baseHttpResponseModel.fromResponse( response: responseRec.$1!, time: responseRec.$2!, diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 384103839..bad04caf8 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -23,6 +23,7 @@ class ResponsePane extends ConsumerWidget{ if (isWorking) { + print("is Working"); return SendingWidget( startSendingTime: startSendingTime, ); diff --git a/packages/apidash_core/lib/services/http_client_manager.dart b/packages/apidash_core/lib/services/http_client_manager.dart index 5e6503ac8..cb1d1a822 100644 --- a/packages/apidash_core/lib/services/http_client_manager.dart +++ b/packages/apidash_core/lib/services/http_client_manager.dart @@ -37,9 +37,12 @@ class HttpClientManager { void cancelRequest(String? requestId) { - print("inside cance request"); + print("inside cancel request"); + print("clients is it or not ${_clients.containsKey(requestId)}"); if (requestId != null && _clients.containsKey(requestId)) { - _clients[requestId]?.close(); + print("inside if"); + _clients[requestId]?.close(); + print("after closed"); _clients.remove(requestId); _cancelledRequests.addLast(requestId); diff --git a/packages/apidash_core/lib/services/http_service.dart b/packages/apidash_core/lib/services/http_service.dart index 85037cd39..654af630d 100644 --- a/packages/apidash_core/lib/services/http_service.dart +++ b/packages/apidash_core/lib/services/http_service.dart @@ -19,6 +19,7 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, }) async { + print("entered send http request"); final client = httpClientManager.createClient(requestId, noSSL: noSSL); (Uri?, String?) uriRec = getValidRequestUri( @@ -35,6 +36,7 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( try { Stopwatch stopwatch = Stopwatch()..start(); if (apiType == APIType.rest) { + print("entered into rest"); var isMultiPartRequest = requestModel.bodyContentType == ContentType.formdata; @@ -70,8 +72,10 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( ); } } + print("Just before multipart request"); http.StreamedResponse multiPartResponse = await multiPartRequest.send(); + print("Just after mutipart request"); stopwatch.stop(); http.Response convertedMultiPartResponse = await convertStreamedResponse(multiPartResponse); @@ -127,12 +131,13 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( return (response, stopwatch.elapsed, null); } catch (e) { + print("Inside error of sendHttpRequest"); if (httpClientManager.wasRequestCancelled(requestId)) { return (null, null, kMsgRequestCancelled); } return (null, null, e.toString()); } finally { - print("etered into finally"); + print("entered into finally"); httpClientManager.closeClient(requestId); } } else { From 613e7006bb0120e358e2ca1aebff3d661d5ab09c Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Tue, 25 Feb 2025 23:33:09 +0530 Subject: [PATCH 23/30] removed debug prints --- lib/providers/collection_providers.dart | 7 ++----- .../apidash_core/lib/services/http_client_manager.dart | 6 +----- packages/apidash_core/lib/services/http_service.dart | 9 --------- .../apidash_core/lib/services/websocket_service.dart | 1 - 4 files changed, 3 insertions(+), 20 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 2585c5065..a5b824903 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -334,14 +334,12 @@ class CollectionStateNotifier late final RequestModel newRequestModel; if (responseRec.$1 == null) { - print("inside response null error"); newRequestModel = requestModel.copyWith( responseStatus: -1, message: responseRec.$3, isWorking: false, ); } else { - print("inside some response"); final httpResponseModel = baseHttpResponseModel.fromResponse( response: responseRec.$1!, time: responseRec.$2!, @@ -691,7 +689,6 @@ class CollectionStateNotifier Future disconnect() async { final requestId = ref.read(selectedIdStateProvider); if (requestId == null || state == null) { - print(requestId); return; } @@ -745,8 +742,8 @@ class CollectionStateNotifier if (requestModel == null || state == null) { return; } - WebSocketResponseModel webSocketResponseModel = requestModel!.webSocketResponseModel!; - List newFrames = requestModel!.webSocketResponseModel!.frames.where((element) => element.id != id).toList(); + WebSocketResponseModel webSocketResponseModel = requestModel.webSocketResponseModel!; + List newFrames = requestModel.webSocketResponseModel!.frames.where((element) => element.id != id).toList(); WebSocketResponseModel newWebSocketResponseModel = webSocketResponseModel.copyWith( frames: newFrames, ); diff --git a/packages/apidash_core/lib/services/http_client_manager.dart b/packages/apidash_core/lib/services/http_client_manager.dart index cb1d1a822..94d87cf14 100644 --- a/packages/apidash_core/lib/services/http_client_manager.dart +++ b/packages/apidash_core/lib/services/http_client_manager.dart @@ -37,12 +37,9 @@ class HttpClientManager { void cancelRequest(String? requestId) { - print("inside cancel request"); - print("clients is it or not ${_clients.containsKey(requestId)}"); if (requestId != null && _clients.containsKey(requestId)) { - print("inside if"); + _clients[requestId]?.close(); - print("after closed"); _clients.remove(requestId); _cancelledRequests.addLast(requestId); @@ -57,7 +54,6 @@ class HttpClientManager { } void closeClient(String requestId) { - print("inside closeClient"); if (_clients.containsKey(requestId)) { _clients[requestId]?.close(); _clients.remove(requestId); diff --git a/packages/apidash_core/lib/services/http_service.dart b/packages/apidash_core/lib/services/http_service.dart index 654af630d..1a70b25e5 100644 --- a/packages/apidash_core/lib/services/http_service.dart +++ b/packages/apidash_core/lib/services/http_service.dart @@ -19,7 +19,6 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, }) async { - print("entered send http request"); final client = httpClientManager.createClient(requestId, noSSL: noSSL); (Uri?, String?) uriRec = getValidRequestUri( @@ -36,7 +35,6 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( try { Stopwatch stopwatch = Stopwatch()..start(); if (apiType == APIType.rest) { - print("entered into rest"); var isMultiPartRequest = requestModel.bodyContentType == ContentType.formdata; @@ -72,10 +70,8 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( ); } } - print("Just before multipart request"); http.StreamedResponse multiPartResponse = await multiPartRequest.send(); - print("Just after mutipart request"); stopwatch.stop(); http.Response convertedMultiPartResponse = await convertStreamedResponse(multiPartResponse); @@ -90,10 +86,8 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( response = await client.head(requestUrl, headers: headers); break; case HTTPVerb.post: - print("entered into post"); response = await client.post(requestUrl, headers: headers, body: body); - print("Response ${response.toString()}"); break; case HTTPVerb.put: response = @@ -131,13 +125,11 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( return (response, stopwatch.elapsed, null); } catch (e) { - print("Inside error of sendHttpRequest"); if (httpClientManager.wasRequestCancelled(requestId)) { return (null, null, kMsgRequestCancelled); } return (null, null, e.toString()); } finally { - print("entered into finally"); httpClientManager.closeClient(requestId); } } else { @@ -146,6 +138,5 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( } void cancelHttpRequest(String? requestId) { - print("inside cancelHttpRequest"); httpClientManager.cancelRequest(requestId); } diff --git a/packages/apidash_core/lib/services/websocket_service.dart b/packages/apidash_core/lib/services/websocket_service.dart index ea57dedcf..46945857c 100644 --- a/packages/apidash_core/lib/services/websocket_service.dart +++ b/packages/apidash_core/lib/services/websocket_service.dart @@ -17,7 +17,6 @@ class WebSocketClient { Future<(String?,DateTime?)> connect(String url,List? headers,List? params) async { - print("inside client connect"); try { String urlWithParams = getValidRequestUri(url,params,defaultUriScheme:SupportedUriSchemes.wss).$1.toString(); From 62c9a670fdb3a2535196cb8eb0c1c7af772e7569 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Wed, 26 Feb 2025 13:03:04 +0530 Subject: [PATCH 24/30] fixed url --- lib/providers/collection_providers.dart | 1 + lib/providers/history_providers.dart | 7 +++ .../details_card/response_pane.dart | 2 - .../home_page/editor_pane/url_card.dart | 42 ++++++++++++++---- .../lib/models/websocket_frame_model.dart | 2 +- .../lib/models/websocket_request_model.dart | 3 +- test/models/history_models.dart | 2 + test/models/websocket_response_models.dart | 44 +++++++++++++++++++ 8 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 test/models/websocket_response_models.dart diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index a5b824903..a0690a9ef 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -171,6 +171,7 @@ class CollectionStateNotifier responseStatus: null, message: null, httpResponseModel: null, + webSocketResponseModel: null, isWorking: false, sendingTime: null, ); diff --git a/lib/providers/history_providers.dart b/lib/providers/history_providers.dart index cc7a587c9..e5ca972f3 100644 --- a/lib/providers/history_providers.dart +++ b/lib/providers/history_providers.dart @@ -1,5 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/models/models.dart'; +import 'package:apidash_core/apidash_core.dart'; import '../services/services.dart' show hiveHandler, HiveHandler; import '../utils/history_utils.dart'; @@ -69,6 +70,12 @@ class HistoryMetaStateNotifier var jsonModel = await hiveHandler.getHistoryRequest(id); if (jsonModel != null) { var jsonMap = Map.from(jsonModel); + // for(var js in jsonMap.entries){ + // if(js.value!.webSocketRequestModel == null){ + // + // } + // + // } var historyRequestModelFromJson = HistoryRequestModel.fromJson(jsonMap); ref.read(selectedHistoryRequestModelProvider.notifier).state = historyRequestModelFromJson; diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index bad04caf8..37160bed4 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -23,7 +23,6 @@ class ResponsePane extends ConsumerWidget{ if (isWorking) { - print("is Working"); return SendingWidget( startSendingTime: startSendingTime, ); @@ -204,7 +203,6 @@ class _WebsocketResponseViewState extends ConsumerState { final displayFrames = _isAtTop ? frames : _pausedFrames; return ListView.builder( controller: _controller, - //physics: const BouncingScrollPhysics(), itemCount: displayFrames.length, itemBuilder: (context, index) { return WebsocketFrame( diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index f5b33cee9..1ae00ac73 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -59,9 +59,16 @@ class EditorPaneRequestURLCard extends ConsumerWidget { APIType.rest => kHSpacer20, _ => kHSpacer8, }, - const Expanded( + switch(apiType){ + APIType.webSocket => const Expanded( + child: URLwebSocketTextField(), + ), + _ => const Expanded( child: URLTextField(), ), + + + }, kHSpacer20, switch (apiType) { APIType.rest || APIType.graphql => const SendRequestButton(), @@ -103,17 +110,36 @@ class URLTextField extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final selectedId = ref.watch(selectedIdStateProvider); - final apiType = ref - .watch(selectedRequestModelProvider.select((value) => value?.apiType)); + return EnvURLField( selectedId: selectedId!, - initialValue:switch (apiType) { - APIType.rest || APIType.graphql=> ref.watch(selectedRequestModelProvider + initialValue: ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.url)), - APIType.webSocket => ref.watch(selectedRequestModelProvider - .select((value) => value?.webSocketRequestModel?.url)), - null => '', + // onChanged: (value) { + // + // ref.read(collectionStateNotifierProvider.notifier).update(url: value); + // }, + onFieldSubmitted: (value) { + ref.read(collectionStateNotifierProvider.notifier).update(url: value); + ref.read(collectionStateNotifierProvider.notifier).sendRequest(); }, + ); + } +} + +class URLwebSocketTextField extends ConsumerWidget { + const URLwebSocketTextField({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedId = ref.watch(selectedIdStateProvider); + + return EnvURLField( + selectedId: selectedId!, + initialValue: ref.watch(selectedRequestModelProvider + .select((value) => value?.webSocketRequestModel?.url)), onChanged: (value) { ref.read(collectionStateNotifierProvider.notifier).update(url: value); diff --git a/packages/apidash_core/lib/models/websocket_frame_model.dart b/packages/apidash_core/lib/models/websocket_frame_model.dart index 38d356a74..ea6c6e413 100644 --- a/packages/apidash_core/lib/models/websocket_frame_model.dart +++ b/packages/apidash_core/lib/models/websocket_frame_model.dart @@ -5,7 +5,7 @@ import 'package:intl/intl.dart'; part 'websocket_frame_model.freezed.dart'; part 'websocket_frame_model.g.dart'; -/// WebSocket Frame Model + @freezed class WebSocketFrameModel with _$WebSocketFrameModel { const WebSocketFrameModel._(); diff --git a/packages/apidash_core/lib/models/websocket_request_model.dart b/packages/apidash_core/lib/models/websocket_request_model.dart index 9b8a59b8c..346479721 100644 --- a/packages/apidash_core/lib/models/websocket_request_model.dart +++ b/packages/apidash_core/lib/models/websocket_request_model.dart @@ -28,7 +28,7 @@ class WebSocketRequestModel with _$WebSocketRequestModel { factory WebSocketRequestModel.fromJson(Map json) => _$WebSocketRequestModelFromJson(json); - /// Headers Map + Map get headersMap => rowsToMap(headers) ?? {}; List? get enabledHeaders => getEnabledRows(headers, isHeaderEnabledList); @@ -45,7 +45,6 @@ class WebSocketRequestModel with _$WebSocketRequestModel { bool get isValidUrl => url.startsWith("ws://") || url.startsWith("wss://"); - /// Resets received messages List resetReceivedMessages() { return []; } diff --git a/test/models/history_models.dart b/test/models/history_models.dart index 46ccc615b..c96797260 100644 --- a/test/models/history_models.dart +++ b/test/models/history_models.dart @@ -21,7 +21,9 @@ final historyRequestModel1 = HistoryRequestModel( historyId: 'historyId1', metaData: historyMetaModel1, httpRequestModel: httpRequestModelGet4, + webSocketRequestModel: null, httpResponseModel: responseModel, + ); final historyMetaModel2 = HistoryMetaModel( diff --git a/test/models/websocket_response_models.dart b/test/models/websocket_response_models.dart new file mode 100644 index 000000000..5b04ce3bd --- /dev/null +++ b/test/models/websocket_response_models.dart @@ -0,0 +1,44 @@ +import 'dart:typed_data'; +import 'package:apidash_core/apidash_core.dart'; + +const int statusCode = 200; +const Map headers = { + "content-length": "16", + "x-cloud-trace-context": "dad62aaf7f640300bbf629f4ae2f2f63", + "content-type": "application/json", + "date": "Sun, 23 Apr 2023 23:46:31 GMT", + "server": "Google Frontend" +}; + +const Map requestHeaders = { + "content-length": "18", + "content-type": "application/json; charset=utf-8" +}; + +const String body = '{"data":"world"}'; +Uint8List bodyBytes = Uint8List.fromList( + [123, 34, 100, 97, 116, 97, 34, 58, 34, 119, 111, 114, 108, 100, 34, 125]); +const String formattedBody = '''{ + "data": "world" +}'''; +const Duration time = Duration(milliseconds: 516); + +HttpResponseModel responseModel = HttpResponseModel( + statusCode: statusCode, + headers: headers, + requestHeaders: requestHeaders, + body: body, + formattedBody: formattedBody, + bodyBytes: bodyBytes, + time: time, +); + +Map responseModelJson = { + "statusCode": statusCode, + "headers": headers, + "requestHeaders": requestHeaders, + "body": body, + "formattedBody": formattedBody, + "bodyBytes": bodyBytes, + "time": 516000, +}; From 3f312b17d19be1c6edd4ea453d42577211c32ac6 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Wed, 26 Feb 2025 21:35:16 +0530 Subject: [PATCH 25/30] changeed request model --- lib/models/history_request_model.dart | 4 +- lib/models/history_request_model.freezed.dart | 72 ++++++++++--------- lib/models/history_request_model.g.dart | 16 +++-- lib/providers/history_providers.dart | 7 -- 4 files changed, 52 insertions(+), 47 deletions(-) diff --git a/lib/models/history_request_model.dart b/lib/models/history_request_model.dart index 6623a5445..7036dbd72 100644 --- a/lib/models/history_request_model.dart +++ b/lib/models/history_request_model.dart @@ -16,8 +16,8 @@ class HistoryRequestModel with _$HistoryRequestModel { required HistoryMetaModel metaData, required HttpRequestModel httpRequestModel, required HttpResponseModel httpResponseModel, - required WebSocketRequestModel webSocketRequestModel, - required WebSocketResponseModel webSocketResponseModel, + required WebSocketRequestModel? webSocketRequestModel, + required WebSocketResponseModel? webSocketResponseModel, }) = _HistoryRequestModel; diff --git a/lib/models/history_request_model.freezed.dart b/lib/models/history_request_model.freezed.dart index ddac2d4d0..4dabe63ca 100644 --- a/lib/models/history_request_model.freezed.dart +++ b/lib/models/history_request_model.freezed.dart @@ -24,9 +24,9 @@ mixin _$HistoryRequestModel { HistoryMetaModel get metaData => throw _privateConstructorUsedError; HttpRequestModel get httpRequestModel => throw _privateConstructorUsedError; HttpResponseModel get httpResponseModel => throw _privateConstructorUsedError; - WebSocketRequestModel get webSocketRequestModel => + WebSocketRequestModel? get webSocketRequestModel => throw _privateConstructorUsedError; - WebSocketResponseModel get webSocketResponseModel => + WebSocketResponseModel? get webSocketResponseModel => throw _privateConstructorUsedError; /// Serializes this HistoryRequestModel to a JSON map. @@ -50,14 +50,14 @@ abstract class $HistoryRequestModelCopyWith<$Res> { HistoryMetaModel metaData, HttpRequestModel httpRequestModel, HttpResponseModel httpResponseModel, - WebSocketRequestModel webSocketRequestModel, - WebSocketResponseModel webSocketResponseModel}); + WebSocketRequestModel? webSocketRequestModel, + WebSocketResponseModel? webSocketResponseModel}); $HistoryMetaModelCopyWith<$Res> get metaData; $HttpRequestModelCopyWith<$Res> get httpRequestModel; $HttpResponseModelCopyWith<$Res> get httpResponseModel; - $WebSocketRequestModelCopyWith<$Res> get webSocketRequestModel; - $WebSocketResponseModelCopyWith<$Res> get webSocketResponseModel; + $WebSocketRequestModelCopyWith<$Res>? get webSocketRequestModel; + $WebSocketResponseModelCopyWith<$Res>? get webSocketResponseModel; } /// @nodoc @@ -79,8 +79,8 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> Object? metaData = null, Object? httpRequestModel = null, Object? httpResponseModel = null, - Object? webSocketRequestModel = null, - Object? webSocketResponseModel = null, + Object? webSocketRequestModel = freezed, + Object? webSocketResponseModel = freezed, }) { return _then(_value.copyWith( historyId: null == historyId @@ -99,14 +99,14 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel, - webSocketRequestModel: null == webSocketRequestModel + webSocketRequestModel: freezed == webSocketRequestModel ? _value.webSocketRequestModel : webSocketRequestModel // ignore: cast_nullable_to_non_nullable - as WebSocketRequestModel, - webSocketResponseModel: null == webSocketResponseModel + as WebSocketRequestModel?, + webSocketResponseModel: freezed == webSocketResponseModel ? _value.webSocketResponseModel : webSocketResponseModel // ignore: cast_nullable_to_non_nullable - as WebSocketResponseModel, + as WebSocketResponseModel?, ) as $Val); } @@ -144,8 +144,12 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') - $WebSocketRequestModelCopyWith<$Res> get webSocketRequestModel { - return $WebSocketRequestModelCopyWith<$Res>(_value.webSocketRequestModel, + $WebSocketRequestModelCopyWith<$Res>? get webSocketRequestModel { + if (_value.webSocketRequestModel == null) { + return null; + } + + return $WebSocketRequestModelCopyWith<$Res>(_value.webSocketRequestModel!, (value) { return _then(_value.copyWith(webSocketRequestModel: value) as $Val); }); @@ -155,8 +159,12 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') - $WebSocketResponseModelCopyWith<$Res> get webSocketResponseModel { - return $WebSocketResponseModelCopyWith<$Res>(_value.webSocketResponseModel, + $WebSocketResponseModelCopyWith<$Res>? get webSocketResponseModel { + if (_value.webSocketResponseModel == null) { + return null; + } + + return $WebSocketResponseModelCopyWith<$Res>(_value.webSocketResponseModel!, (value) { return _then(_value.copyWith(webSocketResponseModel: value) as $Val); }); @@ -176,8 +184,8 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res> HistoryMetaModel metaData, HttpRequestModel httpRequestModel, HttpResponseModel httpResponseModel, - WebSocketRequestModel webSocketRequestModel, - WebSocketResponseModel webSocketResponseModel}); + WebSocketRequestModel? webSocketRequestModel, + WebSocketResponseModel? webSocketResponseModel}); @override $HistoryMetaModelCopyWith<$Res> get metaData; @@ -186,9 +194,9 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res> @override $HttpResponseModelCopyWith<$Res> get httpResponseModel; @override - $WebSocketRequestModelCopyWith<$Res> get webSocketRequestModel; + $WebSocketRequestModelCopyWith<$Res>? get webSocketRequestModel; @override - $WebSocketResponseModelCopyWith<$Res> get webSocketResponseModel; + $WebSocketResponseModelCopyWith<$Res>? get webSocketResponseModel; } /// @nodoc @@ -208,8 +216,8 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> Object? metaData = null, Object? httpRequestModel = null, Object? httpResponseModel = null, - Object? webSocketRequestModel = null, - Object? webSocketResponseModel = null, + Object? webSocketRequestModel = freezed, + Object? webSocketResponseModel = freezed, }) { return _then(_$HistoryRequestModelImpl( historyId: null == historyId @@ -228,14 +236,14 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel, - webSocketRequestModel: null == webSocketRequestModel + webSocketRequestModel: freezed == webSocketRequestModel ? _value.webSocketRequestModel : webSocketRequestModel // ignore: cast_nullable_to_non_nullable - as WebSocketRequestModel, - webSocketResponseModel: null == webSocketResponseModel + as WebSocketRequestModel?, + webSocketResponseModel: freezed == webSocketResponseModel ? _value.webSocketResponseModel : webSocketResponseModel // ignore: cast_nullable_to_non_nullable - as WebSocketResponseModel, + as WebSocketResponseModel?, )); } } @@ -264,9 +272,9 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { @override final HttpResponseModel httpResponseModel; @override - final WebSocketRequestModel webSocketRequestModel; + final WebSocketRequestModel? webSocketRequestModel; @override - final WebSocketResponseModel webSocketResponseModel; + final WebSocketResponseModel? webSocketResponseModel; @override String toString() { @@ -326,8 +334,8 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { required final HistoryMetaModel metaData, required final HttpRequestModel httpRequestModel, required final HttpResponseModel httpResponseModel, - required final WebSocketRequestModel webSocketRequestModel, - required final WebSocketResponseModel webSocketResponseModel}) = + required final WebSocketRequestModel? webSocketRequestModel, + required final WebSocketResponseModel? webSocketResponseModel}) = _$HistoryRequestModelImpl; factory _HistoryRequestModel.fromJson(Map json) = @@ -342,9 +350,9 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { @override HttpResponseModel get httpResponseModel; @override - WebSocketRequestModel get webSocketRequestModel; + WebSocketRequestModel? get webSocketRequestModel; @override - WebSocketResponseModel get webSocketResponseModel; + WebSocketResponseModel? get webSocketResponseModel; /// Create a copy of HistoryRequestModel /// with the given fields replaced by the non-null parameter values. diff --git a/lib/models/history_request_model.g.dart b/lib/models/history_request_model.g.dart index 611b5bf86..f3aad531f 100644 --- a/lib/models/history_request_model.g.dart +++ b/lib/models/history_request_model.g.dart @@ -15,10 +15,14 @@ _$HistoryRequestModelImpl _$$HistoryRequestModelImplFromJson(Map json) => Map.from(json['httpRequestModel'] as Map)), httpResponseModel: HttpResponseModel.fromJson( Map.from(json['httpResponseModel'] as Map)), - webSocketRequestModel: WebSocketRequestModel.fromJson( - Map.from(json['webSocketRequestModel'] as Map)), - webSocketResponseModel: WebSocketResponseModel.fromJson( - Map.from(json['webSocketResponseModel'] as Map)), + webSocketRequestModel: json['webSocketRequestModel'] == null + ? null + : WebSocketRequestModel.fromJson( + Map.from(json['webSocketRequestModel'] as Map)), + webSocketResponseModel: json['webSocketResponseModel'] == null + ? null + : WebSocketResponseModel.fromJson( + Map.from(json['webSocketResponseModel'] as Map)), ); Map _$$HistoryRequestModelImplToJson( @@ -28,6 +32,6 @@ Map _$$HistoryRequestModelImplToJson( 'metaData': instance.metaData.toJson(), 'httpRequestModel': instance.httpRequestModel.toJson(), 'httpResponseModel': instance.httpResponseModel.toJson(), - 'webSocketRequestModel': instance.webSocketRequestModel.toJson(), - 'webSocketResponseModel': instance.webSocketResponseModel.toJson(), + 'webSocketRequestModel': instance.webSocketRequestModel?.toJson(), + 'webSocketResponseModel': instance.webSocketResponseModel?.toJson(), }; diff --git a/lib/providers/history_providers.dart b/lib/providers/history_providers.dart index e5ca972f3..cc7a587c9 100644 --- a/lib/providers/history_providers.dart +++ b/lib/providers/history_providers.dart @@ -1,6 +1,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/models/models.dart'; -import 'package:apidash_core/apidash_core.dart'; import '../services/services.dart' show hiveHandler, HiveHandler; import '../utils/history_utils.dart'; @@ -70,12 +69,6 @@ class HistoryMetaStateNotifier var jsonModel = await hiveHandler.getHistoryRequest(id); if (jsonModel != null) { var jsonMap = Map.from(jsonModel); - // for(var js in jsonMap.entries){ - // if(js.value!.webSocketRequestModel == null){ - // - // } - // - // } var historyRequestModelFromJson = HistoryRequestModel.fromJson(jsonMap); ref.read(selectedHistoryRequestModelProvider.notifier).state = historyRequestModelFromJson; From 2a23b459a1171b4103d75347ed7855e3950250f7 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sat, 1 Mar 2025 19:58:03 +0530 Subject: [PATCH 26/30] fixed url --- .../home_page/editor_pane/url_card.dart | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index 1ae00ac73..018b717e5 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -59,16 +59,7 @@ class EditorPaneRequestURLCard extends ConsumerWidget { APIType.rest => kHSpacer20, _ => kHSpacer8, }, - switch(apiType){ - APIType.webSocket => const Expanded( - child: URLwebSocketTextField(), - ), - _ => const Expanded( - child: URLTextField(), - ), - - - }, + const URLTextField(), kHSpacer20, switch (apiType) { APIType.rest || APIType.graphql => const SendRequestButton(), @@ -110,17 +101,27 @@ class URLTextField extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final selectedId = ref.watch(selectedIdStateProvider); - + final apiType = ref + .watch(selectedRequestModelProvider.select((value) => value?.apiType)); return EnvURLField( selectedId: selectedId!, - initialValue: ref.watch(selectedRequestModelProvider - .select((value) => value?.httpRequestModel?.url)), - // onChanged: (value) { - // - // ref.read(collectionStateNotifierProvider.notifier).update(url: value); - // }, - onFieldSubmitted: (value) { + initialValue:switch(apiType){ + APIType.rest || APIType.graphql => ref + .read(collectionStateNotifierProvider.notifier) + .getRequestModel(selectedId) + ?.httpRequestModel + ?.url, + APIType.webSocket => ref + .read(collectionStateNotifierProvider.notifier) + .getRequestModel(selectedId) + ?.webSocketRequestModel + ?.url, + _=>"" + }, + onChanged: (value) { ref.read(collectionStateNotifierProvider.notifier).update(url: value); + }, + onFieldSubmitted: (value) { ref.read(collectionStateNotifierProvider.notifier).sendRequest(); }, ); @@ -138,8 +139,11 @@ class URLwebSocketTextField extends ConsumerWidget { return EnvURLField( selectedId: selectedId!, - initialValue: ref.watch(selectedRequestModelProvider - .select((value) => value?.webSocketRequestModel?.url)), + initialValue: ref + .read(collectionStateNotifierProvider.notifier) + .getRequestModel(selectedId) + ?.httpRequestModel + ?.url, onChanged: (value) { ref.read(collectionStateNotifierProvider.notifier).update(url: value); From 78e390433dc73ee188dc529ff4df9537caa4b2d0 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Sat, 1 Mar 2025 21:38:59 +0530 Subject: [PATCH 27/30] removed web socket url --- .../home_page/editor_pane/url_card.dart | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index 018b717e5..97c7ffaa8 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -59,7 +59,9 @@ class EditorPaneRequestURLCard extends ConsumerWidget { APIType.rest => kHSpacer20, _ => kHSpacer8, }, - const URLTextField(), + const Expanded( + child: URLTextField(), + ), kHSpacer20, switch (apiType) { APIType.rest || APIType.graphql => const SendRequestButton(), @@ -128,32 +130,7 @@ class URLTextField extends ConsumerWidget { } } -class URLwebSocketTextField extends ConsumerWidget { - const URLwebSocketTextField({ - super.key, - }); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final selectedId = ref.watch(selectedIdStateProvider); - return EnvURLField( - selectedId: selectedId!, - initialValue: ref - .read(collectionStateNotifierProvider.notifier) - .getRequestModel(selectedId) - ?.httpRequestModel - ?.url, - onChanged: (value) { - - ref.read(collectionStateNotifierProvider.notifier).update(url: value); - }, - onFieldSubmitted: (value) { - ref.read(collectionStateNotifierProvider.notifier).sendRequest(); - }, - ); - } -} class SendRequestButton extends ConsumerWidget { final Function()? onTap; From 08e91dbca4ff05fea23573cac2967c0a1a4534ac Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Tue, 4 Mar 2025 19:45:33 +0530 Subject: [PATCH 28/30] last commit --- .../request_pane/request_form_data.dart | 3 +- packages/insomnia_collection/pubspec.lock | 573 ++++++++++++++++++ pubspec.lock | 50 +- 3 files changed, 600 insertions(+), 26 deletions(-) create mode 100644 packages/insomnia_collection/pubspec.lock diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart index 6b0a48c2b..a7458f4b0 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:apidash/screens/common_widgets/envfield_cell.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:data_table_2/data_table_2.dart'; @@ -138,7 +139,7 @@ class _FormDataBodyState extends ConsumerState { }, initialValue: formRows[index].value, ) - : CellField( + : EnvCellField( keyId: "$selectedId-$index-form-v-$seed", initialValue: formRows[index].value, hintText: kHintAddValue, diff --git a/packages/insomnia_collection/pubspec.lock b/packages/insomnia_collection/pubspec.lock new file mode 100644 index 000000000..e2a8a7007 --- /dev/null +++ b/packages/insomnia_collection/pubspec.lock @@ -0,0 +1,573 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 + url: "https://pub.dev" + source: hosted + version: "80.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e" + url: "https://pub.dev" + source: hosted + version: "7.3.0" + args: + dependency: transitive + description: + name: args + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + url: "https://pub.dev" + source: hosted + version: "2.6.0" + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + build: + dependency: transitive + description: + name: build + sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" + url: "https://pub.dev" + source: hosted + version: "4.0.4" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 + url: "https://pub.dev" + source: hosted + version: "2.4.4" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" + url: "https://pub.dev" + source: hosted + version: "2.4.15" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" + url: "https://pub.dev" + source: hosted + version: "8.0.0" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61" + url: "https://pub.dev" + source: hosted + version: "8.9.4" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + url: "https://pub.dev" + source: hosted + version: "4.10.1" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 + url: "https://pub.dev" + source: hosted + version: "1.11.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "59a584c24b3acdc5250bb856d0d3e9c0b798ed14a4af1ddb7dc1c7b41df91c9c" + url: "https://pub.dev" + source: hosted + version: "2.5.8" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + url: "https://pub.dev" + source: hosted + version: "2.4.4" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + http: + dependency: transitive + description: + name: http + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + url: "https://pub.dev" + source: hosted + version: "1.3.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + js: + dependency: transitive + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: "81f04dee10969f89f604e1249382d46b97a1ccad53872875369622b5bfc9e58a" + url: "https://pub.dev" + source: hosted + version: "6.9.4" + lints: + dependency: "direct dev" + description: + name: lints + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + meta: + dependency: transitive + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" + url: "https://pub.dev" + source: hosted + version: "1.3.5" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test: + dependency: "direct dev" + description: + name: test + sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" + url: "https://pub.dev" + source: hosted + version: "1.25.15" + test_api: + dependency: transitive + description: + name: test_api + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" + source: hosted + version: "0.7.4" + test_core: + dependency: transitive + description: + name: test_core + sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" + url: "https://pub.dev" + source: hosted + version: "0.6.8" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" + source: hosted + version: "15.0.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.7.0-0 <4.0.0" diff --git a/pubspec.lock b/pubspec.lock index 3504805f4..ff9c6365a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -176,10 +176,10 @@ packages: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" charcode: dependency: transitive description: @@ -240,10 +240,10 @@ packages: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.19.1" conventional_commit: dependency: transitive description: @@ -940,10 +940,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -964,10 +964,10 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" mime: dependency: transitive description: @@ -1519,10 +1519,10 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" spot: dependency: "direct dev" description: @@ -1543,10 +1543,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.12.1" state_notifier: dependency: transitive description: @@ -1559,10 +1559,10 @@ packages: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" stream_transform: dependency: transitive description: @@ -1575,10 +1575,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" sync_http: dependency: transitive description: @@ -1591,34 +1591,34 @@ packages: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test: dependency: "direct dev" description: name: test - sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" + sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" url: "https://pub.dev" source: hosted - version: "1.25.8" + version: "1.25.15" test_api: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.4" test_core: dependency: transitive description: name: test_core - sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" + sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.8" textwrap: dependency: transitive description: @@ -1925,5 +1925,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=3.5.3 <3.999.0" + dart: ">=3.7.0-0 <3.999.0" flutter: ">=3.24.2" From 411c7b4cb7bf5cdbc4f6e8f94f6f0d9d340f9876 Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Tue, 4 Mar 2025 19:53:46 +0530 Subject: [PATCH 29/30] redo --- .../details_card/request_pane/request_form_data.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart index a7458f4b0..6b0a48c2b 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart @@ -1,7 +1,6 @@ import 'dart:math'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; -import 'package:apidash/screens/common_widgets/envfield_cell.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:data_table_2/data_table_2.dart'; @@ -139,7 +138,7 @@ class _FormDataBodyState extends ConsumerState { }, initialValue: formRows[index].value, ) - : EnvCellField( + : CellField( keyId: "$selectedId-$index-form-v-$seed", initialValue: formRows[index].value, hintText: kHintAddValue, From d63a8101367b0e0b586dce78db7ee60491c1f30e Mon Sep 17 00:00:00 2001 From: Clasherzz Date: Tue, 4 Mar 2025 22:43:44 +0530 Subject: [PATCH 30/30] final commit --- lib/utils/ui_utils.dart | 1 + packages/apidash_design_system/lib/tokens/colors.dart | 2 ++ pubspec.lock | 1 - 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/utils/ui_utils.dart b/lib/utils/ui_utils.dart index 4f72a1a3f..134edf55d 100644 --- a/lib/utils/ui_utils.dart +++ b/lib/utils/ui_utils.dart @@ -36,6 +36,7 @@ Color getAPIColor( method, ), APIType.graphql => kColorGQL, + APIType.webSocket => kColorWS, }; if (brightness == Brightness.dark) { col = getDarkModeColor(col); diff --git a/packages/apidash_design_system/lib/tokens/colors.dart b/packages/apidash_design_system/lib/tokens/colors.dart index 11943bd32..d0bd38033 100644 --- a/packages/apidash_design_system/lib/tokens/colors.dart +++ b/packages/apidash_design_system/lib/tokens/colors.dart @@ -26,6 +26,8 @@ final kColorHttpMethodDelete = Colors.red.shade800; final kColorGQL = Colors.pink.shade600; +final kColorWS = Colors.deepOrange.shade800; + const kHintOpacity = 0.6; const kForegroundOpacity = 0.05; const kOverlayBackgroundOpacity = 0.5; diff --git a/pubspec.lock b/pubspec.lock index 1e44ef58d..c95ad17ff 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1953,4 +1953,3 @@ packages: sdks: dart: ">=3.7.0-0 <3.999.0" flutter: ">=3.29.0" -