From fcc940ec2e1cf338c2924db39cb9b32c35523c20 Mon Sep 17 00:00:00 2001 From: Jeet Dalal Date: Sun, 11 Aug 2024 13:40:47 +0530 Subject: [PATCH 01/31] resolved issue #178(switch from GET->POST if payload exists) --- .../request_pane/request_body.dart | 31 +++++++++++- .../request_pane/request_form_data.dart | 5 +- pubspec.yaml | 1 + test/providers/collection_providers_test.dart | 50 +++++++++++++++++++ test/providers/helpers.dart | 40 +++++++++++++++ test/providers/ui_providers_test.dart | 2 - 6 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 test/providers/collection_providers_test.dart create mode 100644 test/providers/helpers.dart 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 39011d81..065feefe 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,6 @@ +import 'dart:developer'; + +import 'package:apidash/models/models.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; @@ -17,6 +20,25 @@ class EditRequestBody extends ConsumerWidget { final contentType = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.bodyContentType)); + void changeToPostMethod() { + RequestModel? model = ref + .read(collectionStateNotifierProvider.notifier) + .getRequestModel(selectedId); + + if (model!.httpRequestModel!.method == HTTPVerb.get) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(selectedId, method: HTTPVerb.post); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text( + "Switched to POST method", + style: TextStyle(color: Colors.white), + ), + backgroundColor: Colors.black, + )); + } + } + return Column( children: [ const SizedBox( @@ -33,8 +55,11 @@ class EditRequestBody extends ConsumerWidget { ), Expanded( child: switch (contentType) { - ContentType.formdata => - const Padding(padding: kPh4, child: FormDataWidget()), + ContentType.formdata => Padding( + padding: kPh4, + child: FormDataWidget( + changeMethodToPost: changeToPostMethod, + )), // TODO: Fix JsonTextFieldEditor & plug it here ContentType.json => Padding( padding: kPt5o10, @@ -43,6 +68,7 @@ class EditRequestBody extends ConsumerWidget { fieldKey: "$selectedId-json-body-editor", initialValue: requestModel?.httpRequestModel?.body, onChanged: (String value) { + changeToPostMethod(); ref .read(collectionStateNotifierProvider.notifier) .update(selectedId, body: value); @@ -56,6 +82,7 @@ class EditRequestBody extends ConsumerWidget { fieldKey: "$selectedId-body-editor", initialValue: requestModel?.httpRequestModel?.body, onChanged: (String value) { + changeToPostMethod(); ref .read(collectionStateNotifierProvider.notifier) .update(selectedId, body: value); 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 5228c660..eff4c821 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 @@ -9,7 +9,8 @@ import 'package:apidash/utils/utils.dart'; import 'package:apidash/consts.dart'; class FormDataWidget extends ConsumerStatefulWidget { - const FormDataWidget({super.key}); + final Function changeMethodToPost; + const FormDataWidget({required this.changeMethodToPost, super.key}); @override ConsumerState createState() => _FormDataBodyState(); } @@ -27,6 +28,7 @@ class _FormDataBodyState extends ConsumerState { } void _onFieldChange(String selectedId) { + widget.changeMethodToPost(); ref.read(collectionStateNotifierProvider.notifier).update( selectedId, formData: formRows.sublist(0, formRows.length - 1), @@ -41,6 +43,7 @@ class _FormDataBodyState extends ConsumerState { .select((value) => value?.httpRequestModel?.formData?.length)); var rF = ref.read(selectedRequestModelProvider)?.httpRequestModel?.formData; bool isFormDataEmpty = rF == null || rF.isEmpty; + formRows = isFormDataEmpty ? [ kFormDataEmptyModel, diff --git a/pubspec.yaml b/pubspec.yaml index 7d119b21..36b5640c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -73,6 +73,7 @@ dependencies: git: url: https://github.com/foss42/curl_converter.git ref: 726e8cd04aeb326211af27f75920be5b21c90bb4 + dependency_overrides: web: ^0.5.0 diff --git a/test/providers/collection_providers_test.dart b/test/providers/collection_providers_test.dart new file mode 100644 index 00000000..7cabaae4 --- /dev/null +++ b/test/providers/collection_providers_test.dart @@ -0,0 +1,50 @@ +import 'package:apidash/consts.dart'; +import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/request_body.dart'; +import 'package:apidash/widgets/editor.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'helpers.dart'; + +void main() async { + setUp(() async => await testSetUp()); + + testWidgets( + 'Request method changes from GET to POST when body is added and Snackbar is shown', + (WidgetTester tester) async { + // Set up the test environment + final container = createContainer(); + final notifier = container.read(collectionStateNotifierProvider.notifier); + + // Ensure the initial request is a GET request with no body + final id = notifier.state!.entries.first.key; + expect( + notifier.getRequestModel(id)!.httpRequestModel!.method, HTTPVerb.get); + expect(notifier.getRequestModel(id)!.httpRequestModel!.body, isNull); + + // Build the EditRequestBody widget + await tester.pumpWidget( + ProviderScope( + // ignore: deprecated_member_use + parent: container, + child: const MaterialApp( + home: Scaffold( + body: EditRequestBody(), + ), + ), + ), + ); + + // Add a body to the request, which should trigger the method change + await tester.enterText(find.byType(TextFieldEditor), 'new body added'); + await tester.pump(); // Process the state change + + // Verify that the request method changed to POST + expect( + notifier.getRequestModel(id)!.httpRequestModel!.method, HTTPVerb.post); + + // Verify that the Snackbar is shown + expect(find.text('Switched to POST method'), findsOneWidget); + }); +} diff --git a/test/providers/helpers.dart b/test/providers/helpers.dart new file mode 100644 index 00000000..f0ab2915 --- /dev/null +++ b/test/providers/helpers.dart @@ -0,0 +1,40 @@ +import 'package:apidash/services/hive_services.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; + +/// A testing utility which creates a [ProviderContainer] and automatically +/// disposes it at the end of the test. +ProviderContainer createContainer({ + ProviderContainer? parent, + List overrides = const [], + List? observers, +}) { + // Create a ProviderContainer, and optionally allow specifying parameters. + final container = ProviderContainer( + parent: parent, + overrides: overrides, + observers: observers, + ); + + // When the test ends, dispose the container. + addTearDown(container.dispose); + + return container; +} + +Future testSetUp() async { + // override path_provider methodCall to point + // path to temporary location for all unit tests + TestWidgetsFlutterBinding.ensureInitialized(); + const MethodChannel channel = + MethodChannel('plugins.flutter.io/path_provider'); + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { + return './test/unit-test-hive-storage/'; + }); + + await openBoxes(); +} diff --git a/test/providers/ui_providers_test.dart b/test/providers/ui_providers_test.dart index ba2b2b85..ea2b5012 100644 --- a/test/providers/ui_providers_test.dart +++ b/test/providers/ui_providers_test.dart @@ -1,6 +1,4 @@ import 'dart:io'; -import 'package:spot/spot.dart'; -import 'package:apidash/consts.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/screens/common_widgets/common_widgets.dart'; import 'package:apidash/screens/dashboard.dart'; From bd5c83525e028958631ce6b0e65680405c6743d9 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 8 Sep 2024 05:05:00 +0530 Subject: [PATCH 02/31] kEncoder -> kJsonEncoder --- lib/codegen/java/okhttp.dart | 2 +- lib/codegen/js/axios.dart | 13 +++++++------ lib/codegen/js/fetch.dart | 4 ++-- lib/codegen/others/har.dart | 2 +- lib/codegen/python/http_client.dart | 4 ++-- lib/codegen/python/requests.dart | 4 ++-- lib/consts.dart | 3 ++- lib/utils/convert_utils.dart | 2 +- lib/utils/http_utils.dart | 2 +- lib/widgets/json_previewer.dart | 6 +++--- lib/widgets/response_widgets.dart | 2 +- 11 files changed, 23 insertions(+), 21 deletions(-) diff --git a/lib/codegen/java/okhttp.dart b/lib/codegen/java/okhttp.dart index 12b2f90f..9045aa55 100644 --- a/lib/codegen/java/okhttp.dart +++ b/lib/codegen/java/okhttp.dart @@ -140,7 +140,7 @@ import okhttp3.MultipartBody;"""; var templateBody = jj.Template(kTemplateRequestBody); result += templateBody.render({ "contentType": contentType, - "body": kEncoder.convert(requestBody) + "body": kJsonEncoder.convert(requestBody) }); } } diff --git a/lib/codegen/js/axios.dart b/lib/codegen/js/axios.dart index faf97304..6314bdcd 100644 --- a/lib/codegen/js/axios.dart +++ b/lib/codegen/js/axios.dart @@ -79,7 +79,7 @@ axios(config) m[i["name"]] = i["value"]; } result += templateParams - .render({"params": padMultilineString(kEncoder.convert(m), 2)}); + .render({"params": padMultilineString(kJsonEncoder.convert(m), 2)}); } var headers = harJson["headers"]; @@ -92,8 +92,8 @@ axios(config) if (requestModel.hasFormData) { m[kHeaderContentType] = ContentType.formdata.header; } - result += templateHeader - .render({"headers": padMultilineString(kEncoder.convert(m), 2)}); + result += templateHeader.render( + {"headers": padMultilineString(kJsonEncoder.convert(m), 2)}); } var templateBody = jj.Template(kTemplateBody); if (requestModel.hasFormData && requestModel.formDataMapList.isNotEmpty) { @@ -108,12 +108,13 @@ axios(config) : "fileInput$formFileCounter.files[0]"; if (element["type"] == "file") formFileCounter++; } - var sanitizedJSObject = sanitzeJSObject(kEncoder.convert(formParams)); + var sanitizedJSObject = + sanitzeJSObject(kJsonEncoder.convert(formParams)); result += templateBody .render({"body": padMultilineString(sanitizedJSObject, 2)}); } else if (harJson["postData"]?["text"] != null) { - result += templateBody - .render({"body": kEncoder.convert(harJson["postData"]["text"])}); + result += templateBody.render( + {"body": kJsonEncoder.convert(harJson["postData"]["text"])}); } result += kStringRequest; return result; diff --git a/lib/codegen/js/fetch.dart b/lib/codegen/js/fetch.dart index 21c4f238..c4ca14b0 100644 --- a/lib/codegen/js/fetch.dart +++ b/lib/codegen/js/fetch.dart @@ -106,7 +106,7 @@ fetch(url, options) } if (m.isNotEmpty) { result += templateHeader.render({ - "headers": padMultilineString(kEncoder.convert(m), 2), + "headers": padMultilineString(kJsonEncoder.convert(m), 2), }); } } @@ -114,7 +114,7 @@ fetch(url, options) if (harJson["postData"]?["text"] != null) { var templateBody = jj.Template(kTemplateBody); result += templateBody.render({ - "body": kEncoder.convert(harJson["postData"]["text"]), + "body": kJsonEncoder.convert(harJson["postData"]["text"]), }); } else if (requestModel.hasFormData) { var templateBody = jj.Template(kTemplateBody); diff --git a/lib/codegen/others/har.dart b/lib/codegen/others/har.dart index 32a35abe..acef6357 100644 --- a/lib/codegen/others/har.dart +++ b/lib/codegen/others/har.dart @@ -9,7 +9,7 @@ class HARCodeGen { String? boundary, }) { try { - var harString = kEncoder.convert(requestModelToHARJsonRequest( + var harString = kJsonEncoder.convert(requestModelToHARJsonRequest( requestModel, defaultUriScheme: defaultUriScheme, useEnabled: true, diff --git a/lib/codegen/python/http_client.dart b/lib/codegen/python/http_client.dart index ea783ebe..f58607c2 100644 --- a/lib/codegen/python/http_client.dart +++ b/lib/codegen/python/http_client.dart @@ -111,7 +111,7 @@ body = b'\r\n'.join(dataList) if (params.isNotEmpty) { hasQuery = true; var templateParams = jj.Template(kTemplateParams); - var paramsString = kEncoder.convert(params); + var paramsString = kJsonEncoder.convert(params); result += templateParams.render({"params": paramsString}); } } @@ -143,7 +143,7 @@ body = b'\r\n'.join(dataList) }); } } - var headersString = kEncoder.convert(headers); + var headersString = kJsonEncoder.convert(headers); var templateHeaders = jj.Template(kTemplateHeaders); result += templateHeaders.render({"headers": headersString}); } diff --git a/lib/codegen/python/requests.dart b/lib/codegen/python/requests.dart index bb41ad9d..8ca4c152 100644 --- a/lib/codegen/python/requests.dart +++ b/lib/codegen/python/requests.dart @@ -107,7 +107,7 @@ print('Response Body:', response.text) if (params.isNotEmpty) { hasQuery = true; var templateParams = jj.Template(kTemplateParams); - var paramsString = kEncoder.convert(params); + var paramsString = kJsonEncoder.convert(params); result += templateParams.render({"params": paramsString}); } } @@ -162,7 +162,7 @@ print('Response Body:', response.text) } if (headers.isNotEmpty) { hasHeaders = true; - var headersString = kEncoder.convert(headers); + var headersString = kJsonEncoder.convert(headers); headersString = refactorHeaderString(headersString); var templateHeaders = jj.Template(kTemplateHeaders); result += templateHeaders.render({"headers": headersString}); diff --git a/lib/consts.dart b/lib/consts.dart index 9d72e0e3..1681069a 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -413,7 +413,8 @@ enum ImportFormat { final String label; } -const JsonEncoder kEncoder = JsonEncoder.withIndent(' '); +const JsonEncoder kJsonEncoder = JsonEncoder.withIndent(' '); +const JsonDecoder kJsonDecoder = JsonDecoder(); const LineSplitter kSplitter = LineSplitter(); const String kGlobalEnvironmentId = "global"; diff --git a/lib/utils/convert_utils.dart b/lib/utils/convert_utils.dart index d0b2ac26..b3c3b2bc 100644 --- a/lib/utils/convert_utils.dart +++ b/lib/utils/convert_utils.dart @@ -150,7 +150,7 @@ Uint8List jsonMapToBytes(Map? map) { if (map == null) { return Uint8List.fromList([]); } else { - String text = kEncoder.convert(map); + String text = kJsonEncoder.convert(map); var l = utf8.encode(text); var bytes = Uint8List.fromList(l); return bytes; diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart index 4688d2af..e323939a 100644 --- a/lib/utils/http_utils.dart +++ b/lib/utils/http_utils.dart @@ -138,7 +138,7 @@ String? formatBody(String? body, MediaType? mediaType) { try { if (subtype.contains(kSubTypeJson)) { final tmp = jsonDecode(body); - String result = kEncoder.convert(tmp); + String result = kJsonEncoder.convert(tmp); return result; } if (subtype.contains(kSubTypeXml)) { diff --git a/lib/widgets/json_previewer.dart b/lib/widgets/json_previewer.dart index 3a4f5648..020015d6 100644 --- a/lib/widgets/json_previewer.dart +++ b/lib/widgets/json_previewer.dart @@ -182,7 +182,7 @@ class _JsonPreviewerState extends State { TextButton( onPressed: () async { await _copy( - kEncoder.convert(widget.code), sm); + kJsonEncoder.convert(widget.code), sm); }, child: const Text( 'Copy', @@ -215,7 +215,7 @@ class _JsonPreviewerState extends State { visualDensity: VisualDensity.compact, onPressed: () async { await _copy( - kEncoder.convert(widget.code), sm); + kJsonEncoder.convert(widget.code), sm); }, icon: const Icon( Icons.copy, @@ -273,7 +273,7 @@ class _JsonPreviewerState extends State { ), onPressed: () async { await _copy( - kEncoder.convert(toJson(node)), sm); + kJsonEncoder.convert(toJson(node)), sm); }, ), ) diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index 0df9343b..42154478 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -262,7 +262,7 @@ class ResponseHeadersHeader extends StatelessWidget { ), if (map.isNotEmpty) CopyButton( - toCopy: kEncoder.convert(map), + toCopy: kJsonEncoder.convert(map), ), ], ), From 802d9e4607abf9644f4e63457a67be8e589d90b8 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 8 Sep 2024 15:17:21 +0530 Subject: [PATCH 03/31] workspace --- lib/app.dart | 2 +- lib/main.dart | 53 ++++++++++++---- lib/models/settings_model.dart | 19 ++++-- lib/providers/settings_providers.dart | 15 ++--- lib/services/history_service.dart | 13 +--- lib/services/hive_services.dart | 37 +++-------- lib/services/services.dart | 1 + lib/services/shared_preferences_services.dart | 23 +++++++ lib/utils/history_utils.dart | 2 +- lib/widgets/widgets.dart | 1 + lib/widgets/workspace_selector.dart | 62 +++++++++++++++++++ pubspec.lock | 56 +++++++++++++++++ pubspec.yaml | 1 + test/providers/ui_providers_test.dart | 2 +- 14 files changed, 220 insertions(+), 67 deletions(-) create mode 100644 lib/services/shared_preferences_services.dart create mode 100644 lib/widgets/workspace_selector.dart diff --git a/lib/app.dart b/lib/app.dart index 3d36968a..7083eb4a 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_portal/flutter_portal.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:window_manager/window_manager.dart' hide WindowCaption; -import 'widgets/widgets.dart' show WindowCaption; +import 'widgets/widgets.dart' show WindowCaption, WorkspaceSelector; import 'providers/providers.dart'; import 'extensions/extensions.dart'; import 'screens/screens.dart'; diff --git a/lib/main.dart b/lib/main.dart index 4a8b07fd..6c70bdf8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,35 +1,62 @@ +import 'package:apidash/providers/settings_providers.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'models/models.dart'; +import 'providers/providers.dart'; import 'services/services.dart'; -import 'consts.dart' show kIsLinux, kIsMacOS, kIsWindows; +import 'consts.dart'; import 'app.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - - await initApp(); - await initWindow(); + final settingsModel = await getSettingsFromSharedPrefs(); + await initApp(settingsModel: settingsModel); + if (kIsDesktop) { + await initWindow(settingsModel: settingsModel); + } runApp( - const ProviderScope( - child: DashApp(), + ProviderScope( + overrides: [ + settingsProvider.overrideWith( + (ref) => ThemeStateNotifier(settingsModel: settingsModel), + ) + ], + child: const DashApp(), ), ); } -Future initApp() async { +Future initApp({SettingsModel? settingsModel}) async { GoogleFonts.config.allowRuntimeFetching = false; - await openBoxes(); - await autoClearHistory(); + await openBoxes( + kIsDesktop, + settingsModel?.workspaceFolderPath, + ); + await autoClearHistory(settingsModel: settingsModel); } -Future initWindow({Size? sz}) async { +Future initWindow({ + Size? sz, + SettingsModel? settingsModel, +}) async { if (kIsLinux) { - await setupInitialWindow(sz: sz); + await setupInitialWindow( + sz: sz ?? settingsModel?.size, + ); } if (kIsMacOS || kIsWindows) { - var win = sz != null ? (sz, const Offset(100, 100)) : getInitialSize(); - await setupWindow(sz: win.$1, off: win.$2); + if (sz != null) { + await setupWindow( + sz: sz, + off: const Offset(100, 100), + ); + } else { + await setupWindow( + sz: settingsModel?.size, + off: settingsModel?.offset, + ); + } } } diff --git a/lib/models/settings_model.dart b/lib/models/settings_model.dart index e82ffdca..e7e5c3b0 100644 --- a/lib/models/settings_model.dart +++ b/lib/models/settings_model.dart @@ -14,6 +14,7 @@ class SettingsModel { this.promptBeforeClosing = true, this.activeEnvironmentId, this.historyRetentionPeriod = HistoryRetentionPeriod.oneWeek, + this.workspaceFolderPath, }); final bool isDark; @@ -26,6 +27,7 @@ class SettingsModel { final bool promptBeforeClosing; final String? activeEnvironmentId; final HistoryRetentionPeriod historyRetentionPeriod; + final String? workspaceFolderPath; SettingsModel copyWith({ bool? isDark, @@ -38,6 +40,7 @@ class SettingsModel { bool? promptBeforeClosing, String? activeEnvironmentId, HistoryRetentionPeriod? historyRetentionPeriod, + String? workspaceFolderPath, }) { return SettingsModel( isDark: isDark ?? this.isDark, @@ -52,6 +55,7 @@ class SettingsModel { activeEnvironmentId: activeEnvironmentId ?? this.activeEnvironmentId, historyRetentionPeriod: historyRetentionPeriod ?? this.historyRetentionPeriod, + workspaceFolderPath: workspaceFolderPath ?? this.workspaceFolderPath, ); } @@ -86,8 +90,7 @@ class SettingsModel { final promptBeforeClosing = data["promptBeforeClosing"] as bool?; final activeEnvironmentId = data["activeEnvironmentId"] as String?; final historyRetentionPeriodStr = data["historyRetentionPeriod"] as String?; - HistoryRetentionPeriod historyRetentionPeriod = - HistoryRetentionPeriod.oneWeek; + HistoryRetentionPeriod? historyRetentionPeriod; if (historyRetentionPeriodStr != null) { try { historyRetentionPeriod = @@ -96,6 +99,7 @@ class SettingsModel { // pass } } + final workspaceFolderPath = data["workspaceFolderPath"] as String?; const sm = SettingsModel(); @@ -109,7 +113,9 @@ class SettingsModel { saveResponses: saveResponses, promptBeforeClosing: promptBeforeClosing, activeEnvironmentId: activeEnvironmentId, - historyRetentionPeriod: historyRetentionPeriod, + historyRetentionPeriod: + historyRetentionPeriod ?? HistoryRetentionPeriod.oneWeek, + workspaceFolderPath: workspaceFolderPath, ); } @@ -127,12 +133,13 @@ class SettingsModel { "promptBeforeClosing": promptBeforeClosing, "activeEnvironmentId": activeEnvironmentId, "historyRetentionPeriod": historyRetentionPeriod.name, + "workspaceFolderPath": workspaceFolderPath, }; } @override String toString() { - return toJson().toString(); + return kJsonEncoder.convert(toJson()); } @override @@ -149,7 +156,8 @@ class SettingsModel { other.saveResponses == saveResponses && other.promptBeforeClosing == promptBeforeClosing && other.activeEnvironmentId == activeEnvironmentId && - other.historyRetentionPeriod == historyRetentionPeriod; + other.historyRetentionPeriod == historyRetentionPeriod && + other.workspaceFolderPath == workspaceFolderPath; } @override @@ -166,6 +174,7 @@ class SettingsModel { promptBeforeClosing, activeEnvironmentId, historyRetentionPeriod, + workspaceFolderPath, ); } } diff --git a/lib/providers/settings_providers.dart b/lib/providers/settings_providers.dart index 6293e04b..43256ab3 100644 --- a/lib/providers/settings_providers.dart +++ b/lib/providers/settings_providers.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../models/models.dart'; -import '../services/services.dart' show hiveHandler, HiveHandler; +import '../services/services.dart'; import '../consts.dart'; final codegenLanguageStateProvider = StateProvider((ref) => @@ -11,14 +11,13 @@ final activeEnvironmentIdStateProvider = StateProvider((ref) => ref.watch(settingsProvider.select((value) => value.activeEnvironmentId))); final StateNotifierProvider - settingsProvider = - StateNotifierProvider((ref) => ThemeStateNotifier(hiveHandler)); + settingsProvider = StateNotifierProvider((ref) => ThemeStateNotifier()); class ThemeStateNotifier extends StateNotifier { - ThemeStateNotifier(this.hiveHandler) : super(const SettingsModel()) { - state = SettingsModel.fromJson(hiveHandler.settings); + ThemeStateNotifier({this.settingsModel}) : super(const SettingsModel()) { + state = settingsModel ?? const SettingsModel(); } - final HiveHandler hiveHandler; + final SettingsModel? settingsModel; Future update({ bool? isDark, @@ -31,6 +30,7 @@ class ThemeStateNotifier extends StateNotifier { bool? promptBeforeClosing, String? activeEnvironmentId, HistoryRetentionPeriod? historyRetentionPeriod, + String? workspaceFolderPath, }) async { state = state.copyWith( isDark: isDark, @@ -43,7 +43,8 @@ class ThemeStateNotifier extends StateNotifier { promptBeforeClosing: promptBeforeClosing, activeEnvironmentId: activeEnvironmentId, historyRetentionPeriod: historyRetentionPeriod, + workspaceFolderPath: workspaceFolderPath, ); - await hiveHandler.saveSettings(state.toJson()); + await setSettingsToSharedPrefs(state); } } diff --git a/lib/services/history_service.dart b/lib/services/history_service.dart index d34d17fb..487b9164 100644 --- a/lib/services/history_service.dart +++ b/lib/services/history_service.dart @@ -1,18 +1,9 @@ import 'package:apidash/models/models.dart'; import 'package:apidash/utils/utils.dart'; -import 'package:apidash/consts.dart'; import 'hive_services.dart'; -Future autoClearHistory() async { - final settingsMap = hiveHandler.settings; - final retentionPeriod = settingsMap['historyRetentionPeriod']; - - HistoryRetentionPeriod historyRetentionPeriod = - HistoryRetentionPeriod.oneWeek; - if (retentionPeriod != null) { - historyRetentionPeriod = - HistoryRetentionPeriod.values.byName(retentionPeriod); - } +Future autoClearHistory({SettingsModel? settingsModel}) async { + final historyRetentionPeriod = settingsModel?.historyRetentionPeriod; DateTime? retentionDate = getRetentionDate(historyRetentionPeriod); if (retentionDate == null) { diff --git a/lib/services/hive_services.dart b/lib/services/hive_services.dart index 1a0f7ac0..3caa3c28 100644 --- a/lib/services/hive_services.dart +++ b/lib/services/hive_services.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:hive_flutter/hive_flutter.dart'; const String kDataBox = "apidash-data"; @@ -11,54 +10,36 @@ const String kHistoryMetaBox = "apidash-history-meta"; const String kHistoryBoxIds = "historyIds"; const String kHistoryLazyBox = "apidash-history-lazy"; -const String kSettingsBox = "apidash-settings"; - -Future openBoxes() async { - await Hive.initFlutter(); +Future openBoxes( + bool isDesktop, + String? workspaceFolderPath, +) async { + if (isDesktop) { + Hive.init(workspaceFolderPath); + } else { + await Hive.initFlutter(); + } await Hive.openBox(kDataBox); - await Hive.openBox(kSettingsBox); await Hive.openBox(kEnvironmentBox); await Hive.openBox(kHistoryMetaBox); await Hive.openLazyBox(kHistoryLazyBox); } -(Size?, Offset?) getInitialSize() { - Size? sz; - Offset? off; - var settingsBox = Hive.box(kSettingsBox); - double? w = settingsBox.get("width") as double?; - double? h = settingsBox.get("height") as double?; - if (w != null && h != null) { - sz = Size(w, h); - } - double? dx = settingsBox.get("dx") as double?; - double? dy = settingsBox.get("dy") as double?; - if (dx != null && dy != null) { - off = Offset(dx, dy); - } - return (sz, off); -} - final hiveHandler = HiveHandler(); class HiveHandler { late final Box dataBox; - late final Box settingsBox; late final Box environmentBox; late final Box historyMetaBox; late final LazyBox historyLazyBox; HiveHandler() { dataBox = Hive.box(kDataBox); - settingsBox = Hive.box(kSettingsBox); environmentBox = Hive.box(kEnvironmentBox); historyMetaBox = Hive.box(kHistoryMetaBox); historyLazyBox = Hive.lazyBox(kHistoryLazyBox); } - Map get settings => settingsBox.toMap(); - Future saveSettings(Map data) => settingsBox.putAll(data); - dynamic getIds() => dataBox.get(kKeyDataBoxIds); Future setIds(List? ids) => dataBox.put(kKeyDataBoxIds, ids); diff --git a/lib/services/services.dart b/lib/services/services.dart index 7551de9b..fd8ca0b0 100644 --- a/lib/services/services.dart +++ b/lib/services/services.dart @@ -2,3 +2,4 @@ export 'http_service.dart'; export 'hive_services.dart'; export 'history_service.dart'; export 'window_services.dart'; +export 'shared_preferences_services.dart'; diff --git a/lib/services/shared_preferences_services.dart b/lib/services/shared_preferences_services.dart new file mode 100644 index 00000000..af1bbd71 --- /dev/null +++ b/lib/services/shared_preferences_services.dart @@ -0,0 +1,23 @@ +import 'package:apidash/consts.dart'; +import 'package:apidash/models/models.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +const String kSharedPrefSettingsKey = 'apidash-settings'; + +Future getSettingsFromSharedPrefs() async { + final prefs = await SharedPreferences.getInstance(); + var settingsStr = prefs.getString(kSharedPrefSettingsKey); + if (settingsStr != null) { + var jsonSettings = kJsonDecoder.convert(settingsStr); + var jsonMap = Map.from(jsonSettings); + var settingsModel = SettingsModel.fromJson(jsonMap); + return settingsModel; + } else { + return null; + } +} + +Future setSettingsToSharedPrefs(SettingsModel settingsModel) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString(kSharedPrefSettingsKey, settingsModel.toString()); +} diff --git a/lib/utils/history_utils.dart b/lib/utils/history_utils.dart index cce87998..e6db9d38 100644 --- a/lib/utils/history_utils.dart +++ b/lib/utils/history_utils.dart @@ -114,7 +114,7 @@ List getRequestGroup( return requestGroup; } -DateTime? getRetentionDate(HistoryRetentionPeriod retentionPeriod) { +DateTime? getRetentionDate(HistoryRetentionPeriod? retentionPeriod) { DateTime now = DateTime.now(); DateTime today = stripTime(now); diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index 06bc4bef..b7a8732e 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -60,3 +60,4 @@ export 'tabs.dart'; export 'texts.dart'; export 'uint8_audio_player.dart'; export 'window_caption.dart'; +export 'workspace_selector.dart'; diff --git a/lib/widgets/workspace_selector.dart b/lib/widgets/workspace_selector.dart new file mode 100644 index 00000000..1ff7ddd5 --- /dev/null +++ b/lib/widgets/workspace_selector.dart @@ -0,0 +1,62 @@ +import 'package:file_selector/file_selector.dart'; +import 'package:apidash/services/hive_services.dart'; +import 'package:flutter/material.dart'; + +class WorkspaceSelector extends StatefulWidget { + final Future Function(String)? onSelect; + const WorkspaceSelector({ + super.key, + required this.onSelect, + }); + + @override + WorkspaceSelectorState createState() => WorkspaceSelectorState(); +} + +class WorkspaceSelectorState extends State { + void selectFolder() async { + String? selectedDirectory = await getDirectoryPath(); + if (selectedDirectory != null) { + widget.onSelect?.call(selectedDirectory); + } + } + + @override + Widget build(BuildContext context) { + const circularLoader = MaterialApp( + home: Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ), + ); + + return FutureBuilder( + future: getHiveSaveFolder(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState != ConnectionState.done) { + return circularLoader; + } + + // If there isn't hive selected folder choose it + if (snapshot.data == null) { + selectFolder(); + return circularLoader; + } + + // Once _hiveSaveFolder is set, display DashApp after hive init + return FutureBuilder( + future: openHiveBoxes(snapshot.data!), + builder: (BuildContext context, AsyncSnapshot snapshot) { + // if loading show circularLoader + if (snapshot.connectionState != ConnectionState.done) { + return circularLoader; + } + // Display widget + return widget.child; + }, + ); + }, + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index f4140996..2c257859 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1215,6 +1215,62 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.8" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f + url: "https://pub.dev" + source: hosted + version: "2.5.2" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0eadf529..a9bf5998 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,6 +63,7 @@ dependencies: provider: ^6.1.2 riverpod: ^2.5.1 scrollable_positioned_list: ^0.3.8 + shared_preferences: ^2.3.2 url_launcher: ^6.2.5 uuid: ^4.3.3 vector_graphics_compiler: ^1.1.9+1 diff --git a/test/providers/ui_providers_test.dart b/test/providers/ui_providers_test.dart index 39ef1ff6..60b67241 100644 --- a/test/providers/ui_providers_test.dart +++ b/test/providers/ui_providers_test.dart @@ -39,7 +39,7 @@ void main() { } return null; }); - await openBoxes(); + await openBoxes(false, null); final flamante = rootBundle.load('google_fonts/OpenSans-Medium.ttf'); final fontLoader = FontLoader('OpenSans')..addFont(flamante); await fontLoader.load(); From 59fdbae41d84f23b8a6d7c9476428a680a8934ce Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 9 Sep 2024 04:03:52 +0530 Subject: [PATCH 04/31] Workspace selector feature --- lib/app.dart | 53 ++++++--- lib/consts.dart | 5 + lib/main.dart | 28 +++-- lib/models/settings_model.dart | 18 +++ lib/services/hive_services.dart | 28 +++-- lib/widgets/field_outlined.dart | 54 +++++++++ lib/widgets/widgets.dart | 1 + lib/widgets/workspace_selector.dart | 167 ++++++++++++++++++++-------- 8 files changed, 273 insertions(+), 81 deletions(-) create mode 100644 lib/widgets/field_outlined.dart diff --git a/lib/app.dart b/lib/app.dart index 7083eb4a..a2011dcd 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:window_manager/window_manager.dart' hide WindowCaption; import 'widgets/widgets.dart' show WindowCaption, WorkspaceSelector; import 'providers/providers.dart'; +import 'services/services.dart'; import 'extensions/extensions.dart'; import 'screens/screens.dart'; import 'consts.dart'; @@ -107,29 +108,49 @@ class DashApp extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isDarkMode = ref.watch(settingsProvider.select((value) => value.isDark)); + final workspaceFolderPath = ref + .watch(settingsProvider.select((value) => value.workspaceFolderPath)); + final showWorkspaceSelector = kIsDesktop && (workspaceFolderPath == null); return Portal( child: MaterialApp( debugShowCheckedModeBanner: false, theme: kLightMaterialAppTheme, darkTheme: kDarkMaterialAppTheme, themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light, - home: Stack( - children: [ - !kIsLinux && !kIsMobile - ? const App() - : context.isMediumWindow - ? const MobileDashboard() - : const Dashboard(), - if (kIsWindows) - SizedBox( - height: 29, - child: WindowCaption( - backgroundColor: Colors.transparent, - brightness: isDarkMode ? Brightness.dark : Brightness.light, - ), + home: showWorkspaceSelector + ? WorkspaceSelector( + onContinue: (val) async { + await openBoxes(kIsDesktop, val); + ref + .read(settingsProvider.notifier) + .update(workspaceFolderPath: val); + }, + onCancel: () async { + try { + await windowManager.destroy(); + } catch (e) { + debugPrint(e.toString()); + } + }, + ) + : Stack( + children: [ + !kIsLinux && !kIsMobile + ? const App() + : context.isMediumWindow + ? const MobileDashboard() + : const Dashboard(), + if (kIsWindows) + SizedBox( + height: 29, + child: WindowCaption( + backgroundColor: Colors.transparent, + brightness: + isDarkMode ? Brightness.dark : Brightness.light, + ), + ), + ], ), - ], - ), ), ); } diff --git a/lib/consts.dart b/lib/consts.dart index 1681069a..cb679187 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -744,6 +744,9 @@ const kLabelSaving = "Saving"; const kLabelSaved = "Saved"; const kLabelCode = "Code"; const kLabelDuplicate = "Duplicate"; +const kLabelSelect = "Select"; +const kLabelContinue = "Continue"; +const kLabelCancel = "Cancel"; // Request Pane const kLabelRequest = "Request"; const kLabelHideCode = "Hide Code"; @@ -778,3 +781,5 @@ const kNullResponseModelError = "Error: Response data does not exist."; const kMsgNullBody = "Response body is missing (null)."; const kMsgNoContent = "No content"; const kMsgUnknowContentType = "Unknown Response Content-Type"; +// Workspace Selector +const kMsgSelectWorkspace = "Create your workspace"; diff --git a/lib/main.dart b/lib/main.dart index 6c70bdf8..b5fa019f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,11 +10,14 @@ import 'app.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - final settingsModel = await getSettingsFromSharedPrefs(); - await initApp(settingsModel: settingsModel); + var settingsModel = await getSettingsFromSharedPrefs(); + final initStatus = await initApp(settingsModel: settingsModel); if (kIsDesktop) { await initWindow(settingsModel: settingsModel); } + if (!initStatus) { + settingsModel = settingsModel?.copyWithPath(workspaceFolderPath: null); + } runApp( ProviderScope( @@ -28,13 +31,22 @@ void main() async { ); } -Future initApp({SettingsModel? settingsModel}) async { +Future initApp({SettingsModel? settingsModel}) async { GoogleFonts.config.allowRuntimeFetching = false; - await openBoxes( - kIsDesktop, - settingsModel?.workspaceFolderPath, - ); - await autoClearHistory(settingsModel: settingsModel); + try { + final openBoxesStatus = await openBoxes( + kIsDesktop, + settingsModel?.workspaceFolderPath, + ); + debugPrint("openBoxesStatus: $openBoxesStatus"); + if (openBoxesStatus) { + await autoClearHistory(settingsModel: settingsModel); + } + return openBoxesStatus; + } catch (e) { + debugPrint("initApp failed due to $e"); + return false; + } } Future initWindow({ diff --git a/lib/models/settings_model.dart b/lib/models/settings_model.dart index e7e5c3b0..6784f214 100644 --- a/lib/models/settings_model.dart +++ b/lib/models/settings_model.dart @@ -59,6 +59,24 @@ class SettingsModel { ); } + SettingsModel copyWithPath({ + String? workspaceFolderPath, + }) { + return SettingsModel( + isDark: isDark, + alwaysShowCollectionPaneScrollbar: alwaysShowCollectionPaneScrollbar, + size: size, + defaultUriScheme: defaultUriScheme, + defaultCodeGenLang: defaultCodeGenLang, + offset: offset, + saveResponses: saveResponses, + promptBeforeClosing: promptBeforeClosing, + activeEnvironmentId: activeEnvironmentId, + historyRetentionPeriod: historyRetentionPeriod, + workspaceFolderPath: workspaceFolderPath, + ); + } + factory SettingsModel.fromJson(Map data) { final isDark = data["isDark"] as bool?; final alwaysShowCollectionPaneScrollbar = diff --git a/lib/services/hive_services.dart b/lib/services/hive_services.dart index 3caa3c28..fab18540 100644 --- a/lib/services/hive_services.dart +++ b/lib/services/hive_services.dart @@ -10,19 +10,29 @@ const String kHistoryMetaBox = "apidash-history-meta"; const String kHistoryBoxIds = "historyIds"; const String kHistoryLazyBox = "apidash-history-lazy"; -Future openBoxes( +Future openBoxes( bool isDesktop, String? workspaceFolderPath, ) async { - if (isDesktop) { - Hive.init(workspaceFolderPath); - } else { - await Hive.initFlutter(); + try { + if (isDesktop) { + if (workspaceFolderPath != null) { + Hive.init(workspaceFolderPath); + } else { + return false; + } + } else { + await Hive.initFlutter(); + } + + await Hive.openBox(kDataBox); + await Hive.openBox(kEnvironmentBox); + await Hive.openBox(kHistoryMetaBox); + await Hive.openLazyBox(kHistoryLazyBox); + return true; + } catch (e) { + return false; } - await Hive.openBox(kDataBox); - await Hive.openBox(kEnvironmentBox); - await Hive.openBox(kHistoryMetaBox); - await Hive.openLazyBox(kHistoryLazyBox); } final hiveHandler = HiveHandler(); diff --git a/lib/widgets/field_outlined.dart b/lib/widgets/field_outlined.dart new file mode 100644 index 00000000..0c981543 --- /dev/null +++ b/lib/widgets/field_outlined.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:apidash/consts.dart'; + +class OutlinedField extends StatelessWidget { + const OutlinedField({ + super.key, + this.keyId, + this.initialValue, + this.hintText, + this.onChanged, + this.colorScheme, + }); + + final String? keyId; + final String? initialValue; + final String? hintText; + final void Function(String)? onChanged; + final ColorScheme? colorScheme; + + @override + Widget build(BuildContext context) { + var clrScheme = colorScheme ?? Theme.of(context).colorScheme; + return TextFormField( + key: keyId != null ? Key(keyId!) : null, + initialValue: initialValue, + style: kCodeStyle.copyWith( + color: clrScheme.onSurface, + ), + decoration: InputDecoration( + hintStyle: kCodeStyle.copyWith( + color: clrScheme.outline.withOpacity( + kHintOpacity, + ), + ), + hintText: hintText, + contentPadding: kP10, + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: clrScheme.primary.withOpacity( + kHintOpacity, + ), + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: clrScheme.surfaceContainerHighest, + ), + ), + isDense: true, + ), + onChanged: onChanged, + ); + } +} diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index b7a8732e..ebf56e8e 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -31,6 +31,7 @@ export 'field_cell_obscurable.dart'; export 'field_cell.dart'; export 'field_header.dart'; export 'field_json_search.dart'; +export 'field_outlined.dart'; export 'field_raw.dart'; export 'field_read_only.dart'; export 'field_url.dart'; diff --git a/lib/widgets/workspace_selector.dart b/lib/widgets/workspace_selector.dart index 1ff7ddd5..2d41b311 100644 --- a/lib/widgets/workspace_selector.dart +++ b/lib/widgets/workspace_selector.dart @@ -1,62 +1,133 @@ -import 'package:file_selector/file_selector.dart'; -import 'package:apidash/services/hive_services.dart'; +import 'package:apidash/consts.dart'; import 'package:flutter/material.dart'; +import 'package:file_selector/file_selector.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:path/path.dart' as p; +import 'field_outlined.dart'; -class WorkspaceSelector extends StatefulWidget { - final Future Function(String)? onSelect; +class WorkspaceSelector extends HookWidget { const WorkspaceSelector({ super.key, - required this.onSelect, + required this.onContinue, + this.onCancel, }); - @override - WorkspaceSelectorState createState() => WorkspaceSelectorState(); -} - -class WorkspaceSelectorState extends State { - void selectFolder() async { - String? selectedDirectory = await getDirectoryPath(); - if (selectedDirectory != null) { - widget.onSelect?.call(selectedDirectory); - } - } + final Future Function(String)? onContinue; + final Future Function()? onCancel; @override Widget build(BuildContext context) { - const circularLoader = MaterialApp( - home: Scaffold( - body: Center( - child: CircularProgressIndicator(), + var selectedDirectory = useState(null); + var workspaceName = useState(null); + return Scaffold( + body: Center( + child: SizedBox( + width: 400, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + kMsgSelectWorkspace, + style: kTextStyleButton, + ), + kVSpacer20, + Row( + children: [ + Text( + "CHOOSE DIRECTORY", + style: kCodeStyle.copyWith( + fontSize: 12, + ), + ), + ], + ), + kVSpacer5, + Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + border: Border.all( + width: 1, + color: Theme.of(context).colorScheme.primaryContainer, + ), + borderRadius: kBorderRadius6, + ), + padding: kP4, + child: Text( + style: kTextStyleButtonSmall, + selectedDirectory.value ?? "", + maxLines: 4, + overflow: TextOverflow.ellipsis, + ), + ), + ), + kHSpacer10, + FilledButton.tonalIcon( + onPressed: () async { + selectedDirectory.value = await getDirectoryPath(); + }, + label: const Text(kLabelSelect), + icon: const Icon(Icons.folder_rounded), + ), + ], + ), + kVSpacer10, + Row( + children: [ + Text( + "WORKSPACE NAME [OPTIONAL]\n(FOLDER WILL BE CREATED IN THE SELECTED DIRECTORY)", + style: kCodeStyle.copyWith( + fontSize: 12, + ), + ), + ], + ), + kVSpacer5, + OutlinedField( + keyId: "workspace-name", + onChanged: (value) { + workspaceName.value = value.trim(); + }, + colorScheme: Theme.of(context).colorScheme, + ), + kVSpacer40, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + FilledButton( + onPressed: selectedDirectory.value == null + ? null + : () async { + String finalPath = selectedDirectory.value!; + if (workspaceName.value != null && + workspaceName.value!.trim().isNotEmpty) { + finalPath = + p.join(finalPath, workspaceName.value); + } + await onContinue?.call(finalPath); + }, + child: const Text(kLabelContinue), + ), + kHSpacer10, + FilledButton( + onPressed: onCancel, + style: FilledButton.styleFrom( + backgroundColor: + Theme.of(context).brightness == Brightness.dark + ? kColorDarkDanger + : kColorLightDanger, + surfaceTintColor: kColorRed, + foregroundColor: + Theme.of(context).colorScheme.onPrimary), + child: const Text(kLabelCancel), + ) + ], + ) + ], + ), ), ), ); - - return FutureBuilder( - future: getHiveSaveFolder(), - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.connectionState != ConnectionState.done) { - return circularLoader; - } - - // If there isn't hive selected folder choose it - if (snapshot.data == null) { - selectFolder(); - return circularLoader; - } - - // Once _hiveSaveFolder is set, display DashApp after hive init - return FutureBuilder( - future: openHiveBoxes(snapshot.data!), - builder: (BuildContext context, AsyncSnapshot snapshot) { - // if loading show circularLoader - if (snapshot.connectionState != ConnectionState.done) { - return circularLoader; - } - // Display widget - return widget.child; - }, - ); - }, - ); } } From 9a056c37024cc2f2b7588d8f0923cfffb853fbea Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 9 Sep 2024 04:11:07 +0530 Subject: [PATCH 05/31] Update settings_model_test.dart --- test/models/settings_model_test.dart | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/models/settings_model_test.dart b/test/models/settings_model_test.dart index 6df01335..0a1a33a9 100644 --- a/test/models/settings_model_test.dart +++ b/test/models/settings_model_test.dart @@ -15,6 +15,7 @@ void main() { promptBeforeClosing: true, activeEnvironmentId: null, historyRetentionPeriod: HistoryRetentionPeriod.oneWeek, + workspaceFolderPath: null, ); test('Testing toJson()', () { @@ -31,6 +32,7 @@ void main() { "promptBeforeClosing": true, "activeEnvironmentId": null, "historyRetentionPeriod": "oneWeek", + "workspaceFolderPath": null, }; expect(sm.toJson(), expectedResult); }); @@ -49,6 +51,7 @@ void main() { "promptBeforeClosing": true, "activeEnvironmentId": null, "historyRetentionPeriod": "oneWeek", + "workspaceFolderPath": null, }; expect(SettingsModel.fromJson(input), sm); }); @@ -75,8 +78,21 @@ void main() { }); test('Testing toString()', () { - const expectedResult = - "{isDark: false, alwaysShowCollectionPaneScrollbar: true, width: 300.0, height: 200.0, dx: 100.0, dy: 150.0, defaultUriScheme: http, defaultCodeGenLang: curl, saveResponses: true, promptBeforeClosing: true, activeEnvironmentId: null, historyRetentionPeriod: oneWeek}"; + const expectedResult = '''{ + "isDark": false, + "alwaysShowCollectionPaneScrollbar": true, + "width": 300.0, + "height": 200.0, + "dx": 100.0, + "dy": 150.0, + "defaultUriScheme": "http", + "defaultCodeGenLang": "curl", + "saveResponses": true, + "promptBeforeClosing": true, + "activeEnvironmentId": null, + "historyRetentionPeriod": "oneWeek", + "workspaceFolderPath": null +}'''; expect(sm.toString(), expectedResult); }); From 83cdc130e54673dfcaae2e3ba47513f3fd5301af Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 9 Sep 2024 04:46:46 +0530 Subject: [PATCH 06/31] Update integration test --- integration_test/test_helper.dart | 17 +++++++++++++---- lib/main.dart | 12 +++++++++--- lib/services/hive_services.dart | 4 ++-- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/integration_test/test_helper.dart b/integration_test/test_helper.dart index 70cafa9d..4cb151dc 100644 --- a/integration_test/test_helper.dart +++ b/integration_test/test_helper.dart @@ -1,3 +1,5 @@ +import 'package:apidash/models/settings_model.dart'; +import 'package:apidash/providers/providers.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -34,17 +36,24 @@ class ApidashTestHelper { final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive; - await app.initApp(); + await app.initApp(false); await app.initWindow(sz: size); return binding; } static Future loadApp(WidgetTester tester) async { - await app.initApp(); + await app.initApp(false); await tester.pumpWidget( - const ProviderScope( - child: DashApp(), + ProviderScope( + overrides: [ + settingsProvider.overrideWith( + (ref) => ThemeStateNotifier( + settingsModel: const SettingsModel() + .copyWithPath(workspaceFolderPath: "test")), + ) + ], + child: const DashApp(), ), ); } diff --git a/lib/main.dart b/lib/main.dart index b5fa019f..51fbd840 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,7 +11,10 @@ import 'app.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); var settingsModel = await getSettingsFromSharedPrefs(); - final initStatus = await initApp(settingsModel: settingsModel); + final initStatus = await initApp( + kIsDesktop, + settingsModel: settingsModel, + ); if (kIsDesktop) { await initWindow(settingsModel: settingsModel); } @@ -31,11 +34,14 @@ void main() async { ); } -Future initApp({SettingsModel? settingsModel}) async { +Future initApp( + bool initializeUsingPath, { + SettingsModel? settingsModel, +}) async { GoogleFonts.config.allowRuntimeFetching = false; try { final openBoxesStatus = await openBoxes( - kIsDesktop, + initializeUsingPath, settingsModel?.workspaceFolderPath, ); debugPrint("openBoxesStatus: $openBoxesStatus"); diff --git a/lib/services/hive_services.dart b/lib/services/hive_services.dart index fab18540..cc7f8960 100644 --- a/lib/services/hive_services.dart +++ b/lib/services/hive_services.dart @@ -11,11 +11,11 @@ const String kHistoryBoxIds = "historyIds"; const String kHistoryLazyBox = "apidash-history-lazy"; Future openBoxes( - bool isDesktop, + bool initializeUsingPath, String? workspaceFolderPath, ) async { try { - if (isDesktop) { + if (initializeUsingPath) { if (workspaceFolderPath != null) { Hive.init(workspaceFolderPath); } else { From 3fa51a39c40d2d17237df9fb9e9dbaf25b5b2ef0 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 9 Sep 2024 05:13:24 +0530 Subject: [PATCH 07/31] Update main.dart --- lib/main.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index 51fbd840..e1e70ec6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -40,6 +40,8 @@ Future initApp( }) async { GoogleFonts.config.allowRuntimeFetching = false; try { + debugPrint("initializeUsingPath: $initializeUsingPath"); + debugPrint("workspaceFolderPath: ${settingsModel?.workspaceFolderPath}"); final openBoxesStatus = await openBoxes( initializeUsingPath, settingsModel?.workspaceFolderPath, From 8820d26885dc1a5b93123a72ea4bdf6b79772f54 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 9 Sep 2024 05:13:42 +0530 Subject: [PATCH 08/31] Add clearSharedPrefs() --- integration_test/test_helper.dart | 2 ++ lib/screens/settings_page.dart | 2 ++ lib/services/shared_preferences_services.dart | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/integration_test/test_helper.dart b/integration_test/test_helper.dart index 4cb151dc..f05a7cf7 100644 --- a/integration_test/test_helper.dart +++ b/integration_test/test_helper.dart @@ -1,5 +1,6 @@ import 'package:apidash/models/settings_model.dart'; import 'package:apidash/providers/providers.dart'; +import 'package:apidash/services/services.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -132,6 +133,7 @@ void apidashWidgetTest( size: width != null ? Size(width, kMinWindowSize.height) : null); await ApidashTestHelper.loadApp(widgetTester); await test(widgetTester, ApidashTestHelper(widgetTester)); + await clearSharedPrefs(); }, semanticsEnabled: false, ); diff --git a/lib/screens/settings_page.dart b/lib/screens/settings_page.dart index 8e9c8486..933b54b9 100644 --- a/lib/screens/settings_page.dart +++ b/lib/screens/settings_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../providers/providers.dart'; +import '../services/services.dart'; import '../widgets/widgets.dart'; import '../common/utils.dart'; import '../consts.dart'; @@ -206,6 +207,7 @@ class SettingsPage extends ConsumerWidget { TextButton( onPressed: () async { Navigator.pop(context, 'Yes'); + await clearSharedPrefs(); await ref .read(collectionStateNotifierProvider .notifier) diff --git a/lib/services/shared_preferences_services.dart b/lib/services/shared_preferences_services.dart index af1bbd71..89d4b590 100644 --- a/lib/services/shared_preferences_services.dart +++ b/lib/services/shared_preferences_services.dart @@ -21,3 +21,8 @@ Future setSettingsToSharedPrefs(SettingsModel settingsModel) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(kSharedPrefSettingsKey, settingsModel.toString()); } + +Future clearSharedPrefs() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(kSharedPrefSettingsKey); +} From 3b32877240e1e0bc00355930ba2505ca2f3c3f3e Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 15 Sep 2024 21:32:06 +0530 Subject: [PATCH 09/31] fix errors --- .../editor_pane/details_card/request_pane/request_body.dart | 2 -- test/providers/helpers.dart | 3 +-- 2 files changed, 1 insertion(+), 4 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 065feefe..c70f54d3 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,5 +1,3 @@ -import 'dart:developer'; - import 'package:apidash/models/models.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; diff --git a/test/providers/helpers.dart b/test/providers/helpers.dart index f0ab2915..73dff64a 100644 --- a/test/providers/helpers.dart +++ b/test/providers/helpers.dart @@ -2,7 +2,6 @@ import 'package:apidash/services/hive_services.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:test/test.dart'; /// A testing utility which creates a [ProviderContainer] and automatically /// disposes it at the end of the test. @@ -36,5 +35,5 @@ Future testSetUp() async { return './test/unit-test-hive-storage/'; }); - await openBoxes(); + await openBoxes(false, null); } From 0f8de3c107fc071305bb0b98123fdbc8feeb20f6 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 00:03:35 +0530 Subject: [PATCH 10/31] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 88e45ec2..49dfe609 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,16 +7,23 @@ assignees: '' --- -**Describe the bug/problem** +#### Describe the bug/problem _Please describe the bug/problem here_ -**Steps to Reproduce the bug/problem** +#### Steps to Reproduce the bug/problem _Please provide the steps to reproduce the behaviour. Screenshot(s)/image(s) are preferred to help explain it better_ -**Expected behavior** +#### Expected behavior _Description of what you expected to happen_ -**Device Info (The device where you encountered this issue):** +#### Device Info (The device where you encountered this issue) - OS: [e.g. Windows, MacOS] - Version: [e.g. Catalina 10.15.7, Monterey 12.3.1, Windows 11 22H2] - Browser (only if you encountered the issue while running the web app): [e.g. chrome, safari] + +#### Flutter Doctor +Please run the `flutter doctor -v` command and provide the details below: + +``` + +``` From 0f72383a46adbfbc576021287e228b3bcf5a955c Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 00:03:57 +0530 Subject: [PATCH 11/31] Update feedback.md --- .github/ISSUE_TEMPLATE/feedback.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feedback.md b/.github/ISSUE_TEMPLATE/feedback.md index 5c8d50a6..31df2527 100644 --- a/.github/ISSUE_TEMPLATE/feedback.md +++ b/.github/ISSUE_TEMPLATE/feedback.md @@ -8,5 +8,5 @@ assignees: '' --- -**Feedback** +#### Feedback _Please feel free to share anything. The stage is all yours._ From 57a8712fd5295cc19567c37d7c34d2257c15dd4e Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 00:04:29 +0530 Subject: [PATCH 12/31] Update feature_request.md --- .github/ISSUE_TEMPLATE/feature_request.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 7c1ec21d..9264284f 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,11 +7,11 @@ assignees: '' --- -**Tell us about the task you want to perform and are unable to do so because the feature is not available** +#### Tell us about the task you want to perform and are unable to do so because the feature is not available _Your response here_ -**Describe the solution/feature you'd like us to add** +#### Describe the solution/feature you'd like us to add _Your response here_ -**Any other feedback you would like to provide regarding the site** +#### Any other feedback you would like to provide regarding the site _Your response here_ From a87e7bf6b051a4a094956d60dd31041ad3261ab6 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 00:14:23 +0530 Subject: [PATCH 13/31] Update hive_services.dart --- lib/services/hive_services.dart | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/services/hive_services.dart b/lib/services/hive_services.dart index cc7f8960..192aeec7 100644 --- a/lib/services/hive_services.dart +++ b/lib/services/hive_services.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:hive_flutter/hive_flutter.dart'; const String kDataBox = "apidash-data"; @@ -35,6 +36,28 @@ Future openBoxes( } } +Future clearHiveBoxes() async { + try { + await Hive.box(kDataBox).clear(); + await Hive.box(kEnvironmentBox).clear(); + await Hive.box(kHistoryMetaBox).clear(); + await Hive.lazyBox(kHistoryLazyBox).clear(); + } catch (e) { + debugPrint("ERROR CLEAR HIVE BOXES: $e"); + } +} + +Future deleteHiveBoxes() async { + try { + await Hive.box(kDataBox).deleteFromDisk(); + await Hive.box(kEnvironmentBox).deleteFromDisk(); + await Hive.box(kHistoryMetaBox).deleteFromDisk(); + await Hive.lazyBox(kHistoryLazyBox).deleteFromDisk(); + } catch (e) { + debugPrint("ERROR DELETE HIVE BOXES: $e"); + } +} + final hiveHandler = HiveHandler(); class HiveHandler { @@ -93,6 +116,8 @@ class HiveHandler { Future clear() async { await dataBox.clear(); await environmentBox.clear(); + await historyMetaBox.clear(); + await historyLazyBox.clear(); } Future removeUnused() async { From f9801c8dc40fee040241c277cd91894d9b072fb2 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 00:18:21 +0530 Subject: [PATCH 14/31] Update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 4bdfd329..9a64d7c0 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,6 @@ coverage/* installers/* .metadata .fvm/ + +# Testing Files & Folders +test-hive-storage From cba19ae6b182dc991f20c91e3fd15b99c11bb8f4 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 00:18:31 +0530 Subject: [PATCH 15/31] Update helpers.dart --- test/providers/helpers.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/providers/helpers.dart b/test/providers/helpers.dart index 73dff64a..2e57affb 100644 --- a/test/providers/helpers.dart +++ b/test/providers/helpers.dart @@ -32,8 +32,10 @@ Future testSetUp() async { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (MethodCall methodCall) async { - return './test/unit-test-hive-storage/'; + return './test-hive-storage/'; }); await openBoxes(false, null); + await deleteHiveBoxes(); + await openBoxes(false, null); } From 7b848791c237938621aea6274f6565c0072bcb9c Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 03:03:17 +0530 Subject: [PATCH 16/31] dataTableShowLogs --- test/widgets/table_request_form_test.dart | 1 + test/widgets/table_request_test.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/test/widgets/table_request_form_test.dart b/test/widgets/table_request_form_test.dart index a1c67424..c21a9b70 100644 --- a/test/widgets/table_request_form_test.dart +++ b/test/widgets/table_request_form_test.dart @@ -6,6 +6,7 @@ import 'package:apidash/models/models.dart'; import 'package:apidash/consts.dart'; void main() { + dataTableShowLogs = false; testWidgets('Testing RequestFormDataTable', (WidgetTester tester) async { const List sampleData = [ FormDataModel(name: 'Key1', value: 'Value1', type: FormDataType.file), diff --git a/test/widgets/table_request_test.dart b/test/widgets/table_request_test.dart index 6e8c2c9f..cc0e3324 100644 --- a/test/widgets/table_request_test.dart +++ b/test/widgets/table_request_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { + dataTableShowLogs = false; testWidgets('Testing RequestDataTable', (WidgetTester tester) async { final Map sampleData = { 'Key1': 'Value1', From a0d93082f4436ee66b437b7e30792186400c8d7a Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 03:03:26 +0530 Subject: [PATCH 17/31] hive updates --- lib/app.dart | 2 +- lib/main.dart | 2 +- lib/services/hive_services.dart | 52 ++++++++++++++----- test/providers/collection_providers_test.dart | 6 ++- test/providers/helpers.dart | 26 ++++++++-- test/providers/ui_providers_test.dart | 17 +----- 6 files changed, 68 insertions(+), 37 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index a2011dcd..48c49a86 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -120,7 +120,7 @@ class DashApp extends ConsumerWidget { home: showWorkspaceSelector ? WorkspaceSelector( onContinue: (val) async { - await openBoxes(kIsDesktop, val); + await initHiveBoxes(kIsDesktop, val); ref .read(settingsProvider.notifier) .update(workspaceFolderPath: val); diff --git a/lib/main.dart b/lib/main.dart index e1e70ec6..7e212dad 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -42,7 +42,7 @@ Future initApp( try { debugPrint("initializeUsingPath: $initializeUsingPath"); debugPrint("workspaceFolderPath: ${settingsModel?.workspaceFolderPath}"); - final openBoxesStatus = await openBoxes( + final openBoxesStatus = await initHiveBoxes( initializeUsingPath, settingsModel?.workspaceFolderPath, ); diff --git a/lib/services/hive_services.dart b/lib/services/hive_services.dart index 192aeec7..9f703ef3 100644 --- a/lib/services/hive_services.dart +++ b/lib/services/hive_services.dart @@ -11,7 +11,7 @@ const String kHistoryMetaBox = "apidash-history-meta"; const String kHistoryBoxIds = "historyIds"; const String kHistoryLazyBox = "apidash-history-lazy"; -Future openBoxes( +Future initHiveBoxes( bool initializeUsingPath, String? workspaceFolderPath, ) async { @@ -25,23 +25,38 @@ Future openBoxes( } else { await Hive.initFlutter(); } - - await Hive.openBox(kDataBox); - await Hive.openBox(kEnvironmentBox); - await Hive.openBox(kHistoryMetaBox); - await Hive.openLazyBox(kHistoryLazyBox); + await openHiveBoxes(); return true; } catch (e) { return false; } } +Future openHiveBoxes() async { + try { + await Hive.openBox(kDataBox); + await Hive.openBox(kEnvironmentBox); + await Hive.openBox(kHistoryMetaBox); + await Hive.openLazyBox(kHistoryLazyBox); + } catch (e) { + debugPrint("ERROR OPEN HIVE BOXES: $e"); + } +} + Future clearHiveBoxes() async { try { - await Hive.box(kDataBox).clear(); - await Hive.box(kEnvironmentBox).clear(); - await Hive.box(kHistoryMetaBox).clear(); - await Hive.lazyBox(kHistoryLazyBox).clear(); + if (Hive.isBoxOpen(kDataBox)) { + await Hive.box(kDataBox).clear(); + } + if (Hive.isBoxOpen(kEnvironmentBox)) { + await Hive.box(kEnvironmentBox).clear(); + } + if (Hive.isBoxOpen(kHistoryMetaBox)) { + await Hive.box(kHistoryMetaBox).clear(); + } + if (Hive.isBoxOpen(kHistoryLazyBox)) { + await Hive.lazyBox(kHistoryLazyBox).clear(); + } } catch (e) { debugPrint("ERROR CLEAR HIVE BOXES: $e"); } @@ -49,10 +64,19 @@ Future clearHiveBoxes() async { Future deleteHiveBoxes() async { try { - await Hive.box(kDataBox).deleteFromDisk(); - await Hive.box(kEnvironmentBox).deleteFromDisk(); - await Hive.box(kHistoryMetaBox).deleteFromDisk(); - await Hive.lazyBox(kHistoryLazyBox).deleteFromDisk(); + if (Hive.isBoxOpen(kDataBox)) { + await Hive.box(kDataBox).deleteFromDisk(); + } + if (Hive.isBoxOpen(kEnvironmentBox)) { + await Hive.box(kEnvironmentBox).deleteFromDisk(); + } + if (Hive.isBoxOpen(kHistoryMetaBox)) { + await Hive.box(kHistoryMetaBox).deleteFromDisk(); + } + if (Hive.isBoxOpen(kHistoryLazyBox)) { + await Hive.lazyBox(kHistoryLazyBox).deleteFromDisk(); + } + await Hive.close(); } catch (e) { debugPrint("ERROR DELETE HIVE BOXES: $e"); } diff --git a/test/providers/collection_providers_test.dart b/test/providers/collection_providers_test.dart index 7cabaae4..1abd8123 100644 --- a/test/providers/collection_providers_test.dart +++ b/test/providers/collection_providers_test.dart @@ -8,7 +8,11 @@ import 'package:apidash/providers/providers.dart'; import 'helpers.dart'; void main() async { - setUp(() async => await testSetUp()); + TestWidgetsFlutterBinding.ensureInitialized(); + + setUp(() async { + await testSetUpTempDirForHive(); + }); testWidgets( 'Request method changes from GET to POST when body is added and Snackbar is shown', diff --git a/test/providers/helpers.dart b/test/providers/helpers.dart index 2e57affb..568a849c 100644 --- a/test/providers/helpers.dart +++ b/test/providers/helpers.dart @@ -1,3 +1,4 @@ +import 'dart:io'; import 'package:apidash/services/hive_services.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -23,10 +24,9 @@ ProviderContainer createContainer({ return container; } -Future testSetUp() async { +Future testSetUpForHive() async { // override path_provider methodCall to point // path to temporary location for all unit tests - TestWidgetsFlutterBinding.ensureInitialized(); const MethodChannel channel = MethodChannel('plugins.flutter.io/path_provider'); @@ -35,7 +35,23 @@ Future testSetUp() async { return './test-hive-storage/'; }); - await openBoxes(false, null); - await deleteHiveBoxes(); - await openBoxes(false, null); + await initHiveBoxes(false, null); + // await deleteHiveBoxes(); + // await openHiveBoxes(); +} + +Future testSetUpTempDirForHive() async { + const MethodChannel channel = + MethodChannel('plugins.flutter.io/path_provider'); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { + if (methodCall.method == 'getApplicationDocumentsDirectory') { + // Create a mock app doc directory for testing + Directory tempDir = + await Directory.systemTemp.createTemp('mock_app_doc_dir'); + return tempDir.path; // Return the path to the mock directory + } + return null; + }); + await initHiveBoxes(false, null); } diff --git a/test/providers/ui_providers_test.dart b/test/providers/ui_providers_test.dart index 60b67241..e8fd0582 100644 --- a/test/providers/ui_providers_test.dart +++ b/test/providers/ui_providers_test.dart @@ -1,4 +1,3 @@ -import 'dart:io'; //import 'package:spot/spot.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/screens/common_widgets/common_widgets.dart'; @@ -12,7 +11,6 @@ import 'package:apidash/screens/home_page/editor_pane/url_card.dart'; import 'package:apidash/screens/home_page/home_page.dart'; import 'package:apidash/screens/settings_page.dart'; import 'package:apidash/screens/history/history_page.dart'; -import 'package:apidash/services/hive_services.dart'; import 'package:apidash/widgets/widgets.dart'; import 'package:extended_text_field/extended_text_field.dart'; import 'package:flutter/material.dart'; @@ -22,24 +20,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import '../extensions/widget_tester_extensions.dart'; import '../test_consts.dart'; +import 'helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); setUp(() async { - const MethodChannel channel = - MethodChannel('plugins.flutter.io/path_provider'); - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(channel, (MethodCall methodCall) async { - if (methodCall.method == 'getApplicationDocumentsDirectory') { - // Create a mock app doc directory for testing - Directory tempDir = - await Directory.systemTemp.createTemp('mock_app_doc_dir'); - return tempDir.path; // Return the path to the mock directory - } - return null; - }); - await openBoxes(false, null); + await testSetUpTempDirForHive(); final flamante = rootBundle.load('google_fonts/OpenSans-Medium.ttf'); final fontLoader = FontLoader('OpenSans')..addFont(flamante); await fontLoader.load(); From 5896ff71595f3476fbf516f5baf9d91bc7cf7a73 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 05:15:49 +0530 Subject: [PATCH 18/31] update --- pubspec.lock | 18 +++++++++--------- pubspec.yaml | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 2c257859..c17219a4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -259,10 +259,10 @@ packages: dependency: "direct main" description: name: dart_style - sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" url: "https://pub.dev" source: hosted - version: "2.3.6" + version: "2.3.7" dartx: dependency: transitive description: @@ -596,10 +596,10 @@ packages: dependency: "direct main" description: name: fvp - sha256: "6462fd078de4478a0990d437463897036cff98aff3f0ac9efbbf817c99654c87" + sha256: "040aa12beccd5bc60631259f27a481c4abc11a389aa4f57a47b643f58fe0b060" url: "https://pub.dev" source: hosted - version: "0.24.1" + version: "0.26.1" glob: dependency: transitive description: @@ -778,10 +778,10 @@ packages: dependency: "direct main" description: name: just_audio - sha256: ee50602364ba83fa6308f5512dd560c713ec3e1f2bc75f0db43618f0d82ef71a + sha256: d8e8aaf417d33e345299c17f6457f72bd4ba0c549dc34607abb5183a354edc4d url: "https://pub.dev" source: hosted - version: "0.9.39" + version: "0.9.40" just_audio_mpv: dependency: "direct main" description: @@ -1552,10 +1552,10 @@ packages: dependency: "direct main" description: name: uuid - sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90" + sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77 url: "https://pub.dev" source: hosted - version: "4.4.2" + version: "4.5.0" vector_graphics: dependency: transitive description: @@ -1727,4 +1727,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.5.0-259.0.dev <3.999.0" - flutter: ">=3.22.0" + flutter: ">=3.24.3" diff --git a/pubspec.yaml b/pubspec.yaml index a9bf5998..41d4f3d0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.4.0+4 environment: sdk: ">=3.0.0 <4.0.0" - flutter: ">=3.19.0" + flutter: ">=3.24.3" dependencies: flutter: @@ -18,7 +18,7 @@ dependencies: url: https://github.com/foss42/curl_converter.git ref: 726e8cd04aeb326211af27f75920be5b21c90bb4 data_table_2: ^2.5.15 - dart_style: ^2.3.6 + dart_style: ^2.3.7 desktop_drop: ^0.4.4 extended_text_field: ^16.0.0 file_selector: ^1.0.3 @@ -30,7 +30,7 @@ dependencies: flutter_svg: ^2.0.10+1 flutter_typeahead: ^5.2.0 freezed_annotation: ^2.4.1 - fvp: ^0.24.1 + fvp: ^0.26.1 google_fonts: ^6.2.1 highlighter: ^0.1.1 hive_flutter: ^1.1.0 @@ -45,7 +45,7 @@ dependencies: url: https://github.com/foss42/json_data_explorer.git ref: b7dde2f85dff4f482eed7eda4ef2a71344ef8b3a json_text_field: ^1.2.0 - just_audio: ^0.9.34 + just_audio: ^0.9.40 just_audio_mpv: ^0.1.7 just_audio_windows: ^0.2.0 lottie: ^3.1.0 @@ -65,7 +65,7 @@ dependencies: scrollable_positioned_list: ^0.3.8 shared_preferences: ^2.3.2 url_launcher: ^6.2.5 - uuid: ^4.3.3 + uuid: ^4.5.0 vector_graphics_compiler: ^1.1.9+1 video_player: ^2.8.7 video_player_platform_interface: ^6.2.2 From 552d735da786803593ea73b9ec4c5af4b2a340b2 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 05:19:08 +0530 Subject: [PATCH 19/31] Update request_form_data.dart --- .../editor_pane/details_card/request_pane/request_form_data.dart | 1 - 1 file changed, 1 deletion(-) 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 35c34066..41671bc7 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 @@ -43,7 +43,6 @@ class _FormDataBodyState extends ConsumerState { .select((value) => value?.httpRequestModel?.formData?.length)); var rF = ref.read(selectedRequestModelProvider)?.httpRequestModel?.formData; bool isFormDataEmpty = rF == null || rF.isEmpty; - formRows = isFormDataEmpty ? [ kFormDataEmptyModel, From edf8c523c823df723243470918ac1b2bdb3ee085 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 15:55:22 +0530 Subject: [PATCH 20/31] Update hive_services.dart --- lib/services/hive_services.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/services/hive_services.dart b/lib/services/hive_services.dart index 9f703ef3..cec74101 100644 --- a/lib/services/hive_services.dart +++ b/lib/services/hive_services.dart @@ -25,21 +25,23 @@ Future initHiveBoxes( } else { await Hive.initFlutter(); } - await openHiveBoxes(); - return true; + final openHiveBoxesStatus = await openHiveBoxes(); + return openHiveBoxesStatus; } catch (e) { return false; } } -Future openHiveBoxes() async { +Future openHiveBoxes() async { try { await Hive.openBox(kDataBox); await Hive.openBox(kEnvironmentBox); await Hive.openBox(kHistoryMetaBox); await Hive.openLazyBox(kHistoryLazyBox); + return true; } catch (e) { debugPrint("ERROR OPEN HIVE BOXES: $e"); + return false; } } From 31c84da762941c1ba48fb05289820901b27d1a55 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 16:52:25 +0530 Subject: [PATCH 21/31] Update request_body.dart --- .../details_card/request_pane/request_body.dart | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 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 c70f54d3..e0e39628 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 @@ -18,21 +18,16 @@ class EditRequestBody extends ConsumerWidget { final contentType = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.bodyContentType)); + final sm = ScaffoldMessenger.of(context); void changeToPostMethod() { - RequestModel? model = ref - .read(collectionStateNotifierProvider.notifier) - .getRequestModel(selectedId); - - if (model!.httpRequestModel!.method == HTTPVerb.get) { + if (requestModel?.httpRequestModel!.method == HTTPVerb.get) { ref .read(collectionStateNotifierProvider.notifier) .update(selectedId, method: HTTPVerb.post); - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text( - "Switched to POST method", - style: TextStyle(color: Colors.white), - ), - backgroundColor: Colors.black, + sm.hideCurrentSnackBar(); + sm.showSnackBar(getSnackBar( + "Switched to POST method", + small: false, )); } } From d9ec943d4055523f8949b94c382c4d3c0a46d59c Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 17:01:16 +0530 Subject: [PATCH 22/31] Update request_form_data.dart --- .../details_card/request_pane/request_form_data.dart | 4 +--- 1 file changed, 1 insertion(+), 3 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 41671bc7..9b0bb123 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 @@ -9,8 +9,7 @@ import 'package:apidash/utils/utils.dart'; import 'package:apidash/consts.dart'; class FormDataWidget extends ConsumerStatefulWidget { - final Function changeMethodToPost; - const FormDataWidget({required this.changeMethodToPost, super.key}); + const FormDataWidget({super.key}); @override ConsumerState createState() => _FormDataBodyState(); } @@ -28,7 +27,6 @@ class _FormDataBodyState extends ConsumerState { } void _onFieldChange(String selectedId) { - widget.changeMethodToPost(); ref.read(collectionStateNotifierProvider.notifier).update( selectedId, formData: formRows.sublist(0, formRows.length - 1), From c6c215ace138e22abf5bd1e508ba4f2386c070a2 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 17:02:43 +0530 Subject: [PATCH 23/31] Update request_body.dart --- .../request_pane/request_body.dart | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 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 e0e39628..86ac5a2f 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,4 +1,3 @@ -import 'package:apidash/models/models.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; @@ -18,19 +17,20 @@ class EditRequestBody extends ConsumerWidget { final contentType = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.bodyContentType)); - final sm = ScaffoldMessenger.of(context); - void changeToPostMethod() { - if (requestModel?.httpRequestModel!.method == HTTPVerb.get) { - ref - .read(collectionStateNotifierProvider.notifier) - .update(selectedId, method: HTTPVerb.post); - sm.hideCurrentSnackBar(); - sm.showSnackBar(getSnackBar( - "Switched to POST method", - small: false, - )); - } - } + // TODO: #178 GET->POST Currently switches to POST everytime user edits body even if the user intentionally chooses GET + // final sm = ScaffoldMessenger.of(context); + // void changeToPostMethod() { + // if (requestModel?.httpRequestModel!.method == HTTPVerb.get) { + // ref + // .read(collectionStateNotifierProvider.notifier) + // .update(selectedId, method: HTTPVerb.post); + // sm.hideCurrentSnackBar(); + // sm.showSnackBar(getSnackBar( + // "Switched to POST method", + // small: false, + // )); + // } + // } return Column( children: [ @@ -48,11 +48,12 @@ class EditRequestBody extends ConsumerWidget { ), Expanded( child: switch (contentType) { - ContentType.formdata => Padding( + ContentType.formdata => const Padding( padding: kPh4, child: FormDataWidget( - changeMethodToPost: changeToPostMethod, - )), + // TODO: See changeToPostMethod above + // changeMethodToPost: changeToPostMethod, + )), // TODO: Fix JsonTextFieldEditor & plug it here ContentType.json => Padding( padding: kPt5o10, @@ -61,7 +62,7 @@ class EditRequestBody extends ConsumerWidget { fieldKey: "$selectedId-json-body-editor", initialValue: requestModel?.httpRequestModel?.body, onChanged: (String value) { - changeToPostMethod(); + // changeToPostMethod(); ref .read(collectionStateNotifierProvider.notifier) .update(selectedId, body: value); @@ -75,7 +76,7 @@ class EditRequestBody extends ConsumerWidget { fieldKey: "$selectedId-body-editor", initialValue: requestModel?.httpRequestModel?.body, onChanged: (String value) { - changeToPostMethod(); + // changeToPostMethod(); ref .read(collectionStateNotifierProvider.notifier) .update(selectedId, body: value); From c1a937497d429fcdf4ea1d8d4535b6095f2aa214 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Mon, 16 Sep 2024 17:05:40 +0530 Subject: [PATCH 24/31] Update collection_providers_test.dart --- test/providers/collection_providers_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/providers/collection_providers_test.dart b/test/providers/collection_providers_test.dart index 1abd8123..fb939522 100644 --- a/test/providers/collection_providers_test.dart +++ b/test/providers/collection_providers_test.dart @@ -50,5 +50,5 @@ void main() async { // Verify that the Snackbar is shown expect(find.text('Switched to POST method'), findsOneWidget); - }); + }, skip: true); } From 28a22218fcc5be9a998f47eabbc39b7a1f89a659 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Tue, 17 Sep 2024 02:30:58 +0530 Subject: [PATCH 25/31] Fixes #415 --- lib/utils/http_utils.dart | 49 +++++++++++++------------ lib/widgets/response_widgets.dart | 14 ++++--- test/widgets/response_widgets_test.dart | 15 +++++--- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart index e323939a..e12f029f 100644 --- a/lib/utils/http_utils.dart +++ b/lib/utils/http_utils.dart @@ -101,33 +101,34 @@ String stripUrlParams(String url) { (List, String?) getResponseBodyViewOptions( MediaType? mediaType) { - if (mediaType != null) { - var type = mediaType.type; - var subtype = mediaType.subtype; - if (kResponseBodyViewOptions.containsKey(type)) { - if (kResponseBodyViewOptions[type]!.containsKey(subtype)) { - return ( - kResponseBodyViewOptions[type]![subtype]!, - kCodeHighlighterMap[subtype] ?? subtype - ); - } - if (subtype.contains(kSubTypeJson)) { - subtype = kSubTypeJson; - } - if (subtype.contains(kSubTypeXml)) { - subtype = kSubTypeXml; - } - if (kResponseBodyViewOptions[type]!.containsKey(subtype)) { - return ( - kResponseBodyViewOptions[type]![subtype]!, - kCodeHighlighterMap[subtype] ?? subtype - ); - } + if (mediaType == null) { + return (kRawBodyViewOptions, null); + } + var type = mediaType.type; + var subtype = mediaType.subtype; + if (kResponseBodyViewOptions.containsKey(type)) { + if (kResponseBodyViewOptions[type]!.containsKey(subtype)) { return ( - kResponseBodyViewOptions[type]![kSubTypeDefaultViewOptions]!, - subtype + kResponseBodyViewOptions[type]![subtype]!, + kCodeHighlighterMap[subtype] ?? subtype ); } + if (subtype.contains(kSubTypeJson)) { + subtype = kSubTypeJson; + } + if (subtype.contains(kSubTypeXml)) { + subtype = kSubTypeXml; + } + if (kResponseBodyViewOptions[type]!.containsKey(subtype)) { + return ( + kResponseBodyViewOptions[type]![subtype]!, + kCodeHighlighterMap[subtype] ?? subtype + ); + } + return ( + kResponseBodyViewOptions[type]![kSubTypeDefaultViewOptions]!, + subtype + ); } return (kNoBodyViewOptions, null); } diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index 42154478..7b269fc1 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -345,12 +345,14 @@ class ResponseBody extends StatelessWidget { ); } - var mediaType = responseModel.mediaType; - if (mediaType == null) { - return ErrorMessage( - message: - '$kMsgUnknowContentType - ${responseModel.contentType}. $kUnexpectedRaiseIssue'); - } + final mediaType = + responseModel.mediaType ?? MediaType(kTypeText, kSubTypePlain); + // Fix #415: Treat null Content-type as plain text instead of Error message + // if (mediaType == null) { + // return ErrorMessage( + // message: + // '$kMsgUnknowContentType - ${responseModel.contentType}. $kUnexpectedRaiseIssue'); + // } var responseBodyView = getResponseBodyViewOptions(mediaType); var options = responseBodyView.$1; diff --git a/test/widgets/response_widgets_test.dart b/test/widgets/response_widgets_test.dart index 1c3c4bef..74df9a1b 100644 --- a/test/widgets/response_widgets_test.dart +++ b/test/widgets/response_widgets_test.dart @@ -214,8 +214,13 @@ void main() { findsOneWidget); }); - testWidgets('Testing Response Body, no mediaType', (tester) async { - var responseModelNoHeaders = responseModel.copyWith(headers: null); + testWidgets( + 'Testing Response Body, no mediaType; shoud be default plaintext preview', + (tester) async { + var responseModelNoHeaders = responseModel.copyWith( + headers: null, + formattedBody: null, + ); var requestModelNoResponseHeaders = testRequestModel.copyWith(httpResponseModel: responseModelNoHeaders); @@ -230,10 +235,8 @@ void main() { ), ); - expect( - find.text( - 'Unknown Response Content-Type - ${responseModelNoHeaders.contentType}. $kUnexpectedRaiseIssue'), - findsOneWidget); + expect(find.text("Raw"), findsOneWidget); + expect(find.text('{"data":"world"}'), findsOneWidget); }); testWidgets('Testing Response Body for No body view', (tester) async { From 65ed9a8fc9f5adfba0f5404ea2d1a28e063fa548 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Tue, 17 Sep 2024 02:40:17 +0530 Subject: [PATCH 26/31] Update ROADMAP.md --- ROADMAP.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 8b4ce1ac..a38951b6 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ ## API Dash Roadmap -- [ ] Environment Variables (https://github.com/foss42/apidash/issues/25) +- [x] Environment Variables (https://github.com/foss42/apidash/issues/25) - [ ] WebSocket support (https://github.com/foss42/apidash/issues/15) - [ ] SSE support (https://github.com/foss42/apidash/issues/116) - [ ] MQTT support (https://github.com/foss42/apidash/issues/115) @@ -8,7 +8,7 @@ - [ ] gRPC support (https://github.com/foss42/apidash/issues/14) - [ ] API Testing Suite (https://github.com/foss42/apidash/discussions/96, https://github.com/foss42/apidash/issues/100) - [ ] API Workflow Builder (https://github.com/foss42/apidash/issues/120) -- [ ] Integration Testing (https://github.com/foss42/apidash/issues/119) +- [x] Integration Testing (https://github.com/foss42/apidash/issues/119) - [ ] Remaining Code Generators (https://github.com/foss42/apidash/discussions/80) - [ ] Embedded WebView in Response Previewer - [ ] Figuring out how to build for various Linux packaging formats (https://github.com/foss42/apidash/discussions/240) From b4f76fb36465e20d86b15abb0e3576e121a7df77 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Tue, 17 Sep 2024 06:11:52 +0530 Subject: [PATCH 27/31] Downgrade flutter min version --- pubspec.lock | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index c17219a4..be9d5cde 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1727,4 +1727,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.5.0-259.0.dev <3.999.0" - flutter: ">=3.24.3" + flutter: ">=3.24.2" diff --git a/pubspec.yaml b/pubspec.yaml index 41d4f3d0..4a9c607e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.4.0+4 environment: sdk: ">=3.0.0 <4.0.0" - flutter: ">=3.24.3" + flutter: ">=3.24.2" dependencies: flutter: From 2f0c97b51ed2d4a4c962977c0274c767187cc164 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Tue, 17 Sep 2024 22:45:18 +0530 Subject: [PATCH 28/31] Update hive_services.dart --- lib/services/hive_services.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/services/hive_services.dart b/lib/services/hive_services.dart index cec74101..09ac8489 100644 --- a/lib/services/hive_services.dart +++ b/lib/services/hive_services.dart @@ -93,6 +93,7 @@ class HiveHandler { late final LazyBox historyLazyBox; HiveHandler() { + debugPrint("Trying to open Hive boxes"); dataBox = Hive.box(kDataBox); environmentBox = Hive.box(kEnvironmentBox); historyMetaBox = Hive.box(kHistoryMetaBox); From 0d05a2d0e31fa272cf04b4a0a4c4d6a55d9216ed Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Tue, 17 Sep 2024 22:45:54 +0530 Subject: [PATCH 29/31] Update yamls --- flutter_launcher_icons.yaml | 12 ++++++------ flutter_native_splash.yaml | 10 ++++++++++ pubspec.lock | 24 ++++++++++++++++++++++++ pubspec.yaml | 1 + 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 flutter_native_splash.yaml diff --git a/flutter_launcher_icons.yaml b/flutter_launcher_icons.yaml index 532dd379..21a66d08 100644 --- a/flutter_launcher_icons.yaml +++ b/flutter_launcher_icons.yaml @@ -1,14 +1,14 @@ -flutter_icons: +flutter_launcher_icons: image_path: "icons/logo.png" - android: false #"ic_launcher" + android: true ios: false image_path_ios: "icons/logo_ios.png" min_sdk_android: 21 web: - generate: true + generate: false windows: - generate: true - icon_size: 256 + generate: false + icon_size: 256 macos: - generate: true + generate: false image_path: "icons/logo_macos.png" diff --git a/flutter_native_splash.yaml b/flutter_native_splash.yaml new file mode 100644 index 00000000..6b3bc1d7 --- /dev/null +++ b/flutter_native_splash.yaml @@ -0,0 +1,10 @@ +flutter_native_splash: + color: "#f8f9ff" + image: icons/logo.png + android_12: + icon_background_color: "#f8f9ff" + image: icons/logo.png + + android: true + ios: false + web: false diff --git a/pubspec.lock b/pubspec.lock index be9d5cde..8f73cfb2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -22,6 +22,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.7.0" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" + url: "https://pub.dev" + source: hosted + version: "2.0.3" archive: dependency: transitive description: @@ -521,6 +529,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.3+1" + flutter_native_splash: + dependency: "direct dev" + description: + name: flutter_native_splash + sha256: aa06fec78de2190f3db4319dd60fdc8d12b2626e93ef9828633928c2dcaea840 + url: "https://pub.dev" + source: hosted + version: "2.4.1" flutter_portal: dependency: "direct main" description: @@ -1484,6 +1500,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" url_launcher: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 4a9c607e..66dde1e8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -87,6 +87,7 @@ dev_dependencies: build_runner: ^2.4.12 flutter_launcher_icons: ^0.13.1 flutter_lints: ^4.0.0 + flutter_native_splash: ^2.4.1 freezed: ^2.5.7 json_serializable: ^6.7.1 integration_test: From 8082d4f734cd001bd269abcfc9d2c05cb36727b4 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Tue, 17 Sep 2024 22:58:24 +0530 Subject: [PATCH 30/31] Update flutter_native_splash.yaml --- flutter_native_splash.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter_native_splash.yaml b/flutter_native_splash.yaml index 6b3bc1d7..c3b079ce 100644 --- a/flutter_native_splash.yaml +++ b/flutter_native_splash.yaml @@ -2,8 +2,8 @@ flutter_native_splash: color: "#f8f9ff" image: icons/logo.png android_12: - icon_background_color: "#f8f9ff" - image: icons/logo.png + color: "#f8f9ff" + image: icons/logo_android12.png android: true ios: false From d6c4d13b227152ef6b1fd0f9fc63671452b71d8d Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 22 Sep 2024 05:39:20 +0530 Subject: [PATCH 31/31] Update importer.dart --- lib/importer/importer.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/importer/importer.dart b/lib/importer/importer.dart index b4388cd8..37c40a28 100644 --- a/lib/importer/importer.dart +++ b/lib/importer/importer.dart @@ -10,8 +10,6 @@ class Importer { switch (fileType) { case ImportFormat.curl: return CurlFileImport().getHttpRequestModel(content); - default: - return null; } } }