From c51018baac0e1bc940d2d8ab4f25f798cc917f41 Mon Sep 17 00:00:00 2001 From: Mohammed Abdul Razak Wahab Date: Sat, 16 Mar 2024 22:15:18 +0530 Subject: [PATCH 01/20] updated video preview logic --- lib/consts.dart | 5 +- lib/widgets/previewer.dart | 8 +- lib/widgets/video_previewer.dart | 147 +++++++++++++++++++++++++++++++ pubspec.lock | 64 ++++++++++++++ pubspec.yaml | 5 +- test/widgets/previewer_test.dart | 6 +- 6 files changed, 228 insertions(+), 7 deletions(-) create mode 100644 lib/widgets/video_previewer.dart diff --git a/lib/consts.dart b/lib/consts.dart index e3d2dc6b..d188e4a2 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -16,7 +16,7 @@ final kIsLinux = !kIsWeb && Platform.isLinux; final kIsApple = !kIsWeb && (Platform.isIOS || Platform.isMacOS); final kIsDesktop = !kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux); - +final kIsRunningTests = Platform.environment.containsKey('FLUTTER_TEST'); final kIsIOS = !kIsWeb && Platform.isIOS; final kIsAndroid = !kIsWeb && Platform.isAndroid; final kIsMobile = !kIsWeb && (Platform.isIOS || Platform.isAndroid); @@ -496,6 +496,9 @@ const kMimeTypeRaiseIssue = const kUnexpectedRaiseIssue = "\nIf the behaviour is unexpected, please raise an issue in API Dash GitHub repo so that we can resolve it."; +const kVideoError = + "There seems to be an issue playing this video. Please raise an issue in API Dash GitHub repo so that we can resolve it."; + const kImageError = "There seems to be an issue rendering this image. Please raise an issue in API Dash GitHub repo so that we can resolve it."; diff --git a/lib/widgets/previewer.dart b/lib/widgets/previewer.dart index dd2f5186..ac213b50 100644 --- a/lib/widgets/previewer.dart +++ b/lib/widgets/previewer.dart @@ -8,6 +8,7 @@ import 'error_message.dart'; import 'uint8_audio_player.dart'; import 'json_previewer.dart'; import 'csv_previewer.dart'; +import 'video_previewer.dart'; import '../consts.dart'; class Previewer extends StatefulWidget { @@ -86,7 +87,12 @@ class _PreviewerState extends State { return CsvPreviewer(body: widget.body); } if (widget.type == kTypeVideo) { - // TODO: Video Player + try { + var preview = VideoPreviewer(videoBytes: widget.bytes); + return preview; + } catch (e) { + return const ErrorMessage(message: kVideoError); + } } String message = widget.hasRaw ? "$kMimeTypeRawRaiseIssueStart${widget.type}/${widget.subtype}$kMimeTypeRaiseIssue" diff --git a/lib/widgets/video_previewer.dart b/lib/widgets/video_previewer.dart new file mode 100644 index 00000000..a6461b5e --- /dev/null +++ b/lib/widgets/video_previewer.dart @@ -0,0 +1,147 @@ +import 'dart:io'; +import 'dart:typed_data'; +import 'package:apidash/consts.dart'; +import 'package:fvp/fvp.dart' as fvp; +import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; +import 'package:video_player/video_player.dart'; +import 'package:path_provider/path_provider.dart'; + +class VideoPreviewer extends StatefulWidget { + const VideoPreviewer({ + super.key, + required this.videoBytes, + }); + + final Uint8List videoBytes; + + @override + State createState() => _VideoPreviewerState(); +} + +class _VideoPreviewerState extends State { + VideoPlayerController? _videoController; + bool _isPlaying = false; + File? _tempVideoFile; + bool _showControls = false; + + @override + void initState() { + super.initState(); + registerWithAllPlatforms(); + _initializeVideoPlayer(); + } + + void registerWithAllPlatforms() { + try { + fvp.registerWith(); + } catch (e) { + // pass + } + } + + void _initializeVideoPlayer() async { + final tempDir = await getTemporaryDirectory(); + _tempVideoFile = File( + '${tempDir.path}/temp_video_${DateTime.now().millisecondsSinceEpoch}.mp4'); + try { + await _tempVideoFile?.writeAsBytes(widget.videoBytes); + _videoController = VideoPlayerController.file(_tempVideoFile!) + ..initialize().then((_) { + if (mounted) { + setState(() { + _videoController!.play(); + _videoController!.setLooping(true); + }); + } + }); + } catch (e) { + return; + } + } + + @override + Widget build(BuildContext context) { + final iconColor = Theme.of(context).iconTheme.color; + final progressBarColors = VideoProgressColors( + playedColor: iconColor!, + bufferedColor: iconColor.withOpacity(0.5), + backgroundColor: iconColor.withOpacity(0.3), + ); + return Scaffold( + body: MouseRegion( + onEnter: (_) => setState(() => _showControls = true), + onExit: (_) => setState(() => _showControls = false), + child: Stack( + children: [ + Center( + child: _videoController?.value.isInitialized == true + ? AspectRatio( + aspectRatio: _videoController!.value.aspectRatio, + child: VideoPlayer(_videoController!), + ) + : const CircularProgressIndicator(), + ), + Positioned( + left: 0, + right: 0, + bottom: 0, + child: _videoController?.value.isInitialized == true + ? SizedBox( + height: 50.0, + child: VideoProgressIndicator( + _videoController!, + allowScrubbing: true, + padding: const EdgeInsets.all(20), + colors: progressBarColors, + ), + ) + : Container(height: 0), + ), + if (_showControls) + Center( + child: GestureDetector( + onTap: () { + if (_videoController!.value.isPlaying) { + _videoController!.pause(); + } else { + _videoController!.play(); + } + setState(() { + _isPlaying = !_isPlaying; + }); + }, + child: Container( + color: Colors.transparent, + child: Icon( + _isPlaying ? Icons.play_arrow : Icons.pause, + size: 64, + color: iconColor, + ), + ), + ), + ), + ], + ), + ), + ); + } + + @override + void dispose() { + _videoController?.pause(); + _videoController?.dispose(); + if (!kIsRunningTests) { + Future.delayed(const Duration(seconds: 1), () async { + try { + if (_tempVideoFile != null) { + await _tempVideoFile!.delete(); + } + } catch (e) { + return; + } + }); + } + super.dispose(); + } +} diff --git a/pubspec.lock b/pubspec.lock index a4e54dfb..af770260 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -217,6 +217,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" csv: dependency: "direct main" description: @@ -448,6 +456,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" + fvp: + dependency: "direct main" + description: + name: fvp + sha256: "995328479ba4641da6760ddc84a168db157a3b9db4f0417fa68713d99344a146" + url: "https://pub.dev" + source: hosted + version: "0.14.0" glob: dependency: transitive description: @@ -496,6 +512,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" html_unescape: dependency: transitive description: @@ -1294,6 +1318,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + video_player: + dependency: "direct main" + description: + name: video_player + sha256: afc65f4b8bcb2c188f64a591f84fb471f4f2e19fc607c65fd8d2f8fedb3dec23 + url: "https://pub.dev" + source: hosted + version: "2.8.3" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: "4dd9b8b86d70d65eecf3dcabfcdfbb9c9115d244d022654aba49a00336d540c2" + url: "https://pub.dev" + source: hosted + version: "2.4.12" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: "309e3962795e761be010869bae65c0b0e45b5230c5cee1bec72197ca7db040ed" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + video_player_platform_interface: + dependency: "direct main" + description: + name: video_player_platform_interface + sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6" + url: "https://pub.dev" + source: hosted + version: "6.2.2" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "41245cef5ef29c4585dbabcbcbe9b209e34376642c7576cabf11b4ad9289d6e4" + url: "https://pub.dev" + source: hosted + version: "2.3.0" vm_service: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6f78ae1e..1556bc6c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: multi_split_view: ^2.4.0 url_launcher: ^6.2.5 flutter_riverpod: ^2.5.1 - riverpod: ^2.5.1 + riverpod: ^2.5.1 uuid: ^4.3.3 davi: ^3.4.1 http: ^1.2.1 @@ -44,6 +44,9 @@ dependencies: package_info_plus: ^5.0.1 flutter_typeahead: ^5.2.0 provider: ^6.1.2 + fvp: ^0.14.0 + video_player: ^2.3.2 + video_player_platform_interface: ^6.2.2 json_data_explorer: git: url: https://github.com/foss42/json_data_explorer.git diff --git a/test/widgets/previewer_test.dart b/test/widgets/previewer_test.dart index c26793bb..c8a33f62 100644 --- a/test/widgets/previewer_test.dart +++ b/test/widgets/previewer_test.dart @@ -5,6 +5,7 @@ import 'package:apidash/consts.dart'; import 'package:flutter/foundation.dart'; import 'package:printing/printing.dart' show PdfPreview; import 'package:flutter_svg/flutter_svg.dart' show SvgPicture; +import 'package:apidash/widgets/video_previewer.dart'; import '../test_consts.dart'; void main() { @@ -63,10 +64,7 @@ void main() { ), ), ); - - expect( - find.text("${kMimeTypeRaiseIssueStart}video/H264$kMimeTypeRaiseIssue"), - findsOneWidget); + expect(find.byType(VideoPreviewer), findsOneWidget); }); testWidgets('Testing when type/subtype is model/step+xml', (tester) async { From 98c2c46dd7bdf7f57ed71de30b701df313cc9beb Mon Sep 17 00:00:00 2001 From: Yousef Rabia Date: Wed, 20 Mar 2024 10:13:56 +0200 Subject: [PATCH 02/20] add sendingTime var for Request Model class --- lib/models/request_model.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index 0ea6d735..3a04c0eb 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -31,6 +31,7 @@ class RequestModel { this.message, this.responseModel, this.isWorking = false, + this.sendingTime, }); final String id; @@ -50,6 +51,7 @@ class RequestModel { final String? message; final ResponseModel? responseModel; final bool isWorking; + final DateTime? sendingTime; List? get enabledRequestHeaders => getEnabledRows(requestHeaders, isHeaderEnabledList); @@ -133,6 +135,7 @@ class RequestModel { String? message, ResponseModel? responseModel, bool? isWorking, + DateTime? sendingTime, }) { var headers = requestHeaders ?? this.requestHeaders; var params = requestParams ?? this.requestParams; @@ -158,6 +161,7 @@ class RequestModel { message: message ?? this.message, responseModel: responseModel ?? this.responseModel, isWorking: isWorking ?? this.isWorking, + sendingTime: sendingTime ?? this.sendingTime, ); } From 99c8a002788e110e17e03fa3121c61567bc6329d Mon Sep 17 00:00:00 2001 From: Yousef Rabia Date: Wed, 20 Mar 2024 10:14:30 +0200 Subject: [PATCH 03/20] Add timer for sending widget --- lib/providers/collection_providers.dart | 5 +- .../details_card/response_pane.dart | 7 +- lib/widgets/response_widgets.dart | 75 ++++++++++++++++--- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index db6b7cf3..9946112f 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -180,7 +180,8 @@ class CollectionStateNotifier // set current model's isWorking to true and update state var map = {...state!}; - map[id] = requestModel.copyWith(isWorking: true); + map[id] = + requestModel.copyWith(isWorking: true, sendingTime: DateTime.now()); state = map; (http.Response?, Duration?, String?)? responseRec = await request( @@ -193,6 +194,7 @@ class CollectionStateNotifier responseStatus: -1, message: responseRec.$3, isWorking: false, + sendingTime: null, ); } else { final responseModel = baseResponseModel.fromResponse( @@ -205,6 +207,7 @@ class CollectionStateNotifier message: kResponseCodeReasons[statusCode], responseModel: responseModel, isWorking: false, + sendingTime: null, ); } diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 703b873d..2cd0cbc9 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -12,12 +12,17 @@ class ResponsePane extends ConsumerWidget { final isWorking = ref.watch( selectedRequestModelProvider.select((value) => value?.isWorking)) ?? false; + final startSendingDate = ref.watch( + selectedRequestModelProvider.select((value) => value?.sendingTime)); final responseStatus = ref.watch( selectedRequestModelProvider.select((value) => value?.responseStatus)); final message = ref .watch(selectedRequestModelProvider.select((value) => value?.message)); + if (isWorking) { - return const SendingWidget(); + return SendingWidget( + startSendingTime: startSendingDate, + ); } if (responseStatus == null) { return const NotSentWidget(); diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index adf74985..66fbc083 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -1,3 +1,6 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http_parser/http_parser.dart'; @@ -24,8 +27,10 @@ class NotSentWidget extends StatelessWidget { ), Text( 'Not Sent', - style: - Theme.of(context).textTheme.titleMedium?.copyWith(color: color), + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(color: color), ), ], ), @@ -33,17 +38,69 @@ class NotSentWidget extends StatelessWidget { } } -class SendingWidget extends StatelessWidget { - const SendingWidget({super.key}); +class SendingWidget extends StatefulWidget { + final DateTime? startSendingTime; + const SendingWidget({super.key, required this.startSendingTime}); + + @override + State createState() => _SendingWidgetState(); +} + +class _SendingWidgetState extends State { + int _millisecondsElapsed = 0; + Timer? _timer; + + @override + void initState() { + super.initState(); + if (widget.startSendingTime != null) { + _millisecondsElapsed = + DateTime.now().difference(widget.startSendingTime!).inMilliseconds; + _timer = Timer.periodic(const Duration(milliseconds: 10), _updateTimer); + } + } + + void _updateTimer(Timer timer) { + setState(() { + _millisecondsElapsed += 10; + }); + } + + @override + void dispose() { + if (_timer != null && _timer!.isActive) _timer?.cancel(); + super.dispose(); + } @override Widget build(BuildContext context) { return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Lottie.asset("assets/sending.json"), - ], + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Visibility( + visible: _millisecondsElapsed > 0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.alarm), + const SizedBox( + width: 10, + ), + Text( + 'Time elapsed: ${humanizeDuration(Duration(milliseconds: _millisecondsElapsed))}', + textAlign: TextAlign.center, + overflow: TextOverflow.fade, + softWrap: false, + style: kTextStyleButton, + ), + ], + ), + ), + Lottie.asset("assets/sending.json"), + ], + ), ), ); } From fec18be44b826c17cec73edc22fc041d80f87721 Mon Sep 17 00:00:00 2001 From: Yousef Rabia Date: Wed, 20 Mar 2024 10:15:06 +0200 Subject: [PATCH 04/20] unit testing for SendingWidget --- test/widgets/response_widgets_test.dart | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/widgets/response_widgets_test.dart b/test/widgets/response_widgets_test.dart index 7877a285..3bdd42a8 100644 --- a/test/widgets/response_widgets_test.dart +++ b/test/widgets/response_widgets_test.dart @@ -10,13 +10,31 @@ import 'package:apidash/models/models.dart'; import '../test_consts.dart'; void main() { - testWidgets('Testing Sending Widget', (tester) async { + testWidgets('Testing Sending Widget Without Timer', (tester) async { await tester.pumpWidget( MaterialApp( title: 'Send', theme: kThemeDataDark, home: const Scaffold( - body: SendingWidget(), + body: SendingWidget( + startSendingTime: null, + ), + ), + ), + ); + + expect(find.byType(Lottie), findsOneWidget); + }); + + testWidgets('Testing Sending Widget With Timer', (tester) async { + await tester.pumpWidget( + MaterialApp( + title: 'Send', + theme: kThemeDataDark, + home: Scaffold( + body: SendingWidget( + startSendingTime: DateTime.now(), + ), ), ), ); From f26ba583cc301d9ca60cce4e9a69af80672f048e Mon Sep 17 00:00:00 2001 From: Yousef Rabia Date: Thu, 21 Mar 2024 00:32:20 +0200 Subject: [PATCH 05/20] update timer testing function --- lib/widgets/response_widgets.dart | 12 ++++++------ test/widgets/response_widgets_test.dart | 7 ++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index 66fbc083..22e84a1e 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http_parser/http_parser.dart'; @@ -40,7 +39,8 @@ class NotSentWidget extends StatelessWidget { class SendingWidget extends StatefulWidget { final DateTime? startSendingTime; - const SendingWidget({super.key, required this.startSendingTime}); + final bool isTest; + const SendingWidget({super.key, required this.startSendingTime, this.isTest=false}); @override State createState() => _SendingWidgetState(); @@ -54,15 +54,15 @@ class _SendingWidgetState extends State { void initState() { super.initState(); if (widget.startSendingTime != null) { - _millisecondsElapsed = + _millisecondsElapsed = widget.isTest ? 0 : DateTime.now().difference(widget.startSendingTime!).inMilliseconds; - _timer = Timer.periodic(const Duration(milliseconds: 10), _updateTimer); + _timer = Timer.periodic(const Duration(milliseconds: 100), _updateTimer); } } void _updateTimer(Timer timer) { setState(() { - _millisecondsElapsed += 10; + _millisecondsElapsed += 100; }); } @@ -80,7 +80,7 @@ class _SendingWidgetState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Visibility( - visible: _millisecondsElapsed > 0, + visible: _millisecondsElapsed >= 0, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ diff --git a/test/widgets/response_widgets_test.dart b/test/widgets/response_widgets_test.dart index 3bdd42a8..a8def9cc 100644 --- a/test/widgets/response_widgets_test.dart +++ b/test/widgets/response_widgets_test.dart @@ -34,12 +34,17 @@ void main() { home: Scaffold( body: SendingWidget( startSendingTime: DateTime.now(), + isTest: true, ), ), ), ); - + expect(find.text('Time elapsed: 0 ms'), findsOneWidget); expect(find.byType(Lottie), findsOneWidget); + + await tester.pump(const Duration(seconds: 1)); + + expect(find.text('Time elapsed: 1.00 s'), findsOneWidget); }); testWidgets('Testing Not Sent Widget', (tester) async { From 12ab5e0b99d7db784646cad7f5ee447c75bc4187 Mon Sep 17 00:00:00 2001 From: Yousef Rabia Date: Thu, 21 Mar 2024 00:42:41 +0200 Subject: [PATCH 06/20] Renamed variable --- .../home_page/editor_pane/details_card/response_pane.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 2cd0cbc9..4a240932 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -12,7 +12,7 @@ class ResponsePane extends ConsumerWidget { final isWorking = ref.watch( selectedRequestModelProvider.select((value) => value?.isWorking)) ?? false; - final startSendingDate = ref.watch( + final startSendingTime = ref.watch( selectedRequestModelProvider.select((value) => value?.sendingTime)); final responseStatus = ref.watch( selectedRequestModelProvider.select((value) => value?.responseStatus)); @@ -21,7 +21,7 @@ class ResponsePane extends ConsumerWidget { if (isWorking) { return SendingWidget( - startSendingTime: startSendingDate, + startSendingTime: startSendingTime, ); } if (responseStatus == null) { From 83b3031a9a7370267e4a7f1426c162c77e67dfc5 Mon Sep 17 00:00:00 2001 From: Yousef Rabia Date: Thu, 21 Mar 2024 00:45:25 +0200 Subject: [PATCH 07/20] Update collection_providers.dart --- lib/providers/collection_providers.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 9946112f..07e26822 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -194,7 +194,6 @@ class CollectionStateNotifier responseStatus: -1, message: responseRec.$3, isWorking: false, - sendingTime: null, ); } else { final responseModel = baseResponseModel.fromResponse( @@ -207,7 +206,6 @@ class CollectionStateNotifier message: kResponseCodeReasons[statusCode], responseModel: responseModel, isWorking: false, - sendingTime: null, ); } From 1db26fa86fd1947895026929f8c9ba138dcbc426 Mon Sep 17 00:00:00 2001 From: Yousef Rabia Date: Fri, 22 Mar 2024 00:41:44 +0200 Subject: [PATCH 08/20] use kAssetSendingLottie --- lib/widgets/response_widgets.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index 22e84a1e..a2f2183a 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -98,7 +98,7 @@ class _SendingWidgetState extends State { ], ), ), - Lottie.asset("assets/sending.json"), + Lottie.asset(kAssetSendingLottie), ], ), ), From ef48f2947fddd06a029c34f8107344271d84b8ca Mon Sep 17 00:00:00 2001 From: Yousef Rabia Date: Sun, 24 Mar 2024 03:49:21 +0200 Subject: [PATCH 09/20] Replace SingleChildScrollView and Column with Stack --- lib/widgets/response_widgets.dart | 56 ++++++++++++++++--------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index a2f2183a..8228f781 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http_parser/http_parser.dart'; @@ -74,36 +75,37 @@ class _SendingWidgetState extends State { @override Widget build(BuildContext context) { - return Center( - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Visibility( - visible: _millisecondsElapsed >= 0, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.alarm), - const SizedBox( - width: 10, - ), - Text( - 'Time elapsed: ${humanizeDuration(Duration(milliseconds: _millisecondsElapsed))}', - textAlign: TextAlign.center, - overflow: TextOverflow.fade, - softWrap: false, - style: kTextStyleButton, - ), - ], - ), - ), - Lottie.asset(kAssetSendingLottie), - ], + return Stack( + children: [ + Center( + child: Lottie.asset(kAssetSendingLottie), ), - ), + Padding( + padding: kPh20t40, + child: Visibility( + visible: _millisecondsElapsed >= 0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.alarm), + const SizedBox( + width: 10, + ), + Text( + 'Time elapsed: ${humanizeDuration(Duration(milliseconds: _millisecondsElapsed))}', + textAlign: TextAlign.center, + overflow: TextOverflow.fade, + softWrap: false, + style: kTextStyleButton, + ), + ], + ), + ), + ), + ], ); } + } class ResponsePaneHeader extends StatelessWidget { From 017bc4f1085181c0c42e1b3b52d21c78d948bf4a Mon Sep 17 00:00:00 2001 From: Yashas H Majmudar Date: Wed, 27 Mar 2024 22:06:32 +0530 Subject: [PATCH 10/20] fix: prompt only when changes made --- lib/app.dart | 2 +- lib/providers/collection_providers.dart | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index f60198af..caae2729 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -57,7 +57,7 @@ class _AppState extends ConsumerState with WindowListener { bool isPreventClose = await windowManager.isPreventClose(); if (isPreventClose) { if (ref.watch( - settingsProvider.select((value) => value.promptBeforeClosing))) { + settingsProvider.select((value) => value.promptBeforeClosing)) && ref.watch(collectionStateNotifierProvider.notifier).changed) { showDialog( context: context, builder: (_) => AlertDialog( diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 75e9d7c5..efe93967 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -1,11 +1,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'settings_providers.dart'; -import 'ui_providers.dart'; +import 'package:http/http.dart' as http; + +import '../consts.dart'; import '../models/models.dart'; import '../services/services.dart' show hiveHandler, HiveHandler, request; import '../utils/utils.dart' show getNewUuid, collectionToHAR; -import '../consts.dart'; -import 'package:http/http.dart' as http; +import 'settings_providers.dart'; +import 'ui_providers.dart'; final selectedIdStateProvider = StateProvider((ref) => null); @@ -46,6 +47,7 @@ class CollectionStateNotifier final Ref ref; final HiveHandler hiveHandler; final baseResponseModel = const ResponseModel(); + bool changed = false; bool hasId(String id) => state?.keys.contains(id) ?? false; @@ -61,6 +63,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newRequestModel; state = map; + changed = true; ref .read(requestSequenceProvider.notifier) .update((state) => [id, ...state]); @@ -94,6 +97,7 @@ class CollectionStateNotifier var map = {...state!}; map.remove(id); state = map; + changed = true; } void clearResponse(String? id) { @@ -107,6 +111,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newModel; state = map; + changed = true; } void duplicate(String id) { @@ -123,6 +128,7 @@ class CollectionStateNotifier var map = {...state!}; map[newId] = newModel; state = map; + changed = true; ref.read(requestSequenceProvider.notifier).state = [...itemIds]; ref.read(selectedIdStateProvider.notifier).state = newId; @@ -167,6 +173,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newModel; state = map; + changed = true; } Future sendRequest(String id) async { @@ -183,6 +190,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = requestModel.copyWith(isWorking: true); state = map; + changed = true; (http.Response?, Duration?, String?)? responseRec = await request( requestModel, @@ -213,6 +221,7 @@ class CollectionStateNotifier map = {...state!}; map[id] = newRequestModel; state = map; + changed = true; } Future clearData() async { @@ -222,6 +231,7 @@ class CollectionStateNotifier ref.read(clearDataStateProvider.notifier).state = false; ref.read(requestSequenceProvider.notifier).state = []; state = {}; + changed = true; } bool loadData() { From 0c04ff3343628a63916bc26f88d55975d796ce9f Mon Sep 17 00:00:00 2001 From: Yashas H Majmudar Date: Wed, 27 Mar 2024 22:10:11 +0530 Subject: [PATCH 11/20] fix: prompt when changes made to reorder --- lib/providers/collection_providers.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index efe93967..6c3f1411 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -75,6 +75,7 @@ class CollectionStateNotifier final itemId = itemIds.removeAt(oldIdx); itemIds.insert(newIdx, itemId); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; + changed = true; } void remove(String id) { From 83c6e428644abd0c4624d999c7267b7ba24b8265 Mon Sep 17 00:00:00 2001 From: Yashas H Majmudar Date: Thu, 28 Mar 2024 14:25:26 +0530 Subject: [PATCH 12/20] fix: cleanup code and logic fixup --- lib/app.dart | 2 +- lib/providers/collection_providers.dart | 19 +++++++++---------- lib/providers/ui_providers.dart | 2 ++ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index caae2729..f6bc7c51 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -57,7 +57,7 @@ class _AppState extends ConsumerState with WindowListener { bool isPreventClose = await windowManager.isPreventClose(); if (isPreventClose) { if (ref.watch( - settingsProvider.select((value) => value.promptBeforeClosing)) && ref.watch(collectionStateNotifierProvider.notifier).changed) { + settingsProvider.select((value) => value.promptBeforeClosing)) && ref.watch(changeMadeProvider)) { showDialog( context: context, builder: (_) => AlertDialog( diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 6c3f1411..ae76450a 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -47,7 +47,6 @@ class CollectionStateNotifier final Ref ref; final HiveHandler hiveHandler; final baseResponseModel = const ResponseModel(); - bool changed = false; bool hasId(String id) => state?.keys.contains(id) ?? false; @@ -63,7 +62,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newRequestModel; state = map; - changed = true; + ref.read(changeMadeProvider.notifier).update((_) => true); ref .read(requestSequenceProvider.notifier) .update((state) => [id, ...state]); @@ -75,7 +74,7 @@ class CollectionStateNotifier final itemId = itemIds.removeAt(oldIdx); itemIds.insert(newIdx, itemId); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; - changed = true; + ref.read(changeMadeProvider.notifier).update((_) => true); } void remove(String id) { @@ -98,7 +97,7 @@ class CollectionStateNotifier var map = {...state!}; map.remove(id); state = map; - changed = true; + ref.read(changeMadeProvider.notifier).update((_) => true); } void clearResponse(String? id) { @@ -112,7 +111,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newModel; state = map; - changed = true; + ref.read(changeMadeProvider.notifier).update((_) => true); } void duplicate(String id) { @@ -129,7 +128,7 @@ class CollectionStateNotifier var map = {...state!}; map[newId] = newModel; state = map; - changed = true; + ref.read(changeMadeProvider.notifier).update((_) => true); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; ref.read(selectedIdStateProvider.notifier).state = newId; @@ -174,7 +173,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newModel; state = map; - changed = true; + ref.read(changeMadeProvider.notifier).update((_) => true); } Future sendRequest(String id) async { @@ -191,7 +190,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = requestModel.copyWith(isWorking: true); state = map; - changed = true; + ref.read(changeMadeProvider.notifier).update((_) => true); (http.Response?, Duration?, String?)? responseRec = await request( requestModel, @@ -222,7 +221,7 @@ class CollectionStateNotifier map = {...state!}; map[id] = newRequestModel; state = map; - changed = true; + ref.read(changeMadeProvider.notifier).update((_) => true); } Future clearData() async { @@ -232,7 +231,7 @@ class CollectionStateNotifier ref.read(clearDataStateProvider.notifier).state = false; ref.read(requestSequenceProvider.notifier).state = []; state = {}; - changed = true; + ref.read(changeMadeProvider.notifier).update((_) => false); } bool loadData() { diff --git a/lib/providers/ui_providers.dart b/lib/providers/ui_providers.dart index 62f83f70..22e2b611 100644 --- a/lib/providers/ui_providers.dart +++ b/lib/providers/ui_providers.dart @@ -6,6 +6,8 @@ final selectedIdEditStateProvider = StateProvider((ref) => null); final codePaneVisibleStateProvider = StateProvider((ref) => false); final saveDataStateProvider = StateProvider((ref) => false); final clearDataStateProvider = StateProvider((ref) => false); +final changeMadeProvider = StateProvider((ref) => false); + // final nameTextFieldControllerProvider = // StateProvider.autoDispose((ref) { // TextEditingController controller = TextEditingController(text: ""); From 34f9d27567a1f63c9cb75b7605b4558b5daa8698 Mon Sep 17 00:00:00 2001 From: Yashas H Majmudar Date: Thu, 28 Mar 2024 17:09:08 +0530 Subject: [PATCH 13/20] fix: renamed changeMade -> hasUnsavedChanges --- lib/app.dart | 2 +- lib/providers/collection_providers.dart | 18 +++++++++--------- lib/providers/ui_providers.dart | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index f6bc7c51..70e95213 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -57,7 +57,7 @@ class _AppState extends ConsumerState with WindowListener { bool isPreventClose = await windowManager.isPreventClose(); if (isPreventClose) { if (ref.watch( - settingsProvider.select((value) => value.promptBeforeClosing)) && ref.watch(changeMadeProvider)) { + settingsProvider.select((value) => value.promptBeforeClosing)) && ref.watch(hasUnsavedChangesProvider)) { showDialog( context: context, builder: (_) => AlertDialog( diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index ae76450a..4a5f5d56 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -62,7 +62,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newRequestModel; state = map; - ref.read(changeMadeProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); ref .read(requestSequenceProvider.notifier) .update((state) => [id, ...state]); @@ -74,7 +74,7 @@ class CollectionStateNotifier final itemId = itemIds.removeAt(oldIdx); itemIds.insert(newIdx, itemId); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; - ref.read(changeMadeProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); } void remove(String id) { @@ -97,7 +97,7 @@ class CollectionStateNotifier var map = {...state!}; map.remove(id); state = map; - ref.read(changeMadeProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); } void clearResponse(String? id) { @@ -111,7 +111,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newModel; state = map; - ref.read(changeMadeProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); } void duplicate(String id) { @@ -128,7 +128,7 @@ class CollectionStateNotifier var map = {...state!}; map[newId] = newModel; state = map; - ref.read(changeMadeProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; ref.read(selectedIdStateProvider.notifier).state = newId; @@ -173,7 +173,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newModel; state = map; - ref.read(changeMadeProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); } Future sendRequest(String id) async { @@ -190,7 +190,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = requestModel.copyWith(isWorking: true); state = map; - ref.read(changeMadeProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); (http.Response?, Duration?, String?)? responseRec = await request( requestModel, @@ -221,7 +221,7 @@ class CollectionStateNotifier map = {...state!}; map[id] = newRequestModel; state = map; - ref.read(changeMadeProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); } Future clearData() async { @@ -231,7 +231,7 @@ class CollectionStateNotifier ref.read(clearDataStateProvider.notifier).state = false; ref.read(requestSequenceProvider.notifier).state = []; state = {}; - ref.read(changeMadeProvider.notifier).update((_) => false); + ref.read(hasUnsavedChangesProvider.notifier).update((_) => false); } bool loadData() { diff --git a/lib/providers/ui_providers.dart b/lib/providers/ui_providers.dart index 22e2b611..e4b10677 100644 --- a/lib/providers/ui_providers.dart +++ b/lib/providers/ui_providers.dart @@ -6,7 +6,7 @@ final selectedIdEditStateProvider = StateProvider((ref) => null); final codePaneVisibleStateProvider = StateProvider((ref) => false); final saveDataStateProvider = StateProvider((ref) => false); final clearDataStateProvider = StateProvider((ref) => false); -final changeMadeProvider = StateProvider((ref) => false); +final hasUnsavedChangesProvider = StateProvider((ref) => false); // final nameTextFieldControllerProvider = // StateProvider.autoDispose((ref) { From 20cf67a594aa8f25468c2e187208cd3625834471 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Thu, 28 Mar 2024 21:11:22 +0530 Subject: [PATCH 14/20] fixes --- lib/consts.dart | 2 +- lib/widgets/video_previewer.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/consts.dart b/lib/consts.dart index d188e4a2..00130897 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -387,7 +387,7 @@ const Map>> kSubTypeDefaultViewOptions: kPreviewBodyViewOptions, }, kTypeVideo: { - kSubTypeDefaultViewOptions: kNoBodyViewOptions, + kSubTypeDefaultViewOptions: kPreviewBodyViewOptions, }, kTypeText: { kSubTypeDefaultViewOptions: kRawBodyViewOptions, diff --git a/lib/widgets/video_previewer.dart b/lib/widgets/video_previewer.dart index a6461b5e..c077e569 100644 --- a/lib/widgets/video_previewer.dart +++ b/lib/widgets/video_previewer.dart @@ -43,7 +43,7 @@ class _VideoPreviewerState extends State { void _initializeVideoPlayer() async { final tempDir = await getTemporaryDirectory(); _tempVideoFile = File( - '${tempDir.path}/temp_video_${DateTime.now().millisecondsSinceEpoch}.mp4'); + '${tempDir.path}/temp_video_${DateTime.now().millisecondsSinceEpoch}'); try { await _tempVideoFile?.writeAsBytes(widget.videoBytes); _videoController = VideoPlayerController.file(_tempVideoFile!) From 4a92a621ad3c01a679e58c07df81d02e6bb6c8b7 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Thu, 28 Mar 2024 21:23:56 +0530 Subject: [PATCH 15/20] Update README.md --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f6f73d62..3297c14e 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,16 @@ Here is the complete list of mimetypes that can be directly previewed in API Das | File Type | Mimetype | Extension | Comment | | --------- | -------------------------- | ----------------- | -------- | | PDF | `application/pdf` | `.pdf` | | -| CSV | `text/csv` | `.csv` | Can be improved | +| Video | `video/mp4` | `.mp4` | | +| Video | `video/webm` | `.webm` | | +| Video | `video/x-ms-wmv` | `.wmv` | | +| Video | `video/x-ms-asf` | `.wmv` | | +| Video | `video/avi` | `.avi` | | +| Video | `video/msvideo` | `.avi` | | +| Video | `video/x-msvideo` | `.avi` | | +| Video | `video/quicktime` | `.mov` | | +| Video | `video/x-quicktime` | `.mov` | | +| Video | `video/x-matroska` | `.mkv` | | | Image | `image/apng` | `.apng` | Animated | | Image | `image/avif` | `.avif` | | | Image | `image/bmp` | `.bmp` | | @@ -188,6 +197,7 @@ Here is the complete list of mimetypes that can be directly previewed in API Das | Audio | `audio/x-m4a` | `.m4a` | | | Audio | `audio/wav` | `.wav` | | | Audio | `audio/wave` | `.wav` | | +| CSV | `text/csv` | `.csv` | Can be improved | We welcome PRs to add support for previewing other multimedia mimetypes. Please go ahead and raise an issue so that we can discuss the approach. We are adding support for other mimetypes with each release. But, if you are looking for any particular mimetype support, please go ahead and open an issue. We will prioritize it's addition. From 4932be5ba75e122237da444a2075a28729669e1d Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Thu, 28 Mar 2024 21:46:54 +0530 Subject: [PATCH 16/20] Update collection_providers.dart --- lib/providers/collection_providers.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 5068f4ce..8f00b039 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -181,8 +181,10 @@ class CollectionStateNotifier // set current model's isWorking to true and update state var map = {...state!}; - map[id] = - requestModel.copyWith(isWorking: true, sendingTime: DateTime.now()); + map[id] = requestModel.copyWith( + isWorking: true, + sendingTime: DateTime.now(), + ); state = map; (http.Response?, Duration?, String?)? responseRec = await request( From 6c8686de0affb7f8b3fad5e11e6ef6d3c003135b Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Thu, 28 Mar 2024 22:02:25 +0530 Subject: [PATCH 17/20] Fix time elapsed sending widget --- lib/widgets/response_widgets.dart | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index 2d913f17..a3d9f20b 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -1,6 +1,4 @@ import 'dart:async'; - -import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http_parser/http_parser.dart'; @@ -38,8 +36,10 @@ class NotSentWidget extends StatelessWidget { class SendingWidget extends StatefulWidget { final DateTime? startSendingTime; - final bool isTest; - const SendingWidget({super.key, required this.startSendingTime, this.isTest=false}); + const SendingWidget({ + super.key, + required this.startSendingTime, + }); @override State createState() => _SendingWidgetState(); @@ -53,8 +53,10 @@ class _SendingWidgetState extends State { void initState() { super.initState(); if (widget.startSendingTime != null) { - _millisecondsElapsed = widget.isTest ? 0 : - DateTime.now().difference(widget.startSendingTime!).inMilliseconds; + _millisecondsElapsed = + (DateTime.now().difference(widget.startSendingTime!).inMilliseconds ~/ + 100) * + 100; _timer = Timer.periodic(const Duration(milliseconds: 100), _updateTimer); } } @@ -85,7 +87,10 @@ class _SendingWidgetState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.alarm), + Icon( + Icons.alarm, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), const SizedBox( width: 10, ), @@ -94,7 +99,9 @@ class _SendingWidgetState extends State { textAlign: TextAlign.center, overflow: TextOverflow.fade, softWrap: false, - style: kTextStyleButton, + style: kTextStyleButton.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), ), ], ), @@ -103,7 +110,6 @@ class _SendingWidgetState extends State { ], ); } - } class ResponsePaneHeader extends StatelessWidget { From 5c74a92296d38ad0f4559caf7507eeffbaa25364 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Thu, 28 Mar 2024 22:06:14 +0530 Subject: [PATCH 18/20] Update response_widgets_test.dart --- test/widgets/response_widgets_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/test/widgets/response_widgets_test.dart b/test/widgets/response_widgets_test.dart index 3bd5d2d6..c5617035 100644 --- a/test/widgets/response_widgets_test.dart +++ b/test/widgets/response_widgets_test.dart @@ -34,7 +34,6 @@ void main() { home: Scaffold( body: SendingWidget( startSendingTime: DateTime.now(), - isTest: true, ), ), ), From 4518d54af3ff0cbe87f1e60e8c088467b9113d1c Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Thu, 28 Mar 2024 23:35:45 +0530 Subject: [PATCH 19/20] Update collection_providers.dart --- lib/providers/collection_providers.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 4a5f5d56..92b07124 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -62,11 +62,11 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newRequestModel; state = map; - ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); ref .read(requestSequenceProvider.notifier) .update((state) => [id, ...state]); ref.read(selectedIdStateProvider.notifier).state = newRequestModel.id; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void reorder(int oldIdx, int newIdx) { @@ -74,7 +74,7 @@ class CollectionStateNotifier final itemId = itemIds.removeAt(oldIdx); itemIds.insert(newIdx, itemId); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; - ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void remove(String id) { @@ -97,7 +97,7 @@ class CollectionStateNotifier var map = {...state!}; map.remove(id); state = map; - ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void clearResponse(String? id) { @@ -111,7 +111,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newModel; state = map; - ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void duplicate(String id) { @@ -128,10 +128,10 @@ class CollectionStateNotifier var map = {...state!}; map[newId] = newModel; state = map; - ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; ref.read(selectedIdStateProvider.notifier).state = newId; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void update( @@ -173,7 +173,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newModel; state = map; - ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).state = true; } Future sendRequest(String id) async { @@ -190,7 +190,6 @@ class CollectionStateNotifier var map = {...state!}; map[id] = requestModel.copyWith(isWorking: true); state = map; - ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); (http.Response?, Duration?, String?)? responseRec = await request( requestModel, @@ -221,7 +220,7 @@ class CollectionStateNotifier map = {...state!}; map[id] = newRequestModel; state = map; - ref.read(hasUnsavedChangesProvider.notifier).update((_) => true); + ref.read(hasUnsavedChangesProvider.notifier).state = true; } Future clearData() async { @@ -231,7 +230,7 @@ class CollectionStateNotifier ref.read(clearDataStateProvider.notifier).state = false; ref.read(requestSequenceProvider.notifier).state = []; state = {}; - ref.read(hasUnsavedChangesProvider.notifier).update((_) => false); + ref.read(hasUnsavedChangesProvider.notifier).state = true; } bool loadData() { @@ -272,6 +271,7 @@ class CollectionStateNotifier } await hiveHandler.removeUnused(); ref.read(saveDataStateProvider.notifier).state = false; + ref.read(hasUnsavedChangesProvider.notifier).state = false; } Future> exportDataToHAR() async { From 5f09e19f8ccfd138cb82343906046de3b725c50d Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Thu, 28 Mar 2024 23:35:58 +0530 Subject: [PATCH 20/20] Update collection_pane.dart --- lib/screens/home_page/collection_pane.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/screens/home_page/collection_pane.dart b/lib/screens/home_page/collection_pane.dart index 0ede2021..934c5b66 100644 --- a/lib/screens/home_page/collection_pane.dart +++ b/lib/screens/home_page/collection_pane.dart @@ -15,6 +15,7 @@ class CollectionPane extends ConsumerWidget { final overlayWidget = OverlayWidgetTemplate(context: context); final collection = ref.watch(collectionStateNotifierProvider); final savingData = ref.watch(saveDataStateProvider); + final hasUnsavedChanges = ref.watch(hasUnsavedChangesProvider); if (collection == null) { return const Center( child: CircularProgressIndicator(), @@ -31,7 +32,7 @@ class CollectionPane extends ConsumerWidget { alignment: WrapAlignment.spaceBetween, children: [ TextButton.icon( - onPressed: savingData + onPressed: (savingData || !hasUnsavedChanges) ? null : () async { overlayWidget.show(